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