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