1 // *********************************************************************
    2 //   Custom DPA Handler code example - Standard Sensors - Template     *
    3 // *********************************************************************
    4 // Copyright (c) MICRORISC s.r.o.
    5 //
    6 // File:    $RCSfile: 1402_Sensor-Template.c,v $
    7 // Version: $Revision: 1.36 $
    8 // Date:    $Date: 2021/05/07 11:19:29 $
    9 //
   10 // Revision history:
   11 //   2020/01/09  Release for DPA 4.12
   12 //   2018/10/25  Release for DPA 3.03
   13 //   2017/11/16  Release for DPA 3.02
   14 //   2017/08/14  Release for DPA 3.01
   15 //
   16 // *********************************************************************
   17 
   18 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/
   19 // IQRF Standards documentation https://doc.iqrf.org/
   20 
   21 // This example implements 6 sensors according to the IQRF Sensors standard. The example does not implement writing data to the sensors.
   22 
   23 // Default IQRF include (modify the path according to your setup)
   24 #include "IQRF.h"
   25 
   26 // Default DPA header (modify the path according to your setup)
   27 #include "DPA.h"
   28 // Default Custom DPA Handler header (modify the path according to your setup)
   29 #include "DPAcustomHandler.h"
   30 // IQRF standards header (modify the path according to your setup)
   31 #include "IQRFstandard.h"
   32 #include "IQRF_HWPID.h"
   33 
   34 //############################################################################################
   35 
   36 // Number of implemented sensors
   37 #define SENSORS_COUNT 7
   38 
   39 // Variables to store sensor value at Get?_????() methods.
   40 uns16 sensorValue @ param3;
   41 uns16 sensorValueHighWord @ param4;
   42 
   43 // Reads sensor value to the sensorValue variable and to responseFRCvalue(2B,4B) variable(s) based on FRC 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 bit Get5_DataBlock();
   51 bit Get6_Binary30();
   52 
   53 // 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)
   54 void StoreValue( uns8 sensorType );
   55 
   56 // FRC parameter
   57 uns8  sensorIndexAndData;
   58 
   59 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
   60 //############################################################################################
   61 bit CustomDpaHandler()
   62 //############################################################################################
   63 {
   64   // 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)
   65 #pragma updateBank default = UserBank_01
   66 
   67 // Handler presence mark
   68   clrwdt();
   69 
   70   // Sleeping parameters, valid when Time != 0
   71   static TPerOSSleep_Request PerOSSleep_Request;
   72 
   73   // Detect DPA event to handle
   74   switch ( GetDpaEvent() )
   75   {
   76     // -------------------------------------------------
   77     case DpaEvent_Interrupt:
   78       // Do an extra quick background interrupt work
   79       // ! 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.
   80       // ! 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.
   81       // ! 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.
   82       // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy.
   83       // ! Make sure race condition does not occur when accessing those variables at other places.
   84       // ! 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.
   85       // ! Do not call any OS functions except setINDFx().
   86       // ! Do not use any OS variables especially for writing access.
   87       // ! 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.
   88       return Carry;
   89 
   90       // -------------------------------------------------
   91     case DpaEvent_Idle:
   92       // Do a quick background work when RF packet is not received
   93 
   94       // Should go to sleep?
   95       if ( PerOSSleep_Request.Time != 0 )
   96       {
   97         // Copy sleep parameters to the DPA request
   98         _DpaMessage.PerOSSleep_Request.Time = PerOSSleep_Request.Time;
   99         _DpaMessage.PerOSSleep_Request.Control = PerOSSleep_Request.Control;
  100         // Switch off sleeping time=flag
  101         PerOSSleep_Request.Time = 0;
  102         // Finalize OS Sleep DPA Request
  103         _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request );
  104         _PNUM = PNUM_OS;
  105         _PCMD = CMD_OS_SLEEP;
  106         // Perform local DPA Request to go to sleep
  107         DpaApiLocalRequest();
  108       }
  109       break;
  110 
  111       // -------------------------------------------------
  112     case DpaEvent_DpaRequest:
  113       // Called to interpret DPA request for peripherals
  114       // -------------------------------------------------
  115       // Peripheral enumeration
  116       if ( IsDpaEnumPeripheralsRequest() )
  117       {
  118         // We implement 1 standard peripheral
  119         _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1;
  120         FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS );
  121         // ToDo: use actual IQRF Alliance allocated HWPID and current version of this handler
  122         _DpaMessage.EnumPeripheralsAnswer.HWPID = HWPID_IQRF_TECH__DEMO_SENSOR_TEMPLATE;
  123         _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0002;
  124 
  125 DpaHandleReturnTRUE:
  126         return TRUE;
  127       }
  128       // -------------------------------------------------
  129       // Get information about peripheral
  130       else if ( IsDpaPeripheralInfoRequest() )
  131       {
  132         if ( _PNUM == PNUM_STD_SENSORS )
  133         {
  134           _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_STD_SENSORS;
  135           _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ;
  136           // Set standard version
  137           _DpaMessage.PeripheralInfoAnswer.Par1 = STD_SENSORS_VERSION;
  138           goto DpaHandleReturnTRUE;
  139         }
  140 
  141         break;
  142       }
  143       // -------------------------------------------------
  144       else
  145       {
  146         // Handle peripheral command
  147 
  148         // Supported peripheral number?
  149         if ( _PNUM == PNUM_STD_SENSORS )
  150         {
  151           // Supported commands?
  152           switch ( _PCMD )
  153           {
  154             // Invalid command
  155             default:
  156               // Return error
  157               DpaApiReturnPeripheralError( ERROR_PCMD );
  158 
  159               // Sensor enumeration
  160             case PCMD_STD_ENUMERATE:
  161               if ( _DpaDataLength != 0 )
  162                 goto _ERROR_DATA_LEN;
  163 
  164               // Then just enumerate their types
  165               _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_TEMPERATURE;
  166               _DpaMessage.Response.PData[1] = STD_SENSOR_TYPE_CO2;
  167               _DpaMessage.Response.PData[2] = STD_SENSOR_TYPE_VOC;
  168               _DpaMessage.Response.PData[3] = STD_SENSOR_TYPE_HUMIDITY;
  169               _DpaMessage.Response.PData[4] = STD_SENSOR_TYPE_BINARYDATA7;
  170               _DpaMessage.Response.PData[5] = STD_SENSOR_TYPE_DATA_BLOCK;
  171               _DpaMessage.Response.PData[6] = STD_SENSOR_TYPE_BINARYDATA30;
  172               W = SENSORS_COUNT;
  173               goto _W2_DpaDataLength;
  174 
  175               // Supported commands. They are handled the same way except one "if" at StoreValue() method
  176             case PCMD_STD_SENSORS_READ_VALUES:
  177             case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES:
  178             {
  179               // No sensor bitmap specified? W = _DpaDataLength. Note: W is used to avoid MOVLB at next if
  180               W = _DpaDataLength;
  181               if ( W == 0 ) // Note: must not modify W
  182               {
  183                 // Actually clears the bitmap
  184 #if &_DpaMessage.Request.PData[0] != &bufferRF[0]
  185 #error
  186 #endif
  187                 clearBufferRF();
  188                 // Simulate 1st only sensor in the bitmap (states of the other unimplemented sensors do not care)
  189                 _DpaMessage.Request.PData[0].0 = 1;
  190                 // Bitmap is 32 bits long = 4
  191                 _DpaDataLength = W = sizeof( _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap );
  192               }
  193 
  194               // Invalid bitmap (data) length (W = _DpaDataLength)?
  195               if ( W != sizeof( _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap ) )
  196               {
  197 _ERROR_DATA_LEN:
  198                 // Return error
  199                 DpaApiReturnPeripheralError( ERROR_DATA_LEN );
  200               }
  201 
  202               // Now read the sensors
  203 
  204               // Prepare pointer (minus 1, see below) to store sensor (types and) values to
  205               // Note: 7 sensors at this example cannot return more than DPA_MAX_DATA_LENGTH bytes of data, so it does not have to be checked...
  206               // ... If it would be the case, then ERROR_FAIL must be returned
  207               FSR1 = &_DpaMessage.Response.PData[-1];
  208 
  209               // Store bitmap of sensors to get values from
  210               uns8  sensorsBitmap = FSR1[1];
  211 
  212               // 1st sensor (index 0) selected?
  213               if ( sensorsBitmap.0 )
  214               {
  215                 Get0_Temperature();
  216                 StoreValue( STD_SENSOR_TYPE_TEMPERATURE );
  217               }
  218 
  219               // 2nd sensor (index 1) selected?
  220               if ( sensorsBitmap.1 )
  221               {
  222                 Get1_CO2();
  223                 StoreValue( STD_SENSOR_TYPE_CO2 );
  224               }
  225 
  226               // 3rd sensor (index 2) selected?
  227               if ( sensorsBitmap.2 )
  228               {
  229                 Get2_VOC();
  230                 StoreValue( STD_SENSOR_TYPE_VOC );
  231               }
  232 
  233               // 4th sensor (index 3) selected?
  234               if ( sensorsBitmap.3 )
  235               {
  236                 Get3_Humidity();
  237                 StoreValue( STD_SENSOR_TYPE_HUMIDITY );
  238               }
  239 
  240               // 5th sensor (index 4) selected?
  241               if ( sensorsBitmap.4 )
  242               {
  243                 Get4_Binary7();
  244                 StoreValue( STD_SENSOR_TYPE_BINARYDATA7 );
  245               }
  246 
  247               // 6th sensor (index 5) selected?
  248               if ( sensorsBitmap.5 )
  249               {
  250                 Get5_DataBlock();
  251                 StoreValue( STD_SENSOR_TYPE_DATA_BLOCK );
  252               }
  253 
  254               // 6th sensor (index 5) selected?
  255               if ( sensorsBitmap.6 )
  256               {
  257                 Get6_Binary30();
  258                 StoreValue( STD_SENSOR_TYPE_BINARYDATA30 );
  259               }
  260 
  261               // Compute returned data bytes count
  262               W = FSR1L - ( (uns16)&_DpaMessage.Response.PData[0] & 0xFF ) + 1;
  263               // Optimization: return W long block of bytes at response
  264 _W2_DpaDataLength:
  265               _DpaDataLength = W;
  266               goto DpaHandleReturnTRUE;
  267             }
  268           }
  269         }
  270 
  271         break;
  272       }
  273 
  274       // -------------------------------------------------
  275     case DpaEvent_Init:
  276       // Do a one time initialization before main loop starts
  277 
  278       // Setup all free GPIOs as inputs (used at Binary7 simulation)
  279       TRISA |= 0b0010.0001;
  280       TRISC |= 0b1111.1100;
  281       TRISB |= 0b0001.0000;
  282 
  283       break;
  284 
  285       // -------------------------------------------------
  286     case DpaEvent_FrcValue:
  287       // Called to get FRC value
  288 
  289       // FSR1 for optimization purposes (avoid MOVLB) will be used to point to DataOutBeforeResponseFRC[0...]
  290       FSR1 = &DataOutBeforeResponseFRC[0];
  291       // Check for correct FRC user data
  292       if ( *FSR1++ /*DataOutBeforeResponseFRC[0]*/ == PNUM_STD_SENSORS )
  293       {
  294         // Data and index
  295         sensorIndexAndData = FSR1[1]; /*DataOutBeforeResponseFRC[2]*/
  296         // Actually used sensor index
  297         uns8 sensorIndex = FSR1[1] /*DataOutBeforeResponseFRC[2]*/ & 0x1f;
  298         // Test sensor type
  299         switch ( *FSR1++ /*DataOutBeforeResponseFRC[1]*/ )
  300         {
  301           default:
  302             goto DpaHandleReturnFALSE;
  303 
  304             // No type specified, use specified index value
  305           case 0x00:
  306             goto _KeepSensorIndex;
  307 
  308             // For other types make the index value based on the requested index value and sensor type
  309           case STD_SENSOR_TYPE_TEMPERATURE:
  310             if ( sensorIndex > 0 )
  311               goto DpaHandleReturnFALSE;
  312             W = 0;
  313             break;
  314 
  315           case STD_SENSOR_TYPE_CO2:
  316             if ( sensorIndex > 0 )
  317               goto DpaHandleReturnFALSE;
  318             W = 1;
  319             break;
  320 
  321           case STD_SENSOR_TYPE_VOC:
  322             if ( sensorIndex > 0 )
  323               goto DpaHandleReturnFALSE;
  324             W = 2;
  325             break;
  326 
  327           case STD_SENSOR_TYPE_HUMIDITY:
  328             if ( sensorIndex > 0 )
  329               goto DpaHandleReturnFALSE;
  330             W = 3;
  331             break;
  332 
  333           case STD_SENSOR_TYPE_BINARYDATA7:
  334             if ( sensorIndex > 0 )
  335               goto DpaHandleReturnFALSE;
  336             W = 4;
  337             break;
  338 
  339           case STD_SENSOR_TYPE_BINARYDATA30:
  340             if ( sensorIndex > 0 )
  341               goto DpaHandleReturnFALSE;
  342             W = 6;
  343             break;
  344         }
  345 
  346         // New sensor index based on type and requested index
  347         sensorIndex = W;
  348 _KeepSensorIndex:
  349 
  350         // Test for supported FRC commands
  351         switch ( _PCMD )
  352         {
  353           default:
  354             goto DpaHandleReturnFALSE;
  355 
  356           case FRC_STD_SENSORS_BIT:
  357           case FRC_STD_SENSORS_1B:
  358           case FRC_STD_SENSORS_2B:
  359           case FRC_STD_SENSORS_4B:
  360             switch ( sensorIndex )
  361             {
  362               default:
  363                 goto DpaHandleReturnFALSE;
  364 
  365               case 0:
  366                 Carry = Get0_Temperature();
  367                 break;
  368 
  369               case 1:
  370                 Carry = Get1_CO2();
  371                 break;
  372 
  373               case 2:
  374                 Carry = Get2_VOC();
  375                 break;
  376 
  377               case 3:
  378                 Carry = Get3_Humidity();
  379                 break;
  380 
  381               case 4:
  382                 Carry = Get4_Binary7();
  383                 break;
  384 
  385               case 6:
  386                 Carry = Get6_Binary30();
  387                 break;
  388             }
  389 
  390             // This type of FRC is not valid for the specified sensor
  391             if ( !Carry )
  392               goto DpaHandleReturnFALSE;
  393 
  394             break;
  395         }
  396 
  397         // Some sensor was measured by FRC, check if there is a sleep request
  398         FSR1++;
  399         if ( INDF1.0 ) // Note: same as DataOutBeforeResponseFRC[3].0
  400         {
  401           // Remember sleep parameters to go to sleep at the Idle event later
  402           PerOSSleep_Request.Time.low8 = FSR1[4 - 3]; // Note: same as DataOutBeforeResponseFRC[4];
  403           PerOSSleep_Request.Time.high8 = FSR1[5 - 3]; // Note: same as DataOutBeforeResponseFRC[5];
  404           PerOSSleep_Request.Control = FSR1[6 - 3]; // Note: same as DataOutBeforeResponseFRC[6];
  405         }
  406       }
  407 
  408       break;
  409 
  410       // -------------------------------------------------
  411     case DpaEvent_FrcResponseTime:
  412       // Called to get FRC response time
  413 
  414       // In this example the FRC commands are fast
  415       switch ( DataOutBeforeResponseFRC[0] )
  416       {
  417         case FRC_STD_SENSORS_BIT:
  418         case FRC_STD_SENSORS_1B:
  419         case FRC_STD_SENSORS_2B:
  420         case FRC_STD_SENSORS_4B:
  421           responseFRCvalue = _FRC_RESPONSE_TIME_40_MS;
  422           break;
  423       }
  424       break;
  425   }
  426 DpaHandleReturnFALSE:
  427   return FALSE;
  428 }
  429 
  430 //############################################################################################
  431 // Increases FSR1 and then stores the byte
  432 void setPlusPlusINDF1( uns8 data @ W )
  433 //############################################################################################
  434 {
  435   FSR1++; // Note: must not modify W
  436   setINDF1( data );
  437 }
  438 
  439 //############################################################################################
  440 // Stores measured sensor value byte(s) and optionally sensor type to the FSR[+1...]
  441 void StoreValue( uns8 sensorType )
  442 //############################################################################################
  443 {
  444   // Is the sensor type to be stored too?
  445   if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES )
  446     setPlusPlusINDF1( sensorType );
  447 
  448   // Store lower value byte (or length in case of multiple bytes)
  449   setPlusPlusINDF1( sensorValue.low8 );
  450 
  451   // 2 bytes?
  452   if ( sensorType.7 == 0 )
  453   {
  454     // Store higher value byte
  455     setPlusPlusINDF1( sensorValue.high8 );
  456     return;
  457   }
  458 
  459   // 4 bytes?
  460   if ( ( sensorType & 0b1110.0000 ) == 0b1010.0000 )
  461   {
  462     setPlusPlusINDF1( sensorValue.high8 );
  463     setPlusPlusINDF1( sensorValueHighWord.low8 );
  464     setPlusPlusINDF1( sensorValueHighWord.high8 );
  465     return;
  466   }
  467 
  468   // Multiple bytes?
  469   if ( ( sensorType & 0b1100.0000 ) == 0b1100.0000 )
  470   {
  471     // Data is expected at bufferINFO, length at sensorValue.low8
  472     setFSR0( _FSR_INFO );
  473     do
  474     {
  475       // Store all data
  476       setPlusPlusINDF1( *FSR0++ );
  477     } while ( --sensorValue.low8 != 0 );
  478     return;
  479   }
  480 }
  481 
  482 //############################################################################################
  483 bit setFRCerror()
  484 //############################################################################################
  485 {
  486 #ifndef __CC5XFREE__
  487   responseFRCvalue4B = FRC_STD_FRC_ERROR_VALUE;
  488 #else
  489   responseFRCvalue4B.low16 = FRC_STD_FRC_ERROR_VALUE;
  490   responseFRCvalue4B.high16 = 0;
  491 #endif
  492   return TRUE;
  493 }
  494 
  495 //############################################################################################
  496 // Sensor index 0: measure temperature using the TR sensor
  497 bit Get0_Temperature()
  498 //############################################################################################
  499 {
  500   // Make sure FSR1 is not modified
  501 
  502   // Measure temperature using TR sensor
  503   bit sensorError = FALSE;
  504   // When error, then adjust the standard error values
  505   if ( getTemperature() == -128 )
  506   {
  507     sensorError = TRUE;
  508     STD_SENSOR_TYPE_TEMPERATURE_SET_ERROR( sensorValue );
  509   }
  510   else
  511   {
  512     // Extent minus sign bit
  513     if ( param3.11 )
  514       param3 |= 0xF000;
  515 
  516     // Return sensor value
  517     sensorValue = param3;
  518   }
  519 
  520   // Test for supported FRC commands
  521   switch ( _PCMD )
  522   {
  523     default:
  524       return FALSE;
  525 
  526     case FRC_STD_SENSORS_1B:
  527       // Return sensor FRC value 1B
  528       // Check for out of limits
  529       if ( sensorError || (int16)sensorValue > (int16)( 105.5 * 16 ) || (int16)sensorValue < ( (int16)-20 * 16 ) )
  530         return setFRCerror();
  531 
  532       // Convert to the "F = ( T + 22 ) * 2 " from 1/16 resolution
  533       responseFRCvalue2B = sensorValue + 4; // Note: do rounding when /8
  534       responseFRCvalue2B /= 8;
  535       responseFRCvalue += 44;
  536       break;
  537 
  538     case FRC_STD_SENSORS_2B:
  539       // Return sensor FRC value 2B
  540       if ( sensorError )
  541         return setFRCerror();
  542 
  543       responseFRCvalue2B = sensorValue ^ 0x8000;
  544       break;
  545   }
  546 
  547   return TRUE;
  548 }
  549 
  550 //############################################################################################
  551 // Sensor index 1: simulate measuring CO2
  552 bit Get1_CO2()
  553 //############################################################################################
  554 {
  555   // Make sure FSR1 is not modified
  556 
  557   bit sensorError = FALSE;
  558   // Fake CO2 return value
  559   sensorValue = 0x0987;
  560   // When error, return standard (FRC) error value(s)
  561   if ( STD_SENSOR_TYPE_CO2_IS_ERROR( sensorValue ) )
  562     sensorError = TRUE;
  563 
  564   // Test for supported FRC commands
  565   switch ( _PCMD )
  566   {
  567     default:
  568       return FALSE;
  569 
  570     case FRC_STD_SENSORS_1B:
  571       // Return sensor FRC value 1B
  572       // Check for out of limits
  573       if ( sensorError || sensorValue > 4016 )
  574         return setFRCerror();
  575 
  576       responseFRCvalue = sensorValue / 16 + 4;
  577       break;
  578 
  579     case FRC_STD_SENSORS_2B:
  580       // Return sensor FRC value 2B
  581       if ( sensorError )
  582         return setFRCerror();
  583 
  584       responseFRCvalue2B = sensorValue + 4;
  585       break;
  586   }
  587 
  588   return TRUE;
  589 }
  590 
  591 //############################################################################################
  592 // Sensor index 2: simulate measuring VOC
  593 bit Get2_VOC()
  594 //############################################################################################
  595 {
  596   // Make sure FSR1 is not modified
  597 
  598   bit sensorError = FALSE;
  599   // Fake VOC return value
  600   sensorValue = 0x0123;
  601   // When error, return standard (FRC) error value(s)
  602   if ( STD_SENSOR_TYPE_VOC_IS_ERROR( sensorValue ) )
  603     sensorError = TRUE;
  604 
  605   // Test for supported FRC commands
  606   switch ( _PCMD )
  607   {
  608     default:
  609       return FALSE;
  610 
  611     case FRC_STD_SENSORS_1B:
  612       // Return sensor FRC value 1B
  613       // Check for out of limits
  614       if ( sensorError || sensorValue > 4016 )
  615         return setFRCerror();
  616 
  617       responseFRCvalue = sensorValue / 16 + 4;
  618       break;
  619 
  620     case FRC_STD_SENSORS_2B:
  621       // Return sensor FRC value 2B
  622       if ( sensorError )
  623         return setFRCerror();
  624 
  625       responseFRCvalue2B = sensorValue + 4;
  626       break;
  627   }
  628 
  629   return TRUE;
  630 }
  631 
  632 //############################################################################################
  633 // Sensor index 3: simulate measuring humidity
  634 bit Get3_Humidity()
  635 //############################################################################################
  636 {
  637   // Make sure FSR1 is not modified
  638 
  639   // Fake humidity return value
  640   sensorValue.low8 = lastRSSI & 0x7F;
  641 
  642   // Test for supported FRC commands
  643   switch ( _PCMD )
  644   {
  645     default:
  646       return FALSE;
  647 
  648     case FRC_STD_SENSORS_1B:
  649       // Return sensor FRC value 1B
  650       if ( STD_SENSOR_TYPE_HUMIDITY_IS_ERROR( sensorValue.low8 ) )
  651         return setFRCerror();
  652 
  653       responseFRCvalue = sensorValue.low8 + 4;
  654       break;
  655   }
  656   return TRUE;
  657 }
  658 
  659 //############################################################################################
  660 // Sensor index 4: simulate binary data
  661 bit Get4_Binary7()
  662 //############################################################################################
  663 {
  664   // Make sure FSR1 is not modified
  665 
  666   bit sensorError = FALSE;
  667   // Fake humidity return value
  668   sensorValue.low8 = 0;
  669 
  670   // Get bits from the available user GPIO inputs (DDC-IO-01 can be used for the simulation)
  671   if ( PORTA.0 )  // SIM C1
  672     sensorValue.0 = 1;
  673   if ( PORTC.2 )  // SIM C2
  674     sensorValue.1 = 1;
  675   if ( PORTA.5 )  // SIM C5
  676     sensorValue.2 = 1;
  677   if ( PORTC.3 )  // SIM C6
  678     sensorValue.3 = 1;
  679   if ( PORTC.4 )  // SIM C7
  680     sensorValue.4 = 1;
  681   if ( PORTC.5 )  // SIM C8
  682     sensorValue.5 = 1;
  683 
  684   // When error, return standard (FRC) error value(s)
  685   if ( STD_SENSOR_TYPE_BINARYDATA7_IS_ERROR( sensorValue.low8 ) )
  686     sensorError = TRUE;
  687 
  688   // Test for supported FRC commands
  689   switch ( _PCMD )
  690   {
  691     default:
  692       return FALSE;
  693 
  694     case FRC_STD_SENSORS_BIT:
  695       // If there is a sensor error, 2-bit FRC cannot indicate it, it returns [01]
  696       if ( !sensorError )
  697       {
  698         // Number of shifts to get the bit out of the return value
  699         uns8 bitLoop = ( INDF1 >> 5 ) + 1;
  700         // Value to get the bit from
  701         W = sensorValue.low8;
  702         do
  703         {
  704           // Get the bit to Carry
  705           W = rr( W );
  706           // Next bit
  707         } while ( --bitLoop != 0 ); // Note: must not modify W and Carry
  708         // Current (prepared by DPA) FRC value is [01], change it to [11] (means bit is set)
  709         responseFRCvalue.1 = 1; // Note: must not modify Carry
  710         // Is bit set?
  711         if ( !Carry )
  712           // Bit is NOT set, return [10]
  713           responseFRCvalue.0 = 0;
  714       }
  715       break;
  716 
  717     case FRC_STD_SENSORS_1B:
  718       // Return sensor FRC value 1B
  719       if ( sensorError )
  720         return setFRCerror();
  721 
  722       responseFRCvalue = sensorValue.low8 + 4;
  723       break;
  724   }
  725   return TRUE;
  726 }
  727 
  728 //############################################################################################
  729 // Sensor index 5: simulate data block
  730 bit Get5_DataBlock()
  731 //############################################################################################
  732 {
  733   // Make sure FSR1 is not modified
  734   uns16 saveFSR1 = FSR1;
  735 
  736   // Get data to bufferINFO
  737   moduleInfo();
  738   // Return length
  739   sensorValue.low8 = sizeof( TModuleInfo );
  740 
  741   FSR1 = saveFSR1;
  742   return FALSE;
  743 }
  744 
  745 //############################################################################################
  746 // Sensor index 6: simulate 30 bit data
  747 bit Get6_Binary30()
  748 //############################################################################################
  749 {
  750   // Make sure FSR1 is not modified
  751   uns16 saveFSR1 = FSR1;
  752   moduleInfo();
  753   responseFRCvalue4B.low8 = sensorValue.low8 = ModuleInfo.MID[0];
  754   responseFRCvalue4B.midL8 = sensorValue.high8 = ModuleInfo.MID[1];
  755   responseFRCvalue4B.midH8 = sensorValueHighWord.low8 = ModuleInfo.MID[2];
  756   responseFRCvalue4B.high8 = sensorValueHighWord.high8 = ModuleInfo.MID[3];
  757   FSR1 = saveFSR1;
  758 
  759   // Test for supported FRC commands
  760   switch ( _PCMD )
  761   {
  762     default:
  763       // Return back default FRC value
  764       setFRCerror();
  765       responseFRCvalue--;
  766       return FALSE;
  767 
  768     case FRC_STD_SENSORS_2B:
  769       if ( ( sensorIndexAndData & 0b10.0000 ) != 0 )
  770 #ifndef __CC5XFREE__
  771         responseFRCvalue4B >>= 15;
  772 #else
  773       {
  774         // Carry = responseFRCvalue4B.15
  775         W = rl( responseFRCvalue4B.midH8 );
  776         responseFRCvalue4B.midL8 = rl( responseFRCvalue4B.midL8 );
  777         responseFRCvalue4B.low8 = rl( responseFRCvalue4B.low8 );
  778         responseFRCvalue4B.low16 = responseFRCvalue4B.high16;
  779       }
  780 #endif
  781 
  782       responseFRCvalue2B.15 = 0;
  783       // Note: fall through does the same as "responseFRCvalue2B += 4;"
  784 
  785     case FRC_STD_SENSORS_4B:
  786 #ifndef __CC5XFREE__
  787       responseFRCvalue4B += 4;
  788 #else
  789       W = 4;
  790       responseFRCvalue4B.low8 += W;
  791       W = 0;
  792       responseFRCvalue4B.midL8 = addWFC( responseFRCvalue4B.midL8 );
  793       responseFRCvalue4B.midH8 = addWFC( responseFRCvalue4B.midH8 );
  794       responseFRCvalue4B.high8 = addWFC( responseFRCvalue4B.high8 );
  795 #endif
  796       break;
  797   }
  798   return TRUE;
  799 }
  800 //############################################################################################
  801 
  802 // 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)
  803 #include "DPAcustomHandler.h"
  804 //############################################################################################