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