1 // $Header: /volume1/cvs/cvsroot/microrisc/iqrf/DPA/Examples/DP2Papp-UART.c,v 1.10 2022/02/25 09:41:25 hynek Exp $ 2 //############################################################################################ 3 // Example DP2P TR module application via UART using HDLC protocol (see DPA UART Interface documentation) 4 //############################################################################################ 5 // Revision history: 6 // 2022/02/24 Release for DPA 4.17 7 // 8 // ********************************************************************* 9 10 #include "../includes/IQRF.h" 11 #include "Dpa.h" 12 13 //############################################################################################ 14 // This example is derived from DP2Papp.c, which uses the SPI. Therefore many same structures are named *SPI* although UART is used. 15 // When trying example below in IQRF IDE then connect it to the COM port using "DPA HDLC" protocol. 16 //############################################################################################ 17 18 // DP2P special (fake PNUM and PCMD) DPA values to indicate that DP2P parameters are specified 19 #define DP2P_PNUM 0xDD 20 #define DP2P_PCMD 0xDD 21 22 // UART baud rate 23 #define BAUDRATE 115200 24 25 typedef struct 26 { 27 // PNUM 28 uns8 PNUM; 29 // PCMD 30 uns8 PCMD; 31 // Zero 32 uns8 _zero_; 33 // Previous fields overlap Header part of the TDP2Prequest 34 // Non-zero value when STD+LP network is used, otherwise STD 35 uns8 STD_LP_network; 36 // Channel to communicate DP2P packets 37 uns8 RfChannel; 38 // Power to send DP2P request 39 uns8 ReqTxPower; 40 // Filter to receive DP2P responses 41 uns8 RespRxFilter; 42 // Access Password to use for de/encryption 43 uns8 AccessPassword[sizeof( _DpaMessage.PerOSSetSecurity_Request.Data )]; 44 } TSPI_DP2PrequestParams; 45 46 // Incoming SPI DP2P packet request 47 typedef union 48 { 49 // Used to send DP2P requests, then only PNUM+PCMD(+_zero_) fields from the next union field are used to specify DPA request PCMD+PNUN 50 51 /* IQRF IDE Terminal example 52 $07$03$00$3E$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$07$00$FF$FF 53 PNUM = PNUM_LEDG = $07 54 PCMD = CMD_LED_PULSE = $03 55 Nodes #1-5 = $3E + 29 x $00 56 SlotLength = 0x00 (default values) 57 Response RF power = $07 58 HWPID 0xFFFF = $FF$FF 59 */ 60 TDP2Prequest DP2Prequest; 61 62 // Used to specify PNUM and PCMD of the DP2P request or to setup DP2P parameters (when PNUM and PCMD equal DP2P_PNUM and DP2P_PCMD respectively) 63 64 /* IQRF IDE Terminal example 65 $DD$DD$00$01$23$07$05$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00 66 STD+LP network = $01 67 channel 35 = $23 68 Request RF power 7 = $07 69 RX filter 5 = $05 70 AccessPassword = 16 x $00 (i.e. empty, not recommended to use!) 71 */ 72 TSPI_DP2PrequestParams DP2PrequestParams; 73 } TSPI_TDP2Prequest; 74 75 // Outgoing SPI DP2P packet invite (fields must exactly overlap TDP2Invite) 76 typedef struct 77 { 78 uns8 Header[3]; // 0x000001 (0x00 is used to detect TSPI_TDP2Pinvite, 0xFF specifies TSPI_TDP2Presponse - see below) 79 uns8 NADR; 80 } TSPI_TDP2Pinvite; 81 82 // Outgoing SPI DP2P packet response 83 typedef union 84 { 85 // Real DP2P response but PNUM and PCMD is overlapped, see the next union field 86 TDP2Presponse DP2Presponse; 87 88 struct 89 { 90 // PNUM 91 uns8 PNUM; 92 // PCMD 93 uns8 PCMD; 94 // 0xFF (remainder from the DP2P Response, used to detect Response) 95 uns8 _0xFF_; 96 } DP2PresponseParams; 97 } TSPI_TDP2Presponse; 98 99 // Packet size limits 100 #define MinRxPacketSize sizeof( TSPI_DP2PrequestParams ) 101 #define MaxRxPacketSize sizeof( TSPI_TDP2Prequest ) 102 103 /* 104 IQRF IDE terminal log (not HDLC encoded) example: 105 <> Length Data (comment) 106 Tx 23 DD.DD.00.01.23.07.05.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00. (Sets DP2P parameters, see details above) 107 Tx 38 07.03.00.3E.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.07.00.FF.FF. (Nodes 1-5 will pulse the LEDG, see details above) 108 Rx 4 01.00.00.01. (Invite from Node #1) 109 Rx 4 07.83.FF.01. (Response from Node #1) 110 Rx 4 01.00.00.02. (Invite from Node #2) 111 Rx 4 07.83.FF.02. (Response from Node #2) 112 Rx 4 01.00.00.03. (Invite from Node #3) 113 Rx 4 07.83.FF.03. (Response from Node #3) 114 Rx 4 01.00.00.04. (Invite from Node #4) 115 Rx 4 07.83.FF.04. (Response from Node #4) 116 Rx 4 01.00.00.06. (Invite from Node #5) 117 Rx 4 07.83.FF.05. (Response from Node #5) 118 119 The same UART level HDLC encoded communication : 120 <> Length Data (comment) 121 Tx 26 7E.DD.DD.00.01.23.07.05.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.D6.7E. (Sets DP2P parameters, see details above) 122 Tx 41 7E.07.03.00.3E.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.07.00.FF.FF.D5.7E. (Nodes 1-5 will pulse the LEDG, see details above) 123 Rx 7 7E.01.00.00.01.3A.7E. (Invite from Node #1) 124 Rx 7 7E.07.83.FF.01.34.7E. (Response from Node #1) 125 Rx 7 7E.01.00.00.02.D8.7E. (Invite from Node #2) 126 Rx 7 7E.07.83.FF.02.D6.7E. (Response from Node #2) 127 Rx 7 7E.01.00.00.03.86.7E. (Invite from Node #3) 128 Rx 7 7E.07.83.FF.03.88.7E. (Response from Node #3) 129 Rx 7 7E.01.00.00.04.05.7E. (Invite from Node #4) 130 Rx 7 7E.07.83.FF.04.0B.7E. (Response from Node #4) 131 Rx 7 7E.01.00.00.05.5B.7E. (Invite from Node #5) 132 Rx 7 7E.07.83.FF.05.55.7E. (Response from Node #5) 133 */ 134 135 //############################################################################################ 136 // UART & HDLC definitions 137 138 // HDLC byte stuffing bytes 139 // Flag Sequence 140 #define HDLC_FRM_FLAG_SEQUENCE 0x7e 141 // Asynchronous Control Escape 142 #define HDLC_FRM_CONTROL_ESCAPE 0x7d 143 // Asynchronous transparency modifier 144 #define HDLC_FRM_ESCAPE_BIT 0x20 145 146 // UART TX states 147 typedef enum 148 { 149 UART_TX_START = 0, 150 UART_TX_DATA = 1, 151 UART_TX_CHSUM = 2, 152 UART_TX_STOP = 3 153 } TUartTxState; 154 155 // State of the UART TX machine 156 uns8 UartTxState; 157 // Length of the UART data to TX 158 uns8 UartTxSize; 159 160 // UART TX packet buffer 161 #define TxUartBuffer bufferAUX 162 163 #define TxUARTbusy() ( !TRMT ) 164 #define WaitTxUART() while ( TxUARTbusy() ) 165 166 // UART RX states 167 typedef enum 168 { 169 UART_RX_WAITHEAD = 0, 170 UART_RX_STOP = 1, 171 UART_RX_PACKET = 2, 172 UART_RX_ESCAPE = 3, 173 } TUartRxState; 174 175 // State of the UART RX machine 176 uns8 UartRxState; // = 0 == UART_RX_WAITHEAD 177 // Size of the received packet from UART 178 uns8 UartRxSize; // = 0 179 180 // UART RX packet buffer 181 #define RxUartBuffer bufferCOM 182 183 #define RxUARTstart() do { UartRxState = UART_RX_WAITHEAD; } while(0) 184 #define RxUARTready() ( UartRxState == UART_RX_STOP && UartRxSize != 0 ) 185 186 void OpenUART(); 187 void TxUART( uns8 dataLength ); 188 189 // Division macro with rounding 190 #define DIV(Dividend,Divisor) (((Dividend+((Divisor)>>1))/(Divisor))) 191 // Macro to compute UART register value from baud rate 192 #define UART_SPBRG_VALUE( Baud ) ( DIV( F_OSC, ( ( ( uns24 )4 ) * ( Baud ) ) ) - 1 ) 193 194 #define IndexedPtr(ptr,buffer,index,maxindex) \ 195 #if ( &buffer[0] >> 8 ) != ( &buffer[maxindex] >> 8 ) \ 196 ptr = (uns16)( buffer + (index) ); \ 197 #else \ 198 ptr.low8 = (uns8)(uns16)( buffer + (index) ); \ 199 ptr.high8 = (uns8)(&buffer[0] >> 8 ); \ 200 #endif \ 201 202 // Definition used for TRx2 having connected pins 203 #define _OUT_A5 TRISA.5 204 #define _OUT_B4 TRISB.4 205 #define _OUT_C5 TRISC.5 206 #define _OUT_C6 TRISC.6 207 #define _OUT_C7 TRISC.7 208 209 //############################################################################################ 210 void APPLICATION() 211 //############################################################################################ 212 { 213 // Indicate start 214 pulseLEDR(); 215 pulseLEDG(); 216 217 // We use UART 218 OpenUART(); 219 220 // Filter used to receive DP2P responses 221 uns8 RespRxFilter; 222 // RF mode to send DP2P Requests 223 uns8 ReqRfMode; 224 225 // Loop forever 226 for ( ;; ) 227 { 228 // Anything at UART received? 229 if ( RxUARTready() ) 230 { 231 // UART incoming packet variable 232 TSPI_TDP2Prequest SPI_TDP2Prequest @ RxUartBuffer; 233 // Check the packet a little 234 if ( SPI_TDP2Prequest.DP2PrequestParams._zero_ == 0 ) 235 { 236 // DP2P parameters to set? 237 if ( SPI_TDP2Prequest.DP2PrequestParams.PNUM == DP2P_PNUM && SPI_TDP2Prequest.DP2PrequestParams.PCMD == DP2P_PCMD ) 238 { 239 // Check the length 240 if ( UartRxSize == sizeof( SPI_TDP2Prequest.DP2PrequestParams ) ) 241 { 242 // Indicate reception 243 pulseLEDR(); 244 245 // Set RF mode and toutRF according to the network type 246 if ( SPI_TDP2Prequest.DP2PrequestParams.STD_LP_network != 0 ) 247 // STD+LP network 248 ReqRfMode = _WPE | _RX_STD | _TX_LP; 249 else 250 // STD network 251 ReqRfMode = _WPE | _RX_STD | _TX_STD | _STDL; 252 253 // Set RF channel 254 setRFchannel( SPI_TDP2Prequest.DP2PrequestParams.RfChannel ); 255 // Set RF power 256 setRFpower( SPI_TDP2Prequest.DP2PrequestParams.ReqTxPower ); 257 // Remember RX filter 258 RespRxFilter = SPI_TDP2Prequest.DP2PrequestParams.RespRxFilter; 259 // Set Access Password 260 copyMemoryBlock( SPI_TDP2Prequest.DP2PrequestParams.AccessPassword, bufferINFO, sizeof( SPI_TDP2Prequest.DP2PrequestParams.AccessPassword ) ); 261 setAccessPassword(); 262 } 263 } 264 else 265 { 266 // Check the length 267 if ( UartRxSize >= offsetof( TDP2Prequest, PDATA ) ) 268 { 269 // Send DP2P request 270 271 // Prepare DPA Request 272 // Get PNUN 273 _PNUM = SPI_TDP2Prequest.DP2PrequestParams.PNUM; 274 // Get PCMD 275 _PCMD = SPI_TDP2Prequest.DP2PrequestParams.PCMD; 276 // DP2P Request variable 277 TDP2Prequest DP2Prequest @ bufferRF; 278 // Make sure header is correct (there were PNUM and PMCD stored) 279 SPI_TDP2Prequest.DP2Prequest.Header[0] = 0; 280 SPI_TDP2Prequest.DP2Prequest.Header[1] = 0; 281 // Set data length 282 PPAR = UartRxSize - offsetof( TDP2Prequest, PDATA ); 283 // Set the DP2P packet length 284 DLEN = sizeof( DP2Prequest ); 285 // Use Access Password for encryption 286 encryptByAccessPassword = TRUE; 287 // Encrypt the DP2P Request 288 copyMemoryBlock( &SPI_TDP2Prequest, bufferRF, sizeof( SPI_TDP2Prequest ) ); 289 encryptBufferRF( sizeof( DP2Prequest ) / 16 ); 290 // Set RF Flags 291 PIN = _DPAF_MASK; 292 // And finally send DP2P Request 293 setRFmode( ReqRfMode ); 294 RFTXpacket(); 295 // Indicate reception 296 pulseLEDR(); 297 } 298 } 299 } 300 // Start UART RX again 301 RxUARTstart(); 302 } 303 304 // Ready to receive STD packets 305 toutRF = 1; 306 setRFmode( _WPE | _RX_STD | _TX_STD ); 307 // Anything from RF received? 308 if ( // There is a signal 309 checkRF( RespRxFilter ) && 310 // Packet was received 311 RFRXpacket() && 312 // DPA flags are used 313 _DPAF && 314 // There is enough data (at least one AES block) 315 DLEN >= 16 && 316 // Real packet has a correct AES-128 block length 317 ( ( PPAR + 15 ) & ~15 ) == DLEN ) 318 { 319 // Decrypt the packet 320 encryptByAccessPassword = TRUE; 321 decryptBufferRF( DLEN / 16 ); 322 323 // DP2P Invite variable 324 TDP2Invite DP2Invite @ bufferRF; 325 // Check the DP2P Invite validity 326 if ( PPAR == sizeof( TDP2Invite ) && DP2Invite.Header[0] == 1 && ( DP2Invite.Header[1] | DP2Invite.Header[2] ) == 0 ) 327 { 328 // Save N address 329 uns8 addr = DP2Invite.NADR; 330 331 // Prepare DP2P Confirm 332 TDP2Confirm DP2Confirm @ bufferRF; 333 DP2Confirm.Header[0] = 0x03; 334 // Encrypt the DP2P Confirm 335 encryptByAccessPassword = TRUE; 336 encryptBufferRF( sizeof( TDP2Confirm ) / 16 ); 337 // And finally send DP2P Confirm 338 RFTXpacket(); 339 // Indicate reception 340 pulseLEDG(); 341 342 // Finish UART TX work 343 WaitTxUART(); 344 // Prepare SPI Invite 345 TSPI_TDP2Pinvite SPI_TDP2Pinvite @ TxUartBuffer; 346 SPI_TDP2Pinvite.NADR = addr; 347 SPI_TDP2Pinvite.Header[0] = 0x01; 348 SPI_TDP2Pinvite.Header[1] = 0x00; 349 SPI_TDP2Pinvite.Header[2] = 0x00; 350 // Send UART outgoing Invite packet 351 TxUART( sizeof( TSPI_TDP2Pinvite ) ); 352 } 353 else 354 { 355 // DP2P Response variable 356 TDP2Presponse DP2Presponse @ bufferRF; 357 // Check the DP2P Response validity 358 if ( PPAR >= offsetof( TDP2Presponse, PDATA ) && ( DP2Presponse.Header[0] & DP2Presponse.Header[1] & DP2Presponse.Header[2] ) == 0xFF ) 359 { 360 // SPI outgoing Response packet variable 361 TSPI_TDP2Presponse SPI_TDP2Presponse @ TxUartBuffer; 362 // Finish UART TX work 363 WaitTxUART(); 364 // Copy to TX buffer 365 copyMemoryBlock( bufferRF, &SPI_TDP2Presponse, sizeof( SPI_TDP2Presponse ) ); 366 // Report PNUM and PCMD back via SPI 367 SPI_TDP2Presponse.DP2PresponseParams.PNUM = _PNUM; 368 SPI_TDP2Presponse.DP2PresponseParams.PCMD = _PCMD; 369 // Send response to UART 370 TxUART( PPAR ); 371 // Indicate reception 372 pulseLEDR(); 373 pulseLEDG(); 374 } 375 } 376 } 377 } 378 } 379 380 //############################################################################################ 381 void OpenUART() 382 //############################################################################################ 383 { 384 // Enable user ISR 385 _enableUserInterrupt = 1; 386 387 // If TR module with connected pins, disconnect them from RX and TX 388 _OUT_C5 = 1; // pin connected with RX 389 _OUT_A5 = 1; // pin connected with TX 390 _OUT_B4 = 1; // pin connected with TX 391 // Set RX, TX pins 392 _OUT_C7 = 1; // RX input 393 _OUT_C6 = 0; // TX output 394 395 #if defined( TR7xG ) 396 UART1MD = 0; 397 unlockPPS(); 398 RC6PPS = 0x10; // TX (Note: RX does not have to be set, use default) 399 lockPPS(); 400 #endif 401 402 // Setup baud rate 403 _SPBRGL = UART_SPBRG_VALUE( BAUDRATE ) & 0xff; 404 _SPBRGH = UART_SPBRG_VALUE( BAUDRATE ) >> 8; 405 // baud rate control setup: BRG16 = 1 406 #if defined( TR7xG ) 407 setBAUD1CON( 0b0000.1.000 ); 408 #else 409 BAUDCON = 0b0000.1.000; 410 #endif 411 412 // Async UART, high speed, 8 bit, TX enabled 413 // CSRC TX9 TXEN SYNC SENDB BRGH TRMT TX9D 414 #if defined( TR7xG ) 415 setTX1STA( 0b0010.0100 ); 416 #else 417 TXSTA = 0b0010.0100; 418 #endif 419 420 // Continuous receive, enable port, 8 bit 421 // SPEN RX9 SREN CREN ADDEN FERR OERR RX9D 422 _RCSTA = 0b1001.0000; 423 424 // Enable UART RX 425 RCIE = TRUE; 426 } 427 428 //############################################################################################ 429 void TxUART( uns8 dataLength @ W ) 430 //############################################################################################ 431 { 432 #pragma updateBank exit = 11 433 434 // Length of the TX packet 435 UartTxSize = dataLength; 436 // Initial UART TX state 437 UartTxState = UART_TX_START; 438 // Enable UART TX 439 TXIE = TRUE; 440 } 441 442 //############################################################################################ 443 uns8 UpdateCrc( uns8 crc @ FSR1H, uns8 value @ W ) 444 //############################################################################################ 445 { 446 #define Poly 0x8c // 0x8C (OneWire x^8 + x^5 + x^4 + 1) is reverse polynomial representation (normal is 0x31, reciprocal is 0x98) 447 448 // Based on http://www.dattalo.com/technical/software/pic/crc_8bit.c 449 // 19 instructions, 20 machine cycles per byte. [Hynek] 450 451 // Data in = W 452 // CRC in = FSR1H 453 // CRC out = W 454 455 /* 456 * Xn = (Xn-1 >> 1 ) ^ ( Xn-1.0 ? 0x8C : 0x00 ) 457 * For 0x8c: 0x46, 0x23, 0x9d, 0xc2, 0x61, 0xbc, 0x5e 458 */ 459 460 #define NextP(CurPoly,Poly) ((uns8)( ((CurPoly) >> 1) ^ ( ( (((CurPoly) & 1) ^ 1 ) - 1 ) & (Poly) ))) 461 462 crc ^= value; 463 #pragma updateBank 0 /* OFF */ 464 value = 0; 465 if ( crc.7 ) 466 value ^= Poly; // Reverse polynomial representation 467 if ( crc.6 ) 468 value ^= NextP( Poly, Poly ); 469 if ( crc.5 ) 470 value ^= NextP( NextP( Poly, Poly ), Poly ); 471 if ( crc.4 ) 472 value ^= NextP( NextP( NextP( Poly, Poly ), Poly ), Poly ); 473 if ( crc.3 ) 474 value ^= NextP( NextP( NextP( NextP( Poly, Poly ), Poly ), Poly ), Poly ); 475 if ( crc.2 ) 476 value ^= NextP( NextP( NextP( NextP( NextP( Poly, Poly ), Poly ), Poly ), Poly ), Poly ); 477 if ( crc.1 ) 478 value ^= NextP( NextP( NextP( NextP( NextP( NextP( Poly, Poly ), Poly ), Poly ), Poly ), Poly ), Poly ); 479 if ( crc.0 ) 480 value ^= NextP( NextP( NextP( NextP( NextP( NextP( NextP( Poly, Poly ), Poly ), Poly ), Poly ), Poly ), Poly ), Poly ); 481 482 return value; 483 #pragma updateBank 1 /* ON */ 484 } 485 486 //############################################################################################ 487 #pragma origin __USER_INTERRUPT // User interrupt service routine 488 #pragma library 0 // Always compile 489 void userIntRoutine() 490 //############################################################################################ 491 { 492 if ( RCIF ) 493 { 494 // Received byte, we ignore FERR 495 uns8 RxByte @ FSR1L; 496 RxByte = _RCREG; 497 498 // 8b RX checksum 499 static uns8 uartRxCrc; 500 501 // State RX machine 502 skip( UartRxState ); 503 #pragma computedGoto 1 504 goto _UART_RX_WAITHEAD; 505 goto _UART_RX_STOP; 506 goto _UART_RX_PACKET; 507 goto _UART_RX_ESCAPE; 508 #pragma computedGoto 0 509 ; 510 // --------------------------- 511 _UART_RX_ESCAPE: 512 switch ( RxByte ) 513 { 514 case HDLC_FRM_FLAG_SEQUENCE: 515 goto _SetUART_RX_PACKET; 516 517 case HDLC_FRM_CONTROL_ESCAPE: 518 { 519 _Set_UART_RX_WAITHEAD: 520 W = UART_RX_WAITHEAD; 521 goto _W2state; 522 } 523 } 524 525 // UART_RX_PACKET 526 UartRxState -= UART_RX_ESCAPE - UART_RX_PACKET; 527 RxByte ^= HDLC_FRM_ESCAPE_BIT; 528 goto _UART_RX_StoreByte; 529 530 // --------------------------- 531 _UART_RX_PACKET: 532 switch ( RxByte ) 533 { 534 case HDLC_FRM_CONTROL_ESCAPE: 535 W = UART_RX_ESCAPE; 536 goto _W2state; 537 538 case HDLC_FRM_FLAG_SEQUENCE: 539 { 540 if ( uartRxCrc == 0 && UartRxSize >= ( MinRxPacketSize + sizeof( uartRxCrc ) ) ) 541 { 542 // Packet received 543 UartRxSize -= sizeof( uartRxCrc ); 544 W = UART_RX_STOP; 545 goto _W2state; 546 } 547 548 goto _SetUART_RX_PACKET; 549 } 550 } 551 552 _UART_RX_StoreByte: 553 // Update checksum 554 uartRxCrc = UpdateCrc( uartRxCrc, RxByte ); 555 556 // If too many bytes 557 if ( UartRxSize >= ( MaxRxPacketSize + sizeof( uartRxCrc ) ) ) 558 goto _Set_UART_RX_WAITHEAD; 559 560 // Address to store the byte 561 // FSR0 = (uns16)&RxUartBuffer[0] + UartRxSize; 562 IndexedPtr( FSR0, RxUartBuffer, UartRxSize, sizeof( RxUartBuffer ) / sizeof( RxUartBuffer[0] ) - 1 ); 563 // Next index 564 UartRxSize++; 565 // Store byte 566 setINDF0( RxByte ); 567 568 goto _UART_RX_STOP; 569 570 // --------------------------- 571 _UART_RX_WAITHEAD: 572 if ( RxByte == HDLC_FRM_FLAG_SEQUENCE ) 573 { 574 _SetUART_RX_PACKET: 575 // Start new packet 576 UartRxSize = 0; 577 // Initialize RX checksum 578 uartRxCrc = 0xff; 579 W = UART_RX_PACKET; 580 581 _W2state: 582 UartRxState = W; 583 goto _UART_RX_STOP; 584 } 585 586 _UART_RX_STOP: 587 } 588 589 // Overrun recovery (we do it after receiving UART byte in order to receive it as soon as possible) 590 if ( OERR ) 591 CREN = 0; 592 #pragma updateBank 0 // Note: to avoid unnecessary MOVLB generated by CC5X, OERR and CREN must share the same bank! 593 // Seems excess, but at the end it is shorted and faster than having this statement at else branch 594 CREN = 1; 595 #pragma updateBank 1 596 597 // If not transmit interrupt and have some data to send then skip 598 if ( !TXIF ) 599 goto UART_TX_END; 600 601 if ( !TXIE ) 602 goto UART_TX_END; 603 604 skip( UartTxState ); 605 #pragma computedGoto 1 606 goto _UART_TX_START; // UART_TX_START 607 goto _UART_TX_DATA_CHSUM;// UART_TX_DATA 608 goto _UART_TX_DATA_CHSUM;// UART_TX_CHSUM 609 goto _UART_TX_STOP; // UART_TX_STOP 610 #pragma computedGoto 0 611 ; 612 // ------------------------- 613 _UART_TX_STOP: 614 // Stop UART TX 615 TXIE = FALSE; 616 // Send end of packet byte (will also set invalid state but the interrupt UART TX machine is stopped so it does not matter) 617 goto UART_TX_HDLC_FRM_FLAG_SEQUENCE; 618 619 // TRUE when previous byte was escaped one 620 static bit wasTxEscape; 621 // Pointer to the data to send 622 static uns16 txPtr; 623 // 8b check sum 624 static uns8 uartTxCrc; 625 626 // ------------------------- 627 _UART_TX_START: 628 // No escape character was sent 629 wasTxEscape = FALSE; 630 // Pointer to the 1st byte to send 631 txPtr = ( (uns16)&TxUartBuffer[0] ); 632 // Initialize ChSum 633 uartTxCrc = 0xff; 634 635 // Send start/end of packet byte 636 UART_TX_HDLC_FRM_FLAG_SEQUENCE: 637 _TXREG = HDLC_FRM_FLAG_SEQUENCE; 638 // Next state (UART_DATA) 639 goto UART_TX_NEXT_STATE; 640 641 // ------------------------- 642 _UART_TX_DATA_CHSUM: 643 // FSR0 points to the data to send 644 FSR0 = txPtr; 645 // Was the last byte escaped? 646 if ( wasTxEscape ) 647 { 648 // Escaping is over 649 wasTxEscape = FALSE; 650 // Send modified byte & Update ChSum 651 W = *FSR0 ^ HDLC_FRM_ESCAPE_BIT; 652 } 653 else 654 // Is byte to be escaped? 655 switch ( *FSR0 ) 656 { 657 case HDLC_FRM_FLAG_SEQUENCE: 658 case HDLC_FRM_CONTROL_ESCAPE: 659 { 660 // Mark the byte was escaped 661 wasTxEscape = TRUE; 662 // Send escape byte 663 W = HDLC_FRM_CONTROL_ESCAPE; 664 665 UART_TXW_END: 666 // TX WREG 667 _TXREG = W; 668 goto UART_TX_END; 669 } 670 671 // No escape 672 default: 673 // Send non-modified byte 674 W = *FSR0; 675 break; 676 } 677 678 // TX WREG 679 _TXREG = W; 680 // Update checksum 681 uartTxCrc = UpdateCrc( uartTxCrc, *FSR0 ); 682 // Move to the next byte 683 txPtr++; 684 // More bytes to send next time? 685 if ( --UartTxSize != 0 ) 686 // Yes, keep state 687 goto UART_TX_END; 688 689 // Next "data" is (not when going to state UART_TX_STOP) checksum 690 txPtr = (uns16)&uartTxCrc; 691 // Size is 1 byte 692 UartTxSize = sizeof( uartTxCrc ); 693 694 // Next state (UART_TX_CHSUM or UART_TX_STOP) 695 UART_TX_NEXT_STATE: 696 // Next UART state 697 UartTxState++; 698 699 UART_TX_END: 700 } 701 702 //############################################################################################