1 // *********************************************************************
    2 //   Custom DPA Handler code example - Buttonless bonding - Coordinator*
    3 // *********************************************************************
    4 // Copyright (c) IQRF Tech s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-ButtonlessBonding_Coordinator.c,v $
    7 // Version: $Revision: 1.1 $
    8 // Date:    $Date: 2017/08/31 12:51:09 $
    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 // Include Node part to define shared stuff
   18 #define COORDINATOR_CUSTOM_HANDLER
   19 #include "CustomDpaHandler-ButtonlessBonding_Node.c"
   20 
   21 //############################################################################################
   22 // Description:
   23 // This example implements button-less bonding on the Coordinator side.
   24 // It works with corresponding handler CustomDpaHandler-ButtonlessBonding_Node.c uploaded at nodes.
   25 // See CustomDpaHandler-ButtonlessBonding_Node.c for more information.
   26 
   27 // --- User peripheral: Add (bond) new Node to the network ---
   28 #define PNUM_USER_ADD_NODE                      (PNUM_USER + 0)
   29 // Command
   30 #define PCMD_ADD_NODE                           0
   31 
   32 // PDATA (same format for both request and response)
   33 // 1. byte: Node MID lsb
   34 // 2. byte: Node MID
   35 // 3. byte: Node MID
   36 // 4. byte: Node MID msb
   37 // 5. byte: Node address to by assigned
   38 
   39 typedef struct
   40 {
   41   uns8 nodeMID[sizeof( BondingNodeMID )]; // MID of bonded Node
   42   uns8 nodeAddress; // Address of the Node
   43 } TPerUserAddNode_RequestResponse;
   44 
   45 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   46 //############################################################################################
   47 bit CustomDpaHandler()
   48 //############################################################################################
   49 {
   50   // Handler presence mark
   51   clrwdt();
   52 
   53   // Place for local static variables used only within CustomDpaHandler() among more events
   54   // Peer2peer service packet announcing bonding interval
   55   TServicePacket servicePacket @ bufferRF;
   56   // Add Node user peripheral PDATA
   57   TPerUserAddNode_RequestResponse dpaMessageUserPdata_AddNode @ _DpaMessage;
   58 
   59   // Detect DPA event to handle (unused event handlers can be commented out or even deleted)
   60   switch ( GetDpaEvent() )
   61   {
   62 #ifdef DpaEvent_Interrupt
   63     // -------------------------------------------------
   64     case DpaEvent_Interrupt:
   65       // Do an extra quick background interrupt work
   66       // ! 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.
   67       // ! 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.
   68       // ! 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.
   69       // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy.
   70       // ! Make sure race condition does not occur when accessing those variables at other places.
   71       // ! 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.
   72       // ! Do not call any OS functions except setINDFx().
   73       // ! Do not use any OS variables especially for writing access.
   74       // ! 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.
   75 
   76       return Carry;
   77 #endif
   78       // -------------------------------------------------
   79     case DpaEvent_DpaRequest:
   80       // Called to interpret DPA request for peripherals
   81       IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest()
   82       {
   83         // -------------------------------------------------
   84         // Peripheral enumeration
   85 
   86         _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1;
   87         FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER_ADD_NODE );
   88         _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x000F;
   89         _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0000;
   90 
   91 DpaHandleReturnTRUE:
   92         return TRUE;
   93       }
   94       else
   95       {
   96         // -------------------------------------------------
   97         // Get information about peripheral
   98 
   99         if ( _PNUM == PNUM_USER_ADD_NODE )
  100         {
  101           _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA;
  102           _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_WRITE;
  103           // _DpaMessage.PeripheralInfoAnswer.Par1 = 0; // ?
  104           // _DpaMessage.PeripheralInfoAnswer.Par2 = 0; // ?
  105           goto DpaHandleReturnTRUE;
  106         }
  107 
  108         break;
  109       }
  110 
  111       // -------------------------------------------------
  112       // Handle peripheral command
  113 
  114       if ( _PNUM == PNUM_USER_ADD_NODE )
  115       {
  116         // Check command
  117         if ( _PCMD != PCMD_ADD_NODE )
  118           DpaApiReturnPeripheralError( ERROR_PCMD );
  119 
  120         // Check data length
  121         if ( _DpaDataLength != sizeof( dpaMessageUserPdata_AddNode ) )
  122           DpaApiReturnPeripheralError( ERROR_DATA_LEN );
  123 
  124         // Set service channel
  125         setRFchannel( SERVICE_CHANNEL );
  126 
  127         // Save requested Node address and MID of bonded Node
  128         uns8 reqAddr = dpaMessageUserPdata_AddNode.nodeAddress;
  129         uns8 tmpNodeMID[sizeof( dpaMessageUserPdata_AddNode.nodeMID )];
  130         copyMemoryBlock( dpaMessageUserPdata_AddNode.nodeMID, tmpNodeMID, sizeof( tmpNodeMID ) );
  131 
  132         // Set MID of bonded Node as the User Key for service packet encrypting
  133         clearBufferINFO();
  134         copyMemoryBlock( tmpNodeMID, bufferINFO, sizeof( tmpNodeMID ) );
  135         setUserKey();
  136 
  137         // Send peer2peer service packet announcing bonding interval
  138         // RF mode (STD/LP) depends on used HWP plugin.
  139         // Set RF to peer2peer mode
  140         setNonetMode();
  141         // Prepare packet to bufferRF
  142         copyMemoryBlock( tmpNodeMID, servicePacket.nodeMID, sizeof( tmpNodeMID ) );
  143         servicePacket.workingChannel = DpaApiReadConfigByte( CFGIND_CHANNEL_A );
  144         // Encrypt data (_DpaMessage.Response.PData is actually bufferRF)
  145         encryptBufferRF( ( sizeof( servicePacket ) + 15 ) / 16 );
  146         DLEN = ( sizeof( servicePacket ) + 15 ) & ~15;
  147         PIN = 0;
  148         pulseLEDR();
  149         RFTXpacket();
  150 
  151         DpaApiSetRfDefaults();
  152         setCoordinatorMode();
  153 
  154         // Try to bond
  155         if ( bondNewNode( reqAddr ) )
  156         {
  157           // Returns:
  158           // Assigned address to the new Node
  159           dpaMessageUserPdata_AddNode.nodeAddress = param2;
  160           // MID of bonded Node
  161           // Both the BondingNodeMID and dpaMessageUserPdata_AddNode share bufferRF!
  162           copyMemoryBlock( BondingNodeMID, tmpNodeMID, sizeof( BondingNodeMID ) );
  163           copyMemoryBlock( tmpNodeMID, dpaMessageUserPdata_AddNode.nodeMID, sizeof( dpaMessageUserPdata_AddNode.nodeMID ) );
  164           _DpaDataLength = sizeof( dpaMessageUserPdata_AddNode );
  165         }
  166         else
  167           DpaApiReturnPeripheralError( ERROR_FAIL );
  168 
  169         goto DpaHandleReturnTRUE;
  170       }
  171 
  172       break;
  173   }
  174 
  175 DpaHandleReturnFALSE:
  176   return FALSE;
  177 }
  178 //############################################################################################
  179 // 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) 
  180 #include "DPAcustomHandler.h"
  181 //############################################################################################