#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; }