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