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