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