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