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 //############################################################################################