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