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