164 lines
5.7 KiB
C
164 lines
5.7 KiB
C
#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;
|
||
} |