1 // ********************************************************************* 2 // Custom DPA Handler code example - Scanning RSSI of neighbors * 3 // ********************************************************************* 4 // Copyright (c) MICRORISC s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-ScanRSSI.c,v $ 7 // Version: $Revision: 1.41 $ 8 // Date: $Date: 2022/02/25 09:41:25 $ 9 // 10 // Revision history: 11 // 2022/02/24 Release for DPA 4.17 12 // 2017/03/13 Release for DPA 3.00 13 // 2015/08/05 Release for DPA 2.20 14 // 15 // ********************************************************************* 16 17 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 18 19 // Default IQRF include (modify the path according to your setup) 20 #include "IQRF.h" 21 22 // Uncomment to compile Custom DPA Handler for Coordinator 23 //#define COORDINATOR_CUSTOM_HANDLER 24 25 // Default DPA header (modify the path according to your setup) 26 #include "DPA.h" 27 // Default Custom DPA Handler header (modify the path according to your setup) 28 #include "DPAcustomHandler.h" 29 30 // This example implements measurement of RSSI among all nodes of the IQRF network. This handler must be uploaded to all Nodes and with COORDINATOR_CUSTOM_HANDLER symbol defined to the coordinator too. 31 // To measure the RSSIs use FRC with command FRC_AcknowledgedBroadcastBits = 0x02 with DPA request for custom peripheral PNUM=0x20, PCMD=0, HWPID=0x001F and data corresponding to the TScanRSSI structure. 32 // When FRC is finished then the same peripheral at C must called. C then sends TScanPacket packet. Then come short 10 timeslots when all Ns send their TScanPacket packets. Timeslots are ordered according to the Ns' VRNs. 33 // When the measurement is finished then PNUM=0x20, PCMD=1 and PNUM=0x20, PCMD=2 are used to read RSSI levels from all nodes. 34 // The result is a bit array of bit pairs i.e. 2 bits for every node at the network. Bit pairs are ordered according the node address. Bits 0b00 indicated that the node of such address was not "listened" at all. 35 // 0b01 means low RSSI, 0b10 means middle RSSI and 0b11 specifies high RSSI 36 // ! Please note that this example stores RSSI levels in the bufferAUX memory buffer which is not generally recommended because bufferAUX is used internally by DPA for certain purposes (i.e. storing batches). 37 // ! Therefore it is important to read levels immediately after RSSI is measure otherwise levels might be overwritten. 38 // This example works only at STD mode, not at LP mode 39 40 // Structure holding data for custom peripheral PNUM=0x20, PCMD=0. This command initiates measurement of RSSI among nodes. It must be used only as a part of FRC_AcknowledgedBroadcastBits. 41 typedef struct 42 { 43 // Maximum VRN in the network (equals number of discovered nodes in the network) 44 uns8 MaxVrn; 45 // TX power used to measure RSSI 46 uns8 TxPower; 47 // If RSSI is equal of less than this number, it gets the level 1 48 uns8 RssiLow; 49 // If RSIS is equal of less than this number, it gets the level 2. If RSSI is greater then it gets code 3. 50 uns8 RssiMid; 51 } TScanRSSI; 52 53 // Structure of the packet used to measure RSSI. 54 typedef struct 55 { 56 // Packet header. equals 'N' 57 uns8 Header; 58 // Address of the node that sent the packet 59 uns8 Address; 60 } TScanPacket; 61 62 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 63 //############################################################################################ 64 bit CustomDpaHandler() 65 //############################################################################################ 66 { 67 // Handler presence mark 68 clrwdt(); 69 70 #ifndef COORDINATOR_CUSTOM_HANDLER 71 // Place for local static variables used only within CustomDpaHandler() among more events 72 static uns8 timer10msCounter; 73 #endif 74 75 // Detect DPA event to handle 76 switch ( GetDpaEvent() ) 77 { 78 #ifndef COORDINATOR_CUSTOM_HANDLER 79 // ------------------------------------------------- 80 case DpaEvent_Interrupt: 81 // Do an extra quick background interrupt work 82 // ! 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. 83 // ! 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. 84 // ! 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. 85 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 86 // ! Make sure race condition does not occur when accessing those variables at other places. 87 // ! 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. 88 // ! Do not call any OS functions except setINDFx(). 89 // ! Do not use any OS variables especially for writing access. 90 // ! 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. 91 92 // If TMR6 interrupt occurred 93 if ( TMR6IF ) 94 { 95 // Unmask interrupt 96 TMR6IF = 0; 97 // Increment count 98 timer10msCounter++; 99 } 100 101 return Carry; 102 103 // ------------------------------------------------- 104 case DpaEvent_Init: 105 // Do a one time initialization before main loop starts 106 { 107 // Setup TMR6 to generate ticks on the background (ticks every 10ms) 108 _PR6 = 250 - 1; 109 // Prescaler 16, Postscaler 10, 16 * 10 * 250 = 40000 = 4MHz * 10ms 110 #if defined( TR7xG ) 111 TMR6MD = 0; 112 T6CON = 0b1.100.1001; 113 // Timer2/4/6 Clock Select bits = FOSC/4 114 T6CLKCON |= 0b0000.0001; 115 #else 116 T6CON = 0b0.1001.1.10; 117 #endif 118 119 TMR6IE = TRUE; 120 } 121 break; 122 123 // ------------------------------------------------- 124 case DpaEvent_AfterSleep: 125 // Called on wake-up from sleep 126 TMR6IE = TRUE; 127 _TMR6ON = TRUE; 128 break; 129 130 // ------------------------------------------------- 131 case DpaEvent_BeforeSleep: 132 // Called before going to sleep (the same handling as DpaEvent_DisableInterrupts event) 133 134 // ------------------------------------------------- 135 case DpaEvent_DisableInterrupts: 136 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond, and Run RFPGM) 137 // Must not use TMR6 any more 138 _TMR6ON = FALSE; 139 TMR6IE = FALSE; 140 break; 141 142 #endif 143 144 // ------------------------------------------------- 145 case DpaEvent_DpaRequest: 146 // Called to interpret DPA request for peripherals 147 // ------------------------------------------------- 148 // Peripheral enumeration 149 if ( IsDpaEnumPeripheralsRequest() ) 150 { 151 // We implement 1 user peripheral 152 _DpaMessage.EnumPeripheralsAnswer.UserPerNr |= 1; 153 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); 154 _DpaMessage.EnumPeripheralsAnswer.HWPID |= 0x001F; 155 _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0x0000; 156 157 DpaHandleReturnTRUE: 158 return TRUE; 159 } 160 // ------------------------------------------------- 161 // Get information about peripheral 162 else if ( IsDpaPeripheralInfoRequest() ) 163 { 164 if ( _PNUM == PNUM_USER + 0 ) 165 { 166 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA; 167 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 168 goto DpaHandleReturnTRUE; 169 } 170 171 break; 172 } 173 // ------------------------------------------------- 174 else 175 { 176 // Handle peripheral 177 if ( _PNUM == PNUM_USER + 0 ) 178 { 179 switch ( _PCMD ) 180 { 181 // Initiate RSSI measurement 182 case 0: 183 { 184 // Check data length 185 if ( _DpaDataLength != sizeof( TScanRSSI ) ) 186 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 187 188 #ifndef COORDINATOR_CUSTOM_HANDLER 189 // At Node it can be called only from FRC acknowledged broadcast, otherwise it is not synchronized! 190 if ( _NADR != BROADCAST_ADDRESS ) 191 DpaApiReturnPeripheralError( ERROR_NADR ); 192 // NOde with temporary address does not measure 193 if ( ntwADDR == TEMPORARY_ADDRESS ) 194 DpaApiReturnPeripheralError( ERROR_FAIL ); 195 #endif 196 // Request data 197 TScanRSSI ScanRSSI @ _DpaMessage.Request.PData; 198 // Copy of request data 199 TScanRSSI ScanRSSICopy; 200 // Make a copy 201 copyMemoryBlock( &ScanRSSI, &ScanRSSICopy, sizeof( ScanRSSICopy ) ); 202 203 // Set non-network RF settings 204 setNonetMode(); 205 setNetworkFilteringOff(); 206 setRFmode( _WPE | _RX_STD | _TX_STD | _STDL ); 207 setRFpower( ScanRSSICopy.TxPower ); 208 209 // Scanning packet 210 TScanPacket ScanPacket @ bufferRF; 211 212 #ifndef COORDINATOR_CUSTOM_HANDLER 213 // Clear bufferAUX 214 clearBufferINFO(); 215 swapBufferINFO(); 216 217 // Give C some extra time to sent its ScanPacket packet 218 waitDelay( 3 ); 219 220 // We use the shortest RX timeout 221 toutRF = 1; 222 // Initialize timer, maximize gap before measurement starts 223 timer10msCounter = MAX_ADDRESS + 2; 224 // We did not send out packet yet 225 bit sent = FALSE; 226 // Loop all timeslots 227 for ( ;; ) 228 { 229 // If we receive ScanPacket from other node 230 if ( checkRF( 0 ) && RFRXpacket() && DLEN == sizeof( ScanPacket ) && ScanPacket.Header == 'N' && ScanPacket.Address <= MAX_ADDRESS ) 231 { 232 // bits variable stores the RSSI level from 1 to 3 according to the thresholds RssiLow and RssiMid 233 uns8 bits @ userReg0; 234 bits = 0b01; 235 if ( lastRSSI > ScanRSSICopy.RssiLow ) 236 { 237 bits++; 238 if ( lastRSSI > ScanRSSICopy.RssiMid ) 239 bits++; 240 } 241 242 // Shift level to the correct bit position according to the node address value 243 uns8 temp @ userReg1; 244 temp = ScanPacket.Address % 4; 245 while ( temp != 0 ) 246 { 247 temp--; 248 bits <<= 2; 249 } 250 251 // Compute byte address according to the node address value 252 FSR0 = ScanPacket.Address / 4; 253 FSR0 += bufferAUX; 254 255 // Combine bits with already stored ones 256 setINDF0( *FSR0 | bits ); 257 } 258 259 // Any timeslots pending? 260 if ( timer10msCounter != ScanRSSICopy.MaxVrn + 1 ) 261 { 262 // Is it my timeslot and the packet was not sent yet? 263 if ( timer10msCounter == ntwVRN && !sent ) 264 { 265 // Packet will be sent 266 sent = TRUE; 267 #endif 268 // Prepare the packet 269 ScanPacket.Header = 'N'; 270 #ifndef COORDINATOR_CUSTOM_HANDLER 271 ScanPacket.Address = ntwADDR; 272 #else 273 ScanPacket.Address = COORDINATOR_ADDRESS; 274 #endif 275 DLEN = sizeof( ScanPacket ); 276 PIN = 0; 277 // Send the packet 278 RFTXpacket(); 279 280 #ifndef COORDINATOR_CUSTOM_HANDLER 281 } 282 } 283 else 284 // Timeslots are over. Exit the loop. 285 break; 286 } 287 #endif 288 // Restore RF settings 289 DpaApiSetRfDefaults(); 290 setNetworkFilteringOn(); 291 // REstore network settings 292 #ifndef COORDINATOR_CUSTOM_HANDLER 293 setNodeMode(); 294 #else 295 setCoordinatorMode(); 296 #endif 297 298 goto DpaHandleReturnTRUE; 299 } 300 301 #ifndef COORDINATOR_CUSTOM_HANDLER 302 case 2: 303 // Return 2nd part of the RSSI bitmaps 304 memoryOffsetFrom = DPA_MAX_DATA_LENGTH; 305 306 case 1: 307 // Check data length 308 if ( _DpaDataLength != 0 ) 309 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 310 311 // Copy result from bufferAUX to the DPA response @ bufferRF 312 swapBufferINFO(); 313 copyBufferINFO2RF(); 314 swapBufferINFO(); 315 316 // Return correct data length 317 if ( _PCMD == 2 ) 318 _DpaDataLength = ( MAX_ADDRESS + 1 ) / 4 - DPA_MAX_DATA_LENGTH; 319 else 320 _DpaDataLength = DPA_MAX_DATA_LENGTH; 321 322 goto DpaHandleReturnTRUE; 323 #endif 324 } 325 } 326 } 327 } 328 329 return FALSE; 330 } 331 //############################################################################################ 332 // Default Custom DPA Handler header; 2nd include implementing a Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup) 333 #include "DPAcustomHandler.h" 334 //############################################################################################