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