diff --git a/hdlc/crc.c b/hdlc/crc.c new file mode 100644 index 0000000..121c210 --- /dev/null +++ b/hdlc/crc.c @@ -0,0 +1,66 @@ +#include "crc.h" + +const int8_t size = 2; +const CRC_t CRC_INIT = 0xFFFFU; +const CRC_t CRC_FINALXOR = 0xFFFFU; +const CRC_t CRC_GOOD = 0xF0B8U; + +static const uint16_t CRC_TAB[256U] = { + 0x0000UL, 0x1189UL, 0x2312UL, 0x329BUL, 0x4624UL, 0x57ADUL, 0x6536UL, 0x74BFUL, + 0x8C48UL, 0x9DC1UL, 0xAF5AUL, 0xBED3UL, 0xCA6CUL, 0xDBE5UL, 0xE97EUL, 0xF8F7UL, + 0x1081UL, 0x0108UL, 0x3393UL, 0x221AUL, 0x56A5UL, 0x472CUL, 0x75B7UL, 0x643EUL, + 0x9CC9UL, 0x8D40UL, 0xBFDBUL, 0xAE52UL, 0xDAEDUL, 0xCB64UL, 0xF9FFUL, 0xE876UL, + 0x2102UL, 0x308BUL, 0x0210UL, 0x1399UL, 0x6726UL, 0x76AFUL, 0x4434UL, 0x55BDUL, + 0xAD4AUL, 0xBCC3UL, 0x8E58UL, 0x9FD1UL, 0xEB6EUL, 0xFAE7UL, 0xC87CUL, 0xD9F5UL, + 0x3183UL, 0x200AUL, 0x1291UL, 0x0318UL, 0x77A7UL, 0x662EUL, 0x54B5UL, 0x453CUL, + 0xBDCBUL, 0xAC42UL, 0x9ED9UL, 0x8F50UL, 0xFBEFUL, 0xEA66UL, 0xD8FDUL, 0xC974UL, + 0x4204UL, 0x538DUL, 0x6116UL, 0x709FUL, 0x0420UL, 0x15A9UL, 0x2732UL, 0x36BBUL, + 0xCE4CUL, 0xDFC5UL, 0xED5EUL, 0xFCD7UL, 0x8868UL, 0x99E1UL, 0xAB7AUL, 0xBAF3UL, + 0x5285UL, 0x430CUL, 0x7197UL, 0x601EUL, 0x14A1UL, 0x0528UL, 0x37B3UL, 0x263AUL, + 0xDECDUL, 0xCF44UL, 0xFDDFUL, 0xEC56UL, 0x98E9UL, 0x8960UL, 0xBBFBUL, 0xAA72UL, + 0x6306UL, 0x728FUL, 0x4014UL, 0x519DUL, 0x2522UL, 0x34ABUL, 0x0630UL, 0x17B9UL, + 0xEF4EUL, 0xFEC7UL, 0xCC5CUL, 0xDDD5UL, 0xA96AUL, 0xB8E3UL, 0x8A78UL, 0x9BF1UL, + 0x7387UL, 0x620EUL, 0x5095UL, 0x411CUL, 0x35A3UL, 0x242AUL, 0x16B1UL, 0x0738UL, + 0xFFCFUL, 0xEE46UL, 0xDCDDUL, 0xCD54UL, 0xB9EBUL, 0xA862UL, 0x9AF9UL, 0x8B70UL, + 0x8408UL, 0x9581UL, 0xA71AUL, 0xB693UL, 0xC22CUL, 0xD3A5UL, 0xE13EUL, 0xF0B7UL, + 0x0840UL, 0x19C9UL, 0x2B52UL, 0x3ADBUL, 0x4E64UL, 0x5FEDUL, 0x6D76UL, 0x7CFFUL, + 0x9489UL, 0x8500UL, 0xB79BUL, 0xA612UL, 0xD2ADUL, 0xC324UL, 0xF1BFUL, 0xE036UL, + 0x18C1UL, 0x0948UL, 0x3BD3UL, 0x2A5AUL, 0x5EE5UL, 0x4F6CUL, 0x7DF7UL, 0x6C7EUL, + 0xA50AUL, 0xB483UL, 0x8618UL, 0x9791UL, 0xE32EUL, 0xF2A7UL, 0xC03CUL, 0xD1B5UL, + 0x2942UL, 0x38CBUL, 0x0A50UL, 0x1BD9UL, 0x6F66UL, 0x7EEFUL, 0x4C74UL, 0x5DFDUL, + 0xB58BUL, 0xA402UL, 0x9699UL, 0x8710UL, 0xF3AFUL, 0xE226UL, 0xD0BDUL, 0xC134UL, + 0x39C3UL, 0x284AUL, 0x1AD1UL, 0x0B58UL, 0x7FE7UL, 0x6E6EUL, 0x5CF5UL, 0x4D7CUL, + 0xC60CUL, 0xD785UL, 0xE51EUL, 0xF497UL, 0x8028UL, 0x91A1UL, 0xA33AUL, 0xB2B3UL, + 0x4A44UL, 0x5BCDUL, 0x6956UL, 0x78DFUL, 0x0C60UL, 0x1DE9UL, 0x2F72UL, 0x3EFBUL, + 0xD68DUL, 0xC704UL, 0xF59FUL, 0xE416UL, 0x90A9UL, 0x8120UL, 0xB3BBUL, 0xA232UL, + 0x5AC5UL, 0x4B4CUL, 0x79D7UL, 0x685EUL, 0x1CE1UL, 0x0D68UL, 0x3FF3UL, 0x2E7AUL, + 0xE70EUL, 0xF687UL, 0xC41CUL, 0xD595UL, 0xA12AUL, 0xB0A3UL, 0x8238UL, 0x93B1UL, + 0x6B46UL, 0x7ACFUL, 0x4854UL, 0x59DDUL, 0x2D62UL, 0x3CEBUL, 0x0E70UL, 0x1FF9UL, + 0xF78FUL, 0xE606UL, 0xD49DUL, 0xC514UL, 0xB1ABUL, 0xA022UL, 0x92B9UL, 0x8330UL, + 0x7BC7UL, 0x6A4EUL, 0x58D5UL, 0x495CUL, 0x3DE3UL, 0x2C6AUL, 0x1EF1UL, 0x0F78UL +}; + +void crc_init(CRC16_CCITT* crc_obj) { + crc_obj->crc = CRC_INIT; + crc_obj->size = 2; +} + +void crc_update(CRC16_CCITT* crc_obj, uint8_t data) { + crc_obj->crc = (crc_obj->crc >> 8U) ^ CRC_TAB[(crc_obj->crc ^ data) & CRC_FINALXOR]; +} + +bool crc_good(const CRC16_CCITT* crc_obj) { + return crc_obj->crc == 0xF0B8U; +} + +void crc_final(CRC16_CCITT* crc_obj) { + crc_obj->crc ^= CRC_FINALXOR; +} + +uint8_t crc_get(const CRC16_CCITT* crc_obj, int8_t pos) { + if (pos == 0){ + return crc_obj->crc; + } else{ + return crc_obj->crc >> 8U; + } +} \ No newline at end of file diff --git a/hdlc/crc.h b/hdlc/crc.h new file mode 100644 index 0000000..4b88f0d --- /dev/null +++ b/hdlc/crc.h @@ -0,0 +1,25 @@ +// +// Created by 79513 on 13.06.2023. +// + +#ifndef CRC16_CCITT_H_ +#define CRC16_CCITT_H_ + +#include +#include + +typedef uint16_t CRC_t; + +typedef struct { + const CRC_t* CRC_TAB; + CRC_t crc; + int size; +} CRC16_CCITT; + +void crc_init(CRC16_CCITT* crc_obj); +void crc_update(CRC16_CCITT* crc_obj, uint8_t data); +bool crc_good(const CRC16_CCITT* crc_obj); +void crc_final(CRC16_CCITT* crc_obj); +uint8_t crc_get(const CRC16_CCITT* crc_obj, int8_t pos); + +#endif diff --git a/hdlc/hdlc.c b/hdlc/hdlc.c deleted file mode 100644 index 96a7672..0000000 --- a/hdlc/hdlc.c +++ /dev/null @@ -1,164 +0,0 @@ -#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; -} \ No newline at end of file diff --git a/hdlc/hdlc.h b/hdlc/hdlc.h index 035fc0a..b160558 100644 --- a/hdlc/hdlc.h +++ b/hdlc/hdlc.h @@ -1,22 +1,167 @@ -#ifndef hdlc_h -#define hdlc_h +#ifndef HDLC_H_ +#define HDLC_H_ #include -#include +#include +#include "crc.h" -typedef void (*sendchar_type)(uint8_t data); -typedef void (*frame_handler_type)(const uint8_t *frame_buffer, - uint16_t frame_length); +#define HDLC_TEMPLATE \ + int16_t (*readByte)(void), \ + void (*writeByte)(uint8_t data), \ + uint16_t rxBuffLen, \ + struct CRC -#define MINIHDLC_MAX_FRAME_LENGTH 64 +#define HDLC_TEMPLATETYPE \ + readByte, \ + writeByte, \ + rxBuffLen, \ + CRC -void hdlc_init(sendchar_type sendchar_function, - frame_handler_type frame_hander_function); -void hdlc_char_receiver(uint8_t data); -void hdlc_send_frame(const uint8_t *frame_buffer, uint8_t frame_length); +struct HDLC { + const uint8_t DATAINVBIT; + const uint8_t DATASTART; + const uint8_t DATAESCAPE; + const uint8_t* DATAESCAPELIST; -void hdlc_send_frame_to_buffer(const uint8_t *frame_buffer, uint8_t frame_length); -uint8_t *hdlc_get_buffer(); -uint32_t hdlc_get_buffer_size(); + int16_t (*readByte)(void); + void (*writeByte)(uint8_t data); + uint16_t rxBuffLen; + CRC16_CCITT rxcrc; -#endif \ No newline at end of file + const uint16_t RXBFLEN; + + int8_t status; + uint16_t len; + CRC16_CCITT txcrc; + uint8_t data[]; +}; + +void escapeAndWriteByte(struct HDLC* hdlc, uint8_t data) { + const uint8_t* escapeList = hdlc->DATAESCAPELIST; + while (*escapeList != 0) { + if (data == *escapeList) { + hdlc->writeByte(hdlc->DATAESCAPE); + data ^= hdlc->DATAINVBIT; + break; + } + escapeList++; + } + hdlc->writeByte(data); +} + +#define ESCAPED (-1) +#define RECEIVING 0 +#define OK 1 +#define CRCERR 2 + +void HDLC_init(struct HDLC* hdlc){ + hdlc->len = 0U; + hdlc->status = RECEIVING; + crc_init(&hdlc->rxcrc); +};; + +void HDLC_transmitStart(struct HDLC *hdlc); +void HDLC_transmitStart(struct HDLC *hdlc) { + hdlc->writeByte(hdlc->DATASTART); + crc_init(&hdlc->txcrc); +} + +void HDLC_transmitByte(struct HDLC* hdlc, uint8_t data); +void HDLC_transmitByte(struct HDLC* hdlc, uint8_t data){ + escapeAndWriteByte(hdlc, data); + crc_update(&hdlc->txcrc, data); +} + +void HDLC_transmitBytes(struct HDLC* hdlc, const void *vdata, uint16_t len); +void HDLC_transmitBytes(struct HDLC* hdlc, const void *vdata, uint16_t len){ + const uint8_t* data = (const uint8_t*)vdata; + while(len) + { + HDLC_transmitByte(hdlc, *data); + ++data; + --len; + } +} + +void HDLC_transmitEnd(struct HDLC *hdlc); +void HDLC_transmitEnd(struct HDLC *hdlc){ + crc_final(&hdlc->txcrc); + for(int i = 0; i < hdlc->txcrc.size; ++i) + escapeAndWriteByte(hdlc, hdlc->txcrc.crc); + + hdlc->writeByte(hdlc->DATASTART); +} + +void HDLC_transmitBlock(struct HDLC* hdlc, const void* vdata, uint16_t len){ + HDLC_transmitStart(hdlc); + HDLC_transmitBytes(hdlc, vdata, len); + HDLC_transmitEnd(hdlc); +} + +uint16_t HDLC_receive(struct HDLC* hdlc); +uint16_t HDLC_receive(struct HDLC* hdlc){ + int16_t c = hdlc->readByte(); + if(c == -1) + return 0U; + + if(hdlc->status >= OK) + HDLC_init(hdlc); + + uint16_t retv = 0U; + + if(c == hdlc->DATASTART) + { + if(hdlc->status == RECEIVING && hdlc->len != 0U) + { + if(crc_good(&hdlc->rxcrc)) + { + hdlc->status = OK; + hdlc->len -= hdlc->rxcrc.size; + retv = hdlc->len; + } + else + { + hdlc->status = CRCERR; + } + } + else + { + HDLC_init(hdlc); + } + } + else + { + if(hdlc->status == ESCAPED) + { + hdlc->status = RECEIVING; + + c ^= hdlc->DATAINVBIT; + crc_update(&hdlc->rxcrc, c); + if (hdlc->len < hdlc->RXBFLEN) + hdlc->data[hdlc->len] = c; + ++hdlc->len; + } + else if(c != hdlc->DATAESCAPE) + { + crc_update(&hdlc->rxcrc, c); + if(hdlc->len < hdlc->RXBFLEN) + hdlc->data[hdlc->len] = c; + ++hdlc->len; + } + else + { + hdlc->status = ESCAPED; + } + } + + return retv; +} +uint16_t HDLC_copyReceivedMessage(const struct HDLC* hdlc, uint8_t buff[]); +uint16_t HDLC_copyReceivedMessage(const struct HDLC* hdlc, uint8_t buff[]){ + const uint16_t datalen = (hdlc->len > hdlc->RXBFLEN) ? hdlc->RXBFLEN : hdlc->len; + memcpy(buff, hdlc->data, datalen); + return datalen; +} +uint16_t HDLC_copyReceivedMessage2(const struct HDLC* hdlc, uint8_t* buff, uint16_t pos, uint16_t num); + +#endif /* HDLC_H_ */ diff --git a/hdlc/main.c b/hdlc/main.c new file mode 100644 index 0000000..9325619 --- /dev/null +++ b/hdlc/main.c @@ -0,0 +1,33 @@ +#include "hdlc.h" +#include + +struct HDLC hdlc; + +void hdlc_sendMsg() { + uint8_t msg[] = "Hello world!"; + HDLC_transmitBlock(&hdlc, msg, sizeof(msg)); +} + +void hdlc_receiveMsg() { + int16_t resp = HDLC_receive(&hdlc); + if(resp != 0U) + { + uint8_t buff[hdlc.RXBFLEN]; + uint16_t size = HDLC_copyReceivedMessage(&hdlc, buff); + + printf("Msg[%u]=%s\n", size, buff); + } +} + +//нужно указать 2 функции на чтение и запись байтов, чтобы работало +int main(void) +{ + HDLC_init(&hdlc); + + hdlc_sendMsg(); + + for(;;) + { + hdlc_receiveMsg(); + } +}