1 // ********************************************************************* 2 // Custom DPA Handler code example - Multiple response example * 3 // ********************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-MultiResponse.c,v $ 7 // Version: $Revision: 1.22 $ 8 // Date: $Date: 2019/05/06 07:13:14 $ 9 // 10 // Revision history: 11 // 2019/01/10 Release for DPA 4.00 12 // 2017/03/13 Release for DPA 3.00 13 // 14 // ********************************************************************* 15 16 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 17 18 // This is an !EXPERIMENTAL EXAMPLE! that shows how to receive responses from more nodes to the one request. 19 // This example works only at STD mode. 20 // Because of used uns24 type it requires an extended version of CC5X compiler. 21 22 // The example allows to send DPA request to multiple selected nodes (addressed by VRN but NOT by logical address). Addressed nodes then send one by one their responses. 23 // Please see TRequest structure below. Just broadcast this structure at PDATA top the PNUM=0x20 and PCMD=0x00. 24 // Only addressed, discovered and routing nodes will respond. 25 26 // Default IQRF include (modify the path according to your setup) 27 #include "IQRF.h" 28 // Default DPA header (modify the path according to your setup) 29 #include "DPA.h" 30 // Default Custom DPA Handler header (modify the path according to your setup) 31 #include "DPAcustomHandler.h" 32 33 //############################################################################################ 34 35 typedef struct 36 { 37 // Length of the response slot in 10 ms units. The length must be big enough to fit the longest response from any addressed node. 38 // Please see MIN_TIMESLOT and MAX_TIMESLOT. 39 uns8 ResponseSlot; 40 // Bitmap of the addressed nodes. Each bit represent one node. VrnBitmap[0].1 is VRN=1, VrnBitmap[0].2 is VRN=2, ..., VrnBitmap[29].7 is VRN=239 41 // Mapping from logical address to VRN is stored at Coordinator external EEPROM table at address 0x5000. See IQRF OS documentation for more information. 42 uns8 VrnBitmap[( MAX_ADDRESS + 7 ) / 8]; 43 // PNUM of the request 44 uns8 PNUM; 45 // PCMD of the request 46 uns8 PCMD; 47 // Optional PDATA 48 uns8 PDATA[0]; 49 } TMultiRequest; 50 51 // Request stored at bufferAUX. We can use bufferAUX because the Batch, that internally uses bufferAUX, is not used. 52 TMultiRequest MultiRequest @ bufferAUX; 53 54 #if &_DpaMessage.Request.PData[0] != &bufferRF[0] || &_DpaMessage.Response.PData[0] != &bufferRF[0] 55 #error We assume DPA data @ bufferRF 56 #endif 57 58 // Indicate response will be sent back 59 static bit sendResponse; 60 61 void CancelResponse(); 62 63 #define myHWPID 0xaAaF 64 65 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 66 //############################################################################################ 67 bit CustomDpaHandler() 68 //############################################################################################ 69 { 70 // Handler presence mark 71 clrwdt(); 72 73 // Saved DPA request/response parameters 74 static uns8 saveDpaDataLength, savePNUM, savePCMD; 75 // Indicate multi-request was send 76 static bit multiResponseRequested; 77 // Delay to send the response back 78 static uns24 responseDelay; 79 80 // Detect DPA event to handle (unused event handlers can be commented out or even deleted) 81 switch ( GetDpaEvent() ) 82 { 83 // ------------------------------------------------- 84 case DpaEvent_Interrupt: 85 // Do an extra quick background interrupt work 86 // ! The time spent handling this event is critical.If there is no interrupt to handle return immediately otherwise keep the code as fast as possible. 87 // ! Make sure the event is the 1st case in the main switch statement at the handler routine.This ensures that the event is handled as the 1st one. 88 // ! It is desirable that this event is handled with immediate return even if it is not used by the custom handler because the Interrupt event is raised on every MCU interrupt and the “empty” return handler ensures the shortest possible interrupt routine response time. 89 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 90 // ! Make sure race condition does not occur when accessing those variables at other places. 91 // ! Make sure( inspect.lst file generated by C compiler ) compiler does not create any hidden temporary local variable( occurs when using division, multiplication or bit shifts ) at the event handler code.The name of such variable is usually Cnumbercnt. 92 // ! Do not call any OS functions except setINDFx(). 93 // ! Do not use any OS variables especially for writing access. 94 // ! All above rules apply also to any other function being called from the event handler code, although calling any function from Interrupt event is not recommended because of additional MCU stack usage. 95 96 // If TMR6 interrupt occurred 97 if ( TMR6IF ) 98 { 99 // Unmask interrupt 100 TMR6IF = 0; 101 // Decrement tick count 102 if ( responseDelay != 0 ) 103 responseDelay--; 104 else 105 TMR6ON = FALSE; 106 } 107 108 return Carry; 109 110 // ------------------------------------------------- 111 case DpaEvent_Idle: 112 // Do a quick background work when RF packet is not received 113 114 // Ready to send the response? 115 if ( sendResponse && !TMR6ON ) 116 { 117 // Cancel response 118 CancelResponse(); 119 // Number of hops = my VRN 120 RTHOPS = ntwVRN; 121 // Just generate new PID 122 ++PID; 123 // No DPA Params used 124 _DpaParams = 0; 125 // Send response to the coordinator 126 _NADR = COORDINATOR_ADDRESS; 127 // Recall stored parameters 128 _PNUM = savePNUM; 129 _PCMD = savePCMD; 130 // Copy stored response data to the right place 131 swapBufferINFO(); 132 copyBufferINFO2RF(); 133 // Prepare data length 134 _DpaDataLength = saveDpaDataLength; 135 // My HWPID 136 _HWPID = myHWPID; 137 // And finally send the response 138 DpaApiRfTxDpaPacket( lastRSSI, 0xff ); 139 } 140 break; 141 142 // ------------------------------------------------- 143 case DpaEvent_Init: 144 // Do a one time initialization work before main loop starts 145 146 // Setup TMR6 to generate ticks on the background (ticks every 10ms) 147 PR6 = 250 - 1; 148 // Prescaler 16, Postscaler 10, 16 * 10 * 250 = 40000 = 4MHz * 10ms 149 T6CON = 0b0.1001.0.10; 150 TMR6IE = TRUE; 151 break; 152 153 // ------------------------------------------------- 154 case DpaEvent_AfterSleep: 155 // Called on wake-up from sleep 156 157 // "Start" timer 158 TMR6IE = TRUE; 159 break; 160 161 // ------------------------------------------------- 162 case DpaEvent_BeforeSleep: 163 // Called before going to sleep (the same handling as DpaEvent_DisableInterrupts event) 164 case DpaEvent_DisableInterrupts: 165 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond, and Run RFPGM) 166 167 // Must not use TMR6 any more 168 TMR6ON = FALSE; 169 TMR6IE = FALSE; 170 171 // ------------------------------------------------- 172 case DpaEvent_FrcResponseTime: 173 // Called to get FRC response time 174 case DpaEvent_FrcValue: 175 // Called to get FRC value 176 case DpaEvent_ReceiveDpaRequest: 177 // Called after DPA request was received 178 179 // Events that will cancel sending response 180 CancelResponse(); 181 break; 182 183 // ------------------------------------------------- 184 case DpaEvent_AfterRouting: 185 // Called after Notification and after routing of the DPA response was finished 186 187 // Is there a multi-response? 188 if ( multiResponseRequested ) 189 { 190 // Reset the flag 191 multiResponseRequested = FALSE; 192 // Delay for the 1st VRN 193 responseDelay = MIN_STD_TIMESLOT; 194 // Bitmap bit mask 195 uns8 mask = 0; 196 // Bitmap byte pointer 197 #if &MultiRequest.VrnBitmap[-1] != &bufferAUX[0] 198 FSR0 = &MultiRequest.VrnBitmap[-1]; 199 #else 200 setFSR0( _FSR_AUX ); 201 #endif 202 // Checked VRN 203 uns8 vrn; 204 for ( vrn = 0; vrn <= ntwVRN; vrn++ ) 205 { 206 // Next mask 207 mask <<= 1; 208 // Start with new mask and next byte? 209 if ( mask == 0 ) 210 { 211 // New mask 212 mask.0 = 1; 213 // Next byte 214 FSR0++; 215 } 216 217 // Is the VRN addressed? 218 if ( ( *FSR0 & mask ) != 0 ) 219 { 220 // Is it me? 221 if ( vrn == ntwVRN ) 222 { 223 // I am addressed :-), so I will run the request and store a response for later sending 224 // Prepare the request 225 _PNUM = MultiRequest.PNUM; 226 _PCMD = MultiRequest.PCMD; 227 setFSR1( _FSR_RF ); 228 copyMemoryBlock( MultiRequest.PDATA, FSR1, _DpaDataLength = saveDpaDataLength - sizeof( MultiRequest ) ); 229 // Run the request. It should take the same time at all nodes. 230 DpaApiLocalRequest(); 231 // Store the response parameters 232 savePNUM = _PNUM; 233 savePCMD = _PCMD; 234 saveDpaDataLength = _DpaDataLength; 235 // Store the response data to bufferAUX 236 copyBufferRF2INFO(); 237 swapBufferINFO(); 238 // Delay to send the response is on 239 sendResponse = TRUE; 240 // Synchronize and start timer 241 TMR6 = 0; 242 TMR6ON = TRUE; 243 break; 244 } 245 else 246 { 247 // Delay for the current VRN 248 uns8 loop = MultiRequest.ResponseSlot; 249 // Loop is faster and shorter than multiplication 250 do 251 { 252 responseDelay += vrn; 253 } while ( --loop != 0 ); 254 // Add some extra time for every addressed VRN before me 255 responseDelay += MIN_STD_TIMESLOT; 256 } 257 } 258 } 259 // Delay is computed, but I was not addressed :-( 260 } 261 break; 262 263 // ------------------------------------------------- 264 case DpaEvent_DpaRequest: 265 // Called to interpret DPA request for peripherals 266 267 // Cancel sending multi response 268 CancelResponse(); 269 270 // ------------------------------------------------- 271 // Peripheral enumeration 272 if ( IsDpaEnumPeripheralsRequest() ) 273 { 274 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 275 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); 276 _DpaMessage.EnumPeripheralsAnswer.HWPID = myHWPID; 277 278 DpaHandleReturnTRUE: 279 return TRUE; 280 } 281 // ------------------------------------------------- 282 // Get information about peripheral 283 else if ( IsDpaPeripheralInfoRequest() ) 284 { 285 if ( _PNUM == PNUM_USER + 0 ) 286 { 287 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA; 288 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 289 goto DpaHandleReturnTRUE; 290 } 291 break; 292 } 293 // ------------------------------------------------- 294 else 295 { 296 // Handle peripheral command 297 if ( _PNUM == PNUM_USER + 0 ) 298 { 299 // Check the command value and other stuff 300 if ( _PCMD == 0 && 301 // Data length is enough? 302 _DpaDataLength >= sizeof( MultiRequest ) && 303 // Broadcast? 304 _NADR == BROADCAST_ADDRESS && 305 // Am I routing? 306 ( DpaApiReadConfigByte( CFGIND_DPA_FLAGS ) & 0b1000 ) == 0 && 307 // I do not have temporary address (i.e. no VRN)? 308 ntwADDR != TEMPORARY_ADDRESS && 309 // I have a non-zero VRN (I am or I was discovered) 310 ntwVRN != 0 && 311 // I am discovered with the last discovery? 312 ntwDID == RTDID ) 313 // Then I can response back 314 { 315 // Save data length 316 saveDpaDataLength = _DpaDataLength; 317 // We will process the request after routing is over 318 multiResponseRequested = TRUE; 319 // Store TMultiRequest to the bufferAUX for lated processing 320 copyBufferRF2INFO(); 321 swapBufferINFO(); 322 // Request was just OK (because of broadcast the response is not sent) 323 goto DpaHandleReturnTRUE; 324 } 325 326 // Invalid command for some reason from above 327 DpaApiReturnPeripheralError( ERROR_FAIL ); 328 } 329 } 330 331 break; 332 } 333 334 return FALSE; 335 } 336 //############################################################################################ 337 void CancelResponse() 338 //############################################################################################ 339 { 340 TMR6ON = FALSE; 341 sendResponse = FALSE; 342 } 343 //############################################################################################ 344 // Default Custom DPA Handler header; 2nd include to implement Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup) 345 #include "DPAcustomHandler.h" 346 //############################################################################################