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