APS Lab
/
STM32F4_SmartMesh_QSL
SmartMesh QSL for STM32F4 version
Fork of COG-AD4050_QSL by
sm_clib/dn_hdlc.c
- Committer:
- APS_Lab
- Date:
- 2018-07-12
- Revision:
- 1:b909b8399252
- Parent:
- 0:8ca1e814a851
File content as of revision 1:b909b8399252:
/* Copyright (c) 2014, Dust Networks. All rights reserved. HDLC library. \license See attached DN_LICENSE.txt. */ #include "dn_hdlc.h" #include "dn_uart.h" #include "dn_lock.h" //=========================== variables ======================================= typedef struct { // admin dn_hdlc_rxFrame_cbt rxFrame_cb; // input uint8_t lastRxByte; bool busyReceiving; bool inputEscaping; uint16_t inputCrc; uint8_t inputBufFill; uint8_t inputBuf[DN_HDLC_INPUT_BUFFER_SIZE]; // output uint16_t outputCrc; } dn_hdlc_vars_t; dn_hdlc_vars_t dn_hdlc_vars; //=========================== prototypes ====================================== // callback handlers void dn_hdlc_rxByte(uint8_t rxbyte); // input void dn_hdlc_inputOpen(); void dn_hdlc_inputWrite(uint8_t b); void dn_hdlc_inputClose(); // helpers uint16_t dn_hdlc_crcIteration(uint16_t crc, uint8_t data_byte); //=========================== public ========================================== /** \brief Setting up the instance. */ void dn_hdlc_init(dn_hdlc_rxFrame_cbt rxFrame_cb) { // reset local variables memset(&dn_hdlc_vars, 0, sizeof(dn_hdlc_vars)); // store params dn_hdlc_vars.rxFrame_cb = rxFrame_cb; // initialize UART dn_uart_init(dn_hdlc_rxByte); } //=========================== private ========================================= //===== callback_handler /** \brief Function which getted called each time a byte is received over UART. \param[in] rxbyte The received byte. */ void dn_hdlc_rxByte(uint8_t rxbyte) { // lock the module dn_lock(); if ( dn_hdlc_vars.busyReceiving==FALSE && dn_hdlc_vars.lastRxByte==DN_HDLC_FLAG && rxbyte!=DN_HDLC_FLAG ) { // start of frame // I'm now receiving dn_hdlc_vars.busyReceiving = TRUE; // create the HDLC frame dn_hdlc_inputOpen(); // add the byte just received dn_hdlc_inputWrite(rxbyte); } else if ( dn_hdlc_vars.busyReceiving==TRUE && rxbyte!=DN_HDLC_FLAG ){ // middle of frame // add the byte just received dn_hdlc_inputWrite(rxbyte); if (dn_hdlc_vars.inputBufFill+1>DN_HDLC_INPUT_BUFFER_SIZE) { // input buffer overflow dn_hdlc_vars.inputBufFill = 0; dn_hdlc_vars.busyReceiving = FALSE; } } else if ( dn_hdlc_vars.busyReceiving==TRUE && rxbyte==DN_HDLC_FLAG ) { // end of frame // finalize the HDLC frame dn_hdlc_inputClose(); if (dn_hdlc_vars.inputBufFill==0) { // invalid HDLC frame } else { // hand over frame to upper layer dn_hdlc_vars.rxFrame_cb(&dn_hdlc_vars.inputBuf[0],dn_hdlc_vars.inputBufFill); // clear inputBuffer dn_hdlc_vars.inputBufFill=0; } dn_hdlc_vars.busyReceiving = FALSE; } dn_hdlc_vars.lastRxByte = rxbyte; // unlock the module dn_unlock(); } //===== output /** \brief Start an HDLC frame in the output buffer. */ void dn_hdlc_outputOpen() { // initialize the value of the CRC dn_hdlc_vars.outputCrc = DN_HDLC_CRCINIT; // send opening HDLC flag dn_uart_txByte(DN_HDLC_FLAG); } /** \brief Add a byte to the outgoing HDLC frame being built. \param[in] b The byte to add. */ void dn_hdlc_outputWrite(uint8_t b) { // iterate through CRC calculator dn_hdlc_vars.outputCrc = dn_hdlc_crcIteration(dn_hdlc_vars.outputCrc,b); // write optional escape byte if (b==DN_HDLC_FLAG || b==DN_HDLC_ESCAPE) { dn_uart_txByte(DN_HDLC_ESCAPE); b = b^DN_HDLC_ESCAPE_MASK; } // data byte dn_uart_txByte(b); } /** \brief Finalize the outgoing HDLC frame. */ void dn_hdlc_outputClose() { uint16_t finalCrc; // finalize the calculation of the CRC finalCrc = ~dn_hdlc_vars.outputCrc; // write the CRC value dn_hdlc_outputWrite((finalCrc>>0)&0xff); dn_hdlc_outputWrite((finalCrc>>8)&0xff); // write closing HDLC flag dn_uart_txByte(DN_HDLC_FLAG); // flush the UART dn_uart_txFlush(); } //===== input /** \brief Start an HDLC frame in the input buffer. */ void dn_hdlc_inputOpen() { // reset the input buffer index dn_hdlc_vars.inputBufFill = 0; // initialize the value of the CRC dn_hdlc_vars.inputCrc = DN_HDLC_CRCINIT; } /** \brief Add a byte to the incoming HDLC frame. \param[in] b The byte to add. */ void dn_hdlc_inputWrite(uint8_t b) { if (b==DN_HDLC_ESCAPE) { dn_hdlc_vars.inputEscaping = TRUE; } else { if (dn_hdlc_vars.inputEscaping==TRUE) { b = b^DN_HDLC_ESCAPE_MASK; dn_hdlc_vars.inputEscaping = FALSE; } // add byte to input buffer dn_hdlc_vars.inputBuf[dn_hdlc_vars.inputBufFill] = b; dn_hdlc_vars.inputBufFill++; // iterate through CRC calculator dn_hdlc_vars.inputCrc = dn_hdlc_crcIteration(dn_hdlc_vars.inputCrc,b); } } /** \brief Finalize the incoming HDLC frame. */ void dn_hdlc_inputClose() { // verify the validity of the frame if (dn_hdlc_vars.inputCrc==DN_HDLC_CRCGOOD) { // the CRC is correct // remove the CRC from the input buffer dn_hdlc_vars.inputBufFill -= 2; } else { // the CRC is incorrect // drop the incoming fram dn_hdlc_vars.inputBufFill = 0; } // reset escaping dn_hdlc_vars.inputEscaping = FALSE; } //=========================== helpers ========================================= /** \brief Perform a single CRC iteration. \param[in] crc The current running CRC value. \param[in] b The new byte. \return The updated CRC running value. */ uint16_t dn_hdlc_crcIteration(uint16_t crc, uint8_t b) { return (crc >> 8) ^ dn_hdlc_fcstab[(crc ^ b) & 0xff]; }