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