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