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