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