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