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 //############################################################################################