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