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