1 // *********************************************************************
    2 //   Custom DPA Handler code example - Standard Sensors - Template     *
    3 // *********************************************************************
    4 // Copyright (c) IQRF Tech s.r.o.
    5 //
    6 // File:    $RCSfile: 1402_Sensor-Template.c,v $
    7 // Version: $Revision: 1.7 $
    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 5 sensors according to the IQRF Sensors standard. The example does not implement writing data to the sensors.
   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 // Number of implemented sensors
   38 #define SENSORS_COUNT 5
   39 
   40 // Variable to store sensor value at Get?_????() methods. This example implements sensors returning maximum 2 bytes of data.
   41 uns16 sensorValue @ param3;
   42 
   43 // Reads sensor value to the sensorValue variable and to responseFRCvalue(2B) variable(s) based on FR command @ _PCMD
   44 // Returns TRUE if the FRC is prepared
   45 bit Get0_Temperature();
   46 bit Get1_CO2();
   47 bit Get2_VOC();
   48 bit Get3_Humidity();
   49 bit Get4_Binary7();
   50 
   51 // Stores sensor value byte(s) to the FSR1[+1...], in case of PCMD_STD_SENSORS_READ_TYPES_AND_VALUES sensor type is stored before value byte(s)
   52 void StoreValue( uns8 sensorType );
   53 
   54 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   55 //############################################################################################
   56 bit CustomDpaHandler()
   57 //############################################################################################
   58 {
   59   // 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)
   60 #pragma updateBank default = UserBank_01
   61 
   62 // Handler presence mark
   63   clrwdt();
   64 
   65   // Sleeping parameters, valid when Time != 0
   66   static TPerOSSleep_Request PerOSSleep_Request;
   67 
   68   // Detect DPA event to handle
   69   switch ( GetDpaEvent() )
   70   {
   71     // -------------------------------------------------
   72     case DpaEvent_Interrupt:
   73       // Do an extra quick background interrupt work
   74       // ! 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.
   75       // ! 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.
   76       // ! 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.
   77       // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy.
   78       // ! Make sure race condition does not occur when accessing those variables at other places.
   79       // ! 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.
   80       // ! Do not call any OS functions except setINDFx().
   81       // ! Do not use any OS variables especially for writing access.
   82       // ! 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.
   83       return Carry;
   84 
   85       // -------------------------------------------------
   86     case DpaEvent_Idle:
   87       // Do a quick background work when RF packet is not received
   88 
   89       // Should go to sleep?
   90       if ( PerOSSleep_Request.Time != 0 )
   91       {
   92         // Copy sleep parameters to the DPA request
   93         _DpaMessage.PerOSSleep_Request.Time = PerOSSleep_Request.Time;
   94         _DpaMessage.PerOSSleep_Request.Control = PerOSSleep_Request.Control;
   95         // Switch off sleeping time=flag
   96         PerOSSleep_Request.Time = 0;
   97         // Finalize OS Sleep DPA Request
   98         _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request );
   99         _PNUM = PNUM_OS;
  100         _PCMD = CMD_OS_SLEEP;
  101         // Perform local DPA Request to go to sleep
  102         DpaApiLocalRequest();
  103       }
  104       break;
  105 
  106       // -------------------------------------------------
  107     case DpaEvent_DpaRequest:
  108       // Called to interpret DPA request for peripherals
  109       // -------------------------------------------------
  110       // Peripheral enumeration
  111       if ( IsDpaEnumPeripheralsRequest() )
  112       {
  113         // We implement 1 standard peripheral
  114         _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1;
  115         FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS );
  116         // ToDo: use actual IQRF Alliance allocated HWPID and current version of this handler
  117         _DpaMessage.EnumPeripheralsAnswer.HWPID = HWPID_MICRORISC__DEMO_SENSOR_TEMPLATE;
  118         _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0000;
  119 
  120 DpaHandleReturnTRUE:
  121         return TRUE;
  122       }
  123       // -------------------------------------------------
  124       // Get information about peripheral
  125       else if ( IsDpaPeripheralInfoRequest() )
  126       {
  127         if ( _PNUM == PNUM_STD_SENSORS )
  128         {
  129           _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_SENSORS;
  130           _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE;
  131           // Set standard version
  132           _DpaMessage.PeripheralInfoAnswer.Par1 = 12;
  133           goto DpaHandleReturnTRUE;
  134         }
  135 
  136         break;
  137       }
  138       // -------------------------------------------------
  139       else
  140       {
  141         // Handle peripheral command
  142 
  143         // Supported peripheral number?
  144         if ( _PNUM == PNUM_STD_SENSORS )
  145         {
  146           // Supported commands?
  147           switch ( _PCMD )
  148           {
  149             // Invalid command
  150             default:
  151               // Return error
  152               DpaApiReturnPeripheralError( ERROR_PCMD );
  153 
  154               // Sensor enumeration
  155             case PCMD_STD_ENUMERATE:
  156               if ( _DpaDataLength != 0 )
  157                 goto _ERROR_DATA_LEN;
  158 
  159               // Then just enumerate their types
  160               _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_TEMPERATURE;
  161               _DpaMessage.Response.PData[1] = STD_SENSOR_TYPE_CO2;
  162               _DpaMessage.Response.PData[2] = STD_SENSOR_TYPE_VOC;
  163               _DpaMessage.Response.PData[3] = STD_SENSOR_TYPE_HUMIDITY;
  164               _DpaMessage.Response.PData[4] = STD_SENSOR_TYPE_BINARYDATA7;
  165               W = SENSORS_COUNT;
  166               goto _W2_DpaDataLength;
  167 
  168               // Supported commands. They are handled the same way except one "if" at StoreValue() method
  169             case PCMD_STD_SENSORS_READ_VALUES:
  170             case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES:
  171             {
  172               // No sensor bitmap specified? W = _DpaDataLength. Note: W is used to avoid MOVLB at next if
  173               W = _DpaDataLength;
  174               if ( W == 0 ) // Note: must not modify W
  175               {
  176                 // Actually clears the bitmap
  177 #if &_DpaMessage.Request.PData[0] != &bufferRF[0]
  178 #error
  179 #endif
  180                 clearBufferRF();
  181                 // Simulate 1st only sensor in the bitmap (states of the other unimplemented sensors do not care)
  182                 _DpaMessage.Request.PData[0].0 = 1;
  183                 // Bitmap is 32 bits long = 4
  184                 _DpaDataLength = W = 4;
  185               }
  186 
  187               // Invalid bitmap (data) length (W = _DpaDataLength)?
  188               if ( W != 4 )
  189               {
  190 _ERROR_DATA_LEN:
  191                 // Return error
  192                 DpaApiReturnPeripheralError( ERROR_DATA_LEN );
  193               }
  194 
  195               // Now read the sensors
  196 
  197               // Prepare pointer (minus 1, see below) to store sensor (types and) values to
  198               // Note: 5 sensors at this example cannot return more than DPA_MAX_DATA_LENGTH bytes of data, so it does not have to be checked...
  199               // ... If it would be the case, then ERROR_FAIL must be returned
  200               FSR1 = &_DpaMessage.Response.PData[-1];
  201 
  202               // Store bitmap of sensors to get values from
  203               uns8  sensorsBitmap = FSR1[1];
  204 
  205               // 1st sensor (index 0) selected?
  206               if ( sensorsBitmap.0 )
  207               {
  208                 Get0_Temperature();
  209                 StoreValue( STD_SENSOR_TYPE_TEMPERATURE );
  210               }
  211 
  212               // 2nd sensor (index 1) selected?
  213               if ( sensorsBitmap.1 )
  214               {
  215                 Get1_CO2();
  216                 StoreValue( STD_SENSOR_TYPE_CO2 );
  217               }
  218 
  219               // 3rd sensor (index 2) selected?
  220               if ( sensorsBitmap.2 )
  221               {
  222                 Get2_VOC();
  223                 StoreValue( STD_SENSOR_TYPE_VOC );
  224               }
  225 
  226               // 4th sensor (index 3) selected?
  227               if ( sensorsBitmap.3 )
  228               {
  229                 Get3_Humidity();
  230                 StoreValue( STD_SENSOR_TYPE_HUMIDITY );
  231               }
  232 
  233               // 5th sensor (index 4) selected?
  234               if ( sensorsBitmap.4 )
  235               {
  236                 Get4_Binary7();
  237                 StoreValue( STD_SENSOR_TYPE_BINARYDATA7 );
  238               }
  239 
  240               // Compute returned data bytes count
  241               W = FSR1L - ( (uns16)&_DpaMessage.Response.PData[0] & 0xFF ) + 1;
  242               // Optimization: return W long block of bytes at response
  243 _W2_DpaDataLength:
  244               _DpaDataLength = W;
  245               goto DpaHandleReturnTRUE;
  246             }
  247           }
  248         }
  249 
  250         break;
  251       }
  252 
  253       // -------------------------------------------------
  254     case DpaEvent_FrcValue:
  255       // Called to get FRC value
  256 
  257       // FSR1 for optimization purposes (avoid MOVLB) will be used to point to DataOutBeforeResponseFRC[0...]
  258       FSR1 = &DataOutBeforeResponseFRC[0];
  259       // Check for correct FRC user data
  260       if ( *FSR1++ /*DataOutBeforeResponseFRC[0]*/ == PNUM_STD_SENSORS )
  261       {
  262         // Actually used sensor index
  263         uns8 sensorIndex = FSR1[1] /*DataOutBeforeResponseFRC[2]*/ & 0x1f;
  264         // Test sensor type
  265         switch ( *FSR1++ /*DataOutBeforeResponseFRC[1]*/ )
  266         {
  267           default:
  268             goto DpaHandleReturnFALSE;
  269 
  270             // No type specified, use specified index value
  271           case 0x00:
  272             goto _KeepSensorIndex;
  273 
  274             // For other types make the index value based on the requested index value and sensor type
  275           case STD_SENSOR_TYPE_TEMPERATURE:
  276             if ( sensorIndex > 0 )
  277               goto DpaHandleReturnFALSE;
  278             W = 0;
  279             break;
  280 
  281           case STD_SENSOR_TYPE_CO2:
  282             if ( sensorIndex > 0 )
  283               goto DpaHandleReturnFALSE;
  284             W = 1;
  285             break;
  286 
  287           case STD_SENSOR_TYPE_VOC:
  288             if ( sensorIndex > 0 )
  289               goto DpaHandleReturnFALSE;
  290             W = 2;
  291             break;
  292 
  293           case STD_SENSOR_TYPE_HUMIDITY:
  294             if ( sensorIndex > 0 )
  295               goto DpaHandleReturnFALSE;
  296             W = 3;
  297             break;
  298 
  299           case STD_SENSOR_TYPE_BINARYDATA7:
  300             if ( sensorIndex > 0 )
  301               goto DpaHandleReturnFALSE;
  302             W = 4;
  303             break;
  304         }
  305 
  306         // New sensor index based on type and requested index
  307         sensorIndex = W;
  308 _KeepSensorIndex:
  309 
  310         // Test for supported FRC commands
  311         switch ( _PCMD )
  312         {
  313           default:
  314             goto DpaHandleReturnFALSE;
  315 
  316           case FRC_STD_SENSORS_BIT:
  317           case FRC_STD_SENSORS_1B:
  318           case FRC_STD_SENSORS_2B:
  319             switch ( sensorIndex )
  320             {
  321               default:
  322                 goto DpaHandleReturnFALSE;
  323 
  324               case 0:
  325                 Carry = Get0_Temperature();
  326                 break;
  327 
  328               case 1:
  329                 Carry = Get1_CO2();
  330                 break;
  331 
  332               case 2:
  333                 Carry = Get2_VOC();
  334                 break;
  335 
  336               case 3:
  337                 Carry = Get3_Humidity();
  338                 break;
  339 
  340               case 4:
  341                 Carry = Get4_Binary7();
  342                 break;
  343             }
  344 
  345             // This type of FRC is not valid for the specified sensor
  346             if ( !Carry )
  347               goto DpaHandleReturnFALSE;
  348 
  349             break;
  350         }
  351 
  352         // Some sensor was measured by FRC, check if there is a sleep request
  353         FSR1++;
  354         if ( INDF1.7 ) // Note: same as DataOutBeforeResponseFRC[3].7
  355         {
  356           // Remember sleep parameters to go to sleep at the Idle event later
  357           PerOSSleep_Request.Time.low8 = FSR1[4 - 3]; // Note: same as DataOutBeforeResponseFRC[4];
  358           PerOSSleep_Request.Time.high8 = FSR1[5 - 3]; // Note: same as DataOutBeforeResponseFRC[5];
  359           PerOSSleep_Request.Control = FSR1[6 - 3]; // Note: same as DataOutBeforeResponseFRC[6];
  360         }
  361       }
  362 
  363       break;
  364 
  365       // -------------------------------------------------
  366     case DpaEvent_FrcResponseTime:
  367       // Called to get FRC response time
  368 
  369       // In this example the FRC commands are fast 
  370       switch ( DataOutBeforeResponseFRC[0] )
  371       {
  372         case FRC_STD_SENSORS_BIT:
  373         case FRC_STD_SENSORS_1B:
  374         case FRC_STD_SENSORS_2B:
  375           responseFRCvalue = _FRC_RESPONSE_TIME_40_MS;
  376           break;
  377       }
  378       break;
  379   }
  380 DpaHandleReturnFALSE:
  381   return FALSE;
  382 }
  383 
  384 //############################################################################################
  385 // Increases FSR1 and then stores the byte
  386 void setPlusPlusINDF1( uns8 data @ W )
  387 //############################################################################################
  388 {
  389   FSR1++; // Note: must not modify W
  390   setINDF1( data );
  391 }
  392 
  393 //############################################################################################
  394 // Stores measured sensor value byte(s) and optionally sensor type to the FSR[+1...]
  395 void StoreValue( uns8 sensorType )
  396 //############################################################################################
  397 {
  398   // Is the sensor type to be stored too?
  399   if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES )
  400     setPlusPlusINDF1( sensorType );
  401 
  402   // Store lower value byte
  403   setPlusPlusINDF1( sensorValue.low8 );
  404 
  405   // No more value bytes to store?
  406   if ( sensorType.7 != 0 )
  407     return;
  408 
  409   // Store higher value byte
  410   setPlusPlusINDF1( sensorValue.high8 );
  411 
  412   // Note: this example implements sensors returning only 1 or 2 bytes of data. If another data widths are returned, then it must be implemented explicitly.
  413 }
  414 
  415 //############################################################################################
  416 bit setFRCerror1B()
  417 //############################################################################################
  418 {
  419   responseFRCvalue = 2;
  420   return TRUE;
  421 }
  422 
  423 //############################################################################################
  424 bit setFRCerror2B()
  425 //############################################################################################
  426 {
  427   responseFRCvalue2B = 2;
  428   return TRUE;
  429 }
  430 
  431 //############################################################################################
  432 // Sensor index 0: measure temperature using the TR sensor
  433 bit Get0_Temperature()
  434 //############################################################################################
  435 {
  436   // Make sure FSR1 is not modified
  437 
  438   // Measure temperature using TR sensor
  439   bit sensorError = FALSE;
  440   // When error, then adjust the standard error values
  441   if ( getTemperature() == -128 )
  442   {
  443     sensorError = TRUE;
  444     param3 = 0x8000;
  445   }
  446 
  447   // Return sensor value
  448   sensorValue = param3;
  449 
  450   // Test for supported FRC commands
  451   switch ( _PCMD )
  452   {
  453     default:
  454       return FALSE;
  455 
  456     case FRC_STD_SENSORS_1B:
  457       // Return sensor FRC value 1B
  458       // Check for out of limits
  459       if ( sensorError || (int16)sensorValue > (int16)( 105.5 * 16 ) || (int16)sensorValue < ( (int16)-20 * 16 ) )
  460         return setFRCerror1B();
  461 
  462       // Convert to the "F = ( T + 22 ) * 2 " from 1/16 resolution
  463       uns16 _sensorValue = sensorValue + 4; // Note: do rounding when /8
  464       responseFRCvalue = (uns8)( _sensorValue / 8 ) + 44;
  465       break;
  466 
  467     case FRC_STD_SENSORS_2B:
  468       // Return sensor FRC value 2B
  469       if ( sensorError )
  470         return setFRCerror2B();
  471 
  472       responseFRCvalue2B = sensorValue ^ 0x8000;
  473       break;
  474   }
  475 
  476   return TRUE;
  477 }
  478 
  479 //############################################################################################
  480 // Sensor index 1: simulate measuring CO2
  481 bit Get1_CO2()
  482 //############################################################################################
  483 {
  484   // Make sure FSR1 is not modified
  485 
  486   bit sensorError = FALSE;
  487   // Fake CO2 return value
  488   sensorValue = 0x0987;
  489   // When error, return standard (FRC) error value(s)
  490   if ( sensorValue == 0x8000 )
  491     sensorError = TRUE;
  492 
  493   // Test for supported FRC commands
  494   switch ( _PCMD )
  495   {
  496     default:
  497       return FALSE;
  498 
  499     case FRC_STD_SENSORS_1B:
  500       // Return sensor FRC value 1B
  501       // Check for out of limits
  502       if ( sensorError || sensorValue > 4016 )
  503         return setFRCerror1B();
  504 
  505       responseFRCvalue = sensorValue / 16 + 4;
  506       break;
  507 
  508     case FRC_STD_SENSORS_2B:
  509       // Return sensor FRC value 2B
  510       if ( sensorError )
  511         return setFRCerror2B();
  512 
  513       responseFRCvalue2B = sensorValue + 4;
  514       break;
  515   }
  516 
  517   return TRUE;
  518 }
  519 
  520 //############################################################################################
  521 // Sensor index 2: simulate measuring VOC
  522 bit Get2_VOC()
  523 //############################################################################################
  524 {
  525   // Make sure FSR1 is not modified
  526 
  527   bit sensorError = FALSE;
  528   // Fake VOC return value
  529   sensorValue = 0x0123;
  530   // When error, return standard (FRC) error value(s)
  531   if ( sensorValue == 0x8000 )
  532     sensorError = TRUE;
  533 
  534   // Test for supported FRC commands
  535   switch ( _PCMD )
  536   {
  537     default:
  538       return FALSE;
  539 
  540     case FRC_STD_SENSORS_1B:
  541       // Return sensor FRC value 1B
  542       // Check for out of limits
  543       if ( sensorError || sensorValue > 4016 )
  544         return setFRCerror1B();
  545 
  546       responseFRCvalue = sensorValue / 16 + 4;
  547       break;
  548 
  549     case FRC_STD_SENSORS_2B:
  550       // Return sensor FRC value 2B
  551       if ( sensorError )
  552         return setFRCerror2B();
  553 
  554       responseFRCvalue2B = sensorValue + 4;
  555       break;
  556   }
  557 
  558   return TRUE;
  559 }
  560 
  561 //############################################################################################
  562 // Sensor index 3: simulate measuring humidity
  563 bit Get3_Humidity()
  564 //############################################################################################
  565 {
  566   // Make sure FSR1 is not modified
  567 
  568   // Fake humidity return value
  569   sensorValue.low8 = 50 * 2;
  570 
  571   // Test for supported FRC commands
  572   switch ( _PCMD )
  573   {
  574     default:
  575       return FALSE;
  576 
  577     case FRC_STD_SENSORS_1B:
  578       // Return sensor FRC value 1B
  579       if ( sensorValue.low8 == 0xEE )
  580         return setFRCerror1B();
  581 
  582       responseFRCvalue = sensorValue.low8 + 4;
  583       break;
  584   }
  585   return TRUE;
  586 }
  587 
  588 //############################################################################################
  589 // Sensor index 3: simulate binary data
  590 bit Get4_Binary7()
  591 //############################################################################################
  592 {
  593   // Make sure FSR1 is not modified
  594 
  595   bit sensorError = FALSE;
  596   // Fake humidity return value
  597   sensorValue.low8 = lastRSSI & 0x7F;
  598   // When error, return standard (FRC) error value(s)
  599   if ( sensorValue.low8 == 0x80 )
  600     sensorError = TRUE;
  601 
  602   // Test for supported FRC commands
  603   switch ( _PCMD )
  604   {
  605     default:
  606       return FALSE;
  607 
  608     case FRC_STD_SENSORS_BIT:
  609       // If there is a sensor error, 2-bit FRC cannot indicate it, it returns [01]
  610       if ( !sensorError )
  611       {
  612         // Number of shifts to get the bit out of the return value
  613         uns8 bitLoop = ( INDF1 >> 5 ) + 1;
  614         // Value to get the bit from
  615         W = sensorValue.low8;
  616         do
  617         {
  618           // Get the bit to Carry
  619           W = rr( W );
  620           // Next bit
  621         } while ( --bitLoop != 0 ); // Note: must not modify W and Carry
  622         // Current (prepared by DPA) FRC value is [01], change it to [11] (means bit is set)
  623         responseFRCvalue.1 = 1; // Note: must not modify Carry
  624         // Is bit set?
  625         if ( !Carry )
  626           // Bit is NOT set, return [10]
  627           responseFRCvalue.0 = 0;
  628       }
  629       break;
  630 
  631     case FRC_STD_SENSORS_1B:
  632       // Return sensor FRC value 1B
  633       if ( sensorError )
  634         return setFRCerror1B();
  635 
  636       responseFRCvalue = sensorValue.low8 + 4;
  637       break;
  638   }
  639   return TRUE;
  640 }
  641 
  642 //############################################################################################
  643 // 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) 
  644 #include "DPAcustomHandler.h"
  645 //############################################################################################