1 // ********************************************************************* 2 // Custom DPA Handler code example - Standard Sensors - Thermometer * 3 // ********************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: 0802_TrThermometer.c,v $ 7 // Version: $Revision: 1.17 $ 8 // Date: $Date: 2019/06/10 15:36:53 $ 9 // 10 // Revision history: 11 // 2018/10/25 Release for DPA 3.03 12 // 2017/11/16 Release for DPA 3.02 13 // 2017/08/14 Release for DPA 3.01 14 // 15 // ********************************************************************* 16 17 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 18 // IQRF Standards documentation https://www.iqrfalliance.org/techDocs/ 19 20 // This example implements 1 temperature sensor according to the IQRF Sensors standard 21 22 // Default IQRF include (modify the path according to your setup) 23 #include "IQRF.h" 24 25 // Uncomment to implement Custom DPA Handler for Coordinator 26 //#define COORDINATOR_CUSTOM_HANDLER 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 // IQRF standards header (modify the path according to your setup) 33 #include "IQRFstandard.h" 34 #include "IQRF_HWPID.h" 35 36 //############################################################################################ 37 38 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 39 //############################################################################################ 40 bit CustomDpaHandler() 41 //############################################################################################ 42 { 43 // This forces CC5X to wisely use MOVLB instructions (doc says: The 'default' bank is used by the compiler for loops and labels when the algorithm gives up finding the optimal choice) 44 #pragma updateBank default = UserBank_01 45 46 // Handler presence mark 47 clrwdt(); 48 49 // Sleeping parameters, valid when Time != 0 50 static TPerOSSleep_Request PerOSSleep_Request; 51 52 // Detect DPA event to handle 53 switch ( GetDpaEvent() ) 54 { 55 // ------------------------------------------------- 56 case DpaEvent_Interrupt: 57 // Do an extra quick background interrupt work 58 // ! 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. 59 // ! 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. 60 // ! 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. 61 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 62 // ! Make sure race condition does not occur when accessing those variables at other places. 63 // ! 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. 64 // ! Do not call any OS functions except setINDFx(). 65 // ! Do not use any OS variables especially for writing access. 66 // ! 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. 67 68 return Carry; 69 70 // ------------------------------------------------- 71 case DpaEvent_Idle: 72 // Do a quick background work when RF packet is not received 73 74 // Should go to sleep? 75 if ( PerOSSleep_Request.Time != 0 ) 76 { 77 // Copy sleep parameters to the DPA request 78 _DpaMessage.PerOSSleep_Request.Time = PerOSSleep_Request.Time; 79 _DpaMessage.PerOSSleep_Request.Control = PerOSSleep_Request.Control; 80 // Switch off sleeping time=flag 81 PerOSSleep_Request.Time = 0; 82 // Finalize OS Sleep DPA Request 83 _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request ); 84 _PNUM = PNUM_OS; 85 _PCMD = CMD_OS_SLEEP; 86 // Perform local DPA Request to go to sleep 87 DpaApiLocalRequest(); 88 } 89 break; 90 91 // ------------------------------------------------- 92 case DpaEvent_DpaRequest: 93 // Called to interpret DPA request for peripherals 94 // ------------------------------------------------- 95 // Peripheral enumeration 96 if ( IsDpaEnumPeripheralsRequest() ) 97 { 98 // We implement 1 standard peripheral 99 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 100 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS ); 101 _DpaMessage.EnumPeripheralsAnswer.HWPID = HWPID_IQRF_TECH__DEMO_TR_THERMOMETER; 102 _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0001; 103 104 DpaHandleReturnTRUE: 105 return TRUE; 106 } 107 // ------------------------------------------------- 108 // Get information about peripheral 109 else if ( IsDpaPeripheralInfoRequest() ) 110 { 111 if ( _PNUM == PNUM_STD_SENSORS ) 112 { 113 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_SENSORS; 114 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 115 // Set standard version 116 _DpaMessage.PeripheralInfoAnswer.Par1 = 13; 117 goto DpaHandleReturnTRUE; 118 } 119 120 break; 121 } 122 // ------------------------------------------------- 123 else 124 { 125 // Handle peripheral command 126 127 // Supported peripheral number? 128 if ( _PNUM == PNUM_STD_SENSORS ) 129 { 130 // Supported commands? 131 switch ( _PCMD ) 132 { 133 // Invalid command 134 default: 135 // Return error 136 DpaApiReturnPeripheralError( ERROR_PCMD ); 137 138 // Sensor enumeration 139 case PCMD_STD_ENUMERATE: 140 if ( _DpaDataLength != 0 ) 141 goto _ERROR_DATA_LEN; 142 143 _DpaDataLength |= 1; // = 1 (optimization as _DpaDataLength was 0 for sure) 144 goto _Enumerate; 145 146 // Supported commands. They are handled almost the same way 147 case PCMD_STD_SENSORS_READ_VALUES: 148 case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES: 149 { 150 // No sensor bitmap specified? W = _DpaDataLength. Note: W is used to avoid MOVLB at next if 151 W = _DpaDataLength; 152 if ( W == 0 ) // Note: must not modify W 153 { 154 // Bitmap is 32 bits long = 4 (Note: using here save MOVLB) 155 _DpaDataLength = W = 4; 156 // Simulate 1st sensor in the bitmap (states of the other unimplemented sensors do not care) 157 _DpaMessage.Request.PData[0].0 = 1; // Note: must not modify W 158 } 159 160 // Invalid bitmap (data) length (W = _DpaDataLength)? 161 if ( W != 4 ) 162 { 163 _ERROR_DATA_LEN: 164 // Return error 165 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 166 } 167 168 // Get ready return data length for temperature data only (Note: optimization, 2 = 4/2 is used to save) 169 _DpaDataLength /= 2; 170 171 // Is my only sensor selected? 172 if ( _DpaMessage.Request.PData[0].0 ) 173 { 174 // Error reading temperature? Note: param3 holds temperature value after calling getTemperature() 175 if ( getTemperature() == -128 ) 176 // Return standard error value 177 param3 = 0x8000; 178 179 // Return the sensor type too? 180 if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES ) 181 { 182 // 3 bytes (1 byte with type, 2 bytes with temperature value) will be returned 183 _DpaDataLength++; 184 _Enumerate: 185 // 1st byte is sensor type 186 _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_TEMPERATURE; 187 // 3rd byte is higher byte of temperature value 188 _DpaMessage.Response.PData[2] = param3.high8; 189 // 2nd byte is lower byte of temperature value 190 W = param3.low8; 191 } 192 else 193 { 194 // 2 bytes to return 195 // 1st byte is lower byte of temperature value 196 _DpaMessage.Response.PData[0] = param3.low8; 197 // 2nd byte is higher byte of temperature value 198 W = param3.high8; 199 } 200 201 // Store 2nd byte for both supported commands 202 _DpaMessage.Response.PData[1] = W; 203 // Handled! 204 goto DpaHandleReturnTRUE; 205 } 206 else 207 { 208 // My sensor not selected, so no data returned 209 _DpaDataLength = 0; 210 goto DpaHandleReturnTRUE; 211 } 212 } 213 } 214 } 215 216 break; 217 } 218 219 // ------------------------------------------------- 220 case DpaEvent_FrcValue: 221 // Called to get FRC value 222 223 // Check for correct FRC and FRC user data (signature byte and sensor index == 0) 224 switch ( _PCMD ) 225 { 226 case FRC_STD_SENSORS_1B: 227 case FRC_STD_SENSORS_2B: 228 // FSR1 for optimization purposes (avoid MOVLB) will be used to point to DataOutBeforeResponseFRC[0...] 229 FSR1 = &DataOutBeforeResponseFRC[0]; 230 231 if ( *FSR1++ /*DataOutBeforeResponseFRC[0]*/ == PNUM_STD_SENSORS && 232 ( *FSR1 /*DataOutBeforeResponseFRC[1]*/ == 0x00 || *FSR1 /*DataOutBeforeResponseFRC[1]*/ == STD_SENSOR_TYPE_TEMPERATURE ) && 233 ( *++FSR1 /*DataOutBeforeResponseFRC[2]*/ & 0x1f ) == 0 ) 234 { 235 // Return error code 236 responseFRCvalue2B = 2; 237 // Get temperature and adjust it for FRC 238 // Temperature OK? 239 if ( getTemperature() != -128 ) 240 { 241 // Return sensor FRC value 2B 242 responseFRCvalue2B = param3 ^ 0x8000; 243 244 // Return sensor FRC value 1B 245 // Check for out of limits 246 if ( (int16)param3 <= (int16)( 105.5 * 16 ) && (int16)param3 >= ( (int16)-20 * 16 ) ) 247 { 248 // CC5x reports "Sign problems, please typecast one operand to unsigned (uns16)" 249 // param3 = (int16)param3 / 8; 250 param3.high8 = asr( param3.high8 ); 251 param3.low8 = rr( param3.low8 ); 252 param3.high8 = asr( param3.high8 ); 253 param3.low8 = rr( param3.low8 ); 254 param3.high8 = asr( param3.high8 ); 255 param3.low8 = rr( param3.low8 ); 256 257 responseFRCvalue = (int8)param3.low8 + 44; 258 } 259 } 260 261 // The sensor was measured by FRC, check if there is a sleep request 262 FSR1++; 263 if ( INDF1.0 ) // Note: same as DataOutBeforeResponseFRC[3].0 264 { 265 // Remember sleep parameters to go to sleep at the Idle event later 266 PerOSSleep_Request.Time.low8 = FSR1[4 - 3]; // Note: same as DataOutBeforeResponseFRC[4] 267 PerOSSleep_Request.Time.high8 = FSR1[5 - 3]; // Note: same as DataOutBeforeResponseFRC[5] 268 PerOSSleep_Request.Control = FSR1[6 - 3]; // Note: same as DataOutBeforeResponseFRC[6] 269 } 270 } 271 break; 272 } 273 break; 274 275 // ------------------------------------------------- 276 case DpaEvent_FrcResponseTime: 277 // Called to get FRC response time 278 279 // In this example the FRC command is a fast one 280 switch ( DataOutBeforeResponseFRC[0] ) 281 { 282 case FRC_STD_SENSORS_1B: 283 case FRC_STD_SENSORS_2B: 284 responseFRCvalue = _FRC_RESPONSE_TIME_40_MS; 285 break; 286 } 287 break; 288 } 289 290 DpaHandleReturnFALSE: 291 return FALSE; 292 } 293 294 //############################################################################################ 295 // 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) 296 #include "DPAcustomHandler.h" 297 //############################################################################################