1 // *********************************************************************
    2 //   Custom DPA Handler code example - Buttonless bonding - Node       *
    3 // *********************************************************************
    4 // Copyright (c) IQRF Tech s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-ButtonlessBonding_Node.c,v $
    7 // Version: $Revision: 1.3 $
    8 // Date:    $Date: 2017/10/19 07:48:35 $
    9 //
   10 // Revision history:
   11 //   2017/08/31  Release for DPA 3.01
   12 //
   13 // *********************************************************************
   14 
   15 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/
   16 
   17 // Default IQRF include (modify the path according to your setup)
   18 #include "IQRF.h"
   19 
   20 // Default DPA header (modify the path according to your setup)
   21 #include "DPA.h"
   22 // Default Custom DPA Handler header (modify the path according to your setup)
   23 #include "DPAcustomHandler.h"
   24 
   25 //############################################################################################
   26 
   27 // Description:
   28 // This example implements button-less bonding on the Node side.
   29 // It works with corresponding handler CustomDpaHandler-ButtonlessBonding_Coordinator.c uploaded at the Coordinator.
   30 //
   31 // How it works:
   32 //  Coordinator:
   33 //   Coordinator implements a user peripheral/command Add Node which requires 5 data bytes (MID of targeted Node and address to be assigned).
   34 //   This command transmits peer-to-peer service packet on the service RF channel with information about working RF channel of the Coordinator.
   35 //   The packet is encrypted by MID of the bonded Node. Then the Coordinator tries to bond new Node with given MID.
   36 //
   37 //  Node:
   38 //   If a Node is not bonded it stays in receiving mode (STD or LP depending on used HWP plugin) on the service RF channel
   39 //   waiting for special peer-to-peer service packet. This packet is encrypted by the MID of the given Node
   40 //   and contains information about working RF channel of the Coordinator. So, only one targeted Node can receive the packet.
   41 //   After service packet receiving the Node switches on the working RF channel and asks 10 s for bonding.
   42 //   If the bonding is not successful the Node switches back on the service RF channel and waits for service packet. 
   43 
   44 // --- Peer2peer service packet announcing bonding interval ---
   45 #define SERVICE_CHANNEL   10        // Must be the same on both Coordinator and Node side
   46 
   47 typedef struct
   48 {
   49   uns8 nodeMID[sizeof( BondingNodeMID )]; // MID of bonded Node
   50   uns8 workingChannel; // Working channel of the Coordinator
   51 } TServicePacket;
   52 
   53 #if !defined( COORDINATOR_CUSTOM_HANDLER )
   54 // Place for global variables shared among CustomDpaHandler() and other function, otherwise local [static] variables are recommended
   55 
   56 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   57 //############################################################################################
   58 bit CustomDpaHandler()
   59 //############################################################################################
   60 {
   61   // Handler presence mark
   62   clrwdt();
   63 
   64   // Place for local static variables used only within CustomDpaHandler() among more events
   65   // Peer2peer service packet announcing bonding interval
   66   TServicePacket servicePacket @ bufferRF;
   67 
   68   // Detect DPA event to handle (unused event handlers can be commented out or even deleted)
   69   switch ( GetDpaEvent() )
   70   {
   71 #ifdef DpaEvent_Interrupt
   72     // -------------------------------------------------
   73     case DpaEvent_Interrupt:
   74       // Do an extra quick background interrupt work
   75       // ! 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.
   76       // ! 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.
   77       // ! 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.
   78       // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy.
   79       // ! Make sure race condition does not occur when accessing those variables at other places.
   80       // ! 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.
   81       // ! Do not call any OS functions except setINDFx().
   82       // ! Do not use any OS variables especially for writing access.
   83       // ! 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.
   84 
   85       return Carry;
   86 #endif
   87       // -------------------------------------------------
   88     case DpaEvent_Idle:
   89       // Do a quick background work when RF packet is not received
   90       break;
   91 
   92       // -------------------------------------------------
   93     case DpaEvent_Reset:
   94       // Called after module is reset
   95       if ( amIBonded() )
   96         // Standard unbonding process using a button is possible
   97         goto DpaHandleReturnFALSE;
   98 
   99       // While the node is not bonded
  100       while ( !amIBonded() )
  101       {
  102         // Set service channel
  103         setRFchannel( SERVICE_CHANNEL );
  104         setNonetMode();
  105 
  106         // Set MID as the User Key for service packet decrypting
  107         moduleInfo();
  108         copyBufferINFO2RF();
  109         clearBufferINFO();
  110         memoryLimit = sizeof( servicePacket.nodeMID );
  111         copyBufferRF2INFO();
  112         setUserKey();
  113 
  114         // Unbonding state indication
  115         uns8 loop = 5;
  116         do
  117         {
  118           _LEDR = 1;
  119           waitMS( 50 );
  120           stopLEDR();
  121           waitMS( 100 );
  122         } while ( --loop != 0 );
  123 
  124         // Waiting for peer2peer service packet announcing bonding interval
  125         while ( 1 )
  126         {
  127           // RF mode (STD/LP) depends on used HWP plugin
  128           if ( RFRXpacket() )
  129           {
  130             if ( DLEN != ( ( sizeof( servicePacket ) + 15 ) & ~15 ) )
  131               continue;
  132 
  133             decryptBufferRF( ( sizeof( servicePacket ) + 15 ) / 16 );
  134             moduleInfo();
  135             // Packet validation, correct MID must be received
  136             memoryOffsetFrom = memoryOffsetTo = offsetof( TServicePacket, nodeMID );
  137             if ( !compareBufferINFO2RF( sizeof( servicePacket.nodeMID ) ) )
  138               continue;
  139 
  140             // Set working channel to the TR configuration
  141             _PNUM = PNUM_OS;
  142             _PCMD = CMD_OS_WRITE_CFG_BYTE;
  143             _DpaMessage.PerOSWriteCfgByte_Request.Triplets[0].Address = CFGIND_CHANNEL_A;
  144             _DpaMessage.PerOSWriteCfgByte_Request.Triplets[0].Value = servicePacket.workingChannel;
  145             _DpaMessage.PerOSWriteCfgByte_Request.Triplets[0].Mask = 0xFF;
  146             _DpaDataLength = sizeof( TPerOSWriteCfgByteTriplet );
  147             // Perform local DPA Request
  148             DpaApiLocalRequest();
  149             break;
  150           }
  151 
  152           if ( wasRFICrestarted() )
  153           {
  154             // Sets also working channel
  155             DpaApiSetRfDefaults();
  156             setRFchannel( SERVICE_CHANNEL );
  157           }
  158         }
  159 
  160         // Bonding
  161         DpaApiSetRfDefaults();
  162         setNodeMode();
  163 
  164         loop = 60;  // 10 s in approx 170 ms units
  165         do
  166         {
  167           pulseLEDR();
  168           // Check RFIC
  169           if ( wasRFICrestarted() )
  170             DpaApiSetRfDefaults();
  171 
  172           // Bonding OK?
  173           if ( bondRequestAdvanced() )
  174           {
  175             // Set DPA API variable
  176             NodeWasBonded = TRUE;
  177             break;
  178           }
  179         } while ( --loop != 0 );
  180       }
  181 
  182       goto DpaHandleReturnTRUE; // return TRUE only if you handle node bonding/unbonding
  183 
  184       // -------------------------------------------------
  185     case DpaEvent_DpaRequest:
  186       // Called to interpret DPA request for peripherals
  187       IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest()
  188       {
  189         // -------------------------------------------------
  190         // Peripheral enumeration
  191 
  192         _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 0; // ?
  193         // FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); // ?
  194         _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x000F; // ????
  195         _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0; // ????
  196 
  197 DpaHandleReturnTRUE:
  198         return TRUE;
  199       }
  200       break;
  201   }
  202 
  203 DpaHandleReturnFALSE:
  204   return FALSE;
  205 }
  206 //############################################################################################
  207 // 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) 
  208 #include "DPAcustomHandler.h"
  209 //############################################################################################
  210 #endif // #if !defined( COORDINATOR_CUSTOM_HANDLER )