1 // *******************************************************************************
    2 //   Custom DPA Handler code example - Demonstrates using of custom FRC commands *
    3 // *******************************************************************************
    4 // Copyright (c) IQRF Tech s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-FRC.c,v $
    7 // Version: $Revision: 1.42 $
    8 // Date:    $Date: 2018/06/14 15:57:09 $
    9 //
   10 // Revision history:
   11 //   2017/03/13  Release for DPA 3.00
   12 //   2015/08/05  Release for DPA 2.20
   13 //   2014/10/31  Release for DPA 2.10
   14 //   2014/04/30  Release for DPA 2.00
   15 //
   16 // *******************************************************************************
   17 
   18 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/
   19 
   20 // Default IQRF include (modify the path according to your setup)
   21 #include "IQRF.h"
   22 
   23 // Default DPA header (modify the path according to your setup)
   24 #include "DPA.h"
   25 // Default Custom DPA Handler header (modify the path according to your setup)
   26 #include "DPAcustomHandler.h"
   27 
   28 //############################################################################################
   29 
   30 // Divides 16bit value by 255
   31 void DivMod255( uns16 value );
   32 
   33 // Application implements 4 FCR commands
   34 // 0x40 - bit command, result bit.0 == 1, result bit.1 == 1 when button is pressed, otherwise bit.1 == 0
   35 // 0x41 - bit command, result bit.0 == 1, result bit.1 == 1 when LEDG is on, otherwise bit.1 == 0
   36 // 0xC0 - byte command, result byte=VRN
   37 // 0xF0 - shows how to return 16bit value even having its bytes equal 0. This command does not do sleeping, but UserData is used to specify which byte of 16bit value to return)
   38 //
   39 // FRC user data specify time to sleep after RFC data is collected, 0 means no sleeping
   40 // Sleeping after FRC can be easily implemented using acknowledged broadcast FRC commands
   41 
   42 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   43 //############################################################################################
   44 bit CustomDpaHandler()
   45 //############################################################################################
   46 {
   47   // Handler presence mark
   48   clrwdt();
   49 
   50   // Go sleep on next Idle
   51   static uns16 sleepTime;
   52 
   53   // Detect DPA event to handle
   54   switch ( GetDpaEvent() )
   55   {
   56     // -------------------------------------------------
   57     case DpaEvent_Interrupt:
   58       // Do an extra quick background interrupt work
   59       // ! 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.
   60       // ! 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.
   61       // ! 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.
   62       // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy.
   63       // ! Make sure race condition does not occur when accessing those variables at other places.
   64       // ! 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.
   65       // ! Do not call any OS functions except setINDFx().
   66       // ! Do not use any OS variables especially for writing access.
   67       // ! 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.
   68 
   69 DpaHandleReturnTRUE:
   70       return TRUE;
   71 
   72       // -------------------------------------------------
   73     case DpaEvent_Init:
   74       // Do a one time initialization work before main loop starts
   75 
   76       // Enable LED during special system actions (discovery, FRC)
   77       _systemLEDindication = TRUE;
   78       break;
   79 
   80       // -------------------------------------------------
   81     case DpaEvent_FrcResponseTime:
   82       // Called to get FRC response time
   83 
   84       switch ( DataOutBeforeResponseFRC[0] )
   85       {
   86         case FRC_USER_BIT_FROM + 0:
   87         case FRC_USER_BIT_FROM + 1:
   88         case FRC_USER_BYTE_FROM + 0:
   89         case FRC_USER_BYTE_FROM + 1:
   90           responseFRCvalue = _FRC_RESPONSE_TIME_40_MS;
   91           break;
   92       }
   93       break;
   94 
   95       // -------------------------------------------------
   96     case DpaEvent_FrcValue:
   97       // Called to get FRC value
   98       uns16 FRC16bData @ DataOutBeforeResponseFRC;
   99       sleepTime = FRC16bData;
  100 
  101       switch ( _PCMD )
  102       {
  103         // This example is sensitive to the bit FRCommand 0x40
  104         case FRC_USER_BIT_FROM + 0:
  105           // bit.1 is set only when button is pressed
  106           if ( buttonPressed )
  107             responseFRCvalue.1 = 1;
  108           break;
  109 
  110           // This example is sensitive to the bit FRCommand 0x41
  111         case FRC_USER_BIT_FROM + 1:
  112           // bit.1 is set only when LEDG is on
  113           if ( _LEDG == 1 )
  114             responseFRCvalue.1 = 1;
  115           break;
  116 
  117           // This example is sensitive to the byte FRCommand 0xF0
  118         case FRC_USER_2BYTE_FROM:
  119           // It returns 2 bytes from getTemperature()
  120 
  121           // Temperature measurement error?
  122           if ( getTemperature() == -128 )
  123             param3 = 0x8000;
  124 
  125           // Is temperature 0?
  126           if ( param3 == 0 )
  127             // Return 0x7FFF instead
  128             param3 = 0x7FFF;
  129 
  130           responseFRCvalue2B = param3;
  131           break;
  132 
  133           // This example is sensitive to the byte FRCommand 0xC0
  134         case FRC_USER_BYTE_FROM + 0:
  135           // Return node's VRN
  136           responseFRCvalue = ntwVRN;
  137           break;
  138 
  139           // This example is sensitive to the byte FRCommand 0xC1
  140         case FRC_USER_BYTE_FROM + 1:
  141         {
  142           // This FRC shows how to return 16 bit value keeping in mind that returned bytes must not be 0
  143           // It converts 16 bit value into 255 radix and increments both quotient and reminder by 1 thus eliminating 0
  144           // It means that the highest value that can be actually returned is 255 * 254 + 254 = 0xFE00 (hex) = 65024 (decimal)
  145           // To compose the original 16b value just do: ( 1stByte - 1 ) + 255 * ( 2ndByte - 1 )
  146 
  147           static uns8 hiByte;
  148 
  149           // Return 1st lower "byte"
  150           if ( FRC16bData == 0 )
  151           {
  152             // Example value to return is 0xABCD
  153             DivMod255( 0xABCD );
  154             // Quotient /255
  155             hiByte = param3.low8 + 1;
  156             // Return reminder /255
  157             responseFRCvalue = param4.low8 + 1;
  158           }
  159           else
  160             // Return quotient
  161             responseFRCvalue = hiByte;
  162 
  163           // fall through to reset sleeping
  164         }
  165 
  166         default:
  167           sleepTime = 0;
  168           break;
  169       }
  170 
  171       break;
  172 
  173       // -------------------------------------------------
  174     case DpaEvent_Idle:
  175       // Do a quick background work when RF packet is not received
  176 
  177       // Go sleep?
  178       if ( sleepTime != 0 )
  179       {
  180         // Prepare OS Sleep DPA Request
  181         _PNUM = PNUM_OS;
  182         _PCMD = CMD_OS_SLEEP;
  183         // Time in 2.097s units
  184         _DpaMessage.PerOSSleep_Request.Time = sleepTime;
  185         sleepTime = 0;
  186         // LEDG flash after wake up & pin wakeup
  187         _DpaMessage.PerOSSleep_Request.Control = 0b1101;
  188         _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request );
  189         // Perform local DPA Request
  190         DpaApiLocalRequest();
  191       }
  192       break;
  193 
  194     case DpaEvent_DpaRequest:
  195       // Called to interpret DPA request for peripherals
  196       // -------------------------------------------------
  197       // Peripheral enumeration
  198       if ( IsDpaEnumPeripheralsRequest() )
  199       {
  200         // We implement no user peripheral
  201         _DpaMessage.EnumPeripheralsAnswer.HWPID = 0x000F;
  202         _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0000;
  203         goto DpaHandleReturnTRUE;
  204       }
  205   }
  206 
  207   return FALSE;
  208 }
  209 
  210 //############################################################################################
  211 /*
  212 * Divides 16bit value by 255
  213 * Input:
  214 *   Dividend: value @ param3:16
  215 * Output:
  216 *   Quotient: @ param3:16
  217 *   Remainder: @ param4.low8:8
  218 * Assumes: param4:16 is adjacent to param3:16
  219 *
  220 * Based on http://www.piclist.com/techref/microchip/math/div/24by8-jah.htm
  221 */
  222 void DivMod255( uns16 value @ param3 )
  223 //############################################################################################
  224 {
  225   #asm
  226     clrf      param4 + 0;
  227 
  228   movlw   16;
  229   movwf   param4 + 1;
  230 
  231 loop:
  232   rlf     value + 0, W;
  233   rlf     value + 1, f;
  234   rlf     param4 + 0, f;
  235   rlf     value + 0, f;
  236 
  237   movlw   255;
  238   subwf   param4 + 0, f;
  239 
  240   btfsc   Carry;
  241   bsf     value + 0, 0;
  242 
  243   btfss   value + 0, 0;
  244   addwf   param4 + 0, f;
  245 
  246   decfsz  param4 + 1, f;
  247   goto    loop;
  248   #endasm
  249 }
  250 
  251 //############################################################################################
  252 // 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) 
  253 #include "DPAcustomHandler.h"
  254 //############################################################################################