Display_Avr_3/hdlc/hdlc.c
2023-06-06 19:59:18 +03:00

164 lines
5.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "hdlc.h"
#define FRAME_BOUNDARY_OCTET 0x7E
/* "Управляющий экранирующий октет", имеет битовую последовательность '01111101', (7D шестнадцатеричный) */
#define CONTROL_ESCAPE_OCTET 0x7D
/* Если любой из этих двух октетов появляется в передаваемых данных, отправляется экранирующий октет, */
/* за которым следует исходный октет данных с инвертированным битом 5 */
#define INVERT_OCTET 0x20
/* Последовательность проверки кадров (FCS) представляет собой 16-битный CRC-CCITT */
/* Функция AVR Libc CRC - это _crc_ccitt_update() */
#define CRC16_CCITT_INIT_VAL 0xFFFF
/* 16-битный копировальный аппарат с младшими и старшими байтами */
#define low(x) ((x) & 0xFF)
#define high(x) (((x)>>8) & 0xFF)
#define lo8(x) ((x)&0xff)
#define hi8(x) ((x)>>8)
struct {
sendchar_type sendchar_function;
frame_handler_type frame_handler;
bool escape_character;
uint16_t frame_position;
uint16_t frame_checksum;
uint8_t receive_frame_buffer[MINIHDLC_MAX_FRAME_LENGTH + 1];
} mhst;
static uint16_t _crc_ccitt_update(uint16_t crc, uint8_t data) {
data ^= lo8(crc);
data ^= data << 4;
return ((((uint16_t) data << 8) | hi8(crc)) ^ (uint8_t) (data >> 4)
^ ((uint16_t) data << 3));
}
void hdlc_init(sendchar_type sendchar_function,
frame_handler_type frame_hander_function) {
mhst.sendchar_function = sendchar_function;
mhst.frame_handler = frame_hander_function;
mhst.frame_position = 0;
mhst.frame_checksum = CRC16_CCITT_INIT_VAL;
mhst.escape_character = false;
}
/* Функция для отправки байта через UART*/
static inline void hdlc_sendchar(uint8_t data) {
if (mhst.sendchar_function) {
(*mhst.sendchar_function)(data);
}
}
/* Функция для поиска допустимого кадра HDLC по входящим данным */
void hdlc_char_receiver(uint8_t data) {
/* FRAME FLAG */
if (data == FRAME_BOUNDARY_OCTET) {
if (mhst.escape_character == true) {
mhst.escape_character = false;
}
/* Если обнаружен допустимый кадр */
else if ((mhst.frame_position >= 2)
&& (mhst.frame_checksum
== ((mhst.receive_frame_buffer[mhst.frame_position - 1]
<< 8)
| (mhst.receive_frame_buffer[mhst.frame_position
- 2] & 0xff))))
{
/* Вызовите пользовательскую функцию и передайте ей фрейм */
(*mhst.frame_handler)(mhst.receive_frame_buffer,
mhst.frame_position - 2);
}
mhst.frame_position = 0;
mhst.frame_checksum = CRC16_CCITT_INIT_VAL;
return;
}
if (mhst.escape_character) {
mhst.escape_character = false;
data ^= INVERT_OCTET;
} else if (data == CONTROL_ESCAPE_OCTET) {
mhst.escape_character = true;
return;
}
mhst.receive_frame_buffer[mhst.frame_position] = data;
if (mhst.frame_position - 2 >= 0) {
mhst.frame_checksum = _crc_ccitt_update(mhst.frame_checksum,
mhst.receive_frame_buffer[mhst.frame_position - 2]);
}
mhst.frame_position++;
if (mhst.frame_position == MINIHDLC_MAX_FRAME_LENGTH) {
mhst.frame_position = 0;
mhst.frame_checksum = CRC16_CCITT_INIT_VAL;
}
}
/* Оберните заданные данные во фрейм HDLC и отправляйте их по байту за раз */
void hdlc_send_frame(const uint8_t *frame_buffer, uint8_t frame_length) {
uint8_t data;
uint16_t fcs = CRC16_CCITT_INIT_VAL;
hdlc_sendchar((uint8_t) FRAME_BOUNDARY_OCTET);
while (frame_length) {
data = *frame_buffer++;
fcs = _crc_ccitt_update(fcs, data);
if ((data == CONTROL_ESCAPE_OCTET) || (data == FRAME_BOUNDARY_OCTET)) {
hdlc_sendchar((uint8_t) CONTROL_ESCAPE_OCTET);
data ^= INVERT_OCTET;
}
hdlc_sendchar((uint8_t) data);
frame_length--;
}
data = low(fcs);
if ((data == CONTROL_ESCAPE_OCTET) || (data == FRAME_BOUNDARY_OCTET)) {
hdlc_sendchar((uint8_t) CONTROL_ESCAPE_OCTET);
data ^= (uint8_t) INVERT_OCTET;
}
hdlc_sendchar((uint8_t) data);
data = high(fcs);
if ((data == CONTROL_ESCAPE_OCTET) || (data == FRAME_BOUNDARY_OCTET)) {
hdlc_sendchar(CONTROL_ESCAPE_OCTET);
data ^= INVERT_OCTET;
}
hdlc_sendchar(data);
hdlc_sendchar(FRAME_BOUNDARY_OCTET);
}
/* Оберните заданные данные во фрейм HDLC и отправьте их в статический буфер */
static uint8_t frame_buffer[MINIHDLC_MAX_FRAME_LENGTH + 1];
static uint32_t frame_buffer_size = 0;
static void buffer_init() {
frame_buffer_size = 0;
}
static void buffer_push(uint8_t data) {
if (frame_buffer_size >= MINIHDLC_MAX_FRAME_LENGTH) {
return;
}
frame_buffer[frame_buffer_size] = data;
frame_buffer_size++;
}
void hdlc_send_frame_to_buffer(const uint8_t *frame_buffer, uint8_t frame_length) {
mhst.sendchar_function = buffer_push;
buffer_init();
hdlc_send_frame(frame_buffer, frame_length);
}
uint8_t *hdlc_get_buffer() {
return frame_buffer;
}
uint32_t hdlc_get_buffer_size() {
return frame_buffer_size;
}