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