rework hdlc protocol, example in main.c

This commit is contained in:
Qukich 2023-06-14 15:36:47 +03:00
parent c0bb094a39
commit a154d92903
5 changed files with 284 additions and 179 deletions

66
hdlc/crc.c Normal file
View File

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

25
hdlc/crc.h Normal file
View File

@ -0,0 +1,25 @@
//
// Created by 79513 on 13.06.2023.
//
#ifndef CRC16_CCITT_H_
#define CRC16_CCITT_H_
#include <stdint.h>
#include <stdbool.h>
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

View File

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

View File

@ -1,22 +1,167 @@
#ifndef hdlc_h #ifndef HDLC_H_
#define hdlc_h #define HDLC_H_
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <string.h>
#include "crc.h"
typedef void (*sendchar_type)(uint8_t data); #define HDLC_TEMPLATE \
typedef void (*frame_handler_type)(const uint8_t *frame_buffer, int16_t (*readByte)(void), \
uint16_t frame_length); 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, struct HDLC {
frame_handler_type frame_hander_function); const uint8_t DATAINVBIT;
void hdlc_char_receiver(uint8_t data); const uint8_t DATASTART;
void hdlc_send_frame(const uint8_t *frame_buffer, uint8_t frame_length); const uint8_t DATAESCAPE;
const uint8_t* DATAESCAPELIST;
void hdlc_send_frame_to_buffer(const uint8_t *frame_buffer, uint8_t frame_length); int16_t (*readByte)(void);
uint8_t *hdlc_get_buffer(); void (*writeByte)(uint8_t data);
uint32_t hdlc_get_buffer_size(); uint16_t rxBuffLen;
CRC16_CCITT rxcrc;
#endif 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_ */

33
hdlc/main.c Normal file
View File

@ -0,0 +1,33 @@
#include "hdlc.h"
#include <stdio.h>
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();
}
}