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.5 $ 8 // Date: $Date: 2019/03/07 08:44:34 $ 9 // 10 // Revision history: 11 // 2019/03/07 Release for DPA 4.01 12 // 13 // ********************************************************************* 14 15 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 16 // IQRF Standards documentation https://www.iqrfalliance.org/techDocs/ 17 18 // This example implements 3 sensors according to the IQRF Sensors standard 19 // Index 0 i.e. 1st sensor is either Dallas 18B20 or MCP9802 temperature sensor at DDC-SE-01 board according to the HW jumper position and symbol DALLASnotMCP. 20 // Index 1 i.e. 2nd sensor is light intensity indicator at DDC-SE-01 board (value range is 0[max light]-127[max dark]). 21 // Index 2 i.e. 3rd sensor is potentiometer value at DDC-SE-01 board (value range is 0[left stop]-127[right stop]). 22 23 // This example must be compiled without a "-bu" compiler switch in order to fit into available Flash memory 24 25 // Default IQRF include (modify the path according to your setup) 26 #include "IQRF.h" 27 28 // We can save more instructions if needed by the symbol below 29 // #define PARAM_CHECK_LEVEL 1 30 31 // Default DPA header (modify the path according to your setup) 32 #include "DPA.h" 33 // Default Custom DPA Handler header (modify the path according to your setup) 34 #include "DPAcustomHandler.h" 35 // IQRF standards header (modify the path according to your setup) 36 #include "IQRFstandard.h" 37 #include "IQRF_HWPID.h" 38 39 // If defined then the handler is compiled for Dallas otherwise for MCP9802 40 #define DALLASnotMCP 41 42 //############################################################################################ 43 44 // Define useful macro that saves some code but not preset at DPA < 3.01 45 #if DPA_VERSION_MASTER < 0x0301 46 // Optimized macro for both testing enumeration peripherals ELSE peripherals information. See examples 47 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequestNoSize() if ( _PCMD == CMD_GET_PER_INFO ) if ( _PNUM == PNUM_ENUMERATION ) 48 49 #if PARAM_CHECK_LEVEL >= 2 50 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() if ( _DpaDataLength == 0 && _PCMD == CMD_GET_PER_INFO ) if ( _PNUM == PNUM_ENUMERATION ) 51 #else 52 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequestNoSize() 53 #endif 54 #endif 55 56 //############################################################################################ 57 58 // Number of implemented sensors 59 #define SENSORS_COUNT 3 60 61 // Variable to store sensor value at Get?_????() methods. This example implements sensors returning maximum 2 bytes of data. 62 uns16 sensorValue @ param3; 63 64 // Reads sensor value to the sensorValue variable and to responseFRCvalue(2B) variable 65 bit Get0_Temperature(); 66 bit Get1_BinaryData_Light(); 67 bit Get2_BinaryData_Potentiometer(); 68 69 // 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) 70 void StoreValue( uns8 sensorType ); 71 72 #ifdef DALLASnotMCP 73 // Sensor connected to PORT C.3 (compatible with DDC-SE-01) 74 #define OneWire_TRIS TRISC.3 75 #define OneWire_IO_IN PORTC.3 76 #define OneWire_IO_OUT LATC.3 77 78 // ms per ticks 79 #define TICKS_LEN 10 80 81 // Writes sensor configuration (resolution) 82 bit Ds18B20WriteConfig( uns8 value ); 83 84 // Resets OneWire 85 bit OneWireReset(); 86 // Reads OneWire byte 87 uns8 OneWireReadByte(); 88 // Writes OneWire byte 89 void OneWireWriteByte( uns8 byte ); 90 91 // DS18B20 commands 92 #define CMD_READROM 0x33 93 #define CMD_CONVERTTEMP 0x44 94 #define CMD_CPYSCRATCHPAD 0x48 95 #define CMD_WSCRATCHPAD 0x4e 96 #define CMD_MATCHROM 0x55 97 #define CMD_RPWRSUPPLY 0xb4 98 #define CMD_RECEEPROM 0xb8 99 #define CMD_RSCRATCHPAD 0xbe 100 #define CMD_SKIPROM 0xcc 101 #define CMD_ALARMSEARCH 0xec 102 #define CMD_SEARCHROM 0xf0 103 104 // Final DS18B20 temperature value read by state machine 105 uns16 temperature; 106 107 #else // DALLASnotMCP 108 // I2C routines 109 void i2c_init(); 110 void i2c_shutdown(); 111 void i2c_waitForIdle(); 112 void i2c_start(); 113 void i2c_stop(); 114 uns8 i2c_read( bit ack ); 115 void i2c_write( uns8 i2cWriteData ); 116 117 bit i2cTimeout; 118 119 // MCP9802 address 120 #define I2C_ADR 0b10010110 121 // Power pin 122 #define PWR_SENSOR_TRIS TRISC.7 123 #define PWR_SENSOR_IO LATC.7 124 125 #endif 126 127 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 128 //############################################################################################ 129 bit CustomDpaHandler() 130 //############################################################################################ 131 { 132 // 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) 133 #pragma updateBank default = UserBank_01 134 135 #ifdef DALLASnotMCP 136 // Finite machine states 137 typedef enum 138 { 139 S_ResetConvertT = 0, 140 S_SkipRomConvertT, 141 S_CmdConvertT, 142 143 S_WaitConvertT, 144 145 S_ResetReadTemp, 146 S_SkipRomReadTemp, 147 S_CmdReadTemp, 148 S_Byte1ReadTemp, 149 S_Byte2ReadTemp 150 } TState; 151 #endif 152 153 // Handler presence mark 154 clrwdt(); 155 156 // Sleeping parameters, valid when Time != 0 157 static TPerOSSleep_Request PerOSSleep_Request; 158 159 #ifdef DALLASnotMCP 160 // Finite machine state 161 static uns8 state; // = S_ResetConvertT = 0 162 // Pre-read lower temperature byte 163 static uns8 temperatureByteLow; 164 // Conversion timeout counter 165 static uns16 timeoutStart; 166 #endif 167 168 // Detect DPA event to handle 169 switch ( GetDpaEvent() ) 170 { 171 // ------------------------------------------------- 172 case DpaEvent_Interrupt: 173 // Do an extra quick background interrupt work 174 175 return Carry; 176 177 // ------------------------------------------------- 178 case DpaEvent_Idle: 179 // Do a quick background work when RF packet is not received 180 181 // Should go to sleep? 182 if ( PerOSSleep_Request.Time != 0 ) 183 { 184 // Copy sleep parameters to the DPA request 185 _DpaMessage.PerOSSleep_Request.Time = PerOSSleep_Request.Time; 186 _DpaMessage.PerOSSleep_Request.Control = PerOSSleep_Request.Control; 187 // Finalize OS Sleep DPA Request 188 _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request ); 189 _PNUM = PNUM_OS; 190 _PCMD = CMD_OS_SLEEP; 191 // Perform local DPA Request to go to sleep 192 DpaApiLocalRequest(); 193 // Switch off sleeping time=flag 194 PerOSSleep_Request.Time = 0; 195 } 196 197 #ifdef DALLASnotMCP 198 // Run finite state machine to read temperature from DS18B20 at background so the temperature value is immediately ready for FRC 199 200 // Make sure 1Wire data pin at LATX.y is low as it might be set by another PORTX.? pin manipulation 201 OneWire_IO_OUT = 0; 202 203 skip( state ); 204 #pragma computedGoto 1 205 goto _S_ResetConvertT; 206 goto _S_SkipRomConvertT; 207 goto _S_CmdConvertT; 208 goto _S_WaitConvertT; 209 goto _S_ResetReadTemp; 210 goto _S_SkipRomReadTemp; 211 goto _S_CmdReadTemp; 212 goto _S_Byte1ReadTemp; 213 goto _S_Byte2ReadTemp; 214 #pragma computedGoto 0 215 ; 216 // -------------- 217 _S_Byte2ReadTemp: 218 temperature.high8 = OneWireReadByte(); 219 temperature.low8 = temperatureByteLow; 220 221 ResetMachine: 222 state = S_ResetConvertT; 223 goto ExitMachine; 224 225 // -------------- 226 _S_ResetConvertT: 227 _S_ResetReadTemp: 228 if ( !OneWireReset() ) 229 { 230 _S_Error_Reset: 231 STD_SENSOR_TYPE_TEMPERATURE_SET_ERROR( temperature ); 232 goto ResetMachine; 233 } 234 goto NextState; 235 236 // -------------- 237 _S_SkipRomConvertT: 238 _S_SkipRomReadTemp: 239 // OneWire: Skip ROM 240 OneWireWriteByte( CMD_SKIPROM ); 241 goto NextState; 242 243 // -------------- 244 _S_CmdConvertT: 245 // OneWire: Convert temperature 246 OneWireWriteByte( CMD_CONVERTTEMP ); 247 // Start timeout for approx 750 ms (the longest conversion time) 248 captureTicks(); 249 // Remember start time 250 timeoutStart = param3; 251 goto NextState; 252 253 // -------------- 254 _S_WaitConvertT: 255 // Measured? 256 if ( OneWireReadByte() == 0xff ) 257 goto NextState; 258 259 // Timeout? 260 captureTicks(); 261 param3 -= timeoutStart; 262 // Yes! 263 if ( param3 > ( 2 + 750 / TICKS_LEN ) ) 264 goto _S_Error_Reset; 265 266 goto ExitMachine; 267 268 // -------------- 269 _S_CmdReadTemp: 270 // OneWire: Read scratchpad 271 OneWireWriteByte( CMD_RSCRATCHPAD ); 272 goto NextState; 273 274 // -------------- 275 _S_Byte1ReadTemp: 276 temperatureByteLow = OneWireReadByte(); 277 goto NextState; 278 279 // -------------- 280 NextState: 281 ++state; 282 283 ExitMachine: 284 #endif 285 break; 286 287 // ------------------------------------------------- 288 case DpaEvent_Init: 289 // Do a one time initialization work before main loop starts 290 291 // Initialize ticks 292 startCapture(); 293 294 // Initialize sensors 295 // C5 (AN4) as input 296 moduleInfo(); 297 // Connected TR pins? 298 if ( !bufferINFO[5].7 ) 299 { 300 TRISC.6 = 1; 301 TRISB.4 = 1; 302 } 303 TRISA.5 = 1; 304 305 // C1 (AN0) as input 306 TRISA.0 = 1; 307 308 #ifdef DALLASnotMCP 309 // Setup DS18B20 for 9bit precision, conversion takes 94ms (see datasheet) 310 Ds18B20WriteConfig( 0b0.00.00000 ); 311 #else 312 // Expect MCP9802 is enabled 313 i2c_init(); 314 #endif 315 break; 316 317 // ------------------------------------------------- 318 case DpaEvent_AfterSleep: 319 // Called after woken up after sleep 320 #ifndef DALLASnotMCP 321 i2c_init(); 322 #endif 323 324 break; 325 326 // ------------------------------------------------- 327 case DpaEvent_BeforeSleep: 328 // Called before going to sleep 329 #ifndef DALLASnotMCP 330 i2c_shutdown(); 331 #endif 332 break; 333 334 // ------------------------------------------------- 335 case DpaEvent_DpaRequest: 336 // Called to interpret DPA request for peripherals 337 // ------------------------------------------------- 338 // Peripheral enumeration 339 IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() 340 { 341 // We implement 2 standard peripherals 342 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 343 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS ); 344 _DpaMessage.EnumPeripheralsAnswer.HWPID = HWPID_IQRF_TECH__DEMO_DDC_SE01_LP; 345 _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0x0000; 346 347 DpaHandleReturnTRUE: 348 return TRUE; 349 } 350 // ------------------------------------------------- 351 // Get information about peripherals 352 else 353 { 354 switch ( _DpaMessage.PeripheralInfoAnswer.PerT = _PNUM ) 355 { 356 case PNUM_STD_SENSORS: 357 // Set standard version 358 _DpaMessage.PeripheralInfoAnswer.Par1 = 15; 359 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 360 goto DpaHandleReturnTRUE; 361 } 362 363 break; 364 } 365 366 { 367 // ------------------------------------------------- 368 // Handle peripheral command 369 370 // Supported peripheral number? 371 switch ( _PNUM ) 372 { 373 case PNUM_STD_SENSORS: 374 { 375 // Supported commands? 376 switch ( _PCMD ) 377 { 378 // Invalid command 379 default: 380 { 381 // Return error 382 _ERROR_PCMD: 383 W = ERROR_PCMD; 384 _ERROR_W: 385 DpaApiReturnPeripheralError( W ); 386 } 387 388 // Sensor enumeration 389 case PCMD_STD_ENUMERATE: 390 if ( _DpaDataLength != 0 ) 391 { 392 _ERROR_DATA_LEN: 393 W = ERROR_DATA_LEN; 394 goto _ERROR_W; 395 } 396 397 _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_TEMPERATURE; 398 _DpaMessage.Response.PData[1] = STD_SENSOR_TYPE_BINARYDATA7; 399 _DpaMessage.Response.PData[2] = STD_SENSOR_TYPE_BINARYDATA7; 400 W = SENSORS_COUNT; 401 goto _W2_DpaDataLength; 402 403 // Supported commands. They are handled the same way except one "if" at StoreValue() method 404 case PCMD_STD_SENSORS_READ_VALUES: 405 case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES: 406 { 407 // No sensor bitmap specified? W = _DpaDataLength. Note: W is used to avoid MOVLB at next if 408 W = _DpaDataLength; 409 if ( W == 0 ) // Note: must not modify W 410 { 411 // Actually clears the bitmap 412 #if &_DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap[0] != &bufferRF[0] 413 #error Cannot use clearBufferRF for clearing bitmap 414 #endif 415 clearBufferRF(); 416 // Simulate 1st only sensor in the bitmap (states of the other unimplemented sensors do not care) 417 _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap[0].0 = 1; 418 // Bitmap is 32 bits long 419 _DpaDataLength = W = sizeof( _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap ); 420 } 421 422 // Invalid bitmap (data) length (W = _DpaDataLength)? 423 if ( W != sizeof( _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap ) ) 424 goto _ERROR_DATA_LEN; 425 426 // Now read the sensors 427 428 // Prepare pointer (minus 1, see below) to store sensor (types and) values to 429 // 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... 430 // ... If it would be the case, then ERROR_FAIL must be returned 431 FSR1 = &_DpaMessage.Response.PData[-1]; 432 433 // Store bitmap of sensors to get values from 434 uns8 sensorsBitmap = FSR1[1 + offsetof( TPerStdSensorRead_Request, Bitmap )]; 435 436 // 1st sensor (index 0) selected? 437 if ( sensorsBitmap.0 ) 438 { 439 Get0_Temperature(); 440 StoreValue( STD_SENSOR_TYPE_TEMPERATURE ); 441 } 442 443 // 2nd sensor (index 1) selected? 444 if ( sensorsBitmap.1 ) 445 { 446 Get1_BinaryData_Light(); 447 StoreValue( STD_SENSOR_TYPE_BINARYDATA7 ); 448 } 449 450 // 3rd sensor (index 2) selected? 451 if ( sensorsBitmap.2 ) 452 { 453 Get2_BinaryData_Potentiometer(); 454 StoreValue( STD_SENSOR_TYPE_BINARYDATA7 ); 455 } 456 457 // Compute returned data bytes count 458 W = FSR1L - ( (uns16)&_DpaMessageIqrfStd & 0xFF ) + 1; 459 // Optimization: return W long block of bytes at response 460 _W2_DpaDataLength: 461 _DpaDataLength = W; 462 goto DpaHandleReturnTRUE; 463 } 464 } 465 } 466 } 467 468 break; 469 } 470 471 // ------------------------------------------------- 472 case DpaEvent_FrcValue: 473 // Called to get FRC value 474 475 // FSR1 for optimization purposes (avoid MOVLB) will be used to point to DataOutBeforeResponseFRC[0...] 476 FSR1 = (uns16)&PerStdSensorFrc; 477 #if offsetof( TPerStdSensorFrc, Header ) != 0 || offsetof( TPerStdSensorFrc, SensorType ) != 1 || offsetof( TPerStdSensorFrc, Options ) != 3 478 #error Cannot optimize 479 #endif 480 // Check for correct FRC user data 481 if ( *FSR1++ /* PerStdSensorFrc.Header */ == PNUM_STD_SENSORS ) 482 { 483 // Actually used sensor index 484 uns8 sensorIndex = FSR1[offsetof( TPerStdSensorFrc, SensorIndex ) - 1] & 0x1f; 485 // Test sensor type 486 switch ( *FSR1++ /* PerStdSensorFrc.SensorType */ ) 487 { 488 default: 489 goto DpaHandleReturnFALSE; 490 491 // No type specified, use specified index value 492 case 0x00: 493 goto _KeepSensorIndex; 494 495 // For other types make the index value based on the requested index value and sensor type 496 case STD_SENSOR_TYPE_TEMPERATURE: 497 if ( sensorIndex > 0 ) 498 goto DpaHandleReturnFALSE; 499 W = 0 + sensorIndex; 500 break; 501 502 case STD_SENSOR_TYPE_BINARYDATA7: 503 if ( sensorIndex > 1 ) 504 goto DpaHandleReturnFALSE; 505 W = 1 + sensorIndex; 506 break; 507 } 508 509 // New sensor index based on type and requested index 510 sensorIndex = W; 511 _KeepSensorIndex: 512 513 // Test for supported FRC commands 514 switch ( _PCMD ) 515 { 516 default: 517 goto DpaHandleReturnFALSE; 518 519 case FRC_STD_SENSORS_BIT: 520 case FRC_STD_SENSORS_1B: 521 case FRC_STD_SENSORS_2B: 522 switch ( sensorIndex ) 523 { 524 default: 525 goto DpaHandleReturnFALSE; 526 527 case 0: 528 Carry = Get0_Temperature(); 529 break; 530 531 case 1: 532 Carry = Get1_BinaryData_Light(); 533 break; 534 535 case 2: 536 Carry = Get2_BinaryData_Potentiometer(); 537 break; 538 } 539 540 // This type of FRC is not valid for the specified sensor 541 if ( !Carry ) 542 goto DpaHandleReturnFALSE; 543 544 break; 545 } 546 547 // Some sensor was measured by FRC, check if there is a sleep request 548 FSR1++; 549 if ( INDF1.0 ) // Note: same as PerStdSensorFrc.Options.0 550 { 551 // Remember sleep parameters to go to sleep at the Idle event later 552 PerOSSleep_Request.Time.low8 = FSR1[offsetof( TPerOSSleep_Request, Time ) + 0 + offsetof( TPerStdSensorFrc, SleepParameters ) - 3]; 553 PerOSSleep_Request.Time.high8 = FSR1[offsetof( TPerOSSleep_Request, Time ) + 1 + offsetof( TPerStdSensorFrc, SleepParameters ) - 3]; 554 PerOSSleep_Request.Control = FSR1[offsetof( TPerOSSleep_Request, Control ) + offsetof( TPerStdSensorFrc, SleepParameters ) - 3]; 555 } 556 } 557 558 break; 559 560 // ------------------------------------------------- 561 case DpaEvent_FrcResponseTime: 562 // Called to get FRC response time 563 564 // In this example the FRC commands are fast 565 switch ( DataOutBeforeResponseFRC[0] ) 566 { 567 case FRC_STD_SENSORS_BIT: 568 case FRC_STD_SENSORS_1B: 569 case FRC_STD_SENSORS_2B: 570 responseFRCvalue = _FRC_RESPONSE_TIME_40_MS; 571 break; 572 } 573 break; 574 } 575 DpaHandleReturnFALSE: 576 return FALSE; 577 } 578 579 //############################################################################################ 580 bit returnTRUE() 581 //############################################################################################ 582 { 583 return TRUE; 584 } 585 586 //############################################################################################ 587 bit returnFALSE() 588 //############################################################################################ 589 { 590 return FALSE; 591 } 592 593 //############################################################################################ 594 // Increases FSR1 and then stores the byte 595 void setPlusPlusINDF1( uns8 data @ W ) 596 //############################################################################################ 597 { 598 FSR1++; // Note: must not modify W 599 setINDF1( data ); 600 } 601 602 //############################################################################################ 603 // Stores measured sensor value byte(s) and optionally sensor type to the FSR[+1...] 604 void StoreValue( uns8 sensorType ) 605 //############################################################################################ 606 { 607 // Is the sensor type to be stored too? 608 if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES ) 609 setPlusPlusINDF1( sensorType ); 610 611 // Store lower value byte 612 setPlusPlusINDF1( sensorValue.low8 ); 613 614 // No more value bytes to store? 615 if ( sensorType.7 != 0 ) 616 return; 617 618 // Store higher value byte 619 setPlusPlusINDF1( sensorValue.high8 ); 620 621 // 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. 622 } 623 624 //############################################################################################ 625 bit setFRCerror() 626 //############################################################################################ 627 { 628 responseFRCvalue2B = 2; 629 return returnTRUE(); 630 } 631 632 //############################################################################################ 633 bit sensorError; 634 bit AdjustFrcTemperature() 635 //############################################################################################ 636 { 637 // Test for supported FRC commands 638 switch ( _PCMD ) 639 { 640 default: 641 return returnFALSE(); 642 643 case FRC_STD_SENSORS_1B: 644 // Return sensor FRC value 1B 645 // Check for out of limits 646 if ( sensorError || (int16)sensorValue > (int16)( 105.5 * 16 ) || (int16)sensorValue < ( (int16)-20 * 16 ) ) 647 return setFRCerror(); 648 649 // Convert to the "F = ( T + 22 ) * 2 " from 1/16 resolution 650 uns16 _sensorValue = sensorValue + 4; // Note: do rounding when /8 651 responseFRCvalue = (uns8)( _sensorValue / 8 ) + 44; 652 break; 653 654 case FRC_STD_SENSORS_2B: 655 // Return sensor FRC value 2B 656 if ( sensorError ) 657 return setFRCerror(); 658 659 responseFRCvalue2B = sensorValue ^ 0x8000; 660 break; 661 } 662 663 return returnTRUE(); 664 } 665 666 //############################################################################################ 667 // Sensor index 1: measure temperature using one of the DDC-SE-01 sensors 668 bit Get0_Temperature() 669 //############################################################################################ 670 { 671 // Make sure FSR1 is not modified 672 673 // Measure temperature using DDC-SE-01 sensors 674 // Read temperature and check for an error 675 676 // Reads temperature from an enabled sensor 677 #ifdef DALLASnotMCP 678 sensorError = FALSE; 679 // Temperature is ready at the background 680 sensorValue = temperature; 681 // When error, return standard (FRC) error value(s) 682 if ( STD_SENSOR_TYPE_TEMPERATURE_IS_ERROR( sensorValue ) ) 683 sensorError = TRUE; 684 #else 685 sensorError = TRUE; 686 // Temperature value must be read from I2C sensor 687 STD_SENSOR_TYPE_TEMPERATURE_SET_ERROR( sensorValue ); 688 i2c_start(); 689 if ( !i2cTimeout ) 690 { 691 // MCP9802 address 692 i2c_write( I2C_ADR ); 693 // pointer: 1 = configuration register 694 i2c_write( 0x01 ); 695 // configuration: 9-bit ADC 696 i2c_write( 0x00 ); 697 i2c_stop(); 698 699 i2c_start(); 700 // MCP9802 address 701 i2c_write( I2C_ADR ); 702 // pointer: 0 = temperature 703 i2c_write( 0 ); 704 i2c_stop(); 705 706 i2c_start(); 707 // MCP9802 address + read 708 i2c_write( 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 writeToSSPCON2( uns8 value ) 971 //############################################################################################ 972 { 973 writeToRAM( &SSPCON2, value ); 974 } 975 976 //############################################################################################ 977 void writeOredToSSPCON2( uns8 value ) 978 //############################################################################################ 979 { 980 writeToSSPCON2( SSPCON2 | value ); 981 } 982 983 //############################################################################################ 984 // I2C routines 985 //############################################################################################ 986 987 //############################################################################################ 988 void i2c_init() 989 //############################################################################################ 990 { 991 // SCL as input (SIM C6) 992 TRISC.3 = 1; 993 // SDA as input (SIM C7) 994 TRISC.4 = 1; 995 996 // I2C master mode SSPCON = 0b00111000 997 writeToRAM( &SSPCON1, 0x38 ); 998 writeToSSPCON2( 0x00 ); 999 1000 // 50 kHz SCL frequency 1001 SSPADD = ( F_OSC / 50000 / 4 ) - 2; 1002 // Disable slew rate control 1003 SMP = 1; 1004 } 1005 1006 //############################################################################################ 1007 void i2c_shutdown() 1008 //############################################################################################ 1009 { 1010 // I2C master mode SSPCON = 0 1011 writeToRAM( &SSPCON1, 0x00 ); 1012 } 1013 1014 //############################################################################################ 1015 void i2c_waitForIdle() 1016 //############################################################################################ 1017 { 1018 i2cTimeout = FALSE; 1019 uns8 timeout; 1020 // Wait for idle and not writing 1021 timeout = 0; 1022 while ( ( SSPCON2 & 0b0001.1111 ) != 0 || RW_ ) 1023 if ( ++timeout == 0 ) 1024 { 1025 i2cTimeout = TRUE; 1026 break; 1027 } 1028 } 1029 1030 //############################################################################################ 1031 void i2c_start() 1032 //############################################################################################ 1033 { 1034 i2c_waitForIdle(); 1035 // SEN = 1 1036 writeOredToSSPCON2( 0x01 ); 1037 } 1038 1039 //############################################################################################ 1040 void i2c_stop() 1041 //############################################################################################ 1042 { 1043 i2c_waitForIdle(); 1044 // PEN = 1 1045 writeOredToSSPCON2( 0x04 ); 1046 } 1047 1048 //############################################################################################ 1049 uns8 i2c_read( bit ack ) 1050 //############################################################################################ 1051 { 1052 i2c_waitForIdle(); 1053 // RCEN = 1 1054 writeOredToSSPCON2( 0x08 ); 1055 1056 i2c_waitForIdle(); 1057 1058 uns8 i2cReadData @ userReg0; 1059 i2cReadData = SSPBUF; 1060 1061 i2c_waitForIdle(); 1062 1063 if ( ack ) 1064 // Acknowledge, ACKDT = 0 1065 writeToSSPCON2( SSPCON2 & 0xDF ); 1066 else 1067 // Not acknowledge, ACKDT = 1 1068 writeOredToSSPCON2( 0x20 ); 1069 1070 // Send acknowledge sequence, ACKEN = 1 1071 writeOredToSSPCON2( 0x10 ); 1072 return i2cReadData; 1073 } 1074 1075 //############################################################################################ 1076 void i2c_write( uns8 i2cWriteData ) 1077 //############################################################################################ 1078 { 1079 i2c_waitForIdle(); 1080 SSPBUF = i2cWriteData; 1081 } 1082 1083 #endif 1084 1085 //############################################################################################ 1086 // 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) 1087 #include "DPAcustomHandler.h" 1088 //############################################################################################