1 // ***********************************************************************************************************
    2 //   Custom DPA Handler code example - Standard Sensors - DDC-SE-01 - LP version                             *
    3 // ***********************************************************************************************************
    4 // Copyright (c) MICRORISC s.r.o.
    5 //
    6 // File:    $RCSfile: 4C02_DDC-SE_LP.c,v $
    7 // Version: $Revision: 1.27 $
    8 // Date:    $Date: 2022/09/12 12:34:37 $
    9 //
   10 // Revision history:
   11 //   2022/02/24  Release for DPA 4.17
   12 //   2021/08/20  Release for DPA 4.16
   13 //   2020/01/02  Release for DPA 4.11
   14 //   2019/03/07  Release for DPA 4.01
   15 //
   16 // *********************************************************************
   17 
   18 // MCR-BuildStdHandler
   19 #message '+CC5X -bu'
   20 
   21 #define _HWPID_     HWPID_IQRF_TECH__DEMO_DDC_SE01_LP
   22 #define _HWPIDver_  0x0000
   23 
   24 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/
   25 // IQRF Standards documentation https://doc.iqrf.org/
   26 
   27 // This example implements 3 sensors according to the IQRF Sensors standard
   28 // Index 0 i.e. 1st sensor is either Dallas 18B20 or MCP9802 temperature sensor at DDC-SE-01 board according to the HW jumper position and symbol DALLASnotMCP.
   29 // Index 1 i.e. 2nd sensor is light intensity indicator at DDC-SE-01 board (value range is 0[max light]-127[max dark]).
   30 // Index 2 i.e. 3rd sensor is potentiometer value at DDC-SE-01 board (value range is 0[left stop]-127[right stop]).
   31 
   32 // This example must be compiled without a "-bu" compiler switch in order to fit into available Flash memory
   33 
   34 // Default IQRF include (modify the path according to your setup)
   35 #include "IQRF.h"
   36 
   37 // We can save more instructions if needed by the symbol below
   38 // #define  PARAM_CHECK_LEVEL 1
   39 
   40 // Default DPA header (modify the path according to your setup)
   41 #include "DPA.h"
   42 // Default Custom DPA Handler header (modify the path according to your setup)
   43 #include "DPAcustomHandler.h"
   44 // IQRF standards header (modify the path according to your setup)
   45 #include "IQRFstandard.h"
   46 #include "IQRF_HWPID.h"
   47 
   48 // If defined then the handler is compiled for Dallas otherwise for MCP9802
   49 //#define   DALLASnotMCP
   50 
   51 //############################################################################################
   52 
   53 // Define useful macro that saves some code but not preset at DPA < 3.01
   54 #if DPA_VERSION_MASTER  < 0x0301
   55 // Optimized macro for both testing enumeration peripherals ELSE peripherals information. See examples
   56 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequestNoSize() if ( _PCMD == CMD_GET_PER_INFO ) if ( _PNUM == PNUM_ENUMERATION )
   57 
   58 #if PARAM_CHECK_LEVEL >= 2
   59 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() if ( _DpaDataLength == 0 && _PCMD == CMD_GET_PER_INFO ) if ( _PNUM == PNUM_ENUMERATION )
   60 #else
   61 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequestNoSize()
   62 #endif
   63 #endif
   64 
   65 //############################################################################################
   66 
   67 // Number of implemented sensors
   68 #define SENSORS_COUNT 3
   69 
   70 // Variable to store sensor value at Get?_????() methods. This example implements sensors returning maximum 2 bytes of data.
   71 uns16 sensorValue @ param3;
   72 
   73 // Reads sensor value to the sensorValue variable and to responseFRCvalue(2B) variable
   74 bit Get0_Temperature();
   75 bit Get1_BinaryData_Light();
   76 bit Get2_BinaryData_Potentiometer();
   77 
   78 // 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)
   79 void StoreValue( uns8 sensorType );
   80 
   81 #ifdef DALLASnotMCP
   82 // Sensor connected to PORT C.3 (compatible with DDC-SE-01)
   83 #define OneWire_TRIS         TRISC.3
   84 #define OneWire_IO_IN        PORTC.3
   85 #define OneWire_IO_OUT       LATC.3
   86 
   87 // ms per ticks
   88 #define TICKS_LEN  10
   89 
   90 // Writes sensor configuration (resolution)
   91 bit Ds18B20WriteConfig( uns8 value );
   92 
   93 // Resets OneWire
   94 bit OneWireReset();
   95 // Reads OneWire byte
   96 uns8 OneWireReadByte();
   97 // Writes OneWire byte
   98 void OneWireWriteByte( uns8 byte );
   99 
  100 // DS18B20 commands
  101 #define CMD_READROM       0x33
  102 #define CMD_CONVERTTEMP   0x44
  103 #define CMD_CPYSCRATCHPAD 0x48
  104 #define CMD_WSCRATCHPAD   0x4e
  105 #define CMD_MATCHROM      0x55
  106 #define CMD_RPWRSUPPLY    0xb4
  107 #define CMD_RECEEPROM     0xb8
  108 #define CMD_RSCRATCHPAD   0xbe
  109 #define CMD_SKIPROM       0xcc
  110 #define CMD_ALARMSEARCH   0xec
  111 #define CMD_SEARCHROM     0xf0
  112 
  113 // Final DS18B20 temperature value read by state machine
  114 uns16 temperature;
  115 
  116 #else // DALLASnotMCP
  117 
  118 // I2C SCL frequency [Hz]
  119 #define I2Cfrequency      50000
  120 
  121 // MCP9802 address
  122 #define I2C_ADR           0b1001.0110
  123 
  124 #endif
  125 
  126 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
  127 //############################################################################################
  128 bit CustomDpaHandler()
  129 //############################################################################################
  130 {
  131   // 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)
  132 #pragma updateBank default = UserBank_01
  133 
  134 #ifdef DALLASnotMCP
  135   // Finite machine states
  136   typedef enum
  137   {
  138     S_ResetConvertT = 0,
  139     S_SkipRomConvertT,
  140     S_CmdConvertT,
  141 
  142     S_WaitConvertT,
  143 
  144     S_ResetReadTemp,
  145     S_SkipRomReadTemp,
  146     S_CmdReadTemp,
  147     S_Byte1ReadTemp,
  148     S_Byte2ReadTemp
  149   } TState;
  150 #endif
  151 
  152   // Handler presence mark
  153   clrwdt();
  154 
  155   // Sleeping parameters, valid when Time != 0
  156   static TPerOSSleep_Request PerOSSleep_Request;
  157 
  158 #ifdef DALLASnotMCP
  159   // Finite machine state
  160   static uns8 state; // = S_ResetConvertT = 0
  161   // Pre-read lower temperature byte
  162   static uns8 temperatureByteLow;
  163   // Conversion timeout counter
  164   static uns16 timeoutStart;
  165 #endif
  166 
  167   // Detect DPA event to handle
  168   switch ( GetDpaEvent() )
  169   {
  170     // -------------------------------------------------
  171     case DpaEvent_Interrupt:
  172       // Do an extra quick background interrupt work
  173 
  174       return Carry;
  175 
  176       // -------------------------------------------------
  177     case DpaEvent_Idle:
  178       // Do a quick background work when RF packet is not received
  179 
  180       // Should go to sleep?
  181       if ( PerOSSleep_Request.Time != 0 )
  182       {
  183         // Copy sleep parameters to the DPA request
  184         _DpaMessage.PerOSSleep_Request.Time = PerOSSleep_Request.Time;
  185         _DpaMessage.PerOSSleep_Request.Control = PerOSSleep_Request.Control;
  186         // Finalize OS Sleep DPA Request
  187         _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request );
  188         _PNUM = PNUM_OS;
  189         _PCMD = CMD_OS_SLEEP;
  190 #ifndef DALLASnotMCP
  191         // I2C down
  192         _DpaApiI2Cshutdown();
  193 #endif
  194         // Perform local DPA Request to go to sleep
  195         DpaApiLocalRequest();
  196 #ifndef DALLASnotMCP
  197         // I2C up
  198         _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) );
  199 #endif
  200         // Switch off sleeping time=flag
  201         PerOSSleep_Request.Time = 0;
  202       }
  203 
  204 #ifdef DALLASnotMCP
  205       // Run finite state machine to read temperature from DS18B20 at background so the temperature value is immediately ready for FRC
  206 
  207       // Make sure 1Wire data pin at LATX.y is low as it might be set by another PORTX.? pin manipulation
  208       OneWire_IO_OUT = 0;
  209 
  210       skip( state );
  211 #pragma computedGoto 1
  212       goto _S_ResetConvertT;
  213       goto _S_SkipRomConvertT;
  214       goto _S_CmdConvertT;
  215       goto _S_WaitConvertT;
  216       goto _S_ResetReadTemp;
  217       goto _S_SkipRomReadTemp;
  218       goto _S_CmdReadTemp;
  219       goto _S_Byte1ReadTemp;
  220       goto _S_Byte2ReadTemp;
  221 #pragma computedGoto 0
  222       ;
  223       // --------------
  224 _S_Byte2ReadTemp:
  225       temperature.high8 = OneWireReadByte();
  226       temperature.low8 = temperatureByteLow;
  227 
  228 ResetMachine:
  229       state = S_ResetConvertT;
  230       goto ExitMachine;
  231 
  232       // --------------
  233 _S_ResetConvertT:
  234 _S_ResetReadTemp:
  235       if ( !OneWireReset() )
  236       {
  237 _S_Error_Reset:
  238         STD_SENSOR_TYPE_TEMPERATURE_SET_ERROR( temperature );
  239         goto ResetMachine;
  240       }
  241       goto NextState;
  242 
  243       // --------------
  244 _S_SkipRomConvertT:
  245 _S_SkipRomReadTemp:
  246       // OneWire: Skip ROM
  247       OneWireWriteByte( CMD_SKIPROM );
  248       goto NextState;
  249 
  250       // --------------
  251 _S_CmdConvertT:
  252       // OneWire: Convert temperature
  253       OneWireWriteByte( CMD_CONVERTTEMP );
  254       // Start timeout for approx 750 ms (the longest conversion time)
  255       captureTicks();
  256       // Remember start time
  257       timeoutStart = param3;
  258       goto NextState;
  259 
  260       // --------------
  261 _S_WaitConvertT:
  262       // Measured?
  263       if ( OneWireReadByte() == 0xff )
  264         goto NextState;
  265 
  266       // Timeout?
  267       captureTicks();
  268       param3 -= timeoutStart;
  269       // Yes!
  270       if ( param3 > ( 2 + 750 / TICKS_LEN ) )
  271         goto _S_Error_Reset;
  272 
  273       goto ExitMachine;
  274 
  275       // --------------
  276 _S_CmdReadTemp:
  277       // OneWire: Read scratchpad
  278       OneWireWriteByte( CMD_RSCRATCHPAD );
  279       goto NextState;
  280 
  281       // --------------
  282 _S_Byte1ReadTemp:
  283       temperatureByteLow = OneWireReadByte();
  284       goto NextState;
  285 
  286       // --------------
  287 NextState:
  288       ++state;
  289 
  290 ExitMachine:
  291 #endif
  292       break;
  293 
  294       // -------------------------------------------------
  295     case DpaEvent_Init:
  296       // Do a one time initialization before main loop starts
  297 
  298       // Initialize ticks
  299       startCapture();
  300 
  301       // Initialize sensors
  302       // C5 (AN4) as input
  303       moduleInfo();
  304       // Connected TR pins?
  305       if ( !bufferINFO[5].7 )
  306       {
  307         TRISC.6 = 1;
  308         TRISB.4 = 1;
  309       }
  310       TRISA.5 = 1;
  311 
  312       // C1 (AN0) as input
  313       TRISA.0 = 1;
  314 
  315 #ifdef DALLASnotMCP
  316       // Setup DS18B20 for 9bit precision, conversion takes 94ms (see datasheet)
  317       Ds18B20WriteConfig( 0b0.00.00000 );
  318 #else
  319       // Expect MCP9802 is enabled
  320       I2Ctimeout = 0xFF;
  321 
  322 #if defined( TR7xG )
  323       // Do PPS for I2C
  324       unlockPPS();
  325       SSP1CLKPPS = 0x13;  // RC3
  326       SSP1DATPPS = 0x14;  // RC4
  327       RC3PPS = 0x14;      // SCK1/SCL1
  328       RC4PPS = 0x15;      // SD01/SDA1
  329       lockPPS();
  330 #endif
  331 
  332       _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) );
  333 #endif
  334       break;
  335 
  336       // -------------------------------------------------
  337     case DpaEvent_AfterSleep:
  338       // Called after woken up after sleep
  339 #ifndef DALLASnotMCP
  340       _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) );
  341 #endif
  342 
  343       break;
  344 
  345       // -------------------------------------------------
  346     case DpaEvent_BeforeSleep:
  347       // Called before going to sleep
  348 #ifndef DALLASnotMCP
  349       _DpaApiI2Cshutdown();
  350 #endif
  351       break;
  352 
  353       // -------------------------------------------------
  354     case DpaEvent_DpaRequest:
  355       // Called to interpret DPA request for peripherals
  356       // -------------------------------------------------
  357       // Peripheral enumeration
  358       IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest()
  359       {
  360         // We implement 2 standard peripherals
  361         _DpaMessage.EnumPeripheralsAnswer.UserPerNr |=  1;
  362         FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS );
  363         _DpaMessage.EnumPeripheralsAnswer.HWPID |= _HWPID_;
  364         _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= _HWPIDver_;
  365 
  366 DpaHandleReturnTRUE:
  367         return TRUE;
  368       }
  369       // -------------------------------------------------
  370       // Get information about peripherals
  371       else
  372       {
  373         switch ( _DpaMessage.PeripheralInfoAnswer.PerT = _PNUM )
  374         {
  375           case PNUM_STD_SENSORS:
  376             // Set standard version
  377             _DpaMessage.PeripheralInfoAnswer.Par1 = STD_SENSORS_VERSION;
  378             _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE;
  379             goto DpaHandleReturnTRUE;
  380         }
  381 
  382         break;
  383       }
  384 
  385       {
  386         // -------------------------------------------------
  387         // Handle peripheral command
  388 
  389         // Supported peripheral number?
  390         switch ( _PNUM )
  391         {
  392           case PNUM_STD_SENSORS:
  393           {
  394             // Supported commands?
  395             switch ( _PCMD )
  396             {
  397               // Invalid command
  398               default:
  399               {
  400                 // Return error
  401 _ERROR_PCMD:
  402                 W = ERROR_PCMD;
  403 _ERROR_W:
  404                 DpaApiReturnPeripheralError( W );
  405               }
  406 
  407               // Sensor enumeration
  408               case PCMD_STD_ENUMERATE:
  409                 if ( _DpaDataLength != 0 )
  410                 {
  411 _ERROR_DATA_LEN:
  412                   W = ERROR_DATA_LEN;
  413                   goto _ERROR_W;
  414                 }
  415 
  416                 _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_TEMPERATURE;
  417                 _DpaMessage.Response.PData[1] = STD_SENSOR_TYPE_BINARYDATA7;
  418                 _DpaMessage.Response.PData[2] = STD_SENSOR_TYPE_BINARYDATA7;
  419                 W = SENSORS_COUNT;
  420                 goto _W2_DpaDataLength;
  421 
  422                 // Supported commands. They are handled the same way except one "if" at StoreValue() method
  423               case PCMD_STD_SENSORS_READ_VALUES:
  424               case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES:
  425               {
  426                 // No sensor bitmap specified? W = _DpaDataLength. Note: W is used to avoid MOVLB at next if
  427                 W = _DpaDataLength;
  428                 if ( W == 0 )   // Note: must not modify W
  429                 {
  430                   // Actually clears the bitmap
  431 #if &_DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap[0] != &bufferRF[0]
  432 #error Cannot use clearBufferRF for clearing bitmap
  433 #endif
  434                   clearBufferRF();
  435                   // Simulate 1st only sensor in the bitmap (states of the other unimplemented sensors do not care)
  436                   _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap[0].0 = 1;
  437                   // Bitmap is 32 bits long
  438                   _DpaDataLength = W = sizeof( _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap );
  439                 }
  440 
  441                 // Invalid bitmap (data) length (W = _DpaDataLength)?
  442                 if ( W != sizeof( _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap ) )
  443                   goto _ERROR_DATA_LEN;
  444 
  445                 // Now read the sensors
  446 
  447                 // Prepare pointer (minus 1, see below) to store sensor (types and) values to
  448                 // Note: 3 sensors at this example cannot return more than DPA_MAX_DATA_LENGTH bytes of data, so it does not have to be checked...
  449                 // ... If it would be the case, then ERROR_FAIL must be returned
  450                 FSR1 = &_DpaMessage.Response.PData[-1];
  451 
  452                 // Store bitmap of sensors to get values from
  453                 uns8 sensorsBitmap = FSR1[1 + offsetof( TPerStdSensorRead_Request, Bitmap )];
  454 
  455                 // 1st sensor (index 0) selected?
  456                 if ( sensorsBitmap.0 )
  457                 {
  458                   Get0_Temperature();
  459                   StoreValue( STD_SENSOR_TYPE_TEMPERATURE );
  460                 }
  461 
  462                 // 2nd sensor (index 1) selected?
  463                 if ( sensorsBitmap.1 )
  464                 {
  465                   Get1_BinaryData_Light();
  466                   StoreValue( STD_SENSOR_TYPE_BINARYDATA7 );
  467                 }
  468 
  469                 // 3rd sensor (index 2) selected?
  470                 if ( sensorsBitmap.2 )
  471                 {
  472                   Get2_BinaryData_Potentiometer();
  473                   StoreValue( STD_SENSOR_TYPE_BINARYDATA7 );
  474                 }
  475 
  476                 // Compute returned data bytes count
  477                 W = FSR1L - ( (uns16)&_DpaMessageIqrfStd & 0xFF ) + 1;
  478                 // Optimization: return W long block of bytes at response
  479 _W2_DpaDataLength:
  480                 _DpaDataLength = W;
  481                 goto DpaHandleReturnTRUE;
  482               }
  483             }
  484           }
  485         }
  486 
  487         break;
  488       }
  489 
  490       // -------------------------------------------------
  491     case DpaEvent_FrcValue:
  492       // Called to get FRC value
  493 
  494       // FSR1 for optimization purposes (avoid MOVLB) will be used to point to DataOutBeforeResponseFRC[0...]
  495       FSR1 = (uns16)&PerStdSensorFrc;
  496 #if offsetof( TPerStdSensorFrc, Header ) != 0 || offsetof( TPerStdSensorFrc, SensorType ) != 1 || offsetof( TPerStdSensorFrc, Options ) != 3
  497 #error Cannot optimize
  498 #endif
  499       // Check for correct FRC user data
  500       if ( *FSR1++ /* PerStdSensorFrc.Header */ == PNUM_STD_SENSORS )
  501       {
  502         // Actually used sensor index
  503         uns8 sensorIndex = FSR1[offsetof( TPerStdSensorFrc, SensorIndex ) - 1] & 0x1f;
  504         // Test sensor type
  505         switch ( *FSR1++ /* PerStdSensorFrc.SensorType */ )
  506         {
  507           default:
  508             goto DpaHandleReturnFALSE;
  509 
  510             // No type specified, use specified index value
  511           case 0x00:
  512             goto _KeepSensorIndex;
  513 
  514             // For other types make the index value based on the requested index value and sensor type
  515           case STD_SENSOR_TYPE_TEMPERATURE:
  516             if ( sensorIndex > 0 )
  517               goto DpaHandleReturnFALSE;
  518             W = 0 + sensorIndex;
  519             break;
  520 
  521           case STD_SENSOR_TYPE_BINARYDATA7:
  522             if ( sensorIndex > 1 )
  523               goto DpaHandleReturnFALSE;
  524             W = 1 + sensorIndex;
  525             break;
  526         }
  527 
  528         // New sensor index based on type and requested index
  529         sensorIndex = W;
  530 _KeepSensorIndex:
  531 
  532         // Test for supported FRC commands
  533         switch ( _PCMD )
  534         {
  535           default:
  536             goto DpaHandleReturnFALSE;
  537 
  538           case FRC_STD_SENSORS_BIT:
  539           case FRC_STD_SENSORS_1B:
  540           case FRC_STD_SENSORS_2B:
  541             switch ( sensorIndex )
  542             {
  543               default:
  544                 goto DpaHandleReturnFALSE;
  545 
  546               case 0:
  547                 Carry = Get0_Temperature();
  548                 break;
  549 
  550               case 1:
  551                 Carry = Get1_BinaryData_Light();
  552                 break;
  553 
  554               case 2:
  555                 Carry = Get2_BinaryData_Potentiometer();
  556                 break;
  557             }
  558 
  559             // This type of FRC is not valid for the specified sensor
  560             if ( !Carry )
  561               goto DpaHandleReturnFALSE;
  562 
  563             break;
  564         }
  565 
  566         // Some sensor was measured by FRC, check if there is a sleep request
  567         FSR1++;
  568         if ( INDF1.0 ) // Note: same as PerStdSensorFrc.Options.0
  569         {
  570           // Remember sleep parameters to go to sleep at the Idle event later
  571           PerOSSleep_Request.Time.low8 = FSR1[offsetof( TPerOSSleep_Request, Time ) + 0 + offsetof( TPerStdSensorFrc, SleepParameters ) - 3];
  572           PerOSSleep_Request.Time.high8 = FSR1[offsetof( TPerOSSleep_Request, Time ) + 1 + offsetof( TPerStdSensorFrc, SleepParameters ) - 3];
  573           PerOSSleep_Request.Control = FSR1[offsetof( TPerOSSleep_Request, Control ) + offsetof( TPerStdSensorFrc, SleepParameters ) - 3];
  574         }
  575       }
  576 
  577       break;
  578 
  579       // -------------------------------------------------
  580     case DpaEvent_FrcResponseTime:
  581       // Called to get FRC response time
  582 
  583       // In this example the FRC commands are fast
  584       switch ( DataOutBeforeResponseFRC[0] )
  585       {
  586         case FRC_STD_SENSORS_BIT:
  587         case FRC_STD_SENSORS_1B:
  588         case FRC_STD_SENSORS_2B:
  589           responseFRCvalue = _FRC_RESPONSE_TIME_40_MS;
  590           break;
  591       }
  592       break;
  593   }
  594 DpaHandleReturnFALSE:
  595   return FALSE;
  596 }
  597 
  598 //############################################################################################
  599 bit returnTRUE()
  600 //############################################################################################
  601 {
  602   return TRUE;
  603 }
  604 
  605 //############################################################################################
  606 bit returnFALSE()
  607 //############################################################################################
  608 {
  609   return FALSE;
  610 }
  611 
  612 //############################################################################################
  613 // Increases FSR1 and then stores the byte
  614 void setPlusPlusINDF1( uns8 data @ W )
  615 //############################################################################################
  616 {
  617   FSR1++; // Note: must not modify W
  618   setINDF1( data );
  619 }
  620 
  621 //############################################################################################
  622 // Stores measured sensor value byte(s) and optionally sensor type to the FSR[+1...]
  623 void StoreValue( uns8 sensorType )
  624 //############################################################################################
  625 {
  626   // Is the sensor type to be stored too?
  627   if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES )
  628     setPlusPlusINDF1( sensorType );
  629 
  630   // Store lower value byte
  631   setPlusPlusINDF1( sensorValue.low8 );
  632 
  633   // No more value bytes to store?
  634   if ( sensorType.7 != 0 )
  635     return;
  636 
  637   // Store higher value byte
  638   setPlusPlusINDF1( sensorValue.high8 );
  639 
  640   // Note: this example implements sensors returning only 1 or 2 bytes of data. If another data widths are returned, then it must be implemented explicitly.
  641 }
  642 
  643 //############################################################################################
  644 bit setFRCerror()
  645 //############################################################################################
  646 {
  647   responseFRCvalue2B = FRC_STD_FRC_ERROR_VALUE;
  648   return returnTRUE();
  649 }
  650 
  651 //############################################################################################
  652 bit sensorError;
  653 bit AdjustFrcTemperature()
  654 //############################################################################################
  655 {
  656   // Test for supported FRC commands
  657   switch ( _PCMD )
  658   {
  659     default:
  660       return returnFALSE();
  661 
  662     case FRC_STD_SENSORS_1B:
  663       // Return sensor FRC value 1B
  664       // Check for out of limits
  665       if ( sensorError || (int16)sensorValue > (int16)( 105.5 * 16 ) || (int16)sensorValue < ( (int16)-20 * 16 ) )
  666         return setFRCerror();
  667 
  668       // Convert to the "F = ( T + 22 ) * 2 " from 1/16 resolution
  669       responseFRCvalue2B = sensorValue + 4; // Note: do rounding when /8
  670       responseFRCvalue2B /= 8;
  671       responseFRCvalue += 44;
  672       break;
  673 
  674     case FRC_STD_SENSORS_2B:
  675       // Return sensor FRC value 2B
  676       if ( sensorError )
  677         return setFRCerror();
  678 
  679       responseFRCvalue2B = sensorValue ^ 0x8000;
  680       break;
  681   }
  682 
  683   return returnTRUE();
  684 }
  685 
  686 //############################################################################################
  687 // Sensor index 1: measure temperature using one of the DDC-SE-01 sensors
  688 bit Get0_Temperature()
  689 //############################################################################################
  690 {
  691   // Make sure FSR1 is not modified
  692 
  693   // Measure temperature using DDC-SE-01 sensors
  694   // Read temperature and check for an error
  695 
  696   // Reads temperature from an enabled sensor
  697 #ifdef DALLASnotMCP
  698   sensorError = FALSE;
  699   // Temperature is ready at the background
  700   sensorValue = temperature;
  701   // When error, return standard (FRC) error value(s)
  702   if ( STD_SENSOR_TYPE_TEMPERATURE_IS_ERROR( sensorValue ) )
  703     sensorError = TRUE;
  704 #else
  705   sensorError = TRUE;
  706   // Temperature value must be read from I2C sensor
  707   STD_SENSOR_TYPE_TEMPERATURE_SET_ERROR( sensorValue );
  708   // MCP9802 address
  709   _DpaApiI2Cstart( I2C_ADR );
  710   if ( !I2CwasTimeout )
  711   {
  712     // pointer: 1 = configuration register
  713     _DpaApiI2Cwrite( 0x01 );
  714     // configuration: 9-bit ADC
  715     _DpaApiI2CwriteAndStop( 0x00 );
  716 
  717     // MCP9802 address
  718     _DpaApiI2Cstart( I2C_ADR );
  719     // pointer: 0 = temperature
  720     _DpaApiI2CwriteAndStop( 0 );
  721 
  722     // MCP9802 address + read
  723     _DpaApiI2Cstart( I2C_ADR | 1 );
  724     // store the result
  725     sensorValue.high8 = _DpaApiI2Cread( TRUE );
  726     sensorValue.low8 = _DpaApiI2Cread( FALSE );
  727     _DpaApiI2Cstop();
  728 
  729     sensorValue += 0x10 / 2;
  730     sensorValue /= 0x10;
  731 
  732     sensorError = FALSE;
  733   }
  734 #endif
  735 
  736   // FrcValues
  737   return AdjustFrcTemperature();
  738 }
  739 
  740 //############################################################################################
  741 bit Get_BinaryData_Final( uns8 _ADCcfg @ W )
  742 //############################################################################################
  743 {
  744 #if defined( TR7xG )
  745   ADPCH = _ADCcfg;
  746 #else
  747   ADCON0 = _ADCcfg;
  748 #endif
  749 
  750   // Read ADC
  751 
  752 #if defined( TR7xG )
  753   // ADC is enabled, ADGO is cleared upon completion, Clock supplied according to ADCLK register, left-justified
  754   ADCON0 = 0b1000.0000;
  755   // ADC Conversion Clock = FOSC/8
  756   ADCLK = 8 / 2 - 1;
  757 #else
  758   // ADC result - left justified, Fosc/8
  759   ADCON1 = 0b0001.0000;
  760 #endif
  761 
  762   // Short delay to stabilize
  763   updateCRC16( W );
  764 
  765   // start ADC
  766   _GO = 1;
  767   // wait for ADC finish
  768   while ( _GO );
  769   // Get ADC value
  770   sensorValue.low8 = ADRESH / 2;
  771 
  772   // Return sensor FRC value
  773 
  774   // Test for supported FRC commands
  775   switch ( _PCMD )
  776   {
  777     default:
  778       return returnFALSE();
  779 
  780     case FRC_STD_SENSORS_BIT:
  781       // If there is a sensor error, 2-bit FRC cannot indicate it, it returns [01]
  782 
  783       // Number of shifts to get the bit out of the return value
  784       uns8 bitLoop = ( INDF1 >> 5 ) + 1;
  785       // Value to get the bit from
  786       W = sensorValue.low8;
  787       do
  788       {
  789         // Get the bit to Carry
  790         W = rr( W );
  791         // Next bit
  792       } while ( --bitLoop != 0 ); // Note: must not modify W and Carry
  793       // Carry = bit = x
  794       // Current (prepared by DPA) FRC value is [01], change it to [1x]
  795       responseFRCvalue = rl( responseFRCvalue );
  796       break;
  797 
  798     case FRC_STD_SENSORS_1B:
  799       responseFRCvalue = sensorValue.low8 + 4;
  800       break;
  801   }
  802 
  803   return returnTRUE();
  804 }
  805 
  806 #if defined( TR7xG )
  807 //############################################################################################
  808 // Might not be needed if ADC registers are kept default
  809 void resetADCregs()
  810 //############################################################################################
  811 {
  812   // Start reseting ADC registers from ADCON0 to ADPCH
  813   FSR0 = &ADCON0;
  814   do
  815   {
  816     setINDF0( 0 );
  817     FSR0++;
  818     // Stop reseting at 1st GPR register, ADPCH is the last implemented register before GPR
  819   } while ( !FSR0L.5 );
  820 }
  821 #endif
  822 
  823 //############################################################################################
  824 // Sensor index 1: returns light intensity indicator value using DDC-SE-01
  825 bit Get1_BinaryData_Light()
  826 //############################################################################################
  827 {
  828   // Make sure FSR1 is not modified
  829 
  830   // ADC initialization (for more info see PIC datasheet) pin C1 (AN0-D/ANA0-G) as analog input
  831   ANSELA.0 = 1;
  832 #if defined( TR7xG )
  833   // Enable ADC
  834   ADCMD = 0;
  835   // Resets all ADC registers
  836   // VREF- is connected to AVSS, VREF+ is connected to VDD
  837   resetADCregs();
  838   //  ADC Positive Input Channel = ANA0
  839   return Get_BinaryData_Final( 0x00 );
  840 #else
  841   // ADC setting (AN0 channel)
  842   return Get_BinaryData_Final( 0b0.00000.01 );
  843 #endif
  844 }
  845 
  846 //############################################################################################
  847 // Sensor index 2: returns potentiometer value using DDC-SE-01
  848 bit Get2_BinaryData_Potentiometer()
  849 //############################################################################################
  850 {
  851   // Make sure FSR1 is not modified
  852 
  853   // ADC initialization (for more info see PIC datasheet) pin C5 (AN4-D/ANA5-G) as analog input
  854   ANSELA.5 = 1;
  855 #if defined( TR7xG )
  856   // Enable ADC
  857   ADCMD = 0;
  858   // Resets all ADC registers
  859   // VREF- is connected to AVSS, VREF+ is connected to VDD
  860   resetADCregs();
  861   //  ADC Positive Input Channel = ANA5
  862   return Get_BinaryData_Final( 0x05 );
  863 #else
  864   // ADC setting (AN4 channel)
  865   return Get_BinaryData_Final( 0b0.00100.01 );
  866 #endif
  867 }
  868 
  869 #ifdef DALLASnotMCP
  870 //############################################################################################
  871 // OneWire and Dallas 18B20 routines
  872 //############################################################################################
  873 
  874 //############################################################################################
  875 void Delay5us( uns8 val @ W ) // Absolutely precise timing but val != 0
  876 //############################################################################################
  877 {
  878   // 16 MHz
  879   // + 0.75us ( W=val, Call )
  880   for ( ;; )
  881   {         // loop time
  882     nop2(); // 0.50us
  883     nop2(); // 1.00us
  884     nop2(); // 1.50us
  885     nop2(); // 2.00us
  886     nop2(); // 2.50us
  887     nop2(); // 3.00us
  888     nop();  // 3.25us
  889     if ( --val == 0 ) // + 0.75us (W--, BTFS )
  890       return;         // + 0.25us
  891     nop2(); // 4.50us
  892   }         // 5.00us (Goto)
  893 }
  894 //############################################################################################
  895 
  896 #define OneWireData0()  { OneWire_TRIS = 0; }     // 0.5us @ 16MHz
  897 #define OneWireData1()  { OneWire_TRIS = 1; }     // 0.5us @ 16MHz
  898 
  899 //############################################################################################
  900 void OneWireWriteByte( uns8 byte )
  901 //############################################################################################
  902 {
  903   uns8 bitLoop = 8;
  904   do
  905   {
  906     // Next sequence is time precision critical
  907     GIE = FALSE;
  908 
  909     OneWireData0();
  910     nop2();         // 1 us [0.5 us]
  911     nop2();         // [1.0 us]
  912     if ( byte.0 )   // 2.5 us [1.75us]
  913       OneWireData1();
  914 
  915     // End of time precision critical sequence
  916     GIE = TRUE;
  917 
  918     // 60us minimum in total, does not have to be precise
  919     Delay5us( ( 60 - 3 ) / 5 + 1 );
  920 
  921     OneWireData1();
  922 
  923     byte >>= 1;
  924   } while ( --bitLoop != 0 );
  925 }
  926 
  927 //############################################################################################
  928 uns8 OneWireReadByte()
  929 //############################################################################################
  930 {
  931   uns8 result;
  932   uns8 bitLoop = 8;
  933   do
  934   {
  935     // Next sequence is time precision critical
  936     GIE = FALSE;
  937 
  938     OneWireData0();
  939     nop2();         // 1 us [0.5 us]
  940     nop2();         // [1.0 us]
  941     OneWireData1();         // 2 us [1.5 us]
  942     Delay5us( 15 / 5 );     // 17 us [16.5 us]
  943 
  944     Carry = 0;              // 17.5 us [16.75 us]
  945     if ( OneWire_IO_IN )    // 18.5 us [ 17.25 us] (condition must not modify Carry)
  946       Carry = 1;
  947 
  948     // End of time precision critical sequence
  949     GIE = TRUE;             // must not modify Carry
  950     result = rr( result );
  951 
  952     // 60us minimum in total, does not have to be precise
  953     Delay5us( ( 60 - 20 ) / 5 + 1 );
  954   } while ( --bitLoop != 0 );
  955 
  956   return result;
  957 }
  958 
  959 //############################################################################################
  960 bit OneWireReset()
  961 //############################################################################################
  962 {
  963   // Setting the pin once to low is enough
  964   OneWire_IO_OUT = 0;
  965   // Reset pulse
  966   OneWireData0();
  967   Delay5us( 500 / 5 );
  968   // Reset pulse end
  969   OneWireData1();
  970   // Next sequence is time precision critical
  971   GIE = FALSE;
  972   // Wait for presence pulse
  973   Delay5us( 70 / 5 );
  974   // End of time precision critical sequence
  975   GIE = TRUE;
  976   // Presence pulse?
  977   if ( OneWire_IO_IN )
  978   {
  979     // No presence, finish initialization sequence
  980     Delay5us( ( 500 - 70 ) / 5 );
  981     return returnFALSE();
  982   }
  983   else
  984   {
  985     // Presence OK, finish initialization sequence
  986     Delay5us( ( 500 - 70 ) / 5 );
  987     return returnTRUE();
  988   }
  989 }
  990 
  991 //############################################################################################
  992 void OneWireCmd( uns8 cmd )
  993 //############################################################################################
  994 {
  995   // OneWire: Skip ROM
  996   OneWireWriteByte( CMD_SKIPROM );
  997   // OneWire: Send command
  998   OneWireWriteByte( cmd );
  999 }
 1000 
 1001 //############################################################################################
 1002 bit Ds18B20WriteConfig( uns8 value )
 1003 //############################################################################################
 1004 {
 1005   if ( OneWireReset() )
 1006   {
 1007     // Write Scratchpad
 1008     OneWireCmd( CMD_WSCRATCHPAD );
 1009 
 1010     // Write TL = ? (we dot not care the value)
 1011     OneWireWriteByte( W );
 1012     // Write TH = ? (we dot not care the value)
 1013     OneWireWriteByte( W );
 1014     // Write Config byte
 1015     OneWireWriteByte( value );
 1016 
 1017     if ( OneWireReset() )
 1018     {
 1019       //  Copy Scratchpad
 1020       OneWireCmd( CMD_CPYSCRATCHPAD );
 1021       return returnTRUE();
 1022     }
 1023   }
 1024   return returnFALSE();
 1025 }
 1026 
 1027 #endif // DALLASnotMCP
 1028 
 1029 //############################################################################################
 1030 // 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)
 1031 #include "DPAcustomHandler.h"
 1032 //############################################################################################