1 // ********************************************************************* 2 // Custom DPA Handler code template * 3 // ********************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-SensorBeaming-Temperature.c,v $ 7 // Version: $Revision: 1.4 $ 8 // Date: $Date: 2021/08/18 20:43:06 $ 9 // 10 // Revision history: 11 // 2021/08/18 Release for DPA 4.16 12 // 13 // ********************************************************************* 14 15 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 16 17 // Default IQRF include (modify the path according to your setup) 18 #include "IQRF.h" 19 20 // Default DPA header (modify the path according to your setup) 21 #include "DPA.h" 22 // Default Custom DPA Handler header (modify the path according to your setup) 23 #include "DPAcustomHandler.h" 24 // IQRF standards header (modify the path according to your setup) 25 #include "standard/IQRFstandard.h" 26 #include "standard/IQRF_HWPID.h" 27 // Uncomment the following includes if the respective component is needed 28 //#include "NFC.c" 29 30 //############################################################################################ 31 32 // Define to pulse LEDG on every Idle event and LEDR after beaming was transmitted. Also regular beaming is every 5 s instead of 60 s 33 #define DEBUGBeaming 34 35 #define _HWPID_ 0x5E7F 36 #define _HWPIDver_ 0x0100 // 1.00 37 38 // Random value. We cannot use DPA random value as it is generated only when event happens 39 uns8 rand; 40 // Variable to store sensor value at Get?_????() methods. 41 uns16 sensorValue; 42 43 void Beaming(); 44 45 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 46 //############################################################################################ 47 // https://doc.iqrf.org/DpaTechGuide/pages/custom-dpa-handler.html 48 bit CustomDpaHandler() 49 //############################################################################################ 50 { 51 // Handler presence mark 52 clrwdt(); 53 54 // Detect DPA event to handle (unused event handlers can be commented out or even deleted) 55 switch ( GetDpaEvent() ) 56 { 57 // ------------------------------------------------- 58 case DpaEvent_Interrupt: 59 // Do an extra quick background interrupt work 60 // ! 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. 61 // ! 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. 62 // ! 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. 63 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 64 // ! Make sure race condition does not occur when accessing those variables at other places. 65 // ! 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. 66 // ! Do not call any OS functions except setINDFx(). 67 // ! Do not use any OS variables especially for writing access. 68 // ! 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. 69 // https://doc.iqrf.org/DpaTechGuide/pages/EventInterrupt.html 70 return Carry; 71 72 // ------------------------------------------------- 73 case DpaEvent_Idle: 74 // Do a quick background work when RF packet is not received 75 // https://doc.iqrf.org/DpaTechGuide/pages/idle.html 76 77 #ifdef DEBUGBeaming 78 // On-line mode indication 79 setLEDG(); 80 #endif 81 if ( buttonPressed ) 82 // Go to Beaming mode 83 Beaming(); 84 break; 85 86 // ------------------------------------------------- 87 case DpaEvent_Reset: 88 // Called after module is reset 89 // https://doc.iqrf.org/DpaTechGuide/pages/ResetEvent.html 90 // Initialize nonzero random value 91 rand = Random.low8 | 1; 92 93 //goto DpaHandleReturnTRUE; // return TRUE only if you handle node bonding/unbonding 94 break; 95 96 // ------------------------------------------------- 97 case DpaEvent_BondingButton: 98 // Called to allow a bonding button customization 99 // https://doc.iqrf.org/DpaTechGuide/pages/bondingbutton.html 100 //goto DpaHandleReturnTRUE; // return TRUE to handle bonding button 101 break; 102 103 // ------------------------------------------------- 104 case DpaEvent_Indicate: 105 // Called to allow a customization of the device indication 106 // https://doc.iqrf.org/DpaTechGuide/pages/IndicateEvent.html 107 //goto DpaHandleReturnTRUE; // return TRUE to skip default indication 108 break; 109 110 // ------------------------------------------------- 111 case DpaEvent_Init: 112 // Do a one time initialization before main loop starts 113 // https://doc.iqrf.org/DpaTechGuide/pages/init.html 114 break; 115 116 // ------------------------------------------------- 117 case DpaEvent_ReceiveDpaRequest: 118 // Called after DPA request was received 119 // https://doc.iqrf.org/DpaTechGuide/pages/receivedparequest.html 120 121 //goto DpaHandleReturnTRUE; // return TRUE to skip default processing 122 break; 123 124 // ------------------------------------------------- 125 case DpaEvent_BeforeSendingDpaResponse: 126 // Called before sending DPA response back to originator of DPA response 127 // https://doc.iqrf.org/DpaTechGuide/pages/beforesendingdparesponse.html 128 break; 129 130 // ------------------------------------------------- 131 case DpaEvent_Notification: 132 // Called after DPA request was processed and after DPA response was sent 133 // https://doc.iqrf.org/DpaTechGuide/pages/notification.html 134 break; 135 136 // ------------------------------------------------- 137 case DpaEvent_AfterRouting: 138 // Called after Notification and after routing of the DPA response was finished 139 // https://doc.iqrf.org/DpaTechGuide/pages/afterrouting.html 140 break; 141 142 // ------------------------------------------------- 143 case DpaEvent_FrcValue: 144 // Called to get FRC value 145 // https://doc.iqrf.org/DpaTechGuide/pages/frcvalue.html 146 break; 147 148 // ------------------------------------------------- 149 case DpaEvent_FrcResponseTime: 150 // Called to get FRC response time 151 // https://doc.iqrf.org/DpaTechGuide/pages/frcresponsetime.html 152 break; 153 154 // ------------------------------------------------- 155 case DpaEvent_BeforeSleep: 156 // Called before going to sleep 157 // https://doc.iqrf.org/DpaTechGuide/pages/beforesleep.html 158 break; 159 160 // ------------------------------------------------- 161 case DpaEvent_AfterSleep: 162 // Called after woken up after sleep 163 // https://doc.iqrf.org/DpaTechGuide/pages/aftersleep.html 164 break; 165 166 // ------------------------------------------------- 167 case DpaEvent_DisableInterrupts: 168 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond and run RFPGM) 169 // https://doc.iqrf.org/DpaTechGuide/pages/eventDisableInterrupts.html 170 break; 171 172 // ------------------------------------------------- 173 case DpaEvent_PeerToPeer: 174 // Called when peer-to-peer (non-networking) packet is received 175 // https://doc.iqrf.org/DpaTechGuide/pages/peertopeer.html 176 break; 177 178 // ------------------------------------------------- 179 case DpaEvent_UserDpaValue: 180 // Called when DPA is required to return User defined DPA value in the response 181 // https://doc.iqrf.org/DpaTechGuide/pages/userdpavalue.html 182 break; 183 184 // ------------------------------------------------- 185 case DpaEvent_VerifyLocalFrc: 186 // Called to verify local FRC command 187 // https://doc.iqrf.org/DpaTechGuide/pages/verifylocalfrc.html 188 189 //goto DpaHandleReturnTRUE; // return TRUE allow FRC command 190 break; 191 192 // ------------------------------------------------- 193 case DpaEvent_DpaRequest: 194 // Called to interpret DPA request for peripherals 195 // https://doc.iqrf.org/DpaTechGuide/pages/EventDpaRequest.html 196 IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() 197 { 198 // ------------------------------------------------- 199 // Peripheral enumeration 200 // https://doc.iqrf.org/DpaTechGuide/pages/enumerate-peripherals.html 201 202 // We implement 1 standard peripheral 203 _DpaMessage.EnumPeripheralsAnswer.UserPerNr |= 1; 204 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS ); 205 _DpaMessage.EnumPeripheralsAnswer.HWPID |= _HWPID_; 206 _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= _HWPIDver_; 207 208 DpaHandleReturnTRUE: 209 return TRUE; 210 } 211 else 212 { 213 // ------------------------------------------------- 214 // Get information about peripheral 215 // https://doc.iqrf.org/DpaTechGuide/pages/get-peripheral-info.html 216 217 if ( _PNUM == PNUM_STD_SENSORS ) 218 { 219 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_SENSORS; 220 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ; 221 // Set standard version 222 _DpaMessage.PeripheralInfoAnswer.Par1 = STD_SENSORS_VERSION; 223 goto DpaHandleReturnTRUE; 224 } 225 226 break; 227 } 228 229 // ------------------------------------------------- 230 // Handle peripheral command 231 // https://doc.iqrf.org/DpaTechGuide/pages/handle-peripheral-request.html 232 233 // Supported peripheral number? 234 if ( _PNUM == PNUM_STD_SENSORS ) 235 { 236 // Supported commands? 237 switch ( _PCMD ) 238 { 239 // Invalid command 240 default: 241 // Return error 242 W = ERROR_PCMD; 243 _ERROR_W: 244 DpaApiReturnPeripheralError( W ); 245 break; 246 247 // Sensor enumeration 248 case PCMD_STD_ENUMERATE: 249 if ( _DpaDataLength != 0 ) 250 { 251 W = ERROR_DATA_LEN; 252 goto _ERROR_W; 253 } 254 255 // Then just enumerate their types 256 // ------------------------------------------------- 257 _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_EXTRA_LOW_VOLTAGE; 258 _DpaMessage.Response.PData[1] = STD_SENSOR_TYPE_TEMPERATURE; 259 _DpaDataLength = 2; 260 // ------------------------------------------------- 261 goto DpaHandleReturnTRUE; 262 } 263 } 264 265 break; 266 } 267 268 DpaHandleReturnFALSE: 269 return FALSE; 270 } 271 272 //############################################################################################ 273 void DpaSleep() 274 //############################################################################################ 275 { 276 // Finalize OS Sleep DPA Request 277 _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request ); 278 _PNUM = PNUM_OS; 279 _PCMD = CMD_OS_SLEEP; 280 // Execute sleep 281 DpaApiLocalRequest(); 282 } 283 284 //############################################################################################ 285 void RandomWait() 286 //############################################################################################ 287 { 288 #pragma updateBank default = UserBank_01 289 290 // Perform local DPA Request to go to sleep 291 292 // Time 32.768 ms * ( 30 + rand(0...31) ) i.e. 983 - 1999 ms 293 rand >>= 1; 294 #pragma updateBank 0 /* OFF */ // Optimization (avoid duplicate bank setting for RandomValue access) 295 W = 0b10111000; // x^8 + x^6 + x^5 + x^4 + 1 296 if ( Carry ) 297 rand ^= W; 298 #pragma updateBank 1 /* ON */ 299 300 // Prepare sleep parameters 301 _DpaMessage.PerOSSleep_Request.Time.low8 = ( rand & 0x1F ) + 30; 302 _DpaMessage.PerOSSleep_Request.Time.high8 = 0; 303 // 32.768 ms unit 304 _DpaMessage.PerOSSleep_Request.Control = 0b0001.0000; 305 // Execute sleep 306 DpaSleep(); 307 } 308 309 //############################################################################################ 310 void Get_Temperature() 311 //############################################################################################ 312 { 313 // https://doc.iqrf.org/IQRF-Standards/StandardSensor/pages/0x01-temperature.html 314 315 // Error reading temperature? Note: param3 holds finer temperature value after calling getTemperature() 316 if ( getTemperature() == -128 ) 317 // Return standard error value 318 param3 = FRC_STD_FRC_ERROR_VALUE; 319 else 320 { 321 // Extent minus sign bit #11 to the bits #12-15 322 if ( param3.11 ) 323 param3 |= 0xF000; 324 // Make a FRC value from the raw value 325 sensorValue = param3 ^ 0x8000; 326 } 327 } 328 329 //############################################################################################ 330 void Get_ExtraLowVoltage() 331 //############################################################################################ 332 { 333 // https://doc.iqrf.org/IQRF-Standards/StandardSensor/pages/0x04-extra-low-voltage.html 334 335 // Voltage [V] = 261.12 / (127 - getSupplyVoltage) 336 uns8 div = 127 - getSupplyVoltage(); 337 // For expected voltage ~3.0V, the divider is 127-40=87, so we will add 1/2 of it for more precise rounding 338 sensorValue = (uns24)( 261.120 * 1000 + 87.0 / 2 ) / div; 339 // Make a FRC value from the raw value 340 sensorValue ^= 0x8000; 341 } 342 343 //############################################################################################ 344 void ReleaseButton() 345 //############################################################################################ 346 { 347 do 348 { 349 clrwdt(); 350 } while ( buttonPressed ); 351 } 352 353 //############################################################################################ 354 void Beaming() 355 //############################################################################################ 356 { 357 setLEDR(); 358 // Wait for button release 359 ReleaseButton(); 360 stopLEDR(); 361 362 // Read 1st voltage 363 Get_ExtraLowVoltage(); 364 365 for ( ;; ) 366 { 367 // Do beaming 368 clrwdt(); 369 // Required time for the temperature sensor after wake-up from sleep 370 waitDelay( 31 ); // Note: in real application sleep instead of active waiting to lower the consumption 371 // Prepare beaming data 372 // Voltage was read 1st time when the device starts beaming and then after every TX in the beaming when the power consumption was the highest 373 _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_EXTRA_LOW_VOLTAGE; 374 _DpaMessage.Response.PData[1] = sensorValue.low8; 375 _DpaMessage.Response.PData[2] = sensorValue.high8; 376 377 Get_Temperature(); 378 _DpaMessage.Response.PData[3] = STD_SENSOR_TYPE_TEMPERATURE; 379 _DpaMessage.Response.PData[4] = sensorValue.low8; 380 _DpaMessage.Response.PData[5] = sensorValue.high8; 381 _DpaDataLength = 6; 382 383 // Do simple LBT 384 uns8 loop = 3; 385 do 386 { 387 if ( !checkRF( DpaApiReadConfigByte( CFGIND_RXFILTER ) + 10 ) ) 388 break; 389 390 RandomWait(); 391 } while ( --loop != 0 ); 392 393 // STD TX 394 // !!! Note: we expect that the aggregating repeaters are STD !!! 395 setRFmode( _TX_STD ); 396 397 // Force not routed packet to be sent from N by DPA API 398 NonroutedRfTxDpaPacket = TRUE; 399 400 // Prepare off-line sensor beaming packet 401 402 // HW profile ID 403 _HWPID = _HWPID_; 404 405 // No DPA Params used 406 _DpaParams = 0; 407 408 // Beaming is broadcast 409 _NADR = BROADCAST_ADDRESS; 410 _NADRhigh = 0; 411 412 // Prepare sensor packet type and quantity data 413 _PNUM = PNUM_STD_SENSORS; 414 _PCMD = PCMD_STD_SENSORS_READ_TYPES_AND_FRC_VALUES | RESPONSE_FLAG; 415 416 // TX DPA message with zero DPA Value and asynchronous 417 // Note: Use DpaValue = 0x01 to indicate asynchronous i.e. non-regular beaming 418 DpaApiRfTxDpaPacket( 0 /*DpaValue*/, 0 ); 419 420 // Measure voltage just after TX 421 Get_ExtraLowVoltage(); 422 423 // Do a sleep between two beamings 424 // Prepare sleep parameters, 2.097 s unit 425 #ifdef DEBUGBeaming 426 pulseLEDR(); 427 _DpaMessage.PerOSSleep_Request.Time = (uns16)( 5 / 2.097 ); // Beaming every ~5 sec 428 #else 429 _DpaMessage.PerOSSleep_Request.Time = (uns16)( 60 / 2.097 ); // Beaming every ~60 sec 430 #endif 431 // Wakeup on negative edge (button press) 432 _DpaMessage.PerOSSleep_Request.Control = 0b0000.0001; 433 // Execute sleep 434 DpaSleep(); 435 436 // Go to On-line mode when button is pressed? 437 if ( buttonPressed ) 438 { 439 // Wait for button release 440 setLEDG(); 441 ReleaseButton(); 442 stopLEDG(); 443 // Break the beaming loop 444 break; 445 } 446 } 447 448 // Restore RF settings 449 DpaApiSetRfDefaults(); 450 } 451 452 //############################################################################################ 453 // Uncomment the following includes if the respective component is needed 454 //#include "NFC.c" 455 456 // 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) 457 #include "DPAcustomHandler.h" 458 //############################################################################################