168 lines
4.4 KiB
C
168 lines
4.4 KiB
C
#ifndef HDLC_H_
|
|
#define HDLC_H_
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include "crc.h"
|
|
|
|
#define HDLC_TEMPLATE \
|
|
int16_t (*readByte)(void), \
|
|
void (*writeByte)(uint8_t data), \
|
|
uint16_t rxBuffLen, \
|
|
struct CRC
|
|
|
|
#define HDLC_TEMPLATETYPE \
|
|
readByte, \
|
|
writeByte, \
|
|
rxBuffLen, \
|
|
CRC
|
|
|
|
struct HDLC {
|
|
const uint8_t DATAINVBIT;
|
|
const uint8_t DATASTART;
|
|
const uint8_t DATAESCAPE;
|
|
const uint8_t* DATAESCAPELIST;
|
|
|
|
int16_t (*readByte)(void);
|
|
void (*writeByte)(uint8_t data);
|
|
uint16_t rxBuffLen;
|
|
CRC16_CCITT rxcrc;
|
|
|
|
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_ */
|