1 // *********************************************************************
    2 //   Custom DPA Handler code example - Standard Sensors - Thermometer  *
    3 // *********************************************************************
    4 // Copyright (c) IQRF Tech s.r.o.
    5 //
    6 // File:    $RCSfile: 0802_TrThermometer.c,v $
    7 // Version: $Revision: 1.5 $
    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 1 temperature sensor according to the IQRF Sensors standard
   18 
   19 // The example will not work at demo DPA version because demo DPA does not support PCMD != 0
   20 
   21 // Default IQRF include (modify the path according to your setup)
   22 #include "IQRF.h"
   23 
   24 // Uncomment to implement Custom DPA Handler for Coordinator
   25 //#define COORDINATOR_CUSTOM_HANDLER
   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 //############################################################################################
   36 
   37 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   38 //############################################################################################
   39 bit CustomDpaHandler()
   40 //############################################################################################
   41 {
   42   // 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)
   43 #pragma updateBank default = UserBank_01
   44 
   45   // Handler presence mark
   46   clrwdt();
   47 
   48   // Sleeping parameters, valid when Time != 0
   49   static TPerOSSleep_Request PerOSSleep_Request;
   50 
   51   // Detect DPA event to handle
   52   switch ( GetDpaEvent() )
   53   {
   54     // -------------------------------------------------
   55     case DpaEvent_Interrupt:
   56       // Do an extra quick background interrupt work
   57       // ! 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.
   58       // ! 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.
   59       // ! 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.
   60       // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy.
   61       // ! Make sure race condition does not occur when accessing those variables at other places.
   62       // ! 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.
   63       // ! Do not call any OS functions except setINDFx().
   64       // ! Do not use any OS variables especially for writing access.
   65       // ! 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.
   66 
   67       return Carry;
   68 
   69       // -------------------------------------------------
   70     case DpaEvent_Idle:
   71       // Do a quick background work when RF packet is not received
   72 
   73       // Should go to sleep?
   74       if ( PerOSSleep_Request.Time != 0 )
   75       {
   76         // Copy sleep parameters to the DPA request
   77         _DpaMessage.PerOSSleep_Request.Time = PerOSSleep_Request.Time;
   78         _DpaMessage.PerOSSleep_Request.Control = PerOSSleep_Request.Control;
   79         // Switch off sleeping time=flag
   80         PerOSSleep_Request.Time = 0;
   81         // Finalize OS Sleep DPA Request
   82         _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request );
   83         _PNUM = PNUM_OS;
   84         _PCMD = CMD_OS_SLEEP;
   85         // Perform local DPA Request to go to sleep
   86         DpaApiLocalRequest();
   87       }
   88       break;
   89 
   90       // -------------------------------------------------
   91     case DpaEvent_DpaRequest:
   92       // Called to interpret DPA request for peripherals
   93       // -------------------------------------------------
   94       // Peripheral enumeration
   95       if ( IsDpaEnumPeripheralsRequest() )
   96       {
   97         // We implement 1 standard peripheral
   98         _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1;
   99         FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS );
  100         _DpaMessage.EnumPeripheralsAnswer.HWPID = HWPID_MICRORISC__DEMO_TR_THERMOMETER;
  101         _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0000;
  102 
  103 DpaHandleReturnTRUE:
  104         return TRUE;
  105       }
  106       // -------------------------------------------------
  107       // Get information about peripheral
  108       else if ( IsDpaPeripheralInfoRequest() )
  109       {
  110         if ( _PNUM == PNUM_STD_SENSORS )
  111         {
  112           _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_SENSORS;
  113           _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE;
  114           // Set standard version
  115           _DpaMessage.PeripheralInfoAnswer.Par1 = 12;
  116           goto DpaHandleReturnTRUE;
  117         }
  118 
  119         break;
  120       }
  121       // -------------------------------------------------
  122       else
  123       {
  124         // Handle peripheral command
  125 
  126         // Supported peripheral number?
  127         if ( _PNUM == PNUM_STD_SENSORS )
  128         {
  129           // Supported commands?
  130           switch ( _PCMD )
  131           {
  132             // Invalid command
  133             default:
  134               // Return error
  135               DpaApiReturnPeripheralError( ERROR_PCMD );
  136 
  137               // Sensor enumeration
  138             case PCMD_STD_ENUMERATE:
  139               if ( _DpaDataLength != 0 )
  140                 goto _ERROR_DATA_LEN;
  141 
  142               _DpaDataLength |= 1; // = 1 (optimization as _DpaDataLength was 0 for sure)
  143               goto _Enumerate;
  144 
  145               // Supported commands. They are handled almost the same way
  146             case PCMD_STD_SENSORS_READ_VALUES:
  147             case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES:
  148             {
  149               // No sensor bitmap specified? W = _DpaDataLength. Note: W is used to avoid MOVLB at next if
  150               W = _DpaDataLength;
  151               if ( W == 0 ) // Note: must not modify W
  152               {
  153                 // Bitmap is 32 bits long = 4 (Note: using here save MOVLB)
  154                 _DpaDataLength = W = 4;
  155                 // Simulate 1st sensor in the bitmap (states of the other unimplemented sensors do not care)
  156                 _DpaMessage.Request.PData[0].0 = 1; // Note: must not modify W
  157               }
  158 
  159               // Invalid bitmap (data) length (W = _DpaDataLength)?
  160               if ( W != 4 )
  161               {
  162 _ERROR_DATA_LEN:
  163                 // Return error
  164                 DpaApiReturnPeripheralError( ERROR_DATA_LEN );
  165               }
  166 
  167               // Get ready return data length for temperature data only (Note: optimization, 2 = 4/2 is used to save)
  168               _DpaDataLength /= 2;
  169 
  170               // Is my only sensor selected?
  171               if ( _DpaMessage.Request.PData[0].0 )
  172               {
  173                 // Error reading temperature? Note: param3 holds temperature value after calling getTemperature()
  174                 if ( getTemperature() == -128 )
  175                   // Return standard error value
  176                   param3 = 0x8000;
  177 
  178                 // Return the sensor type too?
  179                 if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES )
  180                 {
  181                   // 3 bytes (1 byte with type, 2 bytes with temperature value) will be returned
  182                   _DpaDataLength++;
  183 _Enumerate:
  184                   // 1st byte is sensor type
  185                   _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_TEMPERATURE;
  186                   // 3rd byte is higher byte of temperature value
  187                   _DpaMessage.Response.PData[2] = param3.high8;
  188                   // 2nd byte is lower byte of temperature value
  189                   W = param3.low8;
  190                 }
  191                 else
  192                 {
  193                   // 2 bytes to return
  194                   // 1st byte is lower byte of temperature value
  195                   _DpaMessage.Response.PData[0] = param3.low8;
  196                   // 2nd byte is higher byte of temperature value
  197                   W = param3.high8;
  198                 }
  199 
  200                 // Store 2nd byte for both supported commands
  201                 _DpaMessage.Response.PData[1] = W;
  202                 // Handled!
  203                 goto DpaHandleReturnTRUE;
  204               }
  205               else
  206               {
  207                 // My sensor not selected, so no data returned
  208                 _DpaDataLength = 0;
  209                 goto DpaHandleReturnTRUE;
  210               }
  211             }
  212           }
  213         }
  214 
  215         break;
  216       }
  217 
  218       // -------------------------------------------------
  219     case DpaEvent_FrcValue:
  220       // Called to get FRC value
  221 
  222       // Check for correct FRC and FRC used data (signature byte and sensor index == 0)
  223       switch ( _PCMD )
  224       {
  225         case FRC_STD_SENSORS_1B:
  226         case FRC_STD_SENSORS_2B:
  227           // FSR1 for optimization purposes (avoid MOVLB) will be used to point to DataOutBeforeResponseFRC[0...]
  228           FSR1 = &DataOutBeforeResponseFRC[0];
  229 
  230           if ( *FSR1++ /*DataOutBeforeResponseFRC[0]*/ == PNUM_STD_SENSORS &&
  231             ( *FSR1 /*DataOutBeforeResponseFRC[1]*/ == 0x00 || *FSR1 /*DataOutBeforeResponseFRC[1]*/ == STD_SENSOR_TYPE_TEMPERATURE ) &&
  232                ( *++FSR1 /*DataOutBeforeResponseFRC[2]*/ & 0x1f ) == 0 )
  233           {
  234             // Return error code 2B
  235             responseFRCvalue2B = 2;
  236             // Return error code 1B
  237             responseFRCvalue = 2;
  238             // Get temperature and adjust it for FRC
  239             // Temperature OK?
  240             if ( getTemperature() != -128 )
  241             {
  242               // Return sensor FRC value 2B
  243               responseFRCvalue2B = param3 ^ 0x8000;
  244 
  245               // Return sensor FRC value 1B
  246               // Check for out of limits
  247               if ( (int16)param3 <= (int16)( 105.5 * 16 ) && (int16)param3 >= ( (int16)-20 * 16 ) )
  248               {
  249                 // CC5x reports "Sign problems, please typecast one operand to unsigned (uns16)"
  250                 // param3 = (int16)param3 / 8;
  251                 param3.high8 = asr( param3.high8 );
  252                 param3.low8 = rr( param3.low8 );
  253                 param3.high8 = asr( param3.high8 );
  254                 param3.low8 = rr( param3.low8 );
  255                 param3.high8 = asr( param3.high8 );
  256                 param3.low8 = rr( param3.low8 );
  257 
  258                 responseFRCvalue = (int8)param3.low8 + 44;
  259               }
  260             }
  261 
  262             // The sensor was measured by FRC, check if there is a sleep request
  263             FSR1++;
  264             if ( INDF1.7 ) // Note: same as DataOutBeforeResponseFRC[3].7
  265             {
  266               // Remember sleep parameters to go to sleep at the Idle event later
  267               PerOSSleep_Request.Time.low8 = FSR1[4 - 3]; // Note: same as DataOutBeforeResponseFRC[4]
  268               PerOSSleep_Request.Time.high8 = FSR1[5 - 3]; // Note: same as DataOutBeforeResponseFRC[5]
  269               PerOSSleep_Request.Control = FSR1[6 - 3]; // Note: same as DataOutBeforeResponseFRC[6]
  270             }
  271           }
  272           break;
  273       }
  274       break;
  275 
  276       // -------------------------------------------------
  277     case DpaEvent_FrcResponseTime:
  278       // Called to get FRC response time
  279 
  280       // In this example the FRC command is a fast one
  281       switch ( DataOutBeforeResponseFRC[0] )
  282       {
  283         case FRC_STD_SENSORS_1B:
  284         case FRC_STD_SENSORS_2B:
  285           responseFRCvalue = _FRC_RESPONSE_TIME_40_MS;
  286           break;
  287       }
  288       break;
  289   }
  290 
  291 DpaHandleReturnFALSE:
  292   return FALSE;
  293 }
  294 
  295 //############################################################################################
  296 // 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) 
  297 #include "DPAcustomHandler.h"
  298 //############################################################################################