1 // *********************************************************************************************************** 2 // Custom DPA Handler code example - Standard Sensors + Binary output - DDC-SE-01 + DDC-RE-01 - LP version * 3 // *********************************************************************************************************** 4 // Copyright (c) MICRORISC s.r.o. 5 // 6 // File: $RCSfile: 4402_DDC-SE+RE_LP.c,v $ 7 // Version: $Revision: 1.20 $ 8 // Date: $Date: 2021/08/18 20:43:06 $ 9 // 10 // Revision history: 11 // 2021/08/18 Release for DPA 4.16 12 // 2020/01/02 Release for DPA 4.11 13 // 2019/03/07 Release for DPA 4.01 14 // 15 // ********************************************************************* 16 17 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 18 // IQRF Standards documentation https://doc.iqrf.org/ 19 20 // This example implements 3 sensors according to the IQRF Sensors standard 21 // Index 0 i.e. 1st sensor is either Dallas 18B20 or MCP9802 temperature sensor at DDC-SE-01 board according to the HW jumper position and symbol DALLASnotMCP. 22 // Index 1 i.e. 2nd sensor is light intensity indicator at DDC-SE-01 board (value range is 0[max light]-127[max dark]). 23 // Index 2 i.e. 3rd sensor is potentiometer value at DDC-SE-01 board (value range is 0[left stop]-127[right stop]). 24 25 // This example also implements 2 binary outputs according to the IQRF Binary Outputs standard 26 // Index 0 i.e. 1st output is Relay #1 @ DDC-RE-01 27 // Index 1 i.e. 2nd output is Relay #2 @ DDC-RE-01 28 29 // This example must be compiled without a "-bu" compiler switch in order to fit into available Flash memory 30 31 // Default IQRF include (modify the path according to your setup) 32 #include "IQRF.h" 33 34 // We can save more instructions if needed by the symbol below 35 // #define PARAM_CHECK_LEVEL 1 36 37 // Default DPA header (modify the path according to your setup) 38 #include "DPA.h" 39 // Default Custom DPA Handler header (modify the path according to your setup) 40 #include "DPAcustomHandler.h" 41 // IQRF standards header (modify the path according to your setup) 42 #include "IQRFstandard.h" 43 #include "IQRF_HWPID.h" 44 45 // If defined then the handler is compiled for Dallas otherwise for MCP9802 46 //#define DALLASnotMCP 47 // !!! Important: with free C5XX compiler, the symbol DALLASnotMCP must not be defined, otherwise the code does not fit into available program memory. 48 49 //############################################################################################ 50 51 // Define useful macro that saves some code but not preset at DPA < 3.01 52 #if DPA_VERSION_MASTER < 0x0301 53 // Optimized macro for both testing enumeration peripherals ELSE peripherals information. See examples 54 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequestNoSize() if ( _PCMD == CMD_GET_PER_INFO ) if ( _PNUM == PNUM_ENUMERATION ) 55 56 #if PARAM_CHECK_LEVEL >= 2 57 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() if ( _DpaDataLength == 0 && _PCMD == CMD_GET_PER_INFO ) if ( _PNUM == PNUM_ENUMERATION ) 58 #else 59 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequestNoSize() 60 #endif 61 #endif 62 63 //############################################################################################ 64 65 // Number of implemented sensors 66 #define SENSORS_COUNT 3 67 68 // Variable to store sensor value at Get?_????() methods. This example implements sensors returning maximum 2 bytes of data. 69 uns16 sensorValue @ param3; 70 71 // Reads sensor value to the sensorValue variable and to responseFRCvalue(2B) variable 72 bit Get0_Temperature(); 73 bit Get1_BinaryData_Light(); 74 bit Get2_BinaryData_Potentiometer(); 75 76 // 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) 77 void StoreValue( uns8 sensorType ); 78 79 // ms per ticks 80 #define TICKS_LEN 10 81 82 #ifdef DALLASnotMCP 83 // Sensor connected to PORT C.3 (compatible with DDC-SE-01) 84 #define OneWire_TRIS TRISC.3 85 #define OneWire_IO_IN PORTC.3 86 #define OneWire_IO_OUT LATC.3 87 88 // Writes sensor configuration (resolution) 89 bit Ds18B20WriteConfig( uns8 value ); 90 91 // Resets OneWire 92 bit OneWireReset(); 93 // Reads OneWire byte 94 uns8 OneWireReadByte(); 95 // Writes OneWire byte 96 void OneWireWriteByte( uns8 byte ); 97 98 // DS18B20 commands 99 #define CMD_READROM 0x33 100 #define CMD_CONVERTTEMP 0x44 101 #define CMD_CPYSCRATCHPAD 0x48 102 #define CMD_WSCRATCHPAD 0x4e 103 #define CMD_MATCHROM 0x55 104 #define CMD_RPWRSUPPLY 0xb4 105 #define CMD_RECEEPROM 0xb8 106 #define CMD_RSCRATCHPAD 0xbe 107 #define CMD_SKIPROM 0xcc 108 #define CMD_ALARMSEARCH 0xec 109 #define CMD_SEARCHROM 0xf0 110 111 // Final DS18B20 temperature value read by state machine 112 uns16 temperature; 113 114 #else // DALLASnotMCP 115 116 // I2C SCL frequency [Hz] 117 #define I2Cfrequency 50000 118 119 // MCP9802 address 120 #define I2C_ADR 0b10010110 121 // Power pin 122 #define PWR_SENSOR_TRIS TRISC.7 123 #define PWR_SENSOR_IO LATC.7 124 125 #endif 126 127 //############################################################################################ 128 129 // Number of implemented binary outputs 130 #define OUTPUTS_COUNT 2 131 132 // Sets and Gets state of the indexed binary output 133 void SetOutput( uns8 state, uns8 index ); 134 bit GetOutput( uns8 index ); 135 136 // DDC-RE-01 relay pins 137 // C.5 = C8 = Relay#1 138 #define RELAY1_LAT LATC.5 139 #define RELAY1_TRIS TRISC.5 140 // C.2 = C2 = Relay#2 141 #define RELAY2_LAT LATC.2 142 #define RELAY2_TRIS TRISC.2 143 144 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 145 //############################################################################################ 146 bit CustomDpaHandler() 147 //############################################################################################ 148 { 149 // 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) 150 #pragma updateBank default = UserBank_01 151 152 #ifdef DALLASnotMCP 153 // Finite machine states 154 typedef enum 155 { 156 S_ResetConvertT = 0, 157 S_SkipRomConvertT, 158 S_CmdConvertT, 159 160 S_WaitConvertT, 161 162 S_ResetReadTemp, 163 S_SkipRomReadTemp, 164 S_CmdReadTemp, 165 S_Byte1ReadTemp, 166 S_Byte2ReadTemp 167 } TState; 168 #endif 169 170 // Handler presence mark 171 clrwdt(); 172 173 // Sleeping parameters, valid when Time != 0 174 static TPerOSSleep_Request PerOSSleep_Request; 175 176 #ifdef DALLASnotMCP 177 // Finite machine state 178 static uns8 state; // = S_ResetConvertT = 0 179 // Pre-read lower temperature byte 180 static uns8 temperatureByteLow; 181 // Conversion timeout counter 182 static uns16 timeoutStart; 183 #endif 184 185 // Timers for outputs. The space must be long enough to fit them all. 2+2 bytes per one binary output. 186 // 2B timeout 187 // 2B startTicks 188 static uns16 Timers[OUTPUTS_COUNT * 2]; 189 190 // Detect DPA event to handle 191 switch ( GetDpaEvent() ) 192 { 193 // ------------------------------------------------- 194 case DpaEvent_Interrupt: 195 // Do an extra quick background interrupt work 196 197 return Carry; 198 199 // ------------------------------------------------- 200 case DpaEvent_Idle: 201 // Do a quick background work when RF packet is not received 202 203 // Should go to sleep? 204 if ( PerOSSleep_Request.Time != 0 ) 205 { 206 // Copy sleep parameters to the DPA request 207 _DpaMessage.PerOSSleep_Request.Time = PerOSSleep_Request.Time; 208 _DpaMessage.PerOSSleep_Request.Control = PerOSSleep_Request.Control; 209 // Finalize OS Sleep DPA Request 210 _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request ); 211 _PNUM = PNUM_OS; 212 _PCMD = CMD_OS_SLEEP; 213 #ifndef DALLASnotMCP 214 // I2C down 215 _DpaApiI2Cshutdown(); 216 #endif 217 // Perform local DPA Request to go to sleep 218 DpaApiLocalRequest(); 219 #ifndef DALLASnotMCP 220 // I2C up 221 _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) ); 222 #endif 223 // Switch off sleeping time=flag 224 PerOSSleep_Request.Time = 0; 225 } 226 227 // Check binary output timers 228 { 229 // Pointer to the timers array 230 FSR1 = (uns16)&Timers[0]; 231 // Output index 232 uns8 index; 233 index = 0; 234 do 235 { 236 // Is timer running (is non-zero)? 237 if ( ( FSR1[1] | INDF1 ) != 0 ) 238 { 239 // Get timer value 240 uns16 timer; 241 timer.low8 = FSR1[0]; 242 timer.high8 = FSR1[1]; 243 // Get start time 244 uns16 timerStart; 245 timerStart.low8 = FSR1[2]; 246 timerStart.high8 = FSR1[3]; 247 // Measure elapsed time 248 captureTicks(); // Note: must not modify FSR1 249 param3 -= timerStart; 250 // It time over? 251 if ( param3 > timer ) 252 { 253 // Set output to OFF 254 SetOutput( 0, index ); 255 // Reset timer 256 setINDF1( 0 ); 257 FSR1++; 258 setINDF1( 0 ); 259 FSR1--; 260 } 261 } 262 // Next timer 263 FSR1 += 2 * sizeof( Timers[0] ); 264 // Next index 265 } while ( ++index < OUTPUTS_COUNT ); 266 } 267 268 #ifdef DALLASnotMCP 269 // Run finite state machine to read temperature from DS18B20 at background so the temperature value is immediately ready for FRC 270 271 // Make sure 1Wire data pin at LATX.y is low as it might be set by another PORTX.? pin manipulation 272 OneWire_IO_OUT = 0; 273 274 skip( state ); 275 #pragma computedGoto 1 276 goto _S_ResetConvertT; 277 goto _S_SkipRomConvertT; 278 goto _S_CmdConvertT; 279 goto _S_WaitConvertT; 280 goto _S_ResetReadTemp; 281 goto _S_SkipRomReadTemp; 282 goto _S_CmdReadTemp; 283 goto _S_Byte1ReadTemp; 284 goto _S_Byte2ReadTemp; 285 #pragma computedGoto 0 286 ; 287 // -------------- 288 _S_Byte2ReadTemp: 289 temperature.high8 = OneWireReadByte(); 290 temperature.low8 = temperatureByteLow; 291 292 ResetMachine: 293 state = S_ResetConvertT; 294 goto ExitMachine; 295 296 // -------------- 297 _S_ResetConvertT: 298 _S_ResetReadTemp: 299 if ( !OneWireReset() ) 300 { 301 _S_Error_Reset: 302 STD_SENSOR_TYPE_TEMPERATURE_SET_ERROR( temperature ); 303 goto ResetMachine; 304 } 305 goto NextState; 306 307 // -------------- 308 _S_SkipRomConvertT: 309 _S_SkipRomReadTemp: 310 // OneWire: Skip ROM 311 OneWireWriteByte( CMD_SKIPROM ); 312 goto NextState; 313 314 // -------------- 315 _S_CmdConvertT: 316 // OneWire: Convert temperature 317 OneWireWriteByte( CMD_CONVERTTEMP ); 318 // Start timeout for approx 750 ms (the longest conversion time) 319 captureTicks(); 320 // Remember start time 321 timeoutStart = param3; 322 goto NextState; 323 324 // -------------- 325 _S_WaitConvertT: 326 // Measured? 327 if ( OneWireReadByte() == 0xff ) 328 goto NextState; 329 330 // Timeout? 331 captureTicks(); 332 param3 -= timeoutStart; 333 // Yes! 334 if ( param3 > ( 2 + 750 / TICKS_LEN ) ) 335 goto _S_Error_Reset; 336 337 goto ExitMachine; 338 339 // -------------- 340 _S_CmdReadTemp: 341 // OneWire: Read scratchpad 342 OneWireWriteByte( CMD_RSCRATCHPAD ); 343 goto NextState; 344 345 // -------------- 346 _S_Byte1ReadTemp: 347 temperatureByteLow = OneWireReadByte(); 348 goto NextState; 349 350 // -------------- 351 NextState: 352 ++state; 353 354 ExitMachine: 355 #endif 356 break; 357 358 // ------------------------------------------------- 359 case DpaEvent_Init: 360 // Do a one time initialization before main loop starts 361 362 // Initialize ticks 363 startCapture(); 364 365 // Initialize relays @ DDC-RE 366 RELAY1_LAT = 0; 367 RELAY2_LAT = 0; 368 RELAY1_TRIS = 0; 369 RELAY2_TRIS = 0; 370 371 // Initialize sensors 372 // C5 (AN4) as input 373 moduleInfo(); 374 // Connected TR pins? 375 if ( !bufferINFO[5].7 ) 376 { 377 TRISC.6 = 1; 378 TRISB.4 = 1; 379 } 380 TRISA.5 = 1; 381 382 // C1 (AN0) as input 383 TRISA.0 = 1; 384 385 #ifdef DALLASnotMCP 386 // Setup DS18B20 for 9bit precision, conversion takes 94ms (see datasheet) 387 Ds18B20WriteConfig( 0b0.00.00000 ); 388 #else 389 // Expect MCP9802 is enabled 390 I2Ctimeout = 0xFF; 391 _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) ); 392 #endif 393 break; 394 395 // ------------------------------------------------- 396 case DpaEvent_AfterSleep: 397 // Called after woken up after sleep 398 #ifndef DALLASnotMCP 399 _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) ); 400 #endif 401 402 break; 403 404 // ------------------------------------------------- 405 case DpaEvent_BeforeSleep: 406 // Called before going to sleep 407 #ifndef DALLASnotMCP 408 _DpaApiI2Cshutdown(); 409 #endif 410 break; 411 412 // ------------------------------------------------- 413 case DpaEvent_DpaRequest: 414 // Called to interpret DPA request for peripherals 415 // ------------------------------------------------- 416 // Peripheral enumeration 417 IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() 418 { 419 // We implement 2 standard peripherals 420 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 2; 421 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS ); 422 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_BINARY_OUTPUTS ); 423 _DpaMessage.EnumPeripheralsAnswer.HWPID = HWPID_IQRF_TECH__DEMO_DDC_SE01_RE01_LP; 424 _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0x0000; 425 426 DpaHandleReturnTRUE: 427 return TRUE; 428 } 429 // ------------------------------------------------- 430 // Get information about peripherals 431 else 432 { 433 #if PERIPHERAL_TYPE_STD_SENSORS != PNUM_STD_SENSORS || PERIPHERAL_TYPE_STD_BINARY_OUTPUTS != PNUM_STD_BINARY_OUTPUTS 434 #error 435 #endif 436 switch ( _DpaMessage.PeripheralInfoAnswer.PerT = _PNUM ) 437 { 438 case PNUM_STD_SENSORS: 439 // Set standard version 440 W = STD_SENSORS_VERSION; 441 goto Par1toVersion; 442 443 case PNUM_STD_BINARY_OUTPUTS: 444 // Set standard version 445 W = STD_BINARY_OUTPUTS_VERSION; 446 Par1toVersion: 447 _DpaMessage.PeripheralInfoAnswer.Par1 = W; 448 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ; 449 goto DpaHandleReturnTRUE; 450 } 451 452 break; 453 } 454 455 { 456 // ------------------------------------------------- 457 // Handle peripheral command 458 459 // Supported peripheral number? 460 switch ( _PNUM ) 461 { 462 case PNUM_STD_SENSORS: 463 { 464 // Supported commands? 465 switch ( _PCMD ) 466 { 467 // Invalid command 468 default: 469 { 470 // Return error 471 _ERROR_PCMD: 472 W = ERROR_PCMD; 473 _ERROR_W: 474 DpaApiReturnPeripheralError( W ); 475 } 476 477 // Sensor enumeration 478 case PCMD_STD_ENUMERATE: 479 if ( _DpaDataLength != 0 ) 480 goto _ERROR_DATA_LEN; 481 482 _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_TEMPERATURE; 483 _DpaMessage.Response.PData[1] = STD_SENSOR_TYPE_BINARYDATA7; 484 _DpaMessage.Response.PData[2] = STD_SENSOR_TYPE_BINARYDATA7; 485 W = SENSORS_COUNT; 486 goto _W2_DpaDataLength; 487 488 // Supported commands. They are handled the same way except one "if" at StoreValue() method 489 case PCMD_STD_SENSORS_READ_VALUES: 490 case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES: 491 { 492 // No sensor bitmap specified? W = _DpaDataLength. Note: W is used to avoid MOVLB at next if 493 W = _DpaDataLength; 494 if ( W == 0 ) // Note: must not modify W 495 { 496 // Actually clears the bitmap 497 #if &_DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap[0] != &bufferRF[0] 498 #error Cannot use clearBufferRF for clearing bitmap 499 #endif 500 clearBufferRF(); 501 // Simulate 1st only sensor in the bitmap (states of the other unimplemented sensors do not care) 502 _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap[0].0 = 1; 503 // Bitmap is 32 bits long 504 _DpaDataLength = W = sizeof( _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap ); 505 } 506 507 // Invalid bitmap (data) length (W = _DpaDataLength)? 508 if ( W != sizeof( _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap ) ) 509 goto _ERROR_DATA_LEN; 510 511 // Now read the sensors 512 513 // Prepare pointer (minus 1, see below) to store sensor (types and) values to 514 // Note: 3 sensors at this example cannot return more than DPA_MAX_DATA_LENGTH bytes of data, so it does not have to be checked... 515 // ... If it would be the case, then ERROR_FAIL must be returned 516 FSR1 = &_DpaMessage.Response.PData[-1]; 517 518 // Store bitmap of sensors to get values from 519 uns8 sensorsBitmap = FSR1[1 + offsetof( TPerStdSensorRead_Request, Bitmap )]; 520 521 // 1st sensor (index 0) selected? 522 if ( sensorsBitmap.0 ) 523 { 524 Get0_Temperature(); 525 StoreValue( STD_SENSOR_TYPE_TEMPERATURE ); 526 } 527 528 // 2nd sensor (index 1) selected? 529 if ( sensorsBitmap.1 ) 530 { 531 Get1_BinaryData_Light(); 532 StoreValue( STD_SENSOR_TYPE_BINARYDATA7 ); 533 } 534 535 // 3rd sensor (index 2) selected? 536 if ( sensorsBitmap.2 ) 537 { 538 Get2_BinaryData_Potentiometer(); 539 StoreValue( STD_SENSOR_TYPE_BINARYDATA7 ); 540 } 541 542 // Compute returned data bytes count 543 W = FSR1L - ( (uns16)&_DpaMessageIqrfStd & 0xFF ) + 1; 544 // Optimization: return W long block of bytes at response 545 _W2_DpaDataLength: 546 _DpaDataLength = W; 547 goto DpaHandleReturnTRUE; 548 } 549 } 550 } 551 552 case PNUM_STD_BINARY_OUTPUTS: 553 { 554 // Supported commands? 555 switch ( _PCMD ) 556 { 557 // Invalid command 558 default: 559 // Return error 560 goto _ERROR_PCMD; 561 562 // Outputs enumeration 563 case PCMD_STD_ENUMERATE: 564 if ( _DpaDataLength != 0 ) 565 goto _ERROR_DATA_LEN; 566 567 // Return number of outputs 568 _DpaMessageIqrfStd.PerStdBinaryOutputEnumerate_Response.Count = OUTPUTS_COUNT; 569 W = sizeof( _DpaMessageIqrfStd.PerStdBinaryOutputEnumerate_Response ); 570 goto _W2_DpaDataLength; 571 572 // Supported commands. 573 case PCMD_STD_BINARY_OUTPUTS_SET: 574 { 575 // Pointers FSR01 to data are already set at the DPA 576 577 // As this template implements < 9 outputs the working bitmap is uns8, if more outputs are implemented then uns16, ..., uns32 must be used 578 #if OUTPUTS_COUNT < 9 579 uns8 inBitmap = *FSR0--; 580 uns8 outBitmap @ _DpaMessageIqrfStd.PerStdBinaryOutputSet_Request.Bitmap[0]; 581 uns8 bitmapMask = 0b1; 582 #else 583 #error Not implemented 584 #endif 585 586 // Number of selected outputs + bitmap length 587 uns8 outputsCount = sizeof( _DpaMessageIqrfStd.PerStdBinaryOutputSet_Request.Bitmap ); 588 // Loop bitmap 589 uns8 index = sizeof( _DpaMessageIqrfStd.PerStdBinaryOutputSet_Request.Bitmap ); 590 do 591 { 592 // Count bits of next byte 593 uns8 byte = *++FSR0; 594 if ( byte != 0 ) 595 { 596 // Brian Kernighan's Algorithm for counting set bits 597 do 598 { 599 outputsCount++; 600 byte &= byte - 1; 601 } while ( byte != 0 ); 602 } 603 604 // Reset bitmap 605 setINDF0( 0 ); 606 } while ( --index != 0 ); 607 608 // Check data length 609 if ( _DpaDataLength != outputsCount ) 610 { 611 _ERROR_DATA_LEN: 612 W = ERROR_DATA_LEN; 613 goto _ERROR_W; 614 } 615 616 // Pointer to the timers array 617 FSR1 = (uns16)&Timers[0]; 618 // Output index 619 index = 0; 620 do 621 { 622 // Output was set? 623 if ( GetOutput( index ) ) 624 // Yes, set in the output bitmap 625 outBitmap |= bitmapMask; 626 627 // Implemented output selected? Set the state. 628 if ( inBitmap.0 ) 629 { 630 // Default is timer off 631 uns16 time = 0; 632 // Desired state 633 uns8 state = *++FSR0; 634 if ( state > 1 ) 635 { 636 // Get time in units s/min 637 time = state & 0x7F; 638 if ( time == 0 ) 639 { 640 // Invalid time 641 W = ERROR_FAIL; 642 _ERROR_FAIL: 643 goto _ERROR_W; 644 } 645 646 // Conversion coefficient, ready for seconds 647 uns16 coef = 1000 / TICKS_LEN; 648 if ( !state.7 ) 649 { 650 // Check for the maximum supported time because of captureTicks method 651 if ( time.low8 > ( (uns24)0xFFFF * TICKS_LEN / 1000 / 60 ) ) 652 goto _ERROR_FAIL; 653 654 // Convert from minutes 655 uns16 coef = 60 * ( 1000 / TICKS_LEN ); 656 } 657 658 // Convert to 250 ms 659 time *= coef; 660 // Set ON 661 state = 1; 662 } 663 664 // Set output 665 SetOutput( state, index ); 666 667 // Set timer but preserve pointer 668 setINDF1( time.low8 ); 669 FSR1++; 670 setINDF1( time.high8 ); 671 FSR1++; 672 // Get start time 673 captureTicks(); //Note: must not destroy FSR1 674 setINDF1( param3.low8 ); 675 FSR1++; 676 setINDF1( param3.high8 ); 677 FSR1 -= 3; 678 } 679 680 // Pointer to the next timer 681 FSR1 += 2 * sizeof( Timers[0] ); 682 // Next bits 683 bitmapMask <<= 1; 684 inBitmap >>= 1; 685 // Next index 686 } while ( ++index < OUTPUTS_COUNT ); 687 688 // Return bitmap 689 _DpaDataLength4: 690 W = sizeof( _DpaMessageIqrfStd.PerStdBinaryOutputSet_Response.PreviousStates ); 691 goto _W2_DpaDataLength; 692 } 693 } 694 } 695 } 696 697 break; 698 } 699 700 // ------------------------------------------------- 701 case DpaEvent_FrcValue: 702 // Called to get FRC value 703 704 // FSR1 for optimization purposes (avoid MOVLB) will be used to point to DataOutBeforeResponseFRC[0...] 705 FSR1 = (uns16)&PerStdSensorFrc; 706 #if offsetof( TPerStdSensorFrc, Header ) != 0 || offsetof( TPerStdSensorFrc, SensorType ) != 1 || offsetof( TPerStdSensorFrc, Options ) != 3 707 #error Cannot optimize 708 #endif 709 // Check for correct FRC user data 710 if ( *FSR1++ /* PerStdSensorFrc.Header */ == PNUM_STD_SENSORS ) 711 { 712 // Actually used sensor index 713 uns8 sensorIndex = FSR1[offsetof( TPerStdSensorFrc, SensorIndex ) - 1] & 0x1f; 714 // Test sensor type 715 switch ( *FSR1++ /* PerStdSensorFrc.SensorType */ ) 716 { 717 default: 718 goto DpaHandleReturnFALSE; 719 720 // No type specified, use specified index value 721 case 0x00: 722 goto _KeepSensorIndex; 723 724 // For other types make the index value based on the requested index value and sensor type 725 case STD_SENSOR_TYPE_TEMPERATURE: 726 if ( sensorIndex > 0 ) 727 goto DpaHandleReturnFALSE; 728 W = 0 + sensorIndex; 729 break; 730 731 case STD_SENSOR_TYPE_BINARYDATA7: 732 if ( sensorIndex > 1 ) 733 goto DpaHandleReturnFALSE; 734 W = 1 + sensorIndex; 735 break; 736 } 737 738 // New sensor index based on type and requested index 739 sensorIndex = W; 740 _KeepSensorIndex: 741 742 // Test for supported FRC commands 743 switch ( _PCMD ) 744 { 745 default: 746 goto DpaHandleReturnFALSE; 747 748 case FRC_STD_SENSORS_BIT: 749 case FRC_STD_SENSORS_1B: 750 case FRC_STD_SENSORS_2B: 751 switch ( sensorIndex ) 752 { 753 default: 754 goto DpaHandleReturnFALSE; 755 756 case 0: 757 Carry = Get0_Temperature(); 758 break; 759 760 case 1: 761 Carry = Get1_BinaryData_Light(); 762 break; 763 764 case 2: 765 Carry = Get2_BinaryData_Potentiometer(); 766 break; 767 } 768 769 // This type of FRC is not valid for the specified sensor 770 if ( !Carry ) 771 goto DpaHandleReturnFALSE; 772 773 break; 774 } 775 776 // Some sensor was measured by FRC, check if there is a sleep request 777 FSR1++; 778 if ( INDF1.0 ) // Note: same as PerStdSensorFrc.Options.0 779 { 780 // Remember sleep parameters to go to sleep at the Idle event later 781 PerOSSleep_Request.Time.low8 = FSR1[offsetof( TPerOSSleep_Request, Time ) + 0 + offsetof( TPerStdSensorFrc, SleepParameters ) - 3]; 782 PerOSSleep_Request.Time.high8 = FSR1[offsetof( TPerOSSleep_Request, Time ) + 1 + offsetof( TPerStdSensorFrc, SleepParameters ) - 3]; 783 PerOSSleep_Request.Control = FSR1[offsetof( TPerOSSleep_Request, Control ) + offsetof( TPerStdSensorFrc, SleepParameters ) - 3]; 784 } 785 } 786 787 break; 788 789 // ------------------------------------------------- 790 case DpaEvent_FrcResponseTime: 791 // Called to get FRC response time 792 793 // In this example the FRC commands are fast 794 switch ( DataOutBeforeResponseFRC[0] ) 795 { 796 case FRC_STD_SENSORS_BIT: 797 case FRC_STD_SENSORS_1B: 798 case FRC_STD_SENSORS_2B: 799 responseFRCvalue = _FRC_RESPONSE_TIME_40_MS; 800 break; 801 } 802 break; 803 } 804 DpaHandleReturnFALSE: 805 return FALSE; 806 } 807 808 //############################################################################################ 809 bit returnTRUE() 810 //############################################################################################ 811 { 812 return TRUE; 813 } 814 815 //############################################################################################ 816 bit returnFALSE() 817 //############################################################################################ 818 { 819 return FALSE; 820 } 821 822 //############################################################################################ 823 // Increases FSR1 and then stores the byte 824 void setPlusPlusINDF1( uns8 data @ W ) 825 //############################################################################################ 826 { 827 FSR1++; // Note: must not modify W 828 setINDF1( data ); 829 } 830 831 //############################################################################################ 832 // Stores measured sensor value byte(s) and optionally sensor type to the FSR[+1...] 833 void StoreValue( uns8 sensorType ) 834 //############################################################################################ 835 { 836 // Is the sensor type to be stored too? 837 if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES ) 838 setPlusPlusINDF1( sensorType ); 839 840 // Store lower value byte 841 setPlusPlusINDF1( sensorValue.low8 ); 842 843 // No more value bytes to store? 844 if ( sensorType.7 != 0 ) 845 return; 846 847 // Store higher value byte 848 setPlusPlusINDF1( sensorValue.high8 ); 849 850 // 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. 851 } 852 853 //############################################################################################ 854 bit setFRCerror() 855 //############################################################################################ 856 { 857 responseFRCvalue2B = FRC_STD_FRC_ERROR_VALUE; 858 return returnTRUE(); 859 } 860 861 //############################################################################################ 862 bit sensorError; 863 bit AdjustFrcTemperature() 864 //############################################################################################ 865 { 866 // Test for supported FRC commands 867 switch ( _PCMD ) 868 { 869 default: 870 return returnFALSE(); 871 872 case FRC_STD_SENSORS_1B: 873 // Return sensor FRC value 1B 874 // Check for out of limits 875 if ( sensorError || (int16)sensorValue > (int16)( 105.5 * 16 ) || (int16)sensorValue < ( (int16)-20 * 16 ) ) 876 return setFRCerror(); 877 878 // Convert to the "F = ( T + 22 ) * 2 " from 1/16 resolution 879 responseFRCvalue2B = sensorValue + 4; // Note: do rounding when /8 880 responseFRCvalue2B /= 8; 881 responseFRCvalue += 44; 882 break; 883 884 case FRC_STD_SENSORS_2B: 885 // Return sensor FRC value 2B 886 if ( sensorError ) 887 return setFRCerror(); 888 889 responseFRCvalue2B = sensorValue ^ 0x8000; 890 break; 891 } 892 893 return returnTRUE(); 894 } 895 896 //############################################################################################ 897 // Sensor index 1: measure temperature using one of the DDC-SE-01 sensors 898 bit Get0_Temperature() 899 //############################################################################################ 900 { 901 // Make sure FSR1 is not modified 902 903 // Measure temperature using DDC-SE-01 sensors 904 // Read temperature and check for an error 905 906 // Reads temperature from an enabled sensor 907 #ifdef DALLASnotMCP 908 sensorError = FALSE; 909 // Temperature is ready at the background 910 sensorValue = temperature; 911 // When error, return standard (FRC) error value(s) 912 if ( STD_SENSOR_TYPE_TEMPERATURE_IS_ERROR( sensorValue ) ) 913 sensorError = TRUE; 914 #else 915 sensorError = TRUE; 916 // Temperature value must be read from I2C sensor 917 STD_SENSOR_TYPE_TEMPERATURE_SET_ERROR( sensorValue ); 918 // MCP9802 address 919 _DpaApiI2Cstart( I2C_ADR ); 920 if ( !I2CwasTimeout ) 921 { 922 // pointer: 1 = configuration register 923 _DpaApiI2Cwrite( 0x01 ); 924 // configuration: 9-bit ADC 925 _DpaApiI2CwriteAndStop( 0x00 ); 926 927 // MCP9802 address 928 _DpaApiI2Cstart( I2C_ADR ); 929 // pointer: 0 = temperature 930 _DpaApiI2CwriteAndStop( 0 ); 931 932 // MCP9802 address + read 933 _DpaApiI2Cstart( I2C_ADR | 1 ); 934 // store the result 935 sensorValue.high8 = _DpaApiI2Cread( TRUE ); 936 sensorValue.low8 = _DpaApiI2Cread( FALSE ); 937 _DpaApiI2Cstop(); 938 939 sensorValue += 0x10 / 2; 940 sensorValue /= 0x10; 941 942 sensorError = FALSE; 943 } 944 #endif 945 946 // FrcValues 947 return AdjustFrcTemperature(); 948 } 949 950 //############################################################################################ 951 // Sensor index 1: returns light intensity indicator value using DDC-SE-01 952 bit Get_BinaryData_Final( uns8 _ADCON0 @ W ) 953 //############################################################################################ 954 { 955 ADCON0 = _ADCON0; 956 // Read ADC 957 958 // ADC result - left justified, Fosc/8 959 ADCON1 = 0b0001.0000; 960 // Do a smallest delay for ADC ACQUISITION TIME 961 waitMS( 1 ); 962 // start ADC 963 GO = 1; 964 // wait for ADC finish 965 while ( GO ); 966 // Get ADC value 967 sensorValue.low8 = ADRESH / 2; 968 969 // Return sensor FRC value 970 971 // Test for supported FRC commands 972 switch ( _PCMD ) 973 { 974 default: 975 return returnFALSE(); 976 977 case FRC_STD_SENSORS_BIT: 978 // If there is a sensor error, 2-bit FRC cannot indicate it, it returns [01] 979 980 // Number of shifts to get the bit out of the return value 981 uns8 bitLoop = ( INDF1 >> 5 ) + 1; 982 // Value to get the bit from 983 W = sensorValue.low8; 984 do 985 { 986 // Get the bit to Carry 987 W = rr( W ); 988 // Next bit 989 } while ( --bitLoop != 0 ); // Note: must not modify W and Carry 990 // Current (prepared by DPA) FRC value is [01], change it to [11] (means bit is set) 991 responseFRCvalue.1 = 1; // Note: must not modify Carry 992 // Is bit set? 993 if ( !Carry ) 994 // Bit is NOT set, return [10] 995 responseFRCvalue.0 = 0; 996 break; 997 998 case FRC_STD_SENSORS_1B: 999 responseFRCvalue = sensorValue.low8 + 4; 1000 break; 1001 } 1002 1003 return returnTRUE(); 1004 } 1005 1006 //############################################################################################ 1007 // Sensor index 1: returns light intensity indicator value using DDC-SE-01 1008 bit Get1_BinaryData_Light() 1009 //############################################################################################ 1010 { 1011 // Make sure FSR1 is not modified 1012 1013 // ADC initialization (for more info see PIC datasheet) pin C1 (AN0) as analog input 1014 ANSELA.0 = 1; 1015 // ADC setting (AN0 channel) 1016 return Get_BinaryData_Final( 0b0.00000.01 ); 1017 } 1018 1019 //############################################################################################ 1020 // Sensor index 2: returns potentiometer value using DDC-SE-01 1021 bit Get2_BinaryData_Potentiometer() 1022 //############################################################################################ 1023 { 1024 // Make sure FSR1 is not modified 1025 1026 // ADC initialization (for more info see PIC datasheet) pin C5 (AN4) as analog input 1027 ANSELA.5 = 1; 1028 // ADC setting (AN4 channel) 1029 return Get_BinaryData_Final( 0b0.00100.01 ); 1030 } 1031 1032 #ifdef DALLASnotMCP 1033 //############################################################################################ 1034 // OneWire and Dallas 18B20 routines 1035 //############################################################################################ 1036 1037 //############################################################################################ 1038 void Delay5us( uns8 val @ W ) // Absolutely precise timing but val != 0 1039 //############################################################################################ 1040 { 1041 // 16 MHz 1042 // + 0.75us ( W=val, Call ) 1043 for ( ;; ) 1044 { // loop time 1045 nop2(); // 0.50us 1046 nop2(); // 1.00us 1047 nop2(); // 1.50us 1048 nop2(); // 2.00us 1049 nop2(); // 2.50us 1050 nop2(); // 3.00us 1051 nop(); // 3.25us 1052 if ( --val == 0 ) // + 0.75us (W--, BTFS ) 1053 return; // + 0.25us 1054 nop2(); // 4.50us 1055 } // 5.00us (Goto) 1056 } 1057 //############################################################################################ 1058 1059 #define OneWireData0() { OneWire_TRIS = 0; } // 0.5us @ 16MHz 1060 #define OneWireData1() { OneWire_TRIS = 1; } // 0.5us @ 16MHz 1061 1062 //############################################################################################ 1063 void OneWireWriteByte( uns8 byte ) 1064 //############################################################################################ 1065 { 1066 uns8 bitLoop = 8; 1067 do 1068 { 1069 // Next sequence is time precision critical 1070 GIE = FALSE; 1071 1072 OneWireData0(); 1073 nop2(); // 1 us [0.5 us] 1074 nop2(); // [1.0 us] 1075 if ( byte.0 ) // 2.5 us [1.75us] 1076 OneWireData1(); 1077 1078 // End of time precision critical sequence 1079 GIE = TRUE; 1080 1081 // 60us minimum in total, does not have to be precise 1082 Delay5us( ( 60 - 3 ) / 5 + 1 ); 1083 1084 OneWireData1(); 1085 1086 byte >>= 1; 1087 } while ( --bitLoop != 0 ); 1088 } 1089 1090 //############################################################################################ 1091 uns8 OneWireReadByte() 1092 //############################################################################################ 1093 { 1094 uns8 result; 1095 uns8 bitLoop = 8; 1096 do 1097 { 1098 // Next sequence is time precision critical 1099 GIE = FALSE; 1100 1101 OneWireData0(); 1102 nop2(); // 1 us [0.5 us] 1103 #if F_OSC == 16000000 1104 nop2(); // [1.0 us] 1105 #endif 1106 OneWireData1(); // 2 us [1.5 us] 1107 Delay5us( 15 / 5 ); // 17 us [16.5 us] 1108 1109 Carry = 0; // 17.5 us [16.75 us] 1110 if ( OneWire_IO_IN ) // 18.5 us [ 17.25 us] (condition must not modify Carry) 1111 Carry = 1; 1112 1113 // End of time precision critical sequence 1114 GIE = TRUE; // must not modify Carry 1115 result = rr( result ); 1116 1117 // 60us minimum in total, does not have to be precise 1118 Delay5us( ( 60 - 20 ) / 5 + 1 ); 1119 } while ( --bitLoop != 0 ); 1120 1121 return result; 1122 } 1123 1124 //############################################################################################ 1125 bit OneWireReset() 1126 //############################################################################################ 1127 { 1128 // Setting the pin once to low is enough 1129 OneWire_IO_OUT = 0; 1130 // Reset pulse 1131 OneWireData0(); 1132 Delay5us( 500 / 5 ); 1133 // Reset pulse end 1134 OneWireData1(); 1135 // Next sequence is time precision critical 1136 GIE = FALSE; 1137 // Wait for presence pulse 1138 Delay5us( 70 / 5 ); 1139 // End of time precision critical sequence 1140 GIE = TRUE; 1141 // Presence pulse? 1142 if ( OneWire_IO_IN ) 1143 { 1144 // No presence, finish initialization sequence 1145 Delay5us( ( 500 - 70 ) / 5 ); 1146 return returnFALSE(); 1147 } 1148 else 1149 { 1150 // Presence OK, finish initialization sequence 1151 Delay5us( ( 500 - 70 ) / 5 ); 1152 return returnTRUE(); 1153 } 1154 } 1155 1156 //############################################################################################ 1157 void OneWireCmd( uns8 cmd ) 1158 //############################################################################################ 1159 { 1160 // OneWire: Skip ROM 1161 OneWireWriteByte( CMD_SKIPROM ); 1162 // OneWire: Send command 1163 OneWireWriteByte( cmd ); 1164 } 1165 1166 //############################################################################################ 1167 bit Ds18B20WriteConfig( uns8 value ) 1168 //############################################################################################ 1169 { 1170 if ( OneWireReset() ) 1171 { 1172 // Write Scratchpad 1173 OneWireCmd( CMD_WSCRATCHPAD ); 1174 1175 // Write TL = ? (we dot not care the value) 1176 OneWireWriteByte( W ); 1177 // Write TH = ? (we dot not care the value) 1178 OneWireWriteByte( W ); 1179 // Write Config byte 1180 OneWireWriteByte( value ); 1181 1182 if ( OneWireReset() ) 1183 { 1184 // Copy Scratchpad 1185 OneWireCmd( CMD_CPYSCRATCHPAD ); 1186 return returnTRUE(); 1187 } 1188 } 1189 return returnFALSE(); 1190 } 1191 1192 #endif // DALLASnotMCP 1193 //############################################################################################ 1194 // Other routines 1195 //############################################################################################ 1196 1197 //############################################################################################ 1198 void SetOutput( uns8 state, uns8 index @ W ) 1199 //############################################################################################ 1200 { 1201 // Note: FSRs must not be modified 1202 // Note: This method is called in the interrupt too! 1203 1204 skip( index ); 1205 #pragma computedGoto 1 1206 goto set0; 1207 goto set1; 1208 #pragma computedGoto 0 1209 ; 1210 // -------------------------------------- 1211 set1: 1212 if ( !state.0 ) 1213 RELAY2_LAT = 0; 1214 else 1215 RELAY2_LAT = 1; 1216 1217 return; 1218 // -------------------------------------- 1219 set0: 1220 if ( !state.0 ) 1221 RELAY1_LAT = 0; 1222 else 1223 RELAY1_LAT = 1; 1224 1225 return; 1226 // -------------------------------------- 1227 } 1228 1229 //############################################################################################ 1230 bit GetOutput( uns8 index @ W ) 1231 //############################################################################################ 1232 { 1233 Carry = FALSE; // Note: must not modify W 1234 1235 // Note: all below must not modify Carry except when needed 1236 skip( index ); 1237 #pragma computedGoto 1 1238 goto get0; 1239 goto get1; 1240 #pragma computedGoto 0 1241 ; 1242 // -------------------------------------- 1243 get1: 1244 if ( RELAY2_LAT ) 1245 Carry = TRUE; 1246 goto _return; 1247 // -------------------------------------- 1248 get0: 1249 if ( RELAY1_LAT ) 1250 Carry = TRUE; 1251 goto _return; 1252 // -------------------------------------- 1253 1254 _return: 1255 return Carry; 1256 } 1257 1258 //############################################################################################ 1259 // 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) 1260 #include "DPAcustomHandler.h" 1261 //############################################################################################