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