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