1 // ********************************************************************* 2 // Custom DPA Handler code example - User peripheral implementation * 3 // ********************************************************************* 4 // 5 // File: $RCSfile: CustomDpaHandler-StreetLighting.c,v $ 6 // Version: $Revision: 1.37 $ 7 // Date: $Date: 2021/11/05 10:25:14 $ 8 // 9 // Revision history: 10 // 2017/03/13 Release for DPA 3.00 11 // 2016/09/27 Release for DPA 2.28 12 // 2015/08/05 Release for DPA 2.20 13 // 2014/10/31 Release for DPA 2.10 14 // 15 // ********************************************************************* 16 17 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 18 19 // This example implements DPA custom handler for Street Lighting application according to the specification HWP-StreetLightingSpecification.pdf 20 // This example works only at STD mode, not at LP mode 21 22 // Default IQRF include (modify the path according to your setup) 23 #include "IQRF.h" 24 25 // Default DPA header (modify the path according to your setup) 26 #include "DPA.h" 27 // Default Custom DPA Handler header (modify the path according to your setup) 28 #include "DPAcustomHandler.h" 29 30 // Light is controlled via an IO PIN. Choose requested pin or use internal LED. 31 //#define LIGHT_TRIS _C6_TRIS 32 //#define LIGHT_PIN _C6_OUT 33 34 // Internal LEDG is used (LIGHT_TRIS def. not needed) 35 #define LIGHT_PIN _LEDG 36 37 // Internal LEDR is used (LIGHT_TRIS def. not needed) 38 //#define LIGHT_PIN _LEDR 39 40 // Check the LIGHT_PIN is defined 41 #ifndef LIGHT_PIN 42 #error Please define IO PIN controlling the Light 43 #endif 44 45 // Street Lighting peripheral 46 #define PNUM_STREET_LIGHT PNUM_USER 47 #define HWPID_STREET_LIGHT 0x0021 48 49 // Peripheral implemented commands 50 #define PCMD_SET_LIGHT 0x00 // Direct light control 51 #define PCMD_SET_ZONE 0x01 // Set light zone 52 #define PCMD_SET_SCHEDULE 0x02 // Set and execute the light schedule 53 #define PCMD_SEND_DATA 0x03 // Exchange general data 54 55 // FRC commands 56 #define FRC_GET_STATE ( FRC_USER_BIT_FROM + 0 ) // FRC bit command - get the light state 57 #define FRC_GET_WARN ( FRC_USER_BIT_FROM + 1 ) // FRC bit command - get the light warning 58 #define FRC_SET_INTENS ( FRC_USER_BIT_FROM + 2 ) // FRC bit command - set intensity of the light, return warning information 59 #define FRC_SET_INTERV ( FRC_USER_BIT_FROM + 3 ) // FRC bit command - set interval, return warning information 60 #define FRC_GET_SCHED_STAT ( FRC_USER_BIT_FROM + 4 ) // FRC bit command - get scheduler status 61 #define FRC_GET_INTENS ( FRC_USER_BYTE_FROM + 0 ) // FRC byte command - get the light intensity 62 #define FRC_GET_ZONE ( FRC_USER_BYTE_FROM + 1 ) // FRC byte command - get the light zone 63 #define FRC_GET_TEMPER ( FRC_USER_BYTE_FROM + 2 ) // FRC byte command - get the light temperature 64 #define FRC_GET_ENRG_CONS ( FRC_USER_BYTE_FROM + 3 ) // FRC byte command - get energy consumption of the light 65 #define FRC_GET_RUN_HRS ( FRC_USER_BYTE_FROM + 4 ) // FRC byte command - get run hours of the light 66 67 // Scheduler definitions 68 #define SCH_CMD_JUMP 0x00 // Jump to interval specified by Param 69 #define SCH_CMD_REPEAT 0xff // Repeat previous interval, number of repetition specified by Param 70 #define SCH_MAX_INDEX 7 // 8 schedule intervals supported in this example, index 0-7 71 #define SCH_INTERV_SIZE sizeof( TSchedInterval ) // Interval size is 2 bytes 72 #define SCH_MAX_LEN ( SCH_MAX_INDEX + 1 ) * SCH_INTERV_SIZE // 8 intervals = 16 bytes 73 #define SCH_ONE_HOUR 3600 74 #define SCH_DEF_PERIOD 60 // Default schedule period is 1 minute 75 #define TICK_1_SEC 100 76 #define TICK_10_MS 10 77 #define SLEEP_TIME 600 // Sleep time is 10 minutes 78 79 // Node eeprom map 80 #define EEP_SCHED_PER_L8 0 81 #define EEP_SCHED_PER_H8 1 82 83 // Filter definitions 84 #define FLT_ZONE_LEN 1 // Zone filter - 1 byte 85 #define FLT_BITMAP_LEN 31 // Network bitmap filter - 31 bytes 86 87 // Initialize schedule period to 60 s during programming 88 #pragma cdata[ __EESTART + PERIPHERAL_EEPROM_START ] = SCH_DEF_PERIOD, 0x00 89 90 // Schedule interval structure 91 typedef struct 92 { 93 uns8 Cmd; // Command 94 uns8 Param; // Parameter 95 }TSchedInterval; 96 97 // Global variables 98 uns8 zoneNr; // Actual device Zone number 99 uns8 intensity; // Actual light intensity 100 101 // Prototypes 102 bit checkNTWbitmap(); 103 bit checkZoneNr(); 104 105 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 106 //############################################################################################ 107 bit CustomDpaHandler() 108 //############################################################################################ 109 { 110 // Handler presence mark 111 clrwdt(); 112 113 static uns16 secCounter, runCounter, sleepTimer; 114 static uns8 tick, PWMtick; 115 static bit buttonTrigger; 116 static bit isSchedulerRunning; // Schedule status 117 static bit scheduleExecute; // Execute schedule interval 118 static bit scheduleStart; // Start schedule in DpaEvent_AfterRouting [Sync] 119 static uns16 schedulePeriod; // Schedule period [s] 120 static uns8 scheduleRepCount; // Schedule repetition counter 121 static uns8 scheduleRepInterv; // Schedule interval repetition count 122 static uns8 scheduleInterval; // Active interval of the scheduler 123 static uns8 scheduleTimer; // Scheduler timer 124 static uns24 energyCons; // Energy consumption 125 static uns24 runHours; // Run hours 126 static uns8 prevZoneNr; // Actual and previous device Zone number 127 static uns8 prevIntensity; // Actual and previous light intensity 128 static TSchedInterval scheduler[SCH_MAX_INDEX + 1]; // Schedule, 8 interval supported in this example 129 130 // Detect DPA event to handle 131 switch ( GetDpaEvent() ) 132 { 133 134 // ------------------------------------------------- 135 case DpaEvent_Interrupt: 136 // Do an extra quick background interrupt work 137 // ! 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. 138 // ! 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. 139 // ! 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. 140 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 141 // ! Make sure race condition does not occur when accessing those variables at other places. 142 // ! 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. 143 // ! Do not call any OS functions except setINDFx(). 144 // ! Do not use any OS variables especially for writing access. 145 // ! 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. 146 147 148 // TMR6 interrupt (period 1 ms) occurred ? 149 if ( TMR6IF ) 150 { 151 // Unmask interrupt 152 TMR6IF = 0; 153 154 // Set RGB LED 155 LIGHT_PIN = intensity > PWMtick; 156 157 // PWM 100 Hz 158 if ( ++PWMtick >= TICK_10_MS ) 159 { 160 // 10ms 161 PWMtick = 0; 162 163 // 1 sec 164 if ( ++tick >= TICK_1_SEC ) 165 { 166 tick = 0; 167 168 // Count the Light run hours 169 if ( intensity != 0 ) 170 { 171 // Light is on for one hour (3600 s) ? 172 if ( --runCounter == 0 ) 173 { 174 //Preset runCounter, increment runHours 175 runCounter = SCH_ONE_HOUR; 176 #ifdef __CC5XFREE__ 177 W = 1; 178 runHours.low8 += W; 179 W = 0; 180 runHours.mid8 = addWFC( runHours.mid8 ); 181 runHours.high8 = addWFC( runHours.high8 ); 182 #else 183 runHours++; 184 #endif 185 } 186 } 187 188 // Schedule execution 189 if ( scheduleTimer != 0 ) 190 { 191 if ( --secCounter == 0 ) 192 { 193 secCounter = schedulePeriod; 194 // Countdown schedule timer 195 if ( --scheduleTimer == 0 ) 196 { 197 if ( isSchedulerRunning ) 198 { 199 // Execute schedule interval in DpaEvent_Idle 200 scheduleExecute = TRUE; 201 } 202 else 203 { 204 // Schedule isn't running, scheduleTimer is set by FRC Set interval 205 // Time elapsed - set previous intensity 206 intensity = prevIntensity; 207 } 208 } 209 } 210 } 211 212 //Inc. sleepTimer 213 sleepTimer++; 214 } 215 } 216 } 217 218 returnTRUE: 219 return TRUE; 220 221 // ------------------------------------------------- 222 case DpaEvent_Idle: 223 // Execute the Light scheduler 224 if ( scheduleExecute ) 225 { 226 // 8 schedule intervals supported in this example 227 if ( scheduleInterval > SCH_MAX_INDEX ) 228 scheduleInterval = 0; // scheduleInterval out of range 0-7, start from interval 0 229 230 // Get actual schedule interval command and parameter 231 FSR0 = (uns16)&scheduler[scheduleInterval]; 232 param3.low8 = FSR0[0]; 233 param3.high8 = FSR0[1]; 234 235 // Jump command ? 236 if ( param3.low8 == SCH_CMD_JUMP ) 237 { 238 // Jump to specified interval during next pass through DpaEvent_Idle event 239 scheduleInterval = param3.high8; 240 } 241 else 242 { 243 // Repeat command ? 244 if ( param3.low8 == SCH_CMD_REPEAT ) 245 { 246 // Get number of repetition and number of previous intervals to repeat 247 if ( scheduleRepCount == 0 ) 248 { 249 // Number of repetition is specified by bits 0-2 250 scheduleRepCount = param3.high8 & 0x07; 251 scheduleRepCount++; 252 // Number of repeated blocks is specified by bits 3-7 253 scheduleRepInterv = param3.high8; 254 scheduleRepInterv = lsr( scheduleRepInterv ); 255 scheduleRepInterv = lsr( scheduleRepInterv ); 256 scheduleRepInterv = lsr( scheduleRepInterv ); 257 scheduleRepInterv++; 258 goto REPEAT; 259 } 260 else 261 { 262 // All previous intervals repeated, repeat again ? 263 if ( --scheduleRepCount != 0 ) 264 { 265 // Execute the first repeated interval during next pass through DpaEvent_Idle event 266 REPEAT: 267 scheduleInterval -= scheduleRepInterv; 268 } 269 else 270 { 271 // Repetition is finished, skip repeat command, execute next interval 272 scheduleInterval++; 273 } 274 } 275 } 276 else 277 { 278 // Set Light intensity specified by current schedule interval 279 prevIntensity = intensity; 280 intensity = param3.high8; 281 scheduleTimer = param3.low8; 282 // Increase interval index 283 scheduleInterval++; 284 // Interval executed 285 scheduleExecute = FALSE; 286 } 287 } 288 } 289 290 // Go sleep after ~10 min. (= 10 * 60 s) since last peripheral command reception 291 if ( sleepTimer == SLEEP_TIME ) 292 { 293 // Stop TMR6, turn off the light 294 GO_SLEEP: 295 TMR6IE = FALSE; 296 TMR6ON = FALSE; 297 LIGHT_PIN = 0; 298 // Prepare OS Sleep DPA Request 299 // Endless sleep 300 sleepTimer = 0x00; 301 _PNUM = PNUM_OS; 302 _PCMD = CMD_OS_SLEEP; 303 _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request ); 304 // Wake up on PIN change, LEDG flash after wake up 305 _DpaMessage.PerOSSleep_Request.Time = 0x0000; 306 _DpaMessage.PerOSSleep_Request.Control = 0b101; 307 // Perform local DPA Request 308 // BeforeSleep and AfterSleep events will not be called in this case! 309 DpaApiLocalRequest(); 310 TMR6ON = TRUE; 311 TMR6IE = TRUE; 312 } 313 goto returnFALSE; 314 315 // ------------------------------------------------- 316 case DpaEvent_DpaRequest: 317 // Called to interpret DPA request for peripherals 318 // ------------------------------------------------- 319 // Peripheral enumeration 320 if ( IsDpaEnumPeripheralsRequest() ) 321 { 322 // We implement 1 user peripheral PNUM = 0x20, HwProfile = 0x0021 323 _DpaMessage.EnumPeripheralsAnswer.UserPerNr |= 1; 324 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); 325 _DpaMessage.EnumPeripheralsAnswer.HWPID |= HWPID_STREET_LIGHT; 326 _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0x0100; 327 goto returnTRUE; 328 } 329 // ------------------------------------------------- 330 // Get information about peripheral 331 else if ( IsDpaPeripheralInfoRequest() ) 332 { 333 if ( _PNUM == PNUM_STREET_LIGHT ) 334 { 335 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA; 336 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 337 goto returnTRUE; 338 } 339 break; 340 } 341 // ------------------------------------------------- 342 else 343 { 344 // Handle Street lighting peripheral 345 if ( _PNUM == PNUM_STREET_LIGHT ) 346 { 347 uns8 _PCMDatW @ W; 348 349 _PCMDatW = _PCMD; 350 _PCMDatW = PCMD_SEND_DATA - _PCMDatW; 351 if ( !Carry ) 352 goto UserErrorPCMD; 353 354 skip( _PCMDatW ); // Reverse order 355 #pragma computedGoto 1 356 goto _PCMD_SEND_DATA; // 0x03 357 goto _PCMD_SET_SCHEDULE; // 0x02 358 goto _PCMD_SET_ZONE; // 0x01 359 goto _PCMD_SET_LIGHT; // 0x00 360 #pragma computedGoto 0 361 ; 362 // Direct light control command 363 _PCMD_SET_LIGHT: 364 // Zone number filter (1 byte zone + 1 byte intensity) ? 365 if ( _DpaDataLength == ( FLT_ZONE_LEN + 1 ) ) 366 { 367 // Check device zone number 368 if ( checkZoneNr() ) 369 { 370 // Zone number ok, set intensity of the light 371 intensity = _DpaMessage.Request.PData[1]; 372 goto SET_INTENS; 373 } 374 else 375 goto PDATA_ERR; // Incorrect zone number, return PDATA_ERROR 376 } 377 378 // Network bitmap filter (31 byte bitmap filter + 1 byte intensity) ? 379 if ( _DpaDataLength == ( FLT_BITMAP_LEN + 1 ) ) 380 { 381 // The first byte of Network bitmap filter must be 0x00 382 if ( _DpaMessage.Request.PData[0] != 0x00 ) 383 goto PDATA_ERR; 384 385 // Check the network bitmap 386 if ( checkNTWbitmap() ) 387 { 388 // Network bitmap OK, set intensity of the light, stop scheduler 389 intensity = _DpaMessage.Request.PData[31]; 390 SET_INTENS: _DpaMessage.Response.PData[0] = prevIntensity; 391 prevIntensity = intensity; 392 isSchedulerRunning = FALSE; 393 scheduleTimer = 0; 394 // Return 1 byte - prevIntensity 395 goto RESP_ONE_BYTE; 396 } 397 else 398 goto PDATA_ERR; // Bit for device ntwADDR in the network bitmap is cleared, return data error 399 } 400 else 401 goto PLEN_ERR; // Incorrect data length 402 403 // Set zone command 404 _PCMD_SET_ZONE: 405 // Network bitmap filter (1 byte new zone value + 30 byte Network bitmap filter) ? 406 if ( _DpaDataLength == FLT_BITMAP_LEN ) 407 { 408 // Check the network bitmap 409 if ( checkNTWbitmap() ) 410 { 411 // Network bitmap ok, check the new zone number value 412 param3.low8 = _DpaMessage.Request.PData[0]; 413 if ( Zero_ ) 414 goto PDATA_ERR; // New zone == 0, return data error 415 do 416 param3.low8 = lsr( param3.low8 ); 417 while ( !Carry ); 418 if ( !Zero_ ) 419 goto PDATA_ERR; // New zone - more than one bit is set, return data error 420 // Ok, set zone, return previous zone 421 zoneNr = W; 422 _DpaMessage.Response.PData[0] = prevZoneNr; 423 prevZoneNr = zoneNr; 424 // Return one byte - prevZoneNr 425 RESP_ONE_BYTE: 426 _DpaDataLength = 0x01; 427 goto CMD_OK; 428 } 429 else 430 goto PDATA_ERR; // Bit for device ntwADDR in the network bitmap is cleared, return data error 431 } 432 else 433 goto PLEN_ERR; // Incorrect data length 434 435 // Set schedule command (max. 8 intervals currently supported) 436 _PCMD_SET_SCHEDULE: 437 // Minimal PLEN is 3 byte (zone number + 1 sched. interval = 3 bytes ), PLEN must be an odd number 438 if ( ( _DpaDataLength < ( FLT_ZONE_LEN + SCH_INTERV_SIZE ) ) || ( _DpaDataLength.0 == 0 ) ) 439 goto PLEN_ERR; 440 441 // Zone number filter ? 442 if ( _DpaMessage.Request.PData[0] != 0x00 ) 443 { 444 // Check device zone number 445 if ( checkZoneNr() ) 446 { 447 // Zone number ok 448 // Subtract size of filter 449 _DpaDataLength -= FLT_ZONE_LEN; 450 // 8 intervals supported in this example 451 if ( _DpaDataLength > SCH_MAX_LEN ) 452 goto PLEN_ERR; 453 // Set schedule intervals 454 param3.low8 = FLT_ZONE_LEN; 455 // Run schedule 456 goto RUN_SCHEDULE; 457 } 458 else 459 goto PDATA_ERR; // Incorrect zone number, return PDATA_ERROR 460 } 461 else 462 { 463 // Minimal PLEN is 33 (Network bitmap filter (31B) + 1 sched. interval (2B) = 33 bytes) 464 if ( _DpaDataLength < ( FLT_BITMAP_LEN + SCH_INTERV_SIZE ) ) 465 goto PLEN_ERR; // Incorrect data length 466 // Check the network bitmap 467 if ( checkNTWbitmap() ) 468 { 469 // Network bitmap ok 470 // Subtract size of filter 471 _DpaDataLength -= FLT_BITMAP_LEN; 472 // 8 intervals supported in this example 473 if ( _DpaDataLength > SCH_MAX_LEN ) 474 goto PDATA_ERR; 475 param3.low8 = FLT_BITMAP_LEN; 476 // Set schedule intervals 477 RUN_SCHEDULE: 478 copyMemoryBlock( _DpaMessage.Request.PData + param3.low8, scheduler, _DpaDataLength ); 479 // Run scheduler (in DpaEvent_AfterRouting [Sync]) 480 scheduleStart = TRUE; 481 // No data is returned 482 _DpaDataLength = 0x00; 483 // Return TRUE to indicate peripheral was handled 484 goto CMD_OK; 485 } 486 else 487 goto PDATA_ERR; // Bit for device ntwADDR in the network bitmap filter is cleared, return data error 488 } 489 490 // Exchange general data command 491 _PCMD_SEND_DATA: 492 // Minimal PLEN is 1 (zone number) 493 if ( _DpaDataLength == 0x00 ) 494 goto PLEN_ERR; 495 496 // Zone number filter ? 497 if ( _DpaMessage.Request.PData[0] != 0x00 ) 498 { 499 // Check device zone number 500 if ( checkZoneNr() ) 501 { 502 // Zone number OK 503 // Application specific data processing 504 // ... 505 // ... 506 // ... 507 // Set schedule period, complete schedule and period is returned in this example 508 param3.low8 = _DpaMessage.Request.PData[FLT_ZONE_LEN]; 509 param3.high8 = _DpaMessage.Request.PData[FLT_ZONE_LEN + 1]; 510 goto SET_SCH_PER; 511 } 512 else 513 goto PDATA_ERR; // Incorrect zone number, return PDATA_ERROR 514 } 515 else 516 { 517 // Network bitmap filter 518 if ( _DpaDataLength < FLT_BITMAP_LEN ) 519 { 520 // Incorrect data length 521 PLEN_ERR: 522 W = ERROR_DATA_LEN; 523 goto UserErrorW; 524 } 525 526 // Check the network bitmap 527 if ( checkNTWbitmap() ) 528 { 529 // Network bitmap OK 530 // Application specific data processing 531 // ... 532 // ... 533 // ... 534 // Set schedule period, complete schedule and period is returned in this example 535 param3.low8 = _DpaMessage.Request.PData[FLT_BITMAP_LEN]; 536 param3.high8 = _DpaMessage.Request.PData[FLT_BITMAP_LEN + 1]; 537 SET_SCH_PER: 538 if ( ( param3 == 0 ) || ( param3 > SCH_ONE_HOUR ) ) 539 goto PDATA_ERR; 540 541 schedulePeriod.low8 = param3.low8; 542 schedulePeriod.high8 = param3.high8; 543 eeWriteByte( EEP_SCHED_PER_L8, param3.low8 ); 544 eeWriteByte( EEP_SCHED_PER_H8, param3.high8 ); 545 copyMemoryBlock( scheduler, _DpaMessage.Response.PData, SCH_MAX_LEN ); 546 _DpaMessage.Response.PData[SCH_MAX_LEN] = schedulePeriod.low8; 547 _DpaMessage.Response.PData[SCH_MAX_LEN + 1] = schedulePeriod.high8; 548 _DpaDataLength = SCH_MAX_LEN + 2; 549 // If the schedule is running, restart it with new period 550 if ( isSchedulerRunning ) 551 scheduleStart = TRUE; 552 CMD_OK: 553 sleepTimer = 0; 554 goto returnTRUE; 555 } 556 else 557 { 558 // Bit for device ntwADDR in the network bitmap filter is cleared, return data error 559 PDATA_ERR: 560 W = ERROR_DATA; 561 goto UserErrorW; 562 } 563 564 // Invalid PCmd error 565 UserErrorPCMD: 566 W = ERROR_PCMD; 567 // User error - err code in W reg 568 UserErrorW: 569 _DpaMessage.ErrorAnswer.ErrN = W; 570 _DpaMessage.ErrorAnswer.PNUMoriginal = _PNUM; 571 _PNUM = PNUM_ERROR_FLAG; 572 _DpaDataLength = sizeof( _DpaMessage.ErrorAnswer ); 573 goto returnTRUE; 574 } 575 } 576 } 577 break; 578 579 // ------------------------------------------------- 580 case DpaEvent_FrcValue: 581 // Called to get FRC value 582 // Process the FRC 583 switch ( _PCMD ) 584 { 585 //FRC bit command - set intensity of the light, return warning information 586 case FRC_SET_INTENS: 587 // Check device zone number 588 if ( DataOutBeforeResponseFRC[0] & zoneNr ) 589 { 590 // Zone number OK, set intensity 591 intensity = DataOutBeforeResponseFRC[1]; 592 prevIntensity = intensity; 593 } 594 // Light state is returned in this example 595 goto RET_STATE; 596 597 // FRC bit command - set interval, return warning information 598 case FRC_SET_INTERV: 599 // Check interval time 600 if ( ( DataOutBeforeResponseFRC[0] != 0x00 ) && ( DataOutBeforeResponseFRC[0] != 0xff ) ) 601 { 602 // Interval OK, stop scheduler, set requested light intensity 603 intensity = DataOutBeforeResponseFRC[1]; 604 isSchedulerRunning = FALSE; 605 606 tick = 0; 607 secCounter = schedulePeriod; 608 scheduleTimer = DataOutBeforeResponseFRC[0]; 609 } 610 // Light state is returned in this example 611 612 // FRC bit command - get the light warning 613 case FRC_GET_WARN: 614 // Bit.0 bit.1 615 // 0 0 - Device didn't respond 616 // 0 1 - Warning (HW failure, high temperature, etc.) 617 // 1 0 - Light is off 618 // 1 1 - Light is on (intensity > 0x00) 619 // Light state is returned in this example 620 621 // FRC bit command - get the light state 622 case FRC_GET_STATE: 623 // Bit.0 is always 1, bit.1 is set when the light intensity > 0x00 624 RET_STATE: 625 if ( intensity != 0x00 ) 626 goto FRCvalueBit1AndSleep; 627 goto CLR_SLEEP; 628 629 // FRC bit command - get scheduler status 630 case FRC_GET_SCHED_STAT: 631 // Bit.0 is always 1, bit.1 is set when the schedule is running 632 if ( isSchedulerRunning ) 633 { 634 FRCvalueBit1AndSleep: 635 responseFRCvalue.1 = TRUE; 636 } 637 goto CLR_SLEEP; 638 639 // FRC byte command - get the light intensity 640 case FRC_GET_INTENS: 641 responseFRCvalue = intensity; 642 if ( intensity != 0xff ) 643 responseFRCvalue++; 644 goto CLR_SLEEP; 645 646 // FRC byte command - get the light zone 647 case FRC_GET_ZONE: 648 responseFRCvalue = zoneNr; 649 goto CLR_SLEEP; 650 651 // FRC byte command - get the light temperature 652 case FRC_GET_TEMPER: 653 responseFRCvalue = getTemperature(); 654 // In case of 0 deg. C fixed value 0x7f is returned 655 if ( responseFRCvalue == 0x00 ) 656 responseFRCvalue = 0x7f; 657 goto CLR_SLEEP; 658 659 // FRC byte command - get energy consumption of the light 660 case FRC_GET_ENRG_CONS: 661 FSR0 = (uns16)&energyCons; // Measurement of consumed energy is application specific 662 goto RET_21bit; 663 664 // FRC byte command - get run hours of the light 665 case FRC_GET_RUN_HRS: 666 FSR0 = (uns16)&runHours; 667 RET_21bit: 668 // Bits 0-6 is returned if DataOutBeforeResponseFRC[0] == 0x00 669 if ( DataOutBeforeResponseFRC[0] == 0x00 ) 670 responseFRCvalue = FSR0[0]; 671 else 672 { 673 // Bits 7-13 is returned if DataOutBeforeResponseFRC[0] == 0x00 674 if ( DataOutBeforeResponseFRC[0] == 0x01 ) 675 { 676 param3.low8 = FSR0[0]; 677 responseFRCvalue = FSR0[1]; 678 goto ROLL; 679 } 680 else 681 { 682 // Bits 14-21 is returned if DataOutBeforeResponseFRC[0] >= 0x02 683 param3.low8 = FSR0[1]; 684 responseFRCvalue = FSR0[2]; 685 param3.low8 = rl( param3.low8 ); 686 responseFRCvalue = rl( responseFRCvalue ); 687 ROLL: 688 param3.low8 = rl( param3.low8 ); 689 responseFRCvalue = rl( responseFRCvalue ); 690 } 691 } 692 693 // Clear MSB, add 1 694 responseFRCvalue.7 = 0; 695 responseFRCvalue++; 696 CLR_SLEEP: 697 sleepTimer = 0x00; 698 break; 699 } 700 break; 701 702 // ------------------------------------------------- 703 case DpaEvent_AfterRouting: 704 // Called after Notification and after routing of the DPA response was finished 705 if ( scheduleStart ) 706 { 707 //Sync start of light scheduler 708 scheduleStart = FALSE; 709 scheduleInterval = 0x00; 710 secCounter = schedulePeriod; 711 tick = 0; 712 scheduleRepCount = 0x00; 713 isSchedulerRunning = TRUE; 714 scheduleExecute = TRUE; 715 } 716 break; 717 718 // ------------------------------------------------- 719 case DpaEvent_Init: 720 // Initialization 721 LIGHT_PIN = 0; 722 #ifdef LIGHT_TRIS 723 LIGHT_TRIS = 0; 724 #endif 725 W = 1; 726 zoneNr = W; 727 prevZoneNr = W; 728 runHours = 0; 729 energyCons = 0; 730 runCounter = SCH_ONE_HOUR; 731 isSchedulerRunning = FALSE; 732 scheduleStart = FALSE; 733 scheduleExecute = FALSE; 734 scheduleTimer = 0; 735 tick = 0; 736 // Read schedule timer 737 schedulePeriod.low8 = eeReadByte( EEP_SCHED_PER_L8 ); 738 schedulePeriod.high8 = eeReadByte( EEP_SCHED_PER_H8 ); 739 // Setup TMR6 to generate PWM for LED switching 740 741 #if F_OSC == 16000000 742 PR6 = 250 - 1; 743 T6CON = 0b0.0000.1.10; // Prescaler 16, Postscaler 1, 1 ms interrupt 744 #else 745 #error Unsupported oscillator frequency 746 #endif 747 748 TMR6IE = TRUE; 749 break; 750 751 // ------------------------------------------------- 752 case DpaEvent_AfterSleep: 753 // Called on wake-up from sleep 754 TMR6IE = TRUE; 755 TMR6ON = TRUE; 756 break; 757 758 // ------------------------------------------------- 759 case DpaEvent_BeforeSleep: 760 // Called before going to sleep (the same handling as DpaEvent_DisableInterrupts event) 761 762 // ------------------------------------------------- 763 case DpaEvent_DisableInterrupts: 764 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond, and Run RFPGM) 765 // Must not use TMR6 any more 766 TMR6ON = FALSE; 767 TMR6IE = FALSE; 768 break; 769 } 770 771 returnFALSE: 772 return FALSE; 773 } 774 775 //############################################################################################ 776 // Check device zone number 777 bit checkZoneNr() 778 //############################################################################################ 779 { 780 W = _DpaMessage.Request.PData[0] & zoneNr; 781 return W != 0; 782 } 783 784 //############################################################################################ 785 // Check the network bit map 786 bit checkNTWbitmap() 787 //############################################################################################ 788 { 789 // Get index of _DpaMessage.Request.PData containing 8-bit filter for device ntwADDR 790 param3.low8 = ntwADDR; 791 param3.high8 = param3.low8 % 8 + 1; // param3.high8 = (ntwADDR % 8) + 1 792 param3.low8 = lsr( param3.low8 ); 793 param3.low8 = lsr( param3.low8 ); 794 param3.low8 = lsr( param3.low8 ); 795 FSR0 = _DpaMessage.Request.PData + param3.low8 + 1; 796 // param3.low8 = Current byte of network bitmap 797 param3.low8 = *FSR0; 798 799 do 800 { 801 param3.low8 = lsr( param3.low8 ); 802 } while ( --param3.high8 != 0 ); 803 804 return Carry; 805 } 806 807 //############################################################################################ 808 // Default Custom DPA Handler header; 2nd include implementing a Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup) 809 #include "DPAcustomHandler.h" 810 //############################################################################################@ 811