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