1 // $Header: /volume1/cvs/cvsroot/microrisc/iqrf/DPA/Examples/DP2Papp.c,v 1.10 2019/10/30 08:53:37 hynek Exp $
    2 //############################################################################################
    3 // Example DP2P TR module application
    4 //############################################################################################
    5 
    6 #include "../includes/IQRF.h"
    7 #include "Dpa.h"
    8 
    9 // DP2P special (fake PNUM and PCMD) DPA values to indicate that DP2P parameters are specified
   10 #define DP2P_PNUM   0xDD
   11 #define DP2P_PCMD   0xDD
   12 
   13 // Incoming SPI DP2P packet request
   14 typedef union
   15 {
   16   // Used to send DP2P requests, then only PNUM+PCMD(+_zero_) fields from the next union field are used to specify DPA request PCMD+PNUN
   17 
   18   /* IQRF IDE Terminal example
   19    $07$03$00$FE$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
   20      PNUM = PNUM_LEDG = $07
   21      PCMD = CMD_LED_PULSE = $03
   22      Nodes #1-7 = $FE + 29 x $00
   23      SlotLength = 0x00 (default values)
   24      Response RF power = $07
   25      HWPID 0xFFFF = $FF$FF
   26   */
   27   TDP2Prequest DP2Prequest;
   28 
   29   // 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)
   30   struct
   31   {
   32     // PNUM
   33     uns8  PNUM;
   34     // PCMD
   35     uns8  PCMD;
   36     // Zero
   37     uns8  _zero_;
   38     // Previous fields overlap Header part of the TDP2Prequest
   39 
   40     // Next fields are used only when PNUM and PCMD equal DP2P_PNUM and DP2P_PCMD respectively
   41 
   42     /* IQRF IDE Terminal example
   43      $DD$DD$00$01$23$07$05$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00$00
   44        STD+LP network = $01
   45        channel 35 = $23
   46        Request RF power 7 = $07
   47        RX filter 5 = $05
   48        AccessPassword = 16 x $00 (i.e. empty, not recommended to use!)
   49     */
   50 
   51     // Non-zero value when STD+LP network is used, otherwise STD
   52     uns8  STD_LP_network;
   53     // Channel to communicate DP2P packets
   54     uns8  RfChannel;
   55     // Power to send DP2P request
   56     uns8  ReqTxPower;
   57     // Filter to receive DP2P responses
   58     uns8  RespRxFilter;
   59     // Access Password to use for de/encryption
   60     uns8  AccessPassword[sizeof( _DpaMessage.PerOSSetSecurity_Request.Data )];
   61   } DP2PrequestParams;
   62 } TSPI_TDP2Prequest;
   63 
   64 // Outgoing SPI DP2P packet invite (fields must exactly overlap TDP2Invite)
   65 typedef struct
   66 {
   67   uns8  Header[3];  // 0x000001 (0x00 is used to detect TSPI_TDP2Pinvite, 0xFF specifies TSPI_TDP2Presponse - see below)
   68   uns8  NADR;
   69 } TSPI_TDP2Pinvite;
   70 
   71 // Outgoing SPI DP2P packet response
   72 typedef union
   73 {
   74   // Real DP2P response but PNUM and PCMD is overlapped, see the next union field
   75   TDP2Presponse DP2Presponse;
   76 
   77   struct
   78   {
   79     // PNUM
   80     uns8  PNUM;
   81     // PCMD
   82     uns8  PCMD;
   83     // 0xFF (remainder from the DP2P Response, used to detect Response)
   84     uns8 _0xFF_;
   85   } DP2PresponseParams;
   86 } TSPI_TDP2Presponse;
   87 
   88 /*
   89 IQRF IDE terminal log example
   90  <> Length Data (comment)
   91  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)
   92  Tx 38     07.03.00.FE.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-7 will pulse the LEDG, see details above)
   93  Rx 4      01.00.00.01. (Invite from Node #1)
   94  Rx 4      07.83.FF.01. (Response from Node #1)
   95  Rx 4      01.00.00.02. (Invite from Node #2)
   96  Rx 4      07.83.FF.02. (Response from Node #2)
   97  Rx 4      01.00.00.03. (Invite from Node #3)
   98  Rx 4      07.83.FF.03. (Response from Node #3)
   99  Rx 4      01.00.00.04. (Invite from Node #4)
  100  Rx 4      07.83.FF.04. (Response from Node #4)
  101  Rx 4      01.00.00.06. (Invite from Node #5)
  102  Rx 4      07.83.FF.05. (Response from Node #5)
  103  Rx 4      01.00.00.06. (Invite from Node #6)
  104  Rx 4      07.83.FF.06. (Response from Node #6)
  105  Rx 4      01.00.00.07. (Invite from Node #7)
  106  Rx 4      07.83.FF.07. (Response from Node #7)
  107 */
  108 
  109 //############################################################################################
  110 void APPLICATION()
  111 //############################################################################################
  112 {
  113   // Indicate start
  114   pulseLEDR();
  115   pulseLEDG();
  116 
  117   // We use SPI
  118   enableSPI();
  119 
  120   // Filter used to receive DP2P responses
  121   uns8 RespRxFilter;
  122   // RF mode to send DP2P Requests
  123   uns8 ReqRfMode;
  124 
  125   // Loop forever
  126   for ( ;; )
  127   {
  128     // Anything at SPI received?
  129     if ( !getStatusSPI() && _SPIRX )
  130     {
  131       // No CRC error
  132       if ( _SPICRCok )
  133       {
  134         // Stop SPI
  135         stopSPI();
  136 
  137         // SPI incoming packet variable
  138         TSPI_TDP2Prequest SPI_TDP2Prequest @ bufferCOM;
  139         // Check the packet a little
  140         if ( SPI_TDP2Prequest.DP2PrequestParams._zero_ == 0 )
  141         {
  142           // DP2P parameters to set?
  143           if ( SPI_TDP2Prequest.DP2PrequestParams.PNUM == DP2P_PNUM && SPI_TDP2Prequest.DP2PrequestParams.PCMD == DP2P_PCMD )
  144           {
  145             // Check the length
  146             if ( SPIpacketLength == sizeof( SPI_TDP2Prequest.DP2PrequestParams ) )
  147             {
  148               // Indicate reception
  149               pulseLEDR();
  150 
  151               // Set RF mode and toutRF according to the network type
  152               if ( SPI_TDP2Prequest.DP2PrequestParams.STD_LP_network != 0 )
  153                 // STD+LP network
  154                 ReqRfMode = _WPE | _RX_STD | _TX_LP;
  155               else
  156                 // STD network
  157                 ReqRfMode = _WPE | _RX_STD | _TX_STD | _STDL;
  158 
  159               // Set RF channel
  160               setRFchannel( SPI_TDP2Prequest.DP2PrequestParams.RfChannel );
  161               // Set RF power
  162               setRFpower( SPI_TDP2Prequest.DP2PrequestParams.ReqTxPower );
  163               // Remember RX filter
  164               RespRxFilter = SPI_TDP2Prequest.DP2PrequestParams.RespRxFilter;
  165               // Set Access Password
  166               copyMemoryBlock( SPI_TDP2Prequest.DP2PrequestParams.AccessPassword, bufferINFO, sizeof( SPI_TDP2Prequest.DP2PrequestParams.AccessPassword ) );
  167               setAccessPassword();
  168             }
  169           }
  170           else
  171           {
  172             // Check the length
  173             if ( SPIpacketLength >= offsetof( TDP2Prequest, PDATA ) )
  174             {
  175               // Send DP2P request
  176 
  177               // Prepare DPA Request
  178               // Get PNUN
  179               _PNUM = SPI_TDP2Prequest.DP2PrequestParams.PNUM;
  180               // Get PCMD
  181               _PCMD = SPI_TDP2Prequest.DP2PrequestParams.PCMD;
  182               // DP2P Request variable
  183               TDP2Prequest DP2Prequest @ bufferRF;
  184               // Make sure header is correct (there were PNUM and PMCD stored)
  185               SPI_TDP2Prequest.DP2Prequest.Header[0] = 0;
  186               SPI_TDP2Prequest.DP2Prequest.Header[1] = 0;
  187               // Set data length
  188               PPAR = SPIpacketLength - offsetof( TDP2Prequest, PDATA );
  189               // Set the DP2P packet length
  190               DLEN = sizeof( DP2Prequest );
  191               // Use Access Password for encryption
  192               encryptByAccessPassword = TRUE;
  193               // Encrypt the DP2P Request
  194               copyBufferCOM2RF();
  195               encryptBufferRF( sizeof( DP2Prequest ) / 16 );
  196               // Set RF Flags
  197               PIN = _DPAF_MASK;
  198               // And finally send DP2P Request
  199               setRFmode( ReqRfMode );
  200               RFTXpacket();
  201               // Indicate reception
  202               pulseLEDR();
  203             }
  204           }
  205         }
  206       }
  207       // Start SPI again
  208       startSPI( 0 );
  209     }
  210 
  211     // Ready to receive STD packets
  212     toutRF = 1;
  213     setRFmode( _WPE | _RX_STD | _TX_STD );
  214     // Anything from RF received?
  215     if ( // There is a signal
  216          checkRF( RespRxFilter ) &&
  217          // Packet was received
  218          RFRXpacket() &&
  219          // DPA flags are used
  220          _DPAF &&
  221          // There is enough data (at least one AES block)
  222          DLEN >= 16 &&
  223          // Real packet has a correct AES-128 block length
  224          ( ( PPAR + 15 ) & ~15 ) == DLEN )
  225     {
  226       // Decrypt the packet
  227       encryptByAccessPassword = TRUE;
  228       decryptBufferRF( DLEN / 16 );
  229 
  230       // DP2P Invite variable
  231       TDP2Invite DP2Invite @ bufferRF;
  232       // Check the DP2P Invite validity
  233       if ( PPAR == sizeof( TDP2Invite ) && DP2Invite.Header[0] == 1 && ( DP2Invite.Header[1] | DP2Invite.Header[2] ) == 0 )
  234       {
  235         // Save N address
  236         uns8 addr = DP2Invite.NADR;
  237 
  238         // Prepare DP2P Confirm
  239         TDP2Confirm DP2Confirm @ bufferRF;
  240         DP2Confirm.Header[0] = 0x03;
  241         // Encrypt the DP2P Confirm
  242         encryptByAccessPassword = TRUE;
  243         encryptBufferRF( sizeof( TDP2Confirm ) / 16 );
  244         // And finally send DP2P Confirm
  245         RFTXpacket();
  246         // Indicate reception
  247         pulseLEDG();
  248 
  249         // Finish SPI work
  250         while ( getStatusSPI() );
  251         stopSPI();
  252         // Prepare SPI Invite
  253         TSPI_TDP2Pinvite SPI_TDP2Pinvite @ bufferCOM;
  254         SPI_TDP2Pinvite.NADR = addr;
  255         SPI_TDP2Pinvite.Header[0] = 0x01;
  256         SPI_TDP2Pinvite.Header[1] = 0x00;
  257         SPI_TDP2Pinvite.Header[2] = 0x00;
  258         // Send SPI outgoing Invite packet
  259         startSPI( sizeof( TSPI_TDP2Pinvite ) );
  260       }
  261       else
  262       {
  263         // DP2P Response variable
  264         TDP2Presponse DP2Presponse @ bufferRF;
  265         // Check the DP2P Response validity
  266         if ( PPAR >= offsetof( TDP2Presponse, PDATA ) && ( DP2Presponse.Header[0] & DP2Presponse.Header[1] & DP2Presponse.Header[2] ) == 0xFF )
  267         {
  268           // SPI outgoing Response packet variable
  269           TSPI_TDP2Presponse SPI_TDP2Presponse @ bufferCOM;
  270           // Finish SPI work
  271           while ( getStatusSPI() );
  272           stopSPI();
  273           // Copy to COM buffer
  274           copyBufferRF2COM();
  275           // Report PNUM and PCMD back via SPI
  276           SPI_TDP2Presponse.DP2PresponseParams.PNUM = _PNUM;
  277           SPI_TDP2Presponse.DP2PresponseParams.PCMD = _PCMD;
  278           // Send response to SPI
  279           startSPI( PPAR );
  280           // Indicate reception
  281           pulseLEDR();
  282           pulseLEDG();
  283         }
  284       }
  285     }
  286   }
  287 }
  288 
  289 //############################################################################################