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