APS Lab
/
STM32F4_SmartMesh_QSL
SmartMesh QSL for STM32F4 version
Fork of COG-AD4050_QSL by
sm_clib/dn_hdlc.c@0:8ca1e814a851, 2018-05-02 (annotated)
- Committer:
- APS_Lab
- Date:
- Wed May 02 09:26:10 2018 +0000
- Revision:
- 0:8ca1e814a851
version1
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
APS_Lab | 0:8ca1e814a851 | 1 | /* |
APS_Lab | 0:8ca1e814a851 | 2 | Copyright (c) 2014, Dust Networks. All rights reserved. |
APS_Lab | 0:8ca1e814a851 | 3 | |
APS_Lab | 0:8ca1e814a851 | 4 | HDLC library. |
APS_Lab | 0:8ca1e814a851 | 5 | |
APS_Lab | 0:8ca1e814a851 | 6 | \license See attached DN_LICENSE.txt. |
APS_Lab | 0:8ca1e814a851 | 7 | */ |
APS_Lab | 0:8ca1e814a851 | 8 | |
APS_Lab | 0:8ca1e814a851 | 9 | #include "dn_hdlc.h" |
APS_Lab | 0:8ca1e814a851 | 10 | #include "dn_uart.h" |
APS_Lab | 0:8ca1e814a851 | 11 | #include "dn_lock.h" |
APS_Lab | 0:8ca1e814a851 | 12 | |
APS_Lab | 0:8ca1e814a851 | 13 | //=========================== variables ======================================= |
APS_Lab | 0:8ca1e814a851 | 14 | |
APS_Lab | 0:8ca1e814a851 | 15 | typedef struct { |
APS_Lab | 0:8ca1e814a851 | 16 | // admin |
APS_Lab | 0:8ca1e814a851 | 17 | dn_hdlc_rxFrame_cbt rxFrame_cb; |
APS_Lab | 0:8ca1e814a851 | 18 | // input |
APS_Lab | 0:8ca1e814a851 | 19 | uint8_t lastRxByte; |
APS_Lab | 0:8ca1e814a851 | 20 | bool busyReceiving; |
APS_Lab | 0:8ca1e814a851 | 21 | bool inputEscaping; |
APS_Lab | 0:8ca1e814a851 | 22 | uint16_t inputCrc; |
APS_Lab | 0:8ca1e814a851 | 23 | uint8_t inputBufFill; |
APS_Lab | 0:8ca1e814a851 | 24 | uint8_t inputBuf[DN_HDLC_INPUT_BUFFER_SIZE]; |
APS_Lab | 0:8ca1e814a851 | 25 | // output |
APS_Lab | 0:8ca1e814a851 | 26 | uint16_t outputCrc; |
APS_Lab | 0:8ca1e814a851 | 27 | } dn_hdlc_vars_t; |
APS_Lab | 0:8ca1e814a851 | 28 | |
APS_Lab | 0:8ca1e814a851 | 29 | dn_hdlc_vars_t dn_hdlc_vars; |
APS_Lab | 0:8ca1e814a851 | 30 | |
APS_Lab | 0:8ca1e814a851 | 31 | //=========================== prototypes ====================================== |
APS_Lab | 0:8ca1e814a851 | 32 | |
APS_Lab | 0:8ca1e814a851 | 33 | // callback handlers |
APS_Lab | 0:8ca1e814a851 | 34 | void dn_hdlc_rxByte(uint8_t rxbyte); |
APS_Lab | 0:8ca1e814a851 | 35 | // input |
APS_Lab | 0:8ca1e814a851 | 36 | void dn_hdlc_inputOpen(); |
APS_Lab | 0:8ca1e814a851 | 37 | void dn_hdlc_inputWrite(uint8_t b); |
APS_Lab | 0:8ca1e814a851 | 38 | void dn_hdlc_inputClose(); |
APS_Lab | 0:8ca1e814a851 | 39 | // helpers |
APS_Lab | 0:8ca1e814a851 | 40 | uint16_t dn_hdlc_crcIteration(uint16_t crc, uint8_t data_byte); |
APS_Lab | 0:8ca1e814a851 | 41 | |
APS_Lab | 0:8ca1e814a851 | 42 | //=========================== public ========================================== |
APS_Lab | 0:8ca1e814a851 | 43 | |
APS_Lab | 0:8ca1e814a851 | 44 | /** |
APS_Lab | 0:8ca1e814a851 | 45 | \brief Setting up the instance. |
APS_Lab | 0:8ca1e814a851 | 46 | */ |
APS_Lab | 0:8ca1e814a851 | 47 | void dn_hdlc_init(dn_hdlc_rxFrame_cbt rxFrame_cb) { |
APS_Lab | 0:8ca1e814a851 | 48 | // reset local variables |
APS_Lab | 0:8ca1e814a851 | 49 | memset(&dn_hdlc_vars, 0, sizeof(dn_hdlc_vars)); |
APS_Lab | 0:8ca1e814a851 | 50 | |
APS_Lab | 0:8ca1e814a851 | 51 | // store params |
APS_Lab | 0:8ca1e814a851 | 52 | dn_hdlc_vars.rxFrame_cb = rxFrame_cb; |
APS_Lab | 0:8ca1e814a851 | 53 | |
APS_Lab | 0:8ca1e814a851 | 54 | // initialize UART |
APS_Lab | 0:8ca1e814a851 | 55 | dn_uart_init(dn_hdlc_rxByte); |
APS_Lab | 0:8ca1e814a851 | 56 | } |
APS_Lab | 0:8ca1e814a851 | 57 | |
APS_Lab | 0:8ca1e814a851 | 58 | //=========================== private ========================================= |
APS_Lab | 0:8ca1e814a851 | 59 | |
APS_Lab | 0:8ca1e814a851 | 60 | //===== callback_handler |
APS_Lab | 0:8ca1e814a851 | 61 | |
APS_Lab | 0:8ca1e814a851 | 62 | /** |
APS_Lab | 0:8ca1e814a851 | 63 | \brief Function which getted called each time a byte is received over UART. |
APS_Lab | 0:8ca1e814a851 | 64 | |
APS_Lab | 0:8ca1e814a851 | 65 | \param[in] rxbyte The received byte. |
APS_Lab | 0:8ca1e814a851 | 66 | */ |
APS_Lab | 0:8ca1e814a851 | 67 | void dn_hdlc_rxByte(uint8_t rxbyte) { |
APS_Lab | 0:8ca1e814a851 | 68 | |
APS_Lab | 0:8ca1e814a851 | 69 | // lock the module |
APS_Lab | 0:8ca1e814a851 | 70 | dn_lock(); |
APS_Lab | 0:8ca1e814a851 | 71 | |
APS_Lab | 0:8ca1e814a851 | 72 | if ( |
APS_Lab | 0:8ca1e814a851 | 73 | dn_hdlc_vars.busyReceiving==FALSE && |
APS_Lab | 0:8ca1e814a851 | 74 | dn_hdlc_vars.lastRxByte==DN_HDLC_FLAG && |
APS_Lab | 0:8ca1e814a851 | 75 | rxbyte!=DN_HDLC_FLAG |
APS_Lab | 0:8ca1e814a851 | 76 | ) { |
APS_Lab | 0:8ca1e814a851 | 77 | // start of frame |
APS_Lab | 0:8ca1e814a851 | 78 | |
APS_Lab | 0:8ca1e814a851 | 79 | // I'm now receiving |
APS_Lab | 0:8ca1e814a851 | 80 | dn_hdlc_vars.busyReceiving = TRUE; |
APS_Lab | 0:8ca1e814a851 | 81 | |
APS_Lab | 0:8ca1e814a851 | 82 | // create the HDLC frame |
APS_Lab | 0:8ca1e814a851 | 83 | dn_hdlc_inputOpen(); |
APS_Lab | 0:8ca1e814a851 | 84 | |
APS_Lab | 0:8ca1e814a851 | 85 | // add the byte just received |
APS_Lab | 0:8ca1e814a851 | 86 | dn_hdlc_inputWrite(rxbyte); |
APS_Lab | 0:8ca1e814a851 | 87 | } else if ( |
APS_Lab | 0:8ca1e814a851 | 88 | dn_hdlc_vars.busyReceiving==TRUE && |
APS_Lab | 0:8ca1e814a851 | 89 | rxbyte!=DN_HDLC_FLAG |
APS_Lab | 0:8ca1e814a851 | 90 | ){ |
APS_Lab | 0:8ca1e814a851 | 91 | // middle of frame |
APS_Lab | 0:8ca1e814a851 | 92 | |
APS_Lab | 0:8ca1e814a851 | 93 | // add the byte just received |
APS_Lab | 0:8ca1e814a851 | 94 | dn_hdlc_inputWrite(rxbyte); |
APS_Lab | 0:8ca1e814a851 | 95 | |
APS_Lab | 0:8ca1e814a851 | 96 | if (dn_hdlc_vars.inputBufFill+1>DN_HDLC_INPUT_BUFFER_SIZE) { |
APS_Lab | 0:8ca1e814a851 | 97 | // input buffer overflow |
APS_Lab | 0:8ca1e814a851 | 98 | dn_hdlc_vars.inputBufFill = 0; |
APS_Lab | 0:8ca1e814a851 | 99 | dn_hdlc_vars.busyReceiving = FALSE; |
APS_Lab | 0:8ca1e814a851 | 100 | } |
APS_Lab | 0:8ca1e814a851 | 101 | } else if ( |
APS_Lab | 0:8ca1e814a851 | 102 | dn_hdlc_vars.busyReceiving==TRUE && |
APS_Lab | 0:8ca1e814a851 | 103 | rxbyte==DN_HDLC_FLAG |
APS_Lab | 0:8ca1e814a851 | 104 | ) { |
APS_Lab | 0:8ca1e814a851 | 105 | // end of frame |
APS_Lab | 0:8ca1e814a851 | 106 | |
APS_Lab | 0:8ca1e814a851 | 107 | // finalize the HDLC frame |
APS_Lab | 0:8ca1e814a851 | 108 | dn_hdlc_inputClose(); |
APS_Lab | 0:8ca1e814a851 | 109 | |
APS_Lab | 0:8ca1e814a851 | 110 | if (dn_hdlc_vars.inputBufFill==0) { |
APS_Lab | 0:8ca1e814a851 | 111 | // invalid HDLC frame |
APS_Lab | 0:8ca1e814a851 | 112 | } else { |
APS_Lab | 0:8ca1e814a851 | 113 | // hand over frame to upper layer |
APS_Lab | 0:8ca1e814a851 | 114 | dn_hdlc_vars.rxFrame_cb(&dn_hdlc_vars.inputBuf[0],dn_hdlc_vars.inputBufFill); |
APS_Lab | 0:8ca1e814a851 | 115 | |
APS_Lab | 0:8ca1e814a851 | 116 | // clear inputBuffer |
APS_Lab | 0:8ca1e814a851 | 117 | dn_hdlc_vars.inputBufFill=0; |
APS_Lab | 0:8ca1e814a851 | 118 | } |
APS_Lab | 0:8ca1e814a851 | 119 | |
APS_Lab | 0:8ca1e814a851 | 120 | dn_hdlc_vars.busyReceiving = FALSE; |
APS_Lab | 0:8ca1e814a851 | 121 | } |
APS_Lab | 0:8ca1e814a851 | 122 | |
APS_Lab | 0:8ca1e814a851 | 123 | dn_hdlc_vars.lastRxByte = rxbyte; |
APS_Lab | 0:8ca1e814a851 | 124 | |
APS_Lab | 0:8ca1e814a851 | 125 | // unlock the module |
APS_Lab | 0:8ca1e814a851 | 126 | dn_unlock(); |
APS_Lab | 0:8ca1e814a851 | 127 | } |
APS_Lab | 0:8ca1e814a851 | 128 | |
APS_Lab | 0:8ca1e814a851 | 129 | //===== output |
APS_Lab | 0:8ca1e814a851 | 130 | |
APS_Lab | 0:8ca1e814a851 | 131 | /** |
APS_Lab | 0:8ca1e814a851 | 132 | \brief Start an HDLC frame in the output buffer. |
APS_Lab | 0:8ca1e814a851 | 133 | */ |
APS_Lab | 0:8ca1e814a851 | 134 | void dn_hdlc_outputOpen() { |
APS_Lab | 0:8ca1e814a851 | 135 | // initialize the value of the CRC |
APS_Lab | 0:8ca1e814a851 | 136 | dn_hdlc_vars.outputCrc = DN_HDLC_CRCINIT; |
APS_Lab | 0:8ca1e814a851 | 137 | |
APS_Lab | 0:8ca1e814a851 | 138 | // send opening HDLC flag |
APS_Lab | 0:8ca1e814a851 | 139 | dn_uart_txByte(DN_HDLC_FLAG); |
APS_Lab | 0:8ca1e814a851 | 140 | } |
APS_Lab | 0:8ca1e814a851 | 141 | |
APS_Lab | 0:8ca1e814a851 | 142 | /** |
APS_Lab | 0:8ca1e814a851 | 143 | \brief Add a byte to the outgoing HDLC frame being built. |
APS_Lab | 0:8ca1e814a851 | 144 | |
APS_Lab | 0:8ca1e814a851 | 145 | \param[in] b The byte to add. |
APS_Lab | 0:8ca1e814a851 | 146 | */ |
APS_Lab | 0:8ca1e814a851 | 147 | void dn_hdlc_outputWrite(uint8_t b) { |
APS_Lab | 0:8ca1e814a851 | 148 | |
APS_Lab | 0:8ca1e814a851 | 149 | // iterate through CRC calculator |
APS_Lab | 0:8ca1e814a851 | 150 | dn_hdlc_vars.outputCrc = dn_hdlc_crcIteration(dn_hdlc_vars.outputCrc,b); |
APS_Lab | 0:8ca1e814a851 | 151 | |
APS_Lab | 0:8ca1e814a851 | 152 | // write optional escape byte |
APS_Lab | 0:8ca1e814a851 | 153 | if (b==DN_HDLC_FLAG || b==DN_HDLC_ESCAPE) { |
APS_Lab | 0:8ca1e814a851 | 154 | dn_uart_txByte(DN_HDLC_ESCAPE); |
APS_Lab | 0:8ca1e814a851 | 155 | b = b^DN_HDLC_ESCAPE_MASK; |
APS_Lab | 0:8ca1e814a851 | 156 | } |
APS_Lab | 0:8ca1e814a851 | 157 | |
APS_Lab | 0:8ca1e814a851 | 158 | // data byte |
APS_Lab | 0:8ca1e814a851 | 159 | dn_uart_txByte(b); |
APS_Lab | 0:8ca1e814a851 | 160 | } |
APS_Lab | 0:8ca1e814a851 | 161 | |
APS_Lab | 0:8ca1e814a851 | 162 | /** |
APS_Lab | 0:8ca1e814a851 | 163 | \brief Finalize the outgoing HDLC frame. |
APS_Lab | 0:8ca1e814a851 | 164 | */ |
APS_Lab | 0:8ca1e814a851 | 165 | void dn_hdlc_outputClose() { |
APS_Lab | 0:8ca1e814a851 | 166 | uint16_t finalCrc; |
APS_Lab | 0:8ca1e814a851 | 167 | |
APS_Lab | 0:8ca1e814a851 | 168 | // finalize the calculation of the CRC |
APS_Lab | 0:8ca1e814a851 | 169 | finalCrc = ~dn_hdlc_vars.outputCrc; |
APS_Lab | 0:8ca1e814a851 | 170 | |
APS_Lab | 0:8ca1e814a851 | 171 | // write the CRC value |
APS_Lab | 0:8ca1e814a851 | 172 | dn_hdlc_outputWrite((finalCrc>>0)&0xff); |
APS_Lab | 0:8ca1e814a851 | 173 | dn_hdlc_outputWrite((finalCrc>>8)&0xff); |
APS_Lab | 0:8ca1e814a851 | 174 | |
APS_Lab | 0:8ca1e814a851 | 175 | // write closing HDLC flag |
APS_Lab | 0:8ca1e814a851 | 176 | dn_uart_txByte(DN_HDLC_FLAG); |
APS_Lab | 0:8ca1e814a851 | 177 | |
APS_Lab | 0:8ca1e814a851 | 178 | // flush the UART |
APS_Lab | 0:8ca1e814a851 | 179 | dn_uart_txFlush(); |
APS_Lab | 0:8ca1e814a851 | 180 | } |
APS_Lab | 0:8ca1e814a851 | 181 | |
APS_Lab | 0:8ca1e814a851 | 182 | //===== input |
APS_Lab | 0:8ca1e814a851 | 183 | |
APS_Lab | 0:8ca1e814a851 | 184 | /** |
APS_Lab | 0:8ca1e814a851 | 185 | \brief Start an HDLC frame in the input buffer. |
APS_Lab | 0:8ca1e814a851 | 186 | */ |
APS_Lab | 0:8ca1e814a851 | 187 | void dn_hdlc_inputOpen() { |
APS_Lab | 0:8ca1e814a851 | 188 | // reset the input buffer index |
APS_Lab | 0:8ca1e814a851 | 189 | dn_hdlc_vars.inputBufFill = 0; |
APS_Lab | 0:8ca1e814a851 | 190 | |
APS_Lab | 0:8ca1e814a851 | 191 | // initialize the value of the CRC |
APS_Lab | 0:8ca1e814a851 | 192 | dn_hdlc_vars.inputCrc = DN_HDLC_CRCINIT; |
APS_Lab | 0:8ca1e814a851 | 193 | } |
APS_Lab | 0:8ca1e814a851 | 194 | |
APS_Lab | 0:8ca1e814a851 | 195 | /** |
APS_Lab | 0:8ca1e814a851 | 196 | \brief Add a byte to the incoming HDLC frame. |
APS_Lab | 0:8ca1e814a851 | 197 | |
APS_Lab | 0:8ca1e814a851 | 198 | \param[in] b The byte to add. |
APS_Lab | 0:8ca1e814a851 | 199 | */ |
APS_Lab | 0:8ca1e814a851 | 200 | void dn_hdlc_inputWrite(uint8_t b) { |
APS_Lab | 0:8ca1e814a851 | 201 | if (b==DN_HDLC_ESCAPE) { |
APS_Lab | 0:8ca1e814a851 | 202 | dn_hdlc_vars.inputEscaping = TRUE; |
APS_Lab | 0:8ca1e814a851 | 203 | } else { |
APS_Lab | 0:8ca1e814a851 | 204 | if (dn_hdlc_vars.inputEscaping==TRUE) { |
APS_Lab | 0:8ca1e814a851 | 205 | b = b^DN_HDLC_ESCAPE_MASK; |
APS_Lab | 0:8ca1e814a851 | 206 | dn_hdlc_vars.inputEscaping = FALSE; |
APS_Lab | 0:8ca1e814a851 | 207 | } |
APS_Lab | 0:8ca1e814a851 | 208 | |
APS_Lab | 0:8ca1e814a851 | 209 | // add byte to input buffer |
APS_Lab | 0:8ca1e814a851 | 210 | dn_hdlc_vars.inputBuf[dn_hdlc_vars.inputBufFill] = b; |
APS_Lab | 0:8ca1e814a851 | 211 | dn_hdlc_vars.inputBufFill++; |
APS_Lab | 0:8ca1e814a851 | 212 | |
APS_Lab | 0:8ca1e814a851 | 213 | // iterate through CRC calculator |
APS_Lab | 0:8ca1e814a851 | 214 | dn_hdlc_vars.inputCrc = dn_hdlc_crcIteration(dn_hdlc_vars.inputCrc,b); |
APS_Lab | 0:8ca1e814a851 | 215 | } |
APS_Lab | 0:8ca1e814a851 | 216 | } |
APS_Lab | 0:8ca1e814a851 | 217 | |
APS_Lab | 0:8ca1e814a851 | 218 | /** |
APS_Lab | 0:8ca1e814a851 | 219 | \brief Finalize the incoming HDLC frame. |
APS_Lab | 0:8ca1e814a851 | 220 | */ |
APS_Lab | 0:8ca1e814a851 | 221 | void dn_hdlc_inputClose() { |
APS_Lab | 0:8ca1e814a851 | 222 | |
APS_Lab | 0:8ca1e814a851 | 223 | // verify the validity of the frame |
APS_Lab | 0:8ca1e814a851 | 224 | if (dn_hdlc_vars.inputCrc==DN_HDLC_CRCGOOD) { |
APS_Lab | 0:8ca1e814a851 | 225 | // the CRC is correct |
APS_Lab | 0:8ca1e814a851 | 226 | |
APS_Lab | 0:8ca1e814a851 | 227 | // remove the CRC from the input buffer |
APS_Lab | 0:8ca1e814a851 | 228 | dn_hdlc_vars.inputBufFill -= 2; |
APS_Lab | 0:8ca1e814a851 | 229 | } else { |
APS_Lab | 0:8ca1e814a851 | 230 | // the CRC is incorrect |
APS_Lab | 0:8ca1e814a851 | 231 | |
APS_Lab | 0:8ca1e814a851 | 232 | // drop the incoming fram |
APS_Lab | 0:8ca1e814a851 | 233 | dn_hdlc_vars.inputBufFill = 0; |
APS_Lab | 0:8ca1e814a851 | 234 | } |
APS_Lab | 0:8ca1e814a851 | 235 | |
APS_Lab | 0:8ca1e814a851 | 236 | // reset escaping |
APS_Lab | 0:8ca1e814a851 | 237 | dn_hdlc_vars.inputEscaping = FALSE; |
APS_Lab | 0:8ca1e814a851 | 238 | } |
APS_Lab | 0:8ca1e814a851 | 239 | |
APS_Lab | 0:8ca1e814a851 | 240 | //=========================== helpers ========================================= |
APS_Lab | 0:8ca1e814a851 | 241 | |
APS_Lab | 0:8ca1e814a851 | 242 | /** |
APS_Lab | 0:8ca1e814a851 | 243 | \brief Perform a single CRC iteration. |
APS_Lab | 0:8ca1e814a851 | 244 | |
APS_Lab | 0:8ca1e814a851 | 245 | \param[in] crc The current running CRC value. |
APS_Lab | 0:8ca1e814a851 | 246 | \param[in] b The new byte. |
APS_Lab | 0:8ca1e814a851 | 247 | |
APS_Lab | 0:8ca1e814a851 | 248 | \return The updated CRC running value. |
APS_Lab | 0:8ca1e814a851 | 249 | */ |
APS_Lab | 0:8ca1e814a851 | 250 | uint16_t dn_hdlc_crcIteration(uint16_t crc, uint8_t b) { |
APS_Lab | 0:8ca1e814a851 | 251 | return (crc >> 8) ^ dn_hdlc_fcstab[(crc ^ b) & 0xff]; |
APS_Lab | 0:8ca1e814a851 | 252 | } |
APS_Lab | 0:8ca1e814a851 | 253 |