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