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