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