1 // ************************************************************************************************ 2 // Custom DPA Handler code example - Shows custom (un)bonding and factory settings using button * 3 // ************************************************************************************************ 4 // Copyright (c) MICRORISC s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-Bonding.c,v $ 7 // Version: $Revision: 1.45 $ 8 // Date: $Date: 2021/08/18 20:43:06 $ 9 // 10 // Revision history: 11 // 2021/08/18 Release for DPA 4.16 12 // 2019/12/11 Release for DPA 4.11 13 // 2019/10/09 Release for DPA 4.10 14 // 2019/06/03 Release for DPA 4.02 15 // 2019/01/10 Release for DPA 4.00 16 // 2018/10/25 Release for DPA 3.03 17 // 2017/08/14 Release for DPA 3.01 18 // 2017/03/13 Release for DPA 3.00 19 // 2015/08/05 Release for DPA 2.20 20 // 21 // ********************************************************************* 22 23 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 24 25 // Default IQRF include (modify the path according to your setup) 26 #include "IQRF.h" 27 28 // Default DPA header (modify the path according to your setup) 29 #include "DPA.h" 30 // Default Custom DPA Handler header (modify the path according to your setup) 31 #include "DPAcustomHandler.h" 32 33 // This code illustrates bonding using a button connected to the custom pin. 34 // Except going to sleep the code behaves the same way as the standard bonding procedure. 35 // Please see https://www.iqrf.org/DpaTechGuide/index.html?page=device-startup.html and the following chapters. 36 // ! Please note, that the overlapping networks support by SmartConnect DPA command https://doc.iqrf.org/DpaTechGuide/pages/smart-connect.html will not work with this example 37 38 // Define to just reassign a bonding button with the button behavior implemented inside DPA 39 // #define USE_DpaEvent_BondingButton 40 41 // Custom bonding button. Change to the pin and an active level of your choice. 42 //#define IsButton ( !PORTA.5 ) 43 #define IsButton buttonPressed 44 45 // Returns TRUE when button is released shortly after LEDG goes out 46 bit ButtonAfterGreen(); 47 // Same as above but with leading gap 48 bit ButtonAfterGreenWithGap(); 49 // RedLED on for 1s 50 void LEDR1s(); 51 52 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 53 //############################################################################################ 54 bit CustomDpaHandler() 55 //############################################################################################ 56 { 57 // Handler presence mark 58 clrwdt(); 59 60 // Detect DPA event to handle 61 switch ( GetDpaEvent() ) 62 { 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 return Carry; 76 77 #ifdef USE_DpaEvent_BondingButton 78 // ------------------------------------------------- 79 case DpaEvent_BondingButton: 80 // Called to allow a bonding button customization 81 82 userReg1.0 = 0; 83 if ( IsButton ) 84 userReg1.0 = 1; 85 86 return TRUE; 87 #else 88 // ------------------------------------------------- 89 case DpaEvent_Reset: 90 // Called after module is reset 91 92 // Handle (un)bonding 93 if ( !amIBonded() ) 94 { 95 // ------------------------------------------------- 96 // Not bonded 97 98 // Very 1st bonding attempt and well released button after 2.5 s gap and LEDG? 99 if ( ButtonAfterGreenWithGap() ) 100 // Factory settings! 101 goto _factoryAndRemoveBond; 102 103 // If and while node is not bonded 104 for ( ;; ) 105 { 106 // If button is not pressed, be ready to be SmartConnected 107 while ( !IsButton ) 108 { 109 // Do and wait for an indication 110 pulseLEDR(); 111 waitMS( 6 ); 112 // Make sure to use LP mode 113 setRFmode( _WPE | _RX_LP | _TX_LP ); 114 115 // Set sometimes a new service channel for SmartConnect, otherwise the last one 116 static uns8 lastServiceChannel; 117 static uns8 channelCnt; 118 // Time to set a new service channel? 119 if ( ( channelCnt & 0x03 ) == 0 ) 120 // Set a new service channel 121 lastServiceChannel = 0; 122 // Next "timer" 123 channelCnt++; 124 125 // Set the SmartConnect service channel 126 setServiceChannel( lastServiceChannel ); 127 // Save last service channel used 128 lastServiceChannel = param2 + 1; 129 130 // Try SmartConnect 131 _checkRFcfg_PQT = TRUE; 132 toutRF = 6; 133 // Use more strict RF RX filter for SmartConnect only 134 checkRF( RxFilter + 4 ); 135 RFRXpacket(); 136 // Restore original RF RX filter 137 checkRF( RxFilter ); 138 // Process SmartConnect packet, if received 139 answerSystemPacket(); 140 // Restore RF settings (and make sure Spirit1 is not locked) 141 wasRFICrestarted(); 142 DpaApiSetRfDefaults(); 143 // SmartConnect success? 144 if ( amIBonded() ) 145 goto _NodeWasBonded; 146 } 147 148 // Bonding by button indication 149 pulseLEDR(); 150 // Traditional bonding using 3 service channels 151 _3CHTX = TRUE; 152 // Bonded? 153 if ( bondRequestAdvanced() ) 154 { 155 _NodeWasBonded: 156 // Indicate bonding for 0.5 s 157 setLEDG(); 158 waitDelay( 50 ); 159 stopLEDG(); 160 // Exit the loop 161 break; 162 } 163 } 164 } 165 else 166 { 167 // ------------------------------------------------- 168 // Bonded 169 170 // If the button is pressed for 2s (Green LED is on during this time) and then released within 0.5s, then un-bond the node (indicated by 1s Red LED) 171 if ( ButtonAfterGreen() ) 172 { 173 // Red LED for 1s 174 LEDR1s(); 175 // Remove bond + implicit restart 176 _DpaDataLength = 0; 177 _PNUM = PNUM_NODE; 178 _PCMD = CMD_NODE_REMOVE_BOND; 179 // Perform local DPA Request 180 DpaApiLocalRequest(); 181 // Unreachable code because of restart 182 } 183 184 // Now wait if the button is still pressed for about 2.5 s and if again released after green LED do factory settings and remove bond 185 if ( ButtonAfterGreenWithGap() ) 186 { 187 _factoryAndRemoveBond: 188 // Red LED for 1s 189 LEDR1s(); 190 // Factory settings + remove bond + implicit restart 191 _DpaDataLength = 0; 192 _PNUM = PNUM_OS; 193 _PCMD = CMD_OS_FACTORY_SETTINGS; 194 // Perform local DPA Request 195 DpaApiLocalRequest(); 196 // Unreachable code because of restart 197 } 198 } 199 200 return TRUE; 201 #endif 202 } 203 204 return FALSE; 205 } 206 207 //############################################################################################ 208 void LEDR1s() 209 //############################################################################################ 210 { 211 setLEDR(); 212 waitDelay( 100 ); 213 stopLEDR(); 214 } 215 216 //############################################################################################ 217 bit ButtonAfterGreen() 218 //############################################################################################ 219 { 220 // Returns TRUE when button is released shortly after LEDG goes out 221 222 // Time for Green LED on 223 startDelay( 200 ); 224 // Green LED on 225 setLEDG(); 226 do 227 { 228 // If button not pressed 229 if ( !IsButton ) 230 { 231 // Switch off Green LED 232 stopLEDG(); 233 // And return FALSE 234 return FALSE; 235 } 236 // Is button still pressed while Green LED is on? 237 } while ( isDelay() ); 238 239 // Switch off Green LED 240 stopLEDG(); 241 // Set testing delay 242 startDelay( 50 ); 243 do 244 { 245 // If the button is released within the delay 246 if ( !IsButton ) 247 // Return TRUE 248 return TRUE; 249 } while ( isDelay() ); 250 // Otherwise return FALSE 251 return FALSE; 252 } 253 254 //############################################################################################ 255 bit ButtonAfterGreenWithGap() 256 //############################################################################################ 257 { 258 // Is button pressed for 2.55s ? 259 startDelay( 255 ); 260 while ( IsButton && isDelay() ); 261 // If not the next call will return FALSE, otherwise will test for button release after Green LED goes off 262 return ButtonAfterGreen(); 263 } 264 265 //############################################################################################ 266 // 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) 267 #include "DPAcustomHandler.h" 268 //############################################################################################