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 //############################################################################################