1 // ************************************************************************************* 2 // Custom DPA Handler code example - Standard Binary output - DDC-RE-01 - LP version * 3 // ************************************************************************************* 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: 4802_DDC-RE_LP.c,v $ 7 // Version: $Revision: 1.4 $ 8 // Date: $Date: 2019/03/07 08:44:34 $ 9 // 10 // Revision history: 11 // 2019/03/07 Release for DPA 4.01 12 // 13 // ********************************************************************* 14 15 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 16 // IQRF Standards documentation https://www.iqrfalliance.org/techDocs/ 17 18 // This example also implements 2 binary outputs according to the IQRF Binary Outputs standard 19 // Index 0 i.e. 1st output is Relay #1 @ DDC-RE-01 20 // Index 1 i.e. 2nd output is Relay #2 @ DDC-RE-01 21 22 // This example must be compiled without a "-bu" compiler switch in order to fit into available Flash memory 23 24 // Default IQRF include (modify the path according to your setup) 25 #include "IQRF.h" 26 27 // We can save more instructions if needed by the symbol below 28 // #define PARAM_CHECK_LEVEL 1 29 30 // Default DPA header (modify the path according to your setup) 31 #include "DPA.h" 32 // Default Custom DPA Handler header (modify the path according to your setup) 33 #include "DPAcustomHandler.h" 34 // IQRF standards header (modify the path according to your setup) 35 #include "IQRFstandard.h" 36 #include "IQRF_HWPID.h" 37 38 //############################################################################################ 39 40 // Define useful macro that saves some code but not preset at DPA < 3.01 41 #if DPA_VERSION_MASTER < 0x0301 42 // Optimized macro for both testing enumeration peripherals ELSE peripherals information. See examples 43 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequestNoSize() if ( _PCMD == CMD_GET_PER_INFO ) if ( _PNUM == PNUM_ENUMERATION ) 44 45 #if PARAM_CHECK_LEVEL >= 2 46 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() if ( _DpaDataLength == 0 && _PCMD == CMD_GET_PER_INFO ) if ( _PNUM == PNUM_ENUMERATION ) 47 #else 48 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequestNoSize() 49 #endif 50 #endif 51 52 //############################################################################################ 53 54 // ms per ticks 55 #define TICKS_LEN 10 56 57 // Number of implemented binary outputs 58 #define OUTPUTS_COUNT 2 59 60 // Sets and Gets state of the indexed binary output 61 void SetOutput( uns8 state, uns8 index ); 62 bit GetOutput( uns8 index ); 63 64 // DDC-RE-01 relay pins 65 // C.5 = C8 = Relay#1 66 #define RELAY1_LAT LATC.5 67 #define RELAY1_TRIS TRISC.5 68 // C.2 = C2 = Relay#2 69 #define RELAY2_LAT LATC.2 70 #define RELAY2_TRIS TRISC.2 71 72 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 73 //############################################################################################ 74 bit CustomDpaHandler() 75 //############################################################################################ 76 { 77 // 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) 78 #pragma updateBank default = UserBank_01 79 80 // Handler presence mark 81 clrwdt(); 82 83 // Timers for outputs. The space must be long enough to fit them all. 2+2 bytes per one binary output. 84 // 2B timeout 85 // 2B startTicks 86 static uns16 Timers[OUTPUTS_COUNT * 2]; 87 88 // Detect DPA event to handle 89 switch ( GetDpaEvent() ) 90 { 91 // ------------------------------------------------- 92 case DpaEvent_Interrupt: 93 // Do an extra quick background interrupt work 94 95 return Carry; 96 97 // ------------------------------------------------- 98 case DpaEvent_Idle: 99 // Do a quick background work when RF packet is not received 100 101 // Check binary output timers 102 { 103 // Pointer to the timers array 104 FSR1 = (uns16)&Timers[0]; 105 // Output index 106 uns8 index; 107 index = 0; 108 do 109 { 110 // Is timer running (is non-zero)? 111 if ( ( FSR1[1] | INDF1 ) != 0 ) 112 { 113 // Get timer value 114 uns16 timer; 115 timer.low8 = FSR1[0]; 116 timer.high8 = FSR1[1]; 117 // Get start time 118 uns16 timerStart; 119 timerStart.low8 = FSR1[2]; 120 timerStart.high8 = FSR1[3]; 121 // Measure elapsed time 122 captureTicks(); // Note: must not modify FSR1 123 param3 -= timerStart; 124 // It time over? 125 if ( param3 > timer ) 126 { 127 // Set output to OFF 128 SetOutput( 0, index ); 129 // Reset timer 130 setINDF1( 0 ); 131 FSR1++; 132 setINDF1( 0 ); 133 FSR1--; 134 } 135 } 136 // Next timer 137 FSR1 += 2 * sizeof( Timers[0] ); 138 // Next index 139 } while ( ++index < OUTPUTS_COUNT ); 140 } 141 break; 142 143 // ------------------------------------------------- 144 case DpaEvent_Init: 145 // Do a one time initialization work before main loop starts 146 147 // Initialize ticks 148 startCapture(); 149 150 // Initialize relays @ DDC-RE 151 RELAY1_LAT = 0; 152 RELAY2_LAT = 0; 153 RELAY1_TRIS = 0; 154 RELAY2_TRIS = 0; 155 156 break; 157 158 // ------------------------------------------------- 159 case DpaEvent_DpaRequest: 160 // Called to interpret DPA request for peripherals 161 // ------------------------------------------------- 162 // Peripheral enumeration 163 IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() 164 { 165 // We implement 2 standard peripherals 166 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 167 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_BINARY_OUTPUTS ); 168 _DpaMessage.EnumPeripheralsAnswer.HWPID = HWPID_IQRF_TECH__DEMO_DDC_RE01_LP; 169 _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0x0000; 170 171 DpaHandleReturnTRUE: 172 return TRUE; 173 } 174 // ------------------------------------------------- 175 // Get information about peripherals 176 else 177 { 178 switch ( _DpaMessage.PeripheralInfoAnswer.PerT = _PNUM ) 179 { 180 case PNUM_STD_BINARY_OUTPUTS: 181 // Set standard version 182 _DpaMessage.PeripheralInfoAnswer.Par1 = 4; 183 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 184 goto DpaHandleReturnTRUE; 185 } 186 187 break; 188 } 189 190 { 191 // ------------------------------------------------- 192 // Handle peripheral command 193 194 // Supported peripheral number? 195 switch ( _PNUM ) 196 { 197 case PNUM_STD_BINARY_OUTPUTS: 198 { 199 // Supported commands? 200 switch ( _PCMD ) 201 { 202 // Invalid command 203 default: 204 // Return error 205 _ERROR_PCMD: 206 W = ERROR_PCMD; 207 goto _ERROR_W; 208 209 // Outputs enumeration 210 case PCMD_STD_ENUMERATE: 211 if ( _DpaDataLength != 0 ) 212 goto _ERROR_DATA_LEN; 213 214 // Return number of outputs 215 _DpaMessageIqrfStd.PerStdBinaryOutputEnumerate_Response.Count = OUTPUTS_COUNT; 216 W = sizeof( _DpaMessageIqrfStd.PerStdBinaryOutputEnumerate_Response ); 217 _W2_DpaDataLength: 218 _DpaDataLength = W; 219 goto DpaHandleReturnTRUE; 220 221 // Supported commands. 222 case PCMD_STD_BINARY_OUTPUTS_SET: 223 { 224 // Pointers FSR01 to data are already set at the DPA 225 226 // As this template implements < 9 outputs the working bitmap is uns8, if more outputs are implemented then uns16, ..., uns32 must be used 227 #if OUTPUTS_COUNT < 9 228 uns8 inBitmap = *FSR0--; 229 uns8 outBitmap @ _DpaMessageIqrfStd.PerStdBinaryOutputSet_Request.Bitmap[0]; 230 uns8 bitmapMask = 0b1; 231 #else 232 #error Not implemented 233 #endif 234 235 // Number of selected outputs + bitmap length 236 uns8 outputsCount = sizeof( _DpaMessageIqrfStd.PerStdBinaryOutputSet_Request.Bitmap ); 237 // Loop bitmap 238 uns8 index = sizeof( _DpaMessageIqrfStd.PerStdBinaryOutputSet_Request.Bitmap ); 239 do 240 { 241 // Count bits of next byte 242 uns8 byte = *++FSR0; 243 if ( byte != 0 ) 244 { 245 // Brian Kernighan's Algorithm for counting set bits 246 do 247 { 248 outputsCount++; 249 byte &= byte - 1; 250 } while ( byte != 0 ); 251 } 252 253 // Reset bitmap 254 setINDF0( 0 ); 255 } while ( --index != 0 ); 256 257 // Check data length 258 if ( _DpaDataLength != outputsCount ) 259 { 260 _ERROR_DATA_LEN: 261 W = ERROR_DATA_LEN; 262 _ERROR_W: 263 DpaApiReturnPeripheralError( W ); 264 } 265 266 // Pointer to the timers array 267 FSR1 = (uns16)&Timers[0]; 268 // Output index 269 index = 0; 270 do 271 { 272 // Output was set? 273 if ( GetOutput( index ) ) 274 // Yes, set in the output bitmap 275 outBitmap |= bitmapMask; 276 277 // Implemented output selected? Set the state. 278 if ( inBitmap.0 ) 279 { 280 // Default is timer off 281 uns16 time = 0; 282 // Desired state 283 uns8 state = *++FSR0; 284 if ( state > 1 ) 285 { 286 // Get time in units s/min 287 time = state & 0x7F; 288 if ( time == 0 ) 289 { 290 // Invalid time 291 W = ERROR_FAIL; 292 _ERROR_FAIL: 293 goto _ERROR_W; 294 } 295 296 // Conversion coefficient, ready for seconds 297 uns16 coef = 1000 / TICKS_LEN; 298 if ( !state.7 ) 299 { 300 // Check for the maximum supported time because of captureTicks method 301 if ( time.low8 > ( (uns24)0xFFFF * TICKS_LEN / 1000 / 60 ) ) 302 goto _ERROR_FAIL; 303 304 // Convert from minutes 305 uns16 coef = 60 * ( 1000 / TICKS_LEN ); 306 } 307 308 // Convert to 250 ms 309 time *= coef; 310 // Set ON 311 state = 1; 312 } 313 314 // Set output 315 SetOutput( state, index ); 316 317 // Set timer but preserve pointer 318 setINDF1( time.low8 ); 319 FSR1++; 320 setINDF1( time.high8 ); 321 FSR1++; 322 // Get start time 323 captureTicks(); //Note: must not destroy FSR1 324 setINDF1( param3.low8 ); 325 FSR1++; 326 setINDF1( param3.high8 ); 327 FSR1 -= 3; 328 } 329 330 // Pointer to the next timer 331 FSR1 += 2 * sizeof( Timers[0] ); 332 // Next bits 333 bitmapMask <<= 1; 334 inBitmap >>= 1; 335 // Next index 336 } while ( ++index < OUTPUTS_COUNT ); 337 338 // Return bitmap 339 _DpaDataLength4: 340 W = sizeof( _DpaMessageIqrfStd.PerStdBinaryOutputSet_Response.PreviousStates ); 341 goto _W2_DpaDataLength; 342 } 343 } 344 } 345 } 346 347 break; 348 } 349 } 350 DpaHandleReturnFALSE: 351 return FALSE; 352 } 353 354 //############################################################################################ 355 void SetOutput( uns8 state, uns8 index @ W ) 356 //############################################################################################ 357 { 358 // Note: FSRs must not be modified 359 // Note: This method is called in the interrupt too! 360 361 skip( index ); 362 #pragma computedGoto 1 363 goto set0; 364 goto set1; 365 #pragma computedGoto 0 366 ; 367 // -------------------------------------- 368 set1: 369 if ( !state.0 ) 370 RELAY2_LAT = 0; 371 else 372 RELAY2_LAT = 1; 373 374 return; 375 // -------------------------------------- 376 set0: 377 if ( !state.0 ) 378 RELAY1_LAT = 0; 379 else 380 RELAY1_LAT = 1; 381 382 return; 383 // -------------------------------------- 384 } 385 386 //############################################################################################ 387 bit GetOutput( uns8 index @ W ) 388 //############################################################################################ 389 { 390 Carry = FALSE; // Note: must not modify W 391 392 // Note: all below must not modify Carry except when needed 393 skip( index ); 394 #pragma computedGoto 1 395 goto get0; 396 goto get1; 397 #pragma computedGoto 0 398 ; 399 // -------------------------------------- 400 get1: 401 if ( RELAY2_LAT ) 402 Carry = TRUE; 403 goto _return; 404 // -------------------------------------- 405 get0: 406 if ( RELAY1_LAT ) 407 Carry = TRUE; 408 goto _return; 409 // -------------------------------------- 410 411 _return: 412 return Carry; 413 } 414 415 //############################################################################################ 416 // 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) 417 #include "DPAcustomHandler.h" 418 //############################################################################################