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