1 // **************************************************************************** 2 // Custom DPA Handler code example - Standard Binary Outputs - Template * 3 // **************************************************************************** 4 // Copyright (c) IQRF Tech s.r.o. 5 // 6 // File: $RCSfile: 0C02_BinaryOutput-Template.c,v $ 7 // Version: $Revision: 1.15 $ 8 // Date: $Date: 2019/04/03 09:27:58 $ 9 // 10 // Revision history: 11 // 2017/11/16 Release for DPA 3.02 12 // 2017/08/14 Release for DPA 3.01 13 // 14 // ********************************************************************* 15 16 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/ 17 // IQRF Standards documentation https://www.iqrfalliance.org/techDocs/ 18 19 // This example implements 4 binary outputs according to the IQRF Binary Outputs standard 20 // Index 0: Red LED 21 // Index 1: Green LED 22 // Index 2: Relay #1 @ DDC-RE-01 23 // Index 3: Relay #2 @ DDC-RE-01 24 25 // Default IQRF include (modify the path according to your setup) 26 #include "IQRF.h" 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 #if DPA_VERSION_MASTER < 0x0301 37 #error DPA version 3.01++ is required 38 #endif 39 40 //############################################################################################ 41 42 // Number of implemented binary outputs 43 #define OUTPUTS_COUNT 4 44 45 // Sets and Gets state of the indexed binary output 46 void SetOutput( uns8 state, uns8 index ); 47 bit GetOutput( uns8 index ); 48 49 // DDC-RE-01 relay pins 50 // C.5 = C8 = Relay#1 51 #define RELAY1_LAT LATC.5 52 #define RELAY1_TRIS TRISC.5 53 // C.2 = C2 = Relay#2 54 #define RELAY2_LAT LATC.2 55 #define RELAY2_TRIS TRISC.2 56 57 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 58 //############################################################################################ 59 bit CustomDpaHandler() 60 //############################################################################################ 61 { 62 // 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) 63 #pragma updateBank default = UserBank_01 64 65 // Timers for outputs. The space must be long enough to fit them all. 2 bytes per one binary output. 66 static uns16 Timers[OUTPUTS_COUNT]; 67 68 // Handler presence mark 69 clrwdt(); 70 71 // Detect DPA event to handle 72 switch ( GetDpaEvent() ) 73 { 74 // ------------------------------------------------- 75 case DpaEvent_Interrupt: 76 // Do an extra quick background interrupt work 77 // ! 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. 78 // ! 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. 79 // ! 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. 80 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 81 // ! Make sure race condition does not occur when accessing those variables at other places. 82 // ! 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. 83 // ! Do not call any OS functions except setINDFx(). 84 // ! Do not use any OS variables especially for writing access. 85 // ! 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. 86 87 // If TMR6 interrupt occurred, every 10 ms 88 if ( TMR6IF ) 89 { 90 // Unmask interrupt 91 TMR6IF = 0; 92 93 // Count 250 ms from 10 ms micro ticks 94 static uns8 count250ms; 95 if ( ++count250ms == ( 250 / 10 ) ) 96 { 97 // 250 ms 98 count250ms = 0; 99 100 // Pointer to the timers array 101 FSR1 = (uns16)&Timers[0]; 102 // Output index 103 static uns8 index; 104 index = 0; 105 do 106 { 107 // Is timer running (is non-zero)? 108 if ( ( FSR1[1] | INDF1 ) != 0 ) 109 { 110 // Get time 111 static uns16 time; 112 time.low8 = *FSR1++; 113 time.high8 = *FSR1; 114 // Is timer over? 115 if ( --time == 0 ) 116 // Set output to OFF 117 SetOutput( 0, index ); 118 119 // Store new time 120 setINDF1( time.high8 ); 121 FSR1--; 122 setINDF1( time.low8 ); 123 } 124 // Next timer 125 FSR1 += sizeof( Timers[0] ); 126 // Next index 127 } while ( ++index < OUTPUTS_COUNT ); 128 } 129 } 130 return Carry; 131 132 // ------------------------------------------------- 133 case DpaEvent_DpaRequest: 134 // Called to interpret DPA request for peripherals 135 // ------------------------------------------------- 136 // Peripheral enumeration 137 if ( IsDpaEnumPeripheralsRequest() ) 138 { 139 // We implement 1 standard peripheral 140 _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1; 141 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_BINARY_OUTPUTS ); 142 _DpaMessage.EnumPeripheralsAnswer.HWPID = HWPID_IQRF_TECH__DEMO_BINARY_OUTPUT; 143 _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0000; 144 145 DpaHandleReturnTRUE: 146 return TRUE; 147 } 148 // ------------------------------------------------- 149 // Get information about peripheral 150 else if ( IsDpaPeripheralInfoRequest() ) 151 { 152 if ( _PNUM == PNUM_STD_BINARY_OUTPUTS ) 153 { 154 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_BINARY_OUTPUTS; 155 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 156 // Set standard version 157 _DpaMessage.PeripheralInfoAnswer.Par1 = 4; 158 goto DpaHandleReturnTRUE; 159 } 160 161 break; 162 } 163 // ------------------------------------------------- 164 else 165 { 166 // Handle peripheral command 167 168 // Supported peripheral number? 169 if ( _PNUM == PNUM_STD_BINARY_OUTPUTS ) 170 { 171 // Supported commands? 172 switch ( _PCMD ) 173 { 174 // Invalid command 175 default: 176 { 177 // Return error 178 W = ERROR_PCMD; 179 ERROR_W: 180 DpaApiReturnPeripheralError( W ); 181 } 182 183 // Outputs enumeration 184 case PCMD_STD_ENUMERATE: 185 if ( _DpaDataLength != 0 ) 186 goto _ERROR_DATA_LEN; 187 188 // Return number of outputs 189 _DpaMessage.Response.PData[0] = OUTPUTS_COUNT; 190 W = 1; 191 goto _DpaDataLengthW; 192 193 // Supported commands. 194 case PCMD_STD_BINARY_OUTPUTS_SET: 195 { 196 // Pointers FSR01 to data are already set at the DPA 197 198 // As this template implements < 9 outputs the working bitmap is uns8, if more outputs are implemented then uns16, ..., uns32 must be used 199 #if OUTPUTS_COUNT < 9 200 uns8 inBitmap = *FSR0--; 201 uns8 outBitmap @ _DpaMessage.Response.PData[0]; 202 uns8 bitmapMask = 0b1; 203 #else 204 #error Not implemented 205 #endif 206 207 // Number of selected outputs + bitmap length 208 uns8 outputsCount = 4; 209 // Loop bitmap 210 uns8 index = 4; 211 do 212 { 213 // Count bits of next byte 214 uns8 byte = *++FSR0; 215 if ( byte != 0 ) 216 { 217 // Brian Kernighan's Algorithm for counting set bits 218 do 219 { 220 outputsCount++; 221 byte &= byte - 1; 222 } while ( byte != 0 ); 223 } 224 225 // Reset bitmap 226 setINDF0( 0 ); 227 } while ( --index != 0 ); 228 229 // Check data length 230 if ( _DpaDataLength != outputsCount ) 231 { 232 _ERROR_DATA_LEN: 233 W = ERROR_DATA_LEN; 234 goto ERROR_W; 235 } 236 237 // Pointer to the timers array 238 FSR1 = (uns16)&Timers[0]; 239 // Output index 240 index = 0; 241 do 242 { 243 // Output was set? 244 if ( GetOutput( index ) ) 245 // Yes, set in the output bitmap 246 outBitmap |= bitmapMask; 247 248 // Implemented output selected? Set the state. 249 if ( inBitmap.0 ) 250 { 251 // Default is timer off 252 uns16 time = 0; 253 // Desired state 254 uns8 state = *++FSR0; 255 if ( state > 1 ) 256 { 257 // Get time in units s/min 258 time = state & 0x7F; 259 if ( time == 0 ) 260 { 261 // Invalid time 262 W = ERROR_FAIL; 263 goto ERROR_W; 264 } 265 266 // Conversion coefficient, ready for minutes to 250 ms 267 uns8 coef = 60 * ( 1000 / 250 ); 268 if ( state.7 ) 269 // Convert from seconds 270 coef = 1000 / 250; 271 272 // Convert to 250 ms 273 time *= coef; 274 // Set ON 275 state = 1; 276 } 277 278 // Set output 279 SetOutput( state, index ); 280 281 // Set timer and preserve pointer 282 GIE = FALSE; 283 setINDF1( time.low8 ); 284 FSR1++; 285 setINDF1( time.high8 ); 286 FSR1--; 287 GIE = TRUE; 288 } 289 290 // Next pointer to the timer 291 FSR1 += sizeof( Timers[0] ); 292 // Next bits 293 bitmapMask <<= 1; 294 inBitmap >>= 1; 295 // Next index 296 } while ( ++index < OUTPUTS_COUNT ); 297 298 // Return bitmap 299 _DpaDataLength4: 300 W = 4; 301 _DpaDataLengthW: 302 _DpaDataLength = W; 303 goto DpaHandleReturnTRUE; 304 } 305 } 306 } 307 308 break; 309 } 310 311 // ------------------------------------------------- 312 case DpaEvent_Init: 313 // Do a one time initialization work before main loop starts 314 315 // Initialize relays @ DDC-RE 316 RELAY1_LAT = 0; 317 RELAY2_LAT = 0; 318 RELAY1_TRIS = 0; 319 RELAY2_TRIS = 0; 320 321 // Setup TMR6 to generate 10 ms ticks 322 #if F_OSC == 16000000 323 PR6 = 250 - 1; 324 T6CON = 0b0.1001.1.10; // Prescaler 16, Postscaler 10, 16 * 10 * 250 = 40000 = 4MHz * 10ms 325 #else 326 #error Unsupported oscillator frequency 327 #endif 328 329 break; 330 331 // ------------------------------------------------- 332 case DpaEvent_AfterSleep: 333 // Called after woken up after sleep 334 335 TMR6IE = TRUE; 336 TMR6ON = TRUE; 337 break; 338 339 // ------------------------------------------------- 340 case DpaEvent_BeforeSleep: 341 // Called before going to sleep 342 343 // ------------------------------------------------- 344 case DpaEvent_DisableInterrupts: 345 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond, and Run RFPGM) 346 347 // Must not use TMR6 any more 348 TMR6ON = FALSE; 349 TMR6IE = FALSE; 350 break; 351 } 352 DpaHandleReturnFALSE: 353 return FALSE; 354 } 355 356 //############################################################################################ 357 static uns8 _state; 358 void SetOutput( uns8 state @ _state, uns8 index @ W ) 359 //############################################################################################ 360 { 361 // Note: FSRs must not be modified 362 // Note: This method is called in the interrupt too! 363 364 skip( index ); 365 #pragma computedGoto 1 366 goto set0; 367 goto set1; 368 goto set2; 369 goto set3; 370 #pragma computedGoto 0 371 ; 372 // -------------------------------------- 373 set3: 374 if ( !state.0 ) 375 RELAY2_LAT = 0; 376 else 377 RELAY2_LAT = 1; 378 379 return; 380 // -------------------------------------- 381 set2: 382 if ( !state.0 ) 383 RELAY1_LAT = 0; 384 else 385 RELAY1_LAT = 1; 386 387 return; 388 // -------------------------------------- 389 set1: 390 if ( !state.0 ) 391 _LEDG = 0; 392 else 393 _LEDG = 1; 394 395 return; 396 // -------------------------------------- 397 set0: 398 if ( !state.0 ) 399 _LEDR = 0; 400 else 401 _LEDR = 1; 402 403 return; 404 } 405 406 //############################################################################################ 407 bit GetOutput( uns8 index @ W ) 408 //############################################################################################ 409 { 410 Carry = FALSE; // Note: must not modify W 411 412 // Note: all below must not modify Carry except when needed 413 skip( index ); 414 #pragma computedGoto 1 415 goto get0; 416 goto get1; 417 goto get2; 418 goto get3; 419 #pragma computedGoto 0 420 ; 421 // -------------------------------------- 422 get3: 423 if ( RELAY2_LAT ) 424 Carry = TRUE; 425 goto _return; 426 // -------------------------------------- 427 get2: 428 if ( RELAY1_LAT ) 429 Carry = TRUE; 430 goto _return; 431 // -------------------------------------- 432 get1: 433 if ( _LEDG ) 434 Carry = TRUE; 435 goto _return; 436 // -------------------------------------- 437 get0: 438 if ( _LEDR ) 439 Carry = TRUE; 440 goto _return; 441 // -------------------------------------- 442 443 _return: 444 return Carry; 445 } 446 447 //############################################################################################ 448 // 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) 449 #include "DPAcustomHandler.h" 450 //############################################################################################