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 )