1 // ********************************************************************* 2 // Custom DPA Handler code example - Auto network example * 3 // ********************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-AutoNetwork.c,v $ 7 // Version: $Revision: 1.52 $ 8 // Date: $Date: 2017/11/16 12:52:54 $ 9 // 10 // Revision history: 11 // 2017/11/16 Release for DPA 3.02 12 // 2017/03/13 Release for DPA 3.00 13 // 2016/09/12 Release for DPA 2.28 14 // 2016/02/10 Release for DPA 2.26 15 // 2015/09/03 Release for DPA 2.21 16 // 2015/08/05 Release for DPA 2.20 17 // 18 // ********************************************************************* 19 20 // On-line DPA documentation http://www.iqrf.org/DpaTechGuide/ 21 22 // This example implements automatic network construction. It works with corresponding AutoNetwork application build with IQRF SDK. 23 // The same code is for [N] devices and [C] (use COORDINATOR_CUSTOM_HANDLER symbol to allow conditional compilation for [C] device) 24 // The handler for [C] devices is used in case the autonetwork is controlled by external device connected to the [C] 25 // Another example CustomDpaHandler-Coordinator-AutoNetwork-Embedded.c demonstrates self-containing [C] handler that controls 26 27 // Define the next symbol to let the [N] variant work at LP mode. 28 // Then TMR6 is not used for timing but less precise captureTicks() IQRF OS function. 29 // The reason is the WDT sleeps during RF communication. 30 //#define DPA_LP 31 32 #ifdef DPA_LP 33 #message "CustomDpaHandler - AutoNetwork.c" compiled for LP mode 34 #else 35 #message "CustomDpaHandler - AutoNetwork.c" compiled for STD mode 36 #endif 37 38 // Default IQRF include (modify the path according to your setup) 39 #include "IQRF.h" 40 // Default DPA header (modify the path according to your setup) 41 #include "DPA.h" 42 // Default Custom DPA Handler header (modify the path according to your setup) 43 #include "DPAcustomHandler.h" 44 45 // Define to disable scanning the working channel, it saves the code size 46 #define DO_NOT_SCAN_CHANNELS 47 48 #if !defined( COORDINATOR_CUSTOM_HANDLER ) && !defined( DO_NOT_SCAN_CHANNELS ) 49 // 1st channel to scan 50 #define FIRST_CHANNEL 0 51 // Last channel to scan + 1 52 #define LAST_CHANNEL 53 53 // RSSI difference threshold to detect working channel 54 #define PEAK_RSSI_THRESHOLD 25 55 #endif 56 57 // Define to enable example authorization of pre-bondig. See code for details. 58 //#define AUTHORIZE_PRE_BONDING 59 60 #if defined( AUTHORIZE_PRE_BONDING ) && !defined( COORDINATOR_CUSTOM_HANDLER ) 61 // Initialize PIN for pre-bonding authorization example 62 #pragma cdata[ __EESTART + PERIPHERAL_EEPROM_START ] = 0x78, 0x56, 0x34, 0x12 63 #endif 64 65 //############################################################################################ 66 67 // For all type of devices the code implements custom peripheral (PNUM=0x20, PCMD=0x00) with PDATA containing TStartBonding. 68 // The command is executed at [N] only when it is broadcast and the device does not have a temporary address. 69 // The command actually sends the peer2peer packet to all not yet bonded nodes to let them know that the bonding interval starts. 70 // The packet is send from all nodes at isolated slots. The slots are identified by nodes' VRNs. 71 72 // [N] device implements also custom bonding routine done inside Reset event. 73 // First the node scans all RF channels from the specified range and tries to detect working channel. At TR-7x modules it tries 74 // to detect RSSI peek of pattern up-peek-down. Whet such a peek is detected it tries to receive TStartBonding peer2peer 75 // packet being sent by the previously described user peripheral command. 76 // When the packet is received then the node uses LBT (listen before talk) to find the RF gap to request bonding. If node is then bonded, 77 // it goes into main DPA loop. If node is not bonded it waits for double plus some random time and it tries bonding again. 78 79 // Start bonding packet, it is sent both to the Peripheral and then as LP peer2peer to not yet bonded nodes 80 // In real application the packet might store more useful information and it also should be somehow protected against potential misuse 81 typedef struct 82 { 83 // Header, equals to TStartBondingHeader 84 uns8 Header; 85 // Total/remaining bonding interval time, 10 ms units 86 uns16 BondingTime; 87 // Total/remaining TStartBonding packet slots before bonding interval really starts 88 uns8 Slots; 89 } TStartBonding; 90 91 /// TStartBondingHeader packet header 92 #define TStartBondingHeader 'B' 93 94 // Packet at DPA memory 95 TStartBonding StartBondingDpa @ _DpaMessage.Request.PData; 96 // Packet at bufferRF (BTW same as above] 97 TStartBonding StartBondingRF @ bufferRF; 98 99 // Length of the LP start bonding packet equals to the slot length (10 ms unit) 100 #define SLOT_LENGTH MIN_LP_TIMESLOT 101 102 #if !defined( COORDINATOR_CUSTOM_HANDLER ) 103 104 // Channel filter 105 #define RXFLT DpaApiReadConfigByte( CFGIND_RXFILTER ) 106 107 // Random value 108 static uns8 rand; 109 // Generates next random value 110 uns8 Rand(); 111 112 #endif // #if !defined( COORDINATOR_CUSTOM_HANDLER ) 113 114 // Sets RF mode for scanning channels 115 void SetScanRfMode(); 116 // Disables used interrupts 117 void DisableInterrupts(); 118 119 // Macros to atomically access Timeout variable, needed only at STD, because the variable is modified by interrupt then 120 #ifndef DPA_LP 121 #define GIEoff() GIE = FALSE 122 #define GIEon() GIE = TRUE 123 #else 124 #define GIEoff() do{}while(0) 125 #define GIEon() do{}while(0) 126 #endif 127 128 #ifdef DPA_LP 129 // Ticks summed by calling myCaptureTicks() 130 uns16 SumTicks; 131 132 void myCaptureTicks(); 133 134 #ifdef __CC5XFREE__ 135 // Same as var1 -= var2 but even at free CC5X compiler version it is compiled nice way and sets the Carry correctly 136 #define Minus16vars(var1,var2) \ 137 var1.low8 -= (uns8)( var2 & 0xFF ); \ 138 W = (uns8)( var2 >> 8 ); \ 139 var1.high8 = subWFB( var1.high8 ); 140 #else 141 #define Minus16vars(var1,var2) var1 -= var2 142 #endif 143 144 #endif 145 146 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 147 //############################################################################################ 148 bit CustomDpaHandler() 149 //############################################################################################ 150 { 151 // Handler presence mark 152 clrwdt(); 153 154 #if !defined( COORDINATOR_CUSTOM_HANDLER ) 155 // Copy of start binding DPA packet later used to be sent as LP peer2peer 156 static TStartBonding StartBondingValues; 157 // To access use GIE=0, because it can be changed by ISR (valid for STD mode only) 158 static uns16 Timeout; 159 160 #ifndef DPA_LP 161 // General timeout variable controlled by TMR6 interrupt, PreScallerInit variable used to count in 10 ms (1) or 100 ms (10) 162 // Prescaller variables used to count Timeout variable in 10 ms (PreScallerInit value is 1) or in 100 ms (PreScallerInit value is 10) 163 static uns8 PreScaller, PreScallerInit; 164 // 10 ms tick used to indicate by LEDs 165 static uns8 Tick10ms; 166 #endif // #ifndef DPA_LP 167 168 #endif // #if !defined( COORDINATOR_CUSTOM_HANDLER ) 169 170 // Detect DPA event to handle (unused event handlers can be commented out or even deleted) 171 switch ( GetDpaEvent() ) 172 { 173 #if !defined( COORDINATOR_CUSTOM_HANDLER ) 174 // ------------------------------------------------- 175 case DpaEvent_Interrupt: 176 // Do an extra quick background interrupt work 177 // ! 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. 178 // ! 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. 179 // ! 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. 180 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 181 // ! Make sure race condition does not occur when accessing those variables at other places. 182 // ! 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. 183 // ! Do not call any OS functions except setINDFx(). 184 // ! Do not use any OS variables especially for writing access. 185 // ! 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. 186 187 #ifndef DPA_LP 188 // If 10 ms TMR6 interrupt occurred 189 if ( TMR6IF ) 190 { 191 // Unmask interrupt 192 TMR6IF = 0; 193 // Increase ticks 194 Tick10ms++; 195 196 // Prescaler is over? 197 if ( --PreScaller == 0 ) 198 { 199 // Yes, initialize it (PreScallerInit is 1 or 10) 200 PreScaller = PreScallerInit; 201 // Timeout is over? 202 if ( Timeout != 0 ) 203 // No, decrement timeout counter (10 or 100 ms unit) 204 Timeout--; 205 } 206 } 207 #endif // #ifndef DPA_LP 208 209 return TRUE; 210 211 // ------------------------------------------------- 212 case DpaEvent_Idle: 213 // Do a quick background work when RF packet is not received 214 215 // Node did not get the real address for the long time? 216 if ( ntwADDR == TEMPORARY_ADDRESS ) 217 { 218 #ifndef DPA_LP 219 GIEoff(); 220 if ( Timeout == 0 ) 221 #else 222 captureTicks(); 223 // Decrease the timeout 224 // To save the code we divide by 8 not by 10, so the time will go a little bit faster, but in this case it is not so important because sleeping inside RFRX is inaccurate anyway 225 param4 += 4; // Rounding for /8 226 param4 /= 8; 227 Minus16vars( Timeout, param4 ); 228 // Overflow? Time is over! 229 if ( !Carry ) 230 #endif // #ifndef DPA_LP 231 { 232 #ifndef DPA_LP 233 // Disable user interrupts 234 DisableInterrupts(); 235 #endif 236 // Unbond Node 237 removeBond(); 238 // And restart device to bond node again 239 _PNUM = PNUM_OS; 240 _PCMD = CMD_OS_RESTART; 241 _DpaDataLength = 0; 242 DpaApiLocalRequest(); 243 } 244 GIEon(); 245 } 246 247 break; 248 249 // ------------------------------------------------- 250 case DpaEvent_Reset: 251 // Called after module is reset to allow (un)bonding 252 253 // Optional: Allow LED indication e.g. during discovery 254 _systemLEDindication = TRUE; 255 256 #ifndef DPA_LP 257 // When run fist time, do some global initializations 258 static bit wasFirstReset; 259 if ( !wasFirstReset ) 260 { 261 // Already called once 262 wasFirstReset = TRUE; 263 264 // Set Timeout prescaler to 10 ms unit 265 PreScaller = PreScallerInit = 1; 266 267 // Setup TMR6 to ISR get ticks on the background (ticks every 10 ms) 268 #if F_OSC == 16000000 269 PR6 = 250 - 1; 270 T6CON = 0b0.1001.1.10; // Prescaler 16, Postscaler 10, 16 * 10 * 250 = 40000 = 4MHz * 10ms 271 #else 272 #error Unsupported oscillator frequency 273 #endif 274 // Enable TMR6 ISR 275 TMR6IE = TRUE; 276 } 277 #endif // #ifndef DPA_LP 278 279 // Is node already bonded? 280 if ( amIBonded() ) 281 { 282 #ifndef DPA_LP 283 // Force unbonding if temporary address was assigned 284 startCapture(); 285 #endif 286 // Do DPA default unbonding 287 goto DpaHandleReturnFALSE; 288 } 289 else 290 { 291 // Take care of custom bonding 292 293 // Generate non-zero random number (seed) based on MID 294 moduleInfo(); 295 // Seed is the lowest MID byte 296 rand = bufferINFO[0]; 297 // Pseudo random seed must not be zero 298 if ( rand == 0 ) 299 rand.4 = 1; 300 301 // Set OS bonding count to the random value 302 bondingCounter = rand; 303 304 // Remember current DPA RF mode 305 uns8 saveRFmode = RFmodeByte; 306 307 // Set RF scanning mode 308 SetScanRfMode(); 309 310 // Loop until not bonded 311 for ( ;; ) 312 { 313 #if !defined( DO_NOT_SCAN_CHANNELS ) 314 315 // Variables to scan channels and identify RSSI peek (up-peek-down) 316 // Set too high channel to force channel scanning initialization when the loop starts 1st time 317 RFchannel = LAST_CHANNEL + 1; 318 // RSSI of the previous channel 319 int8 lastRSSI; 320 // RSSI of the previous-previous channel 321 int8 veryLastRSSI; 322 323 #endif // #if !defined( DO_NOT_SCAN_CHANNELS ) 324 325 // Scan working channel 326 for ( ;; ) 327 { 328 #if !defined( DO_NOT_SCAN_CHANNELS ) 329 // Restart channel scanning from the 1st channel? 330 if ( RFchannel == LAST_CHANNEL + 1 ) 331 { 332 // Yes! 333 // Current channel is 1st channel 334 RFchannel = FIRST_CHANNEL; 335 336 // RSSI of the previous channel, reset to very low value to force next fake RSSI increase 337 lastRSSI = 0; 338 veryLastRSSI = 0; 339 340 // Check RFIC 341 if ( wasRFICrestarted() ) 342 DpaApiSetRfDefaults(); 343 } 344 345 // Set current channel 346 setRFchannel( RFchannel ); 347 348 // Measure RSSI 349 checkRF( 90 ); 350 // Read stabilized RSSI 351 int8 RSSI = getRSSI(); 352 353 // Is there a peak RSSI over the threshold? 354 { 355 int8 diffRSSI = lastRSSI - RSSI; 356 if ( diffRSSI >= PEAK_RSSI_THRESHOLD ) 357 { 358 int8 diffRSSI = lastRSSI - veryLastRSSI; 359 if ( diffRSSI >= PEAK_RSSI_THRESHOLD ) 360 { 361 // Set detected channel 362 setRFchannel( RFchannel - 1 ); 363 // Set normal filter 364 checkRF( RXFLT ); 365 366 #else 367 // Check RFIC 368 if ( wasRFICrestarted() ) 369 DpaApiSetRfDefaults(); 370 371 #endif // #if !defined( DO_NOT_SCAN_CHANNELS ) 372 // Timeout to receive LP packet at _RX_STD 373 toutRF = SLOT_LENGTH; 374 // Try to receive start bonding packet 375 if ( RFRXpacket() && DLEN == sizeof( StartBondingRF ) && StartBondingRF.Header == TStartBondingHeader ) 376 // If received then exit the channel scanning loop 377 break; 378 #if !defined( DO_NOT_SCAN_CHANNELS ) 379 } 380 } 381 } 382 383 // Shift buffers of (last-)last RSSIs 384 veryLastRSSI = lastRSSI; 385 lastRSSI = RSSI; 386 // Go to the next channel 387 RFchannel++; 388 #endif // #if !defined( DO_NOT_SCAN_CHANNELS ) 389 390 // Indicate by LEDs 391 #ifndef DPA_LP 392 if ( Tick10ms.3 ) 393 #else 394 captureTicks(); 395 if ( param3.3 ) 396 #endif 397 { 398 _LEDG = 1; 399 _LEDR = 0; 400 } 401 else 402 { 403 _LEDG = 0; 404 _LEDR = 1; 405 } 406 } 407 408 // Start bonding LP packet was received 409 _LEDG = _LEDR = 1; 410 411 // Start with the shortest gap between bonding attempts 412 uns8 BondingGapLength = 1; 413 414 // Set timeout to the remaining length of the bonding interval 415 GIEoff(); 416 Timeout = StartBondingRF.BondingTime; 417 GIEon(); 418 419 #ifdef DPA_LP 420 // Start measuring time at LP mode 421 startCapture(); 422 SumTicks = 0; 423 #endif // #ifdef DPA_LP 424 // But first actively wait the remaining slots 425 userReg0 = SLOT_LENGTH; 426 do 427 { 428 clrwdt(); 429 waitDelay( StartBondingRF.Slots ); 430 } while ( --userReg0 != 0 ); 431 432 // And now wait some random time so nodes will not be synchronized when doing LBT 433 waitDelay( Rand() / 2 ); 434 435 // Loop till the bonding interval is valid 436 for ( ;; ) 437 { 438 // Indicate 439 _LEDG = 0; 440 // Do LBT (listen before talk) for 400 x ( 1ms + checkRF ) 441 uns16 loop = 400; 442 do 443 { 444 // Indicate 445 #ifndef DPA_LP 446 _LEDR = Tick10ms.3; 447 #else 448 myCaptureTicks(); 449 _LEDR = param3.3; 450 #endif 451 Rand(); 452 waitMS( 1 ); 453 454 // Bonding interval is over? 455 #ifndef DPA_LP 456 GIEoff(); 457 if ( Timeout == 0 ) 458 { 459 GIEon(); 460 goto ExitBondingLoop; 461 } 462 GIEon(); 463 #else 464 myCaptureTicks(); 465 // Decrease the timeout 466 Minus16vars( Timeout, SumTicks ); 467 // Overflow? Time is over! 468 if ( !Carry ) 469 goto ExitBondingLoop; 470 471 SumTicks = 0; 472 #endif // #ifndef DPA_LP 473 474 } while ( !checkRF( RXFLT ) && --loop != 0 ); 475 476 // Indicate 477 _LEDR = 0; 478 479 // RF was quiet? 480 if ( loop == 0 ) 481 { 482 // Indicate 483 pulseLEDR(); 484 485 // Set original RF settings 486 setRFmode(saveRFmode); 487 488 // Set node mode and network filtering 489 setNetworkFilteringOn(); 490 setNodeMode(); 491 492 #if defined( AUTHORIZE_PRE_BONDING ) 493 // In this example first 4 bytes of EEPROM peripheral must be pre-filled with 32bit PIN code 494 // The PIN code will be checked at the node or coordinator that provides pre-bonding 495 eeReadData( PERIPHERAL_EEPROM_START, sizeof( UserBondingData ) ); 496 setFSR0( _FSR_INFO ); 497 copyMemoryBlock( FSR0, UserBondingData, sizeof( UserBondingData ) ); 498 #endif // #if defined( AUTHORIZE_PRE_BONDING ) 499 500 // Execute bonding 501 #ifndef DPA_LP 502 // To keep captureTicks() the most precise as possible 503 waitNewTick(); 504 #endif // #ifndef DPA_LP 505 506 // Are we bonded? 507 if ( bondRequestAdvanced() ) 508 { 509 // Bonded! 510 // Set DPA API variable 511 NodeWasBonded = TRUE; 512 #ifndef DPA_LP 513 // Now timeout will measure at 100 ms 514 PreScallerInit = 10; 515 GIEoff(); 516 #endif // #ifndef DPA_LP 517 // Time to wait for getting real address 518 Timeout.low8 = UserBondingData[0]; 519 Timeout.high8 = UserBondingData[1]; 520 GIEon(); 521 522 #if !defined( DO_NOT_SCAN_CHANNELS ) 523 // Write working channel to the configuration 524 _PNUM = PNUM_OS; 525 _PCMD = CMD_OS_WRITE_CFG_BYTE; 526 _DpaDataLength = sizeof( TPerOSWriteCfgByteTriplet ); 527 _DpaMessage.PerOSWriteCfgByte_Request.Triplets[0].Value = RFchannel; 528 _DpaMessage.PerOSWriteCfgByte_Request.Triplets[0].Address = CFGIND_CHANNEL_A; 529 _DpaMessage.PerOSWriteCfgByte_Request.Triplets[0].Mask = 0xFF; 530 DpaApiLocalRequest(); 531 532 #endif // #if !defined( DO_NOT_SCAN_CHANNELS ) 533 // Go to the DPA main loop 534 DpaApiSetRfDefaults(); 535 goto DpaHandleReturnTRUE; 536 } 537 538 // Decrease bonding counter back 539 bondingCounter--; 540 541 SetScanRfMode(); 542 } 543 544 // Increase bonding count by incommensurable value with 256 545 bondingCounter += 65; 546 547 // Wait some random time proportional to the gap 548 uns16 bondDelay = (uns16)BondingGapLength * 2; 549 userReg0 = BondingGapLength | 0b11.1111; 550 startLongDelay( bondDelay + ( Rand() & userReg0 ) ); 551 do 552 { 553 // Indicate 554 #ifndef DPA_LP 555 _LEDG = Tick10ms.3; 556 #else 557 myCaptureTicks(); 558 _LEDG = param3.3; 559 clrwdt(); 560 #endif 561 } while ( isDelay() ); 562 563 // Next gap size will be doubled (2^n-1) 564 Carry = 1; 565 BondingGapLength = rl( BondingGapLength ); 566 } 567 ExitBondingLoop: 568 } 569 } 570 break; 571 572 // ------------------------------------------------- 573 case DpaEvent_AfterRouting: 574 // Called after Notification and after routing of the DPA response was finished 575 576 // Request to send peer2peer LP start bonding packet? 577 if ( StartBondingValues.BondingTime != 0 ) 578 { 579 // Wait number of slots equal to the VRN 580 uns8 loop @ userReg0; 581 loop = ntwVRN; 582 do 583 { 584 // Decrease number of remaining slots 585 StartBondingValues.Slots--; 586 // Decrease remaining bonding interval time 587 StartBondingValues.BondingTime -= SLOT_LENGTH; 588 waitDelay( SLOT_LENGTH ); 589 clrwdt(); 590 } while ( --userReg0 != 0 ); 591 592 // Now send peer2peer packet 593 // Set RF to peer2peer packet 594 SetScanRfMode(); 595 // Prepare packet to bufferRF 596 StartBondingRF.Header = TStartBondingHeader; 597 StartBondingRF.BondingTime = StartBondingValues.BondingTime; 598 StartBondingRF.Slots = StartBondingValues.Slots; 599 // Send the packet 600 DLEN = sizeof( StartBondingRF ); 601 PIN = 0; 602 RFTXpacket(); 603 // Restore RF mode 604 DpaApiSetRfDefaults(); 605 // and filtering 606 setNetworkFilteringOn(); 607 // and node mode 608 setNodeMode(); 609 // Peer2peer packet was already sent 610 StartBondingValues.BondingTime = 0; 611 } 612 613 break; 614 615 #ifndef DPA_LP 616 // ------------------------------------------------- 617 case DpaEvent_AfterSleep: 618 // Called after woken up after sleep 619 620 // Use TMR6 again 621 TMR6IE = TRUE; 622 TMR6ON = TRUE; 623 break; 624 625 // ------------------------------------------------- 626 case DpaEvent_BeforeSleep: 627 // Called before going to sleep 628 // Fall through! 629 630 // ------------------------------------------------- 631 case DpaEvent_DisableInterrupts: 632 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart and RFPGM) 633 634 // Do not need to use TMR6 any more 635 DisableInterrupts(); 636 break; 637 #endif // #ifndef DPA_LP 638 639 #endif // #if !defined( COORDINATOR_CUSTOM_HANDLER ) 640 641 #if defined( AUTHORIZE_PRE_BONDING ) 642 // ------------------------------------------------- 643 case DpaEvent_AuthorizePreBonding: 644 // Called when remote bonding is enabled and a node requests pre-bonding 645 646 // 32 bit PIN that has to be matched is stored at first 4 bytes of peripheral RAM 647 // PIN must be same as the PIN sent from the requesting NODE. Requesting node PIN is stored at its EEPROM peripheral. 648 if ( UserBondingData[0] != PeripheralRam[0] || PeripheralRam[1] != UserBondingData[1] || UserBondingData[2] != PeripheralRam[2] || PeripheralRam[3] != UserBondingData[3] ) 649 // If PINs do not match, reject the pre-bonding request 650 goto DpaHandleReturnTRUE; 651 652 break; 653 #endif // #if defined( AUTHORIZE_PRE_BONDING ) 654 655 // ------------------------------------------------- 656 case DpaEvent_DpaRequest: 657 // Called to interpret DPA request for peripherals 658 // ------------------------------------------------- 659 // Peripheral enumeration 660 if ( IsDpaEnumPeripheralsRequest() ) 661 { 662 // We implement one user peripheral 663 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 664 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); 665 // We implement a HW Profile 666 _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x000F; 667 668 DpaHandleReturnTRUE: 669 return TRUE; 670 } 671 // ------------------------------------------------- 672 // Get information about peripheral 673 else if ( IsDpaPeripheralInfoRequest() ) 674 { 675 // We handle one user peripheral 676 if ( _PNUM == PNUM_USER + 0 ) 677 { 678 // It is user type peripheral 679 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA; 680 // And write only style 681 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_WRITE; 682 goto DpaHandleReturnTRUE; 683 } 684 685 break; 686 } 687 // ------------------------------------------------- 688 else 689 { 690 // Handle broadcast only peripheral command 691 if ( 692 // My peripheral 693 _PNUM == PNUM_USER + 0 && 694 // My command 695 _PCMD == 0 && 696 // Correct data length 697 _DpaDataLength == sizeof( StartBondingDpa ) 698 #if !defined( DO_NOT_SCAN_CHANNELS ) && !defined( COORDINATOR_CUSTOM_HANDLER ) 699 // Broadcast 700 && _NADR == BROADCAST_ADDRESS && 701 // And I do not have temporary address (i.e. no VRN) 702 ntwADDR != TEMPORARY_ADDRESS 703 #endif // #if !defined( DO_NOT_SCAN_CHANNELS ) && !defined( COORDINATOR_CUSTOM_HANDLER ) 704 ) 705 { 706 #if !defined( COORDINATOR_CUSTOM_HANDLER ) 707 // [N] version 708 709 // Store peer2peer start bonding packet values 710 StartBondingValues.BondingTime = StartBondingDpa.BondingTime; 711 StartBondingValues.Slots = StartBondingDpa.Slots; 712 #else // #if !defined( COORDINATOR_CUSTOM_HANDLER ) 713 // [C] version 714 715 // Now send peer2peer packet 716 // Set RF to peer2peer packet 717 SetScanRfMode(); 718 // Prepare packet to bufferRF 719 // ! StartBondingRF == StartBondingDpa ! 720 StartBondingRF.Header = TStartBondingHeader; 721 // Send the packet 722 DLEN = sizeof( StartBondingRF ); 723 PIN = 0; 724 RFTXpacket(); 725 // Restore RF mode 726 DpaApiSetRfDefaults(); 727 // and filtering 728 setNetworkFilteringOn(); 729 // and coordinator mode 730 setCoordinatorMode(); 731 #endif // #if !defined( COORDINATOR_CUSTOM_HANDLER ) 732 733 goto DpaHandleReturnTRUE; 734 } 735 else 736 DpaApiReturnPeripheralError( ERROR_FAIL ); 737 } 738 } 739 740 DpaHandleReturnFALSE: 741 return FALSE; 742 } 743 744 #if !defined( COORDINATOR_CUSTOM_HANDLER ) 745 //############################################################################################ 746 uns8 Rand() 747 //############################################################################################ 748 { 749 rand = lsr( rand ); 750 #pragma updateBank 0 /* OFF */ // Optimization (avoid duplicate bank setting for RandomValue access) 751 W = 0b10111000; // x^8 + x^6 + x^5 + x^4 + 1 752 if ( Carry ) 753 rand ^= W; 754 755 return rand; 756 #pragma updateBank 1 /* ON */ 757 } 758 759 #ifndef DPA_LP 760 //############################################################################################ 761 void DisableInterrupts() 762 //############################################################################################ 763 { 764 TMR6ON = FALSE; 765 TMR6IE = FALSE; 766 } 767 #endif // #ifndef DPA_LP 768 #endif // #if !defined( COORDINATOR_CUSTOM_HANDLER ) 769 770 771 #ifdef DPA_LP 772 //############################################################################################ 773 void myCaptureTicks() 774 //############################################################################################ 775 { 776 captureTicks(); 777 SumTicks += param4; 778 } 779 #endif 780 781 //############################################################################################ 782 void SetScanRfMode() 783 //############################################################################################ 784 { 785 setNonetMode(); 786 setNetworkFilteringOff(); 787 setRFmode( _WPE | _RX_STD | _TX_LP ); 788 } 789 790 //############################################################################################ 791 // 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) 792 #include "DPAcustomHandler.h" 793 //############################################################################################