1 // ********************************************************************* 2 // Custom DPA Handler - Beaming example * 3 // ********************************************************************* 4 // Copyright (c) MICRORISC s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-SensorBeaming.c,v $ 7 // Version: $Revision: 1.27 $ 8 // Date: $Date: 2026/02/11 13:54:37 $ 9 // 10 // Revision history: 11 // 2023/03/07 Release for DPA 4.30 12 // 2022/02/24 Release for DPA 4.17 13 // 2020/09/03 Release for DPA 4.15 14 // 15 // ********************************************************************* 16 17 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 18 19 /* 20 * This is public example of the beaming sensor code. 21 * The actual beamed quantities' values are fake. Please see the code below. 22 * TR7xD: After the button is pressed for a longer time the LEDR pulses and data are beamed. 23 * TR7xG: After selecting 1st DPA menu item Beaming the data are once beamed. 24 */ 25 26 // Default IQRF include (modify the path according to your setup) 27 #include "IQRF.h" 28 29 // Default DPA header (modify the path according to your setup) 30 #include "DPA.h" 31 // Default Custom DPA Handler header (modify the path according to your setup) 32 #include "DPAcustomHandler.h" 33 // IQRF standards header (modify the path according to your setup) 34 #include "standard/IQRFstandard.h" 35 #include "standard/IQRF_HWPID.h" 36 37 // This HWPID 38 #define _HWPID_ 0x123F 39 40 // Define to return sensors in error 41 //#define SENSOR_ERRORS 42 43 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 44 //############################################################################################ 45 bit CustomDpaHandler() 46 //############################################################################################ 47 { 48 #pragma updateBank default = UserBank_01 49 50 #ifdef DpaEvent_MenuActivated 51 static beamOnceAtIdle; 52 #endif 53 54 // Handler presence mark 55 clrwdt(); 56 57 // Detect DPA event to handle (unused event handlers can be commented out or even deleted) 58 switch ( GetDpaEvent() ) 59 { 60 // ------------------------------------------------- 61 case DpaEvent_Interrupt: 62 // Do an extra quick background interrupt work 63 return Carry; 64 65 // ------------------------------------------------- 66 case DpaEvent_Idle: 67 // Do a quick background work when RF packet is not received 68 { 69 #ifndef DpaEvent_MenuActivated 70 if ( amIBonded() ) 71 { 72 // To detect long button press 73 static uns8 buttonCnt; 74 75 if ( !buttonPressed ) 76 buttonCnt = 0; 77 else 78 { 79 // Note: when run at LP mode, than the press time must be adjusted for shorter counts that even depends on LPtoutRF value 80 if ( ++buttonCnt == 0 ) 81 #else 82 if ( beamOnceAtIdle ) 83 { 84 beamOnceAtIdle = FALSE; 85 #endif 86 { // Beam once 87 // Indicate button was pressed for the longer time and then wait for its release 88 setLEDR(); 89 do 90 { 91 clrwdt(); 92 } while ( buttonPressed ); 93 stopLEDR(); 94 95 // Set STD RF mode 96 uns8 rfmode = RFmodeByte; 97 setRFmode( _TX_STD ); 98 99 // Prepare off-line sensor packet 100 101 // No DPA Params used 102 _DpaParams = 0; 103 104 // Beaming is broadcast (could be unicast too) 105 _NADR = BROADCAST_ADDRESS; 106 _NADRhigh = 0; 107 108 // Prepare sensor packet type and quantity data 109 110 _PNUM = PNUM_STD_SENSORS; 111 _PCMD = PCMD_STD_SENSORS_READ_TYPES_AND_FRC_VALUES | RESPONSE_FLAG; 112 // HW profile ID 113 _HWPID = _HWPID_; 114 115 { // 1st sensor/quantity 116 // Fake "living" temperature value = NodeAddress + [0-15]/16; 117 _DpaMessage.Request.PData[0] = STD_SENSOR_TYPE_TEMPERATURE; 118 shadowDef uns16 temperature @ ( &_DpaMessage.Request.PData[1] ); 119 #ifndef SENSOR_ERRORS 120 temperature = (uns16)ntwADDR * 16; 121 temperature |= ( Random.low8 & ( 16 - 1 ) ); 122 temperature |= 0x8000; 123 #else 124 temperature = FRC_STD_FRC_ERROR_VALUE; 125 #endif 126 // Length of the data inside DPA Request message 127 _DpaDataLength = sizeof( uns8 ) + STD_SENSOR_TYPE_SIZE( STD_SENSOR_TYPE_TEMPERATURE ); 128 } 129 130 { // Optional 2nd sensor/quantity 131 // Fake "living" humidity value = NodeAddress + [0-1]/2; 132 _DpaMessage.Request.PData[3] = STD_SENSOR_TYPE_HUMIDITY; 133 #ifndef SENSOR_ERRORS 134 _DpaMessage.Request.PData[4] = 4 + ( ntwADDR & 0x3F ) * 2; 135 _DpaMessage.Request.PData[4] |= Random.high8 & 0x01; 136 #else 137 _DpaMessage.Request.PData[4] = FRC_STD_FRC_ERROR_VALUE; 138 #endif 139 // Length of the data inside DPA Request message 140 _DpaDataLength += sizeof( uns8 ) + STD_SENSOR_TYPE_SIZE( STD_SENSOR_TYPE_HUMIDITY ); 141 } 142 143 { // Optional 3rd sensor/quantity 144 // Fake CO2 value 145 _DpaMessage.Request.PData[5] = STD_SENSOR_TYPE_CO2; 146 shadowDef uns16 co2 @ ( &_DpaMessage.Request.PData[6] ); 147 #ifndef SENSOR_ERRORS 148 co2 = 2345 + 4; 149 #else 150 co2 = FRC_STD_FRC_ERROR_VALUE; 151 #endif 152 // Length of the data inside DPA Request message 153 _DpaDataLength += sizeof( uns8 ) + STD_SENSOR_TYPE_SIZE( STD_SENSOR_TYPE_CO2 ); 154 } 155 156 { // Optional 4th sensor/quantity 157 // Fake Binary30 158 _DpaMessage.Request.PData[8] = STD_SENSOR_TYPE_BINARYDATA30; 159 shadowDef uns32 bin30 @ ( &_DpaMessage.Request.PData[9] ); 160 #ifndef SENSOR_ERRORS 161 #if !defined( __CC5XFREE__ ) // CC5X free edition does not support 32bit assignment 162 bin30 = 0x3456789A + 4; 163 #else 164 bin30.low16 = ( 0x3456789A + 4 ) & 0xFfFf; 165 bin30.high16 = ( 0x3456789A + 4 ) >> 16; 166 #endif 167 #else 168 #if !defined( __CC5XFREE__ ) // CC5X free edition does not support 32bit assignment 169 bin30 = FRC_STD_FRC_ERROR_VALUE; 170 #else 171 bin30.low16 = FRC_STD_FRC_ERROR_VALUE; 172 bin30.high16 = 0; 173 #endif 174 #endif 175 // Length of the data inside DPA Request message 176 _DpaDataLength += sizeof( uns8 ) + STD_SENSOR_TYPE_SIZE( STD_SENSOR_TYPE_BINARYDATA30 ); 177 } 178 179 { // Optional 5th sensor/quantity 180 // Fake Binary7 181 _DpaMessage.Request.PData[13] = STD_SENSOR_TYPE_BINARYDATA7; 182 #ifndef SENSOR_ERRORS 183 _DpaMessage.Request.PData[14] = ( ntwADDR & 0x7F ) + 4; 184 #else 185 _DpaMessage.Request.PData[14] = FRC_STD_FRC_ERROR_VALUE; 186 #endif 187 // Length of the data inside DPA Request message 188 _DpaDataLength += sizeof( uns8 ) + STD_SENSOR_TYPE_SIZE( STD_SENSOR_TYPE_BINARYDATA7 ); 189 } 190 191 // Do simplified LBT 192 uns8 loop = 3; 193 do 194 { 195 if ( !checkRF( RxFilter + 10 ) ) 196 break; 197 198 // Do some wait (better to do a random time sleep) 199 waitMS( 5 ); 200 } while ( --loop != 0 ); 201 202 // Force not routed packet to be sent from N by DPA API 203 NonroutedRfTxDpaPacket = TRUE; 204 205 // TX DPA message with zero DPA Value and asynchronous 206 // Note: Use DpaValue = 0x01 to indicate asynchronous i.e. non-regular beaming 207 DpaApiRfTxDpaPacket( 0 /*DpaValue*/, 0 ); 208 // Beaming indication 209 pulseLEDG(); 210 // Restore RF mode 211 setRFmode( rfmode ); 212 } 213 } 214 #ifndef DpaEvent_MenuActivated 215 } 216 #endif 217 break; 218 } 219 220 // ------------------------------------------------- 221 case DpaEvent_FrcValue: 222 // Called to get FRC value 223 // https://doc.iqrf.org/DpaTechGuide/pages/frcvalue.html 224 225 // Do not respond directly to the sensor FRCs 226 if ( DataOutBeforeResponseFRC[0] == PNUM_STD_SENSORS ) 227 { 228 // Test for un-supported FRC commands 229 switch ( _PCMD ) 230 { 231 case FRC_STD_SENSORS_BIT: 232 case FRC_STD_SENSORS_1B: 233 case FRC_STD_SENSORS_2B: 234 case FRC_STD_SENSORS_4B: 235 236 // Let's wait longer than FRC response time to cause responseFRC timeout to return nothing at all 237 do { 238 clrwdt(); 239 } while ( isDelay() ); 240 241 break; 242 } 243 } 244 break; 245 246 // ------------------------------------------------- 247 #ifdef DpaEvent_MenuActivated 248 case DpaEvent_MenuActivated: 249 // Called to customize DPA menu 250 // https://doc.iqrf.org/DpaTechGuide/pages/menuactivated.html 251 252 switch ( userReg1 ) 253 { 254 case DMENU_Online: 255 userReg1 = DMENU_Item_Implemented_Beaming; 256 goto DpaHandleReturnTRUE; // return TRUE to allow customizing menu specified by userReg1 257 } 258 break; 259 #endif 260 261 // ------------------------------------------------- 262 #ifdef DpaEvent_MenuItemSelected 263 case DpaEvent_MenuItemSelected: 264 // Called to indicate "OK" or "Error" for selected menu item 265 // https://doc.iqrf.org/DpaTechGuide/pages/menuitemselected.html 266 267 switch ( userReg1 ) 268 { 269 case MakeDMenuAndItem( DMENU_Online, DMENU_Item_Beaming ): 270 if ( amIBonded() ) 271 { 272 beamOnceAtIdle = TRUE; 273 goto DpaHandleReturnTRUE; // return TRUE to indicate "OK" for menu item specified by userReg1, otherwise to indicate Error 274 } 275 break; 276 } 277 break; 278 #endif 279 280 // ------------------------------------------------- 281 case DpaEvent_DpaRequest: 282 // Called to interpret DPA request for peripherals 283 if ( IsDpaEnumPeripheralsRequest() ) 284 { 285 // ------------------------------------------------- 286 // Peripheral enumeration 287 _DpaMessage.EnumPeripheralsAnswer.HWPID |= _HWPID_; 288 _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0; 289 290 DpaHandleReturnTRUE: 291 return TRUE; 292 } 293 294 break; 295 } 296 297 DpaHandleReturnFALSE: 298 return FALSE; 299 } 300 301 //############################################################################################ 302 // Default Custom DPA Handler header; 2nd include implementing a Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup) 303 #include "DPAcustomHandler.h" 304 //############################################################################################