1 // ********************************************************************* 2 // Custom DPA Handler code example - Standard Sensors - Template * 3 // ********************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: 1402_Sensor-Template.c,v $ 7 // Version: $Revision: 1.10 $ 8 // Date: $Date: 2017/12/11 19:26:49 $ 9 // 10 // Revision history: 11 // 2017/11/16 Release for DPA 3.02 12 // 2017/08/14 Release for DPA 3.01 13 // 14 // ********************************************************************* 15 16 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 17 18 // This example implements 5 sensors according to the IQRF Sensors standard. The example does not implement writing data to the sensors. 19 20 // The example will not work at demo DPA version because demo DPA does not support PCMD != 0 21 22 // Default IQRF include (modify the path according to your setup) 23 #include "IQRF.h" 24 25 // Uncomment to implement Custom DPA Handler for Coordinator 26 //#define COORDINATOR_CUSTOM_HANDLER 27 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 // IQRF standards header (modify the path according to your setup) 33 #include "IQRFstandard.h" 34 #include "IQRF_HWPID.h" 35 36 //############################################################################################ 37 38 // Number of implemented sensors 39 #define SENSORS_COUNT 5 40 41 // Variable to store sensor value at Get?_????() methods. This example implements sensors returning maximum 2 bytes of data. 42 uns16 sensorValue @ param3; 43 44 // Reads sensor value to the sensorValue variable and to responseFRCvalue(2B) variable(s) based on FR command @ _PCMD 45 // Returns TRUE if the FRC is prepared 46 bit Get0_Temperature(); 47 bit Get1_CO2(); 48 bit Get2_VOC(); 49 bit Get3_Humidity(); 50 bit Get4_Binary7(); 51 52 // Stores sensor value byte(s) to the FSR1[+1...], in case of PCMD_STD_SENSORS_READ_TYPES_AND_VALUES sensor type is stored before value byte(s) 53 void StoreValue( uns8 sensorType ); 54 55 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 56 //############################################################################################ 57 bit CustomDpaHandler() 58 //############################################################################################ 59 { 60 // This forces CC5X to wisely use MOVLB instructions (doc says: The 'default' bank is used by the compiler for loops and labels when the algorithm gives up finding the optimal choice) 61 #pragma updateBank default = UserBank_01 62 63 // Handler presence mark 64 clrwdt(); 65 66 // Sleeping parameters, valid when Time != 0 67 static TPerOSSleep_Request PerOSSleep_Request; 68 69 // Detect DPA event to handle 70 switch ( GetDpaEvent() ) 71 { 72 // ------------------------------------------------- 73 case DpaEvent_Interrupt: 74 // Do an extra quick background interrupt work 75 // ! 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. 76 // ! 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. 77 // ! 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. 78 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 79 // ! Make sure race condition does not occur when accessing those variables at other places. 80 // ! 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. 81 // ! Do not call any OS functions except setINDFx(). 82 // ! Do not use any OS variables especially for writing access. 83 // ! 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. 84 return Carry; 85 86 // ------------------------------------------------- 87 case DpaEvent_Idle: 88 // Do a quick background work when RF packet is not received 89 90 // Should go to sleep? 91 if ( PerOSSleep_Request.Time != 0 ) 92 { 93 // Copy sleep parameters to the DPA request 94 _DpaMessage.PerOSSleep_Request.Time = PerOSSleep_Request.Time; 95 _DpaMessage.PerOSSleep_Request.Control = PerOSSleep_Request.Control; 96 // Switch off sleeping time=flag 97 PerOSSleep_Request.Time = 0; 98 // Finalize OS Sleep DPA Request 99 _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request ); 100 _PNUM = PNUM_OS; 101 _PCMD = CMD_OS_SLEEP; 102 // Perform local DPA Request to go to sleep 103 DpaApiLocalRequest(); 104 } 105 break; 106 107 // ------------------------------------------------- 108 case DpaEvent_DpaRequest: 109 // Called to interpret DPA request for peripherals 110 // ------------------------------------------------- 111 // Peripheral enumeration 112 if ( IsDpaEnumPeripheralsRequest() ) 113 { 114 // We implement 1 standard peripheral 115 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 116 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS ); 117 // ToDo: use actual IQRF Alliance allocated HWPID and current version of this handler 118 _DpaMessage.EnumPeripheralsAnswer.HWPID = HWPID_MICRORISC__DEMO_SENSOR_TEMPLATE; 119 _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0000; 120 121 DpaHandleReturnTRUE: 122 return TRUE; 123 } 124 // ------------------------------------------------- 125 // Get information about peripheral 126 else if ( IsDpaPeripheralInfoRequest() ) 127 { 128 if ( _PNUM == PNUM_STD_SENSORS ) 129 { 130 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_SENSORS; 131 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 132 // Set standard version 133 _DpaMessage.PeripheralInfoAnswer.Par1 = 13; 134 goto DpaHandleReturnTRUE; 135 } 136 137 break; 138 } 139 // ------------------------------------------------- 140 else 141 { 142 // Handle peripheral command 143 144 // Supported peripheral number? 145 if ( _PNUM == PNUM_STD_SENSORS ) 146 { 147 // Supported commands? 148 switch ( _PCMD ) 149 { 150 // Invalid command 151 default: 152 // Return error 153 DpaApiReturnPeripheralError( ERROR_PCMD ); 154 155 // Sensor enumeration 156 case PCMD_STD_ENUMERATE: 157 if ( _DpaDataLength != 0 ) 158 goto _ERROR_DATA_LEN; 159 160 // Then just enumerate their types 161 _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_TEMPERATURE; 162 _DpaMessage.Response.PData[1] = STD_SENSOR_TYPE_CO2; 163 _DpaMessage.Response.PData[2] = STD_SENSOR_TYPE_VOC; 164 _DpaMessage.Response.PData[3] = STD_SENSOR_TYPE_HUMIDITY; 165 _DpaMessage.Response.PData[4] = STD_SENSOR_TYPE_BINARYDATA7; 166 W = SENSORS_COUNT; 167 goto _W2_DpaDataLength; 168 169 // Supported commands. They are handled the same way except one "if" at StoreValue() method 170 case PCMD_STD_SENSORS_READ_VALUES: 171 case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES: 172 { 173 // No sensor bitmap specified? W = _DpaDataLength. Note: W is used to avoid MOVLB at next if 174 W = _DpaDataLength; 175 if ( W == 0 ) // Note: must not modify W 176 { 177 // Actually clears the bitmap 178 #if &_DpaMessage.Request.PData[0] != &bufferRF[0] 179 #error 180 #endif 181 clearBufferRF(); 182 // Simulate 1st only sensor in the bitmap (states of the other unimplemented sensors do not care) 183 _DpaMessage.Request.PData[0].0 = 1; 184 // Bitmap is 32 bits long = 4 185 _DpaDataLength = W = 4; 186 } 187 188 // Invalid bitmap (data) length (W = _DpaDataLength)? 189 if ( W != 4 ) 190 { 191 _ERROR_DATA_LEN: 192 // Return error 193 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 194 } 195 196 // Now read the sensors 197 198 // Prepare pointer (minus 1, see below) to store sensor (types and) values to 199 // Note: 5 sensors at this example cannot return more than DPA_MAX_DATA_LENGTH bytes of data, so it does not have to be checked... 200 // ... If it would be the case, then ERROR_FAIL must be returned 201 FSR1 = &_DpaMessage.Response.PData[-1]; 202 203 // Store bitmap of sensors to get values from 204 uns8 sensorsBitmap = FSR1[1]; 205 206 // 1st sensor (index 0) selected? 207 if ( sensorsBitmap.0 ) 208 { 209 Get0_Temperature(); 210 StoreValue( STD_SENSOR_TYPE_TEMPERATURE ); 211 } 212 213 // 2nd sensor (index 1) selected? 214 if ( sensorsBitmap.1 ) 215 { 216 Get1_CO2(); 217 StoreValue( STD_SENSOR_TYPE_CO2 ); 218 } 219 220 // 3rd sensor (index 2) selected? 221 if ( sensorsBitmap.2 ) 222 { 223 Get2_VOC(); 224 StoreValue( STD_SENSOR_TYPE_VOC ); 225 } 226 227 // 4th sensor (index 3) selected? 228 if ( sensorsBitmap.3 ) 229 { 230 Get3_Humidity(); 231 StoreValue( STD_SENSOR_TYPE_HUMIDITY ); 232 } 233 234 // 5th sensor (index 4) selected? 235 if ( sensorsBitmap.4 ) 236 { 237 Get4_Binary7(); 238 StoreValue( STD_SENSOR_TYPE_BINARYDATA7 ); 239 } 240 241 // Compute returned data bytes count 242 W = FSR1L - ( (uns16)&_DpaMessage.Response.PData[0] & 0xFF ) + 1; 243 // Optimization: return W long block of bytes at response 244 _W2_DpaDataLength: 245 _DpaDataLength = W; 246 goto DpaHandleReturnTRUE; 247 } 248 } 249 } 250 251 break; 252 } 253 254 // ------------------------------------------------- 255 case DpaEvent_FrcValue: 256 // Called to get FRC value 257 258 // FSR1 for optimization purposes (avoid MOVLB) will be used to point to DataOutBeforeResponseFRC[0...] 259 FSR1 = &DataOutBeforeResponseFRC[0]; 260 // Check for correct FRC user data 261 if ( *FSR1++ /*DataOutBeforeResponseFRC[0]*/ == PNUM_STD_SENSORS ) 262 { 263 // Actually used sensor index 264 uns8 sensorIndex = FSR1[1] /*DataOutBeforeResponseFRC[2]*/ & 0x1f; 265 // Test sensor type 266 switch ( *FSR1++ /*DataOutBeforeResponseFRC[1]*/ ) 267 { 268 default: 269 goto DpaHandleReturnFALSE; 270 271 // No type specified, use specified index value 272 case 0x00: 273 goto _KeepSensorIndex; 274 275 // For other types make the index value based on the requested index value and sensor type 276 case STD_SENSOR_TYPE_TEMPERATURE: 277 if ( sensorIndex > 0 ) 278 goto DpaHandleReturnFALSE; 279 W = 0; 280 break; 281 282 case STD_SENSOR_TYPE_CO2: 283 if ( sensorIndex > 0 ) 284 goto DpaHandleReturnFALSE; 285 W = 1; 286 break; 287 288 case STD_SENSOR_TYPE_VOC: 289 if ( sensorIndex > 0 ) 290 goto DpaHandleReturnFALSE; 291 W = 2; 292 break; 293 294 case STD_SENSOR_TYPE_HUMIDITY: 295 if ( sensorIndex > 0 ) 296 goto DpaHandleReturnFALSE; 297 W = 3; 298 break; 299 300 case STD_SENSOR_TYPE_BINARYDATA7: 301 if ( sensorIndex > 0 ) 302 goto DpaHandleReturnFALSE; 303 W = 4; 304 break; 305 } 306 307 // New sensor index based on type and requested index 308 sensorIndex = W; 309 _KeepSensorIndex: 310 311 // Test for supported FRC commands 312 switch ( _PCMD ) 313 { 314 default: 315 goto DpaHandleReturnFALSE; 316 317 case FRC_STD_SENSORS_BIT: 318 case FRC_STD_SENSORS_1B: 319 case FRC_STD_SENSORS_2B: 320 switch ( sensorIndex ) 321 { 322 default: 323 goto DpaHandleReturnFALSE; 324 325 case 0: 326 Carry = Get0_Temperature(); 327 break; 328 329 case 1: 330 Carry = Get1_CO2(); 331 break; 332 333 case 2: 334 Carry = Get2_VOC(); 335 break; 336 337 case 3: 338 Carry = Get3_Humidity(); 339 break; 340 341 case 4: 342 Carry = Get4_Binary7(); 343 break; 344 } 345 346 // This type of FRC is not valid for the specified sensor 347 if ( !Carry ) 348 goto DpaHandleReturnFALSE; 349 350 break; 351 } 352 353 // Some sensor was measured by FRC, check if there is a sleep request 354 FSR1++; 355 if ( INDF1.0 ) // Note: same as DataOutBeforeResponseFRC[3].0 356 { 357 // Remember sleep parameters to go to sleep at the Idle event later 358 PerOSSleep_Request.Time.low8 = FSR1[4 - 3]; // Note: same as DataOutBeforeResponseFRC[4]; 359 PerOSSleep_Request.Time.high8 = FSR1[5 - 3]; // Note: same as DataOutBeforeResponseFRC[5]; 360 PerOSSleep_Request.Control = FSR1[6 - 3]; // Note: same as DataOutBeforeResponseFRC[6]; 361 } 362 } 363 364 break; 365 366 // ------------------------------------------------- 367 case DpaEvent_FrcResponseTime: 368 // Called to get FRC response time 369 370 // In this example the FRC commands are fast 371 switch ( DataOutBeforeResponseFRC[0] ) 372 { 373 case FRC_STD_SENSORS_BIT: 374 case FRC_STD_SENSORS_1B: 375 case FRC_STD_SENSORS_2B: 376 responseFRCvalue = _FRC_RESPONSE_TIME_40_MS; 377 break; 378 } 379 break; 380 } 381 DpaHandleReturnFALSE: 382 return FALSE; 383 } 384 385 //############################################################################################ 386 // Increases FSR1 and then stores the byte 387 void setPlusPlusINDF1( uns8 data @ W ) 388 //############################################################################################ 389 { 390 FSR1++; // Note: must not modify W 391 setINDF1( data ); 392 } 393 394 //############################################################################################ 395 // Stores measured sensor value byte(s) and optionally sensor type to the FSR[+1...] 396 void StoreValue( uns8 sensorType ) 397 //############################################################################################ 398 { 399 // Is the sensor type to be stored too? 400 if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES ) 401 setPlusPlusINDF1( sensorType ); 402 403 // Store lower value byte 404 setPlusPlusINDF1( sensorValue.low8 ); 405 406 // No more value bytes to store? 407 if ( sensorType.7 != 0 ) 408 return; 409 410 // Store higher value byte 411 setPlusPlusINDF1( sensorValue.high8 ); 412 413 // Note: this example implements sensors returning only 1 or 2 bytes of data. If another data widths are returned, then it must be implemented explicitly. 414 } 415 416 //############################################################################################ 417 bit setFRCerror1B() 418 //############################################################################################ 419 { 420 responseFRCvalue = 2; 421 return TRUE; 422 } 423 424 //############################################################################################ 425 bit setFRCerror2B() 426 //############################################################################################ 427 { 428 responseFRCvalue2B = 2; 429 return TRUE; 430 } 431 432 //############################################################################################ 433 // Sensor index 0: measure temperature using the TR sensor 434 bit Get0_Temperature() 435 //############################################################################################ 436 { 437 // Make sure FSR1 is not modified 438 439 // Measure temperature using TR sensor 440 bit sensorError = FALSE; 441 // When error, then adjust the standard error values 442 if ( getTemperature() == -128 ) 443 { 444 sensorError = TRUE; 445 param3 = 0x8000; 446 } 447 448 // Return sensor value 449 sensorValue = param3; 450 451 // Test for supported FRC commands 452 switch ( _PCMD ) 453 { 454 default: 455 return FALSE; 456 457 case FRC_STD_SENSORS_1B: 458 // Return sensor FRC value 1B 459 // Check for out of limits 460 if ( sensorError || (int16)sensorValue > (int16)( 105.5 * 16 ) || (int16)sensorValue < ( (int16)-20 * 16 ) ) 461 return setFRCerror1B(); 462 463 // Convert to the "F = ( T + 22 ) * 2 " from 1/16 resolution 464 uns16 _sensorValue = sensorValue + 4; // Note: do rounding when /8 465 responseFRCvalue = (uns8)( _sensorValue / 8 ) + 44; 466 break; 467 468 case FRC_STD_SENSORS_2B: 469 // Return sensor FRC value 2B 470 if ( sensorError ) 471 return setFRCerror2B(); 472 473 responseFRCvalue2B = sensorValue ^ 0x8000; 474 break; 475 } 476 477 return TRUE; 478 } 479 480 //############################################################################################ 481 // Sensor index 1: simulate measuring CO2 482 bit Get1_CO2() 483 //############################################################################################ 484 { 485 // Make sure FSR1 is not modified 486 487 bit sensorError = FALSE; 488 // Fake CO2 return value 489 sensorValue = 0x0987; 490 // When error, return standard (FRC) error value(s) 491 if ( sensorValue == 0x8000 ) 492 sensorError = TRUE; 493 494 // Test for supported FRC commands 495 switch ( _PCMD ) 496 { 497 default: 498 return FALSE; 499 500 case FRC_STD_SENSORS_1B: 501 // Return sensor FRC value 1B 502 // Check for out of limits 503 if ( sensorError || sensorValue > 4016 ) 504 return setFRCerror1B(); 505 506 responseFRCvalue = sensorValue / 16 + 4; 507 break; 508 509 case FRC_STD_SENSORS_2B: 510 // Return sensor FRC value 2B 511 if ( sensorError ) 512 return setFRCerror2B(); 513 514 responseFRCvalue2B = sensorValue + 4; 515 break; 516 } 517 518 return TRUE; 519 } 520 521 //############################################################################################ 522 // Sensor index 2: simulate measuring VOC 523 bit Get2_VOC() 524 //############################################################################################ 525 { 526 // Make sure FSR1 is not modified 527 528 bit sensorError = FALSE; 529 // Fake VOC return value 530 sensorValue = 0x0123; 531 // When error, return standard (FRC) error value(s) 532 if ( sensorValue == 0x8000 ) 533 sensorError = TRUE; 534 535 // Test for supported FRC commands 536 switch ( _PCMD ) 537 { 538 default: 539 return FALSE; 540 541 case FRC_STD_SENSORS_1B: 542 // Return sensor FRC value 1B 543 // Check for out of limits 544 if ( sensorError || sensorValue > 4016 ) 545 return setFRCerror1B(); 546 547 responseFRCvalue = sensorValue / 16 + 4; 548 break; 549 550 case FRC_STD_SENSORS_2B: 551 // Return sensor FRC value 2B 552 if ( sensorError ) 553 return setFRCerror2B(); 554 555 responseFRCvalue2B = sensorValue + 4; 556 break; 557 } 558 559 return TRUE; 560 } 561 562 //############################################################################################ 563 // Sensor index 3: simulate measuring humidity 564 bit Get3_Humidity() 565 //############################################################################################ 566 { 567 // Make sure FSR1 is not modified 568 569 // Fake humidity return value 570 sensorValue.low8 = 50 * 2; 571 572 // Test for supported FRC commands 573 switch ( _PCMD ) 574 { 575 default: 576 return FALSE; 577 578 case FRC_STD_SENSORS_1B: 579 // Return sensor FRC value 1B 580 if ( sensorValue.low8 == 0xEE ) 581 return setFRCerror1B(); 582 583 responseFRCvalue = sensorValue.low8 + 4; 584 break; 585 } 586 return TRUE; 587 } 588 589 //############################################################################################ 590 // Sensor index 3: simulate binary data 591 bit Get4_Binary7() 592 //############################################################################################ 593 { 594 // Make sure FSR1 is not modified 595 596 bit sensorError = FALSE; 597 // Fake humidity return value 598 sensorValue.low8 = lastRSSI & 0x7F; 599 // When error, return standard (FRC) error value(s) 600 if ( sensorValue.low8 == 0x80 ) 601 sensorError = TRUE; 602 603 // Test for supported FRC commands 604 switch ( _PCMD ) 605 { 606 default: 607 return FALSE; 608 609 case FRC_STD_SENSORS_BIT: 610 // If there is a sensor error, 2-bit FRC cannot indicate it, it returns [01] 611 if ( !sensorError ) 612 { 613 // Number of shifts to get the bit out of the return value 614 uns8 bitLoop = ( INDF1 >> 5 ) + 1; 615 // Value to get the bit from 616 W = sensorValue.low8; 617 do 618 { 619 // Get the bit to Carry 620 W = rr( W ); 621 // Next bit 622 } while ( --bitLoop != 0 ); // Note: must not modify W and Carry 623 // Current (prepared by DPA) FRC value is [01], change it to [11] (means bit is set) 624 responseFRCvalue.1 = 1; // Note: must not modify Carry 625 // Is bit set? 626 if ( !Carry ) 627 // Bit is NOT set, return [10] 628 responseFRCvalue.0 = 0; 629 } 630 break; 631 632 case FRC_STD_SENSORS_1B: 633 // Return sensor FRC value 1B 634 if ( sensorError ) 635 return setFRCerror1B(); 636 637 responseFRCvalue = sensorValue.low8 + 4; 638 break; 639 } 640 return TRUE; 641 } 642 643 //############################################################################################ 644 // 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) 645 #include "DPAcustomHandler.h" 646 //############################################################################################