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.5 $
    8 // Date:    $Date: 2019/03/07 08:44:34 $
    9 //
   10 // Revision history:
   11 //   2019/03/07  Release for DPA 4.01
   12 //
   13 // *********************************************************************
   14 
   15 // Online DPA documentation http://www.iqrf.org/DpaTechGuide/
   16 // IQRF Standards documentation https://www.iqrfalliance.org/techDocs/
   17 
   18 // This example implements 3 sensors according to the IQRF Sensors standard
   19 // 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.
   20 // Index 1 i.e. 2nd sensor is light intensity indicator at DDC-SE-01 board (value range is 0[max light]-127[max dark]).
   21 // Index 2 i.e. 3rd sensor is potentiometer value at DDC-SE-01 board (value range is 0[left stop]-127[right stop]).
   22 
   23 // This example must be compiled without a "-bu" compiler switch in order to fit into available Flash memory
   24 
   25 // Default IQRF include (modify the path according to your setup)
   26 #include "IQRF.h"
   27 
   28 // We can save more instructions if needed by the symbol below
   29 // #define  PARAM_CHECK_LEVEL 1
   30 
   31 // Default DPA header (modify the path according to your setup)
   32 #include "DPA.h"
   33 // Default Custom DPA Handler header (modify the path according to your setup)
   34 #include "DPAcustomHandler.h"
   35 // IQRF standards header (modify the path according to your setup)
   36 #include "IQRFstandard.h"
   37 #include "IQRF_HWPID.h"
   38 
   39 // If defined then the handler is compiled for Dallas otherwise for MCP9802
   40 #define DALLASnotMCP
   41 
   42 //############################################################################################
   43 
   44 // Define useful macro that saves some code but not preset at DPA < 3.01
   45 #if DPA_VERSION_MASTER  < 0x0301
   46 // Optimized macro for both testing enumeration peripherals ELSE peripherals information. See examples
   47 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequestNoSize() if ( _PCMD == CMD_GET_PER_INFO ) if ( _PNUM == PNUM_ENUMERATION )
   48 
   49 #if PARAM_CHECK_LEVEL >= 2
   50 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() if ( _DpaDataLength == 0 && _PCMD == CMD_GET_PER_INFO ) if ( _PNUM == PNUM_ENUMERATION )
   51 #else
   52 #define IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest() IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequestNoSize()
   53 #endif
   54 #endif
   55 
   56 //############################################################################################
   57 
   58 // Number of implemented sensors
   59 #define SENSORS_COUNT 3
   60 
   61 // Variable to store sensor value at Get?_????() methods. This example implements sensors returning maximum 2 bytes of data.
   62 uns16 sensorValue @ param3;
   63 
   64 // Reads sensor value to the sensorValue variable and to responseFRCvalue(2B) variable
   65 bit Get0_Temperature();
   66 bit Get1_BinaryData_Light();
   67 bit Get2_BinaryData_Potentiometer();
   68 
   69 // 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)
   70 void StoreValue( uns8 sensorType );
   71 
   72 #ifdef DALLASnotMCP
   73 // Sensor connected to PORT C.3 (compatible with DDC-SE-01)
   74 #define OneWire_TRIS         TRISC.3
   75 #define OneWire_IO_IN        PORTC.3
   76 #define OneWire_IO_OUT       LATC.3
   77 
   78 // ms per ticks
   79 #define TICKS_LEN  10
   80 
   81 // Writes sensor configuration (resolution)
   82 bit Ds18B20WriteConfig( uns8 value );
   83 
   84 // Resets OneWire
   85 bit OneWireReset();
   86 // Reads OneWire byte
   87 uns8 OneWireReadByte();
   88 // Writes OneWire byte
   89 void OneWireWriteByte( uns8 byte );
   90 
   91 // DS18B20 commands
   92 #define CMD_READROM       0x33
   93 #define CMD_CONVERTTEMP   0x44
   94 #define CMD_CPYSCRATCHPAD 0x48
   95 #define CMD_WSCRATCHPAD   0x4e
   96 #define CMD_MATCHROM      0x55
   97 #define CMD_RPWRSUPPLY    0xb4
   98 #define CMD_RECEEPROM     0xb8
   99 #define CMD_RSCRATCHPAD   0xbe
  100 #define CMD_SKIPROM       0xcc
  101 #define CMD_ALARMSEARCH   0xec
  102 #define CMD_SEARCHROM     0xf0
  103 
  104 // Final DS18B20 temperature value read by state machine
  105 uns16 temperature;
  106 
  107 #else // DALLASnotMCP
  108 // I2C routines
  109 void i2c_init();
  110 void i2c_shutdown();
  111 void i2c_waitForIdle();
  112 void i2c_start();
  113 void i2c_stop();
  114 uns8 i2c_read( bit ack );
  115 void i2c_write( uns8 i2cWriteData );
  116 
  117 bit i2cTimeout;
  118 
  119 // MCP9802 address
  120 #define I2C_ADR             0b10010110
  121 // Power pin
  122 #define PWR_SENSOR_TRIS     TRISC.7
  123 #define PWR_SENSOR_IO       LATC.7
  124 
  125 #endif
  126 
  127 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
  128 //############################################################################################
  129 bit CustomDpaHandler()
  130 //############################################################################################
  131 {
  132   // 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)
  133 #pragma updateBank default = UserBank_01
  134 
  135 #ifdef DALLASnotMCP
  136   // Finite machine states
  137   typedef enum
  138   {
  139     S_ResetConvertT = 0,
  140     S_SkipRomConvertT,
  141     S_CmdConvertT,
  142 
  143     S_WaitConvertT,
  144 
  145     S_ResetReadTemp,
  146     S_SkipRomReadTemp,
  147     S_CmdReadTemp,
  148     S_Byte1ReadTemp,
  149     S_Byte2ReadTemp
  150   } TState;
  151 #endif
  152 
  153   // Handler presence mark
  154   clrwdt();
  155 
  156   // Sleeping parameters, valid when Time != 0
  157   static TPerOSSleep_Request PerOSSleep_Request;
  158 
  159 #ifdef DALLASnotMCP
  160   // Finite machine state
  161   static uns8 state; // = S_ResetConvertT = 0
  162   // Pre-read lower temperature byte
  163   static uns8 temperatureByteLow;
  164   // Conversion timeout counter
  165   static uns16 timeoutStart;
  166 #endif
  167 
  168   // Detect DPA event to handle
  169   switch ( GetDpaEvent() )
  170   {
  171     // -------------------------------------------------
  172     case DpaEvent_Interrupt:
  173       // Do an extra quick background interrupt work
  174 
  175       return Carry;
  176 
  177       // -------------------------------------------------
  178     case DpaEvent_Idle:
  179       // Do a quick background work when RF packet is not received
  180 
  181       // Should go to sleep?
  182       if ( PerOSSleep_Request.Time != 0 )
  183       {
  184         // Copy sleep parameters to the DPA request
  185         _DpaMessage.PerOSSleep_Request.Time = PerOSSleep_Request.Time;
  186         _DpaMessage.PerOSSleep_Request.Control = PerOSSleep_Request.Control;
  187         // Finalize OS Sleep DPA Request
  188         _DpaDataLength = sizeof( _DpaMessage.PerOSSleep_Request );
  189         _PNUM = PNUM_OS;
  190         _PCMD = CMD_OS_SLEEP;
  191         // Perform local DPA Request to go to sleep
  192         DpaApiLocalRequest();
  193         // Switch off sleeping time=flag
  194         PerOSSleep_Request.Time = 0;
  195       }
  196 
  197 #ifdef DALLASnotMCP
  198       // Run finite state machine to read temperature from DS18B20 at background so the temperature value is immediately ready for FRC 
  199 
  200       // Make sure 1Wire data pin at LATX.y is low as it might be set by another PORTX.? pin manipulation
  201       OneWire_IO_OUT = 0;
  202 
  203       skip( state );
  204 #pragma computedGoto 1
  205       goto _S_ResetConvertT;
  206       goto _S_SkipRomConvertT;
  207       goto _S_CmdConvertT;
  208       goto _S_WaitConvertT;
  209       goto _S_ResetReadTemp;
  210       goto _S_SkipRomReadTemp;
  211       goto _S_CmdReadTemp;
  212       goto _S_Byte1ReadTemp;
  213       goto _S_Byte2ReadTemp;
  214 #pragma computedGoto 0
  215       ;
  216       // --------------
  217 _S_Byte2ReadTemp:
  218       temperature.high8 = OneWireReadByte();
  219       temperature.low8 = temperatureByteLow;
  220 
  221 ResetMachine:
  222       state = S_ResetConvertT;
  223       goto ExitMachine;
  224 
  225       // --------------
  226 _S_ResetConvertT:
  227 _S_ResetReadTemp:
  228       if ( !OneWireReset() )
  229       {
  230 _S_Error_Reset:
  231         STD_SENSOR_TYPE_TEMPERATURE_SET_ERROR( temperature );
  232         goto ResetMachine;
  233       }
  234       goto NextState;
  235 
  236       // --------------
  237 _S_SkipRomConvertT:
  238 _S_SkipRomReadTemp:
  239       // OneWire: Skip ROM
  240       OneWireWriteByte( CMD_SKIPROM );
  241       goto NextState;
  242 
  243       // --------------
  244 _S_CmdConvertT:
  245       // OneWire: Convert temperature
  246       OneWireWriteByte( CMD_CONVERTTEMP );
  247       // Start timeout for approx 750 ms (the longest conversion time)
  248       captureTicks();
  249       // Remember start time
  250       timeoutStart = param3;
  251       goto NextState;
  252 
  253       // --------------
  254 _S_WaitConvertT:
  255       // Measured?
  256       if ( OneWireReadByte() == 0xff )
  257         goto NextState;
  258 
  259       // Timeout?
  260       captureTicks();
  261       param3 -= timeoutStart;
  262       // Yes!
  263       if ( param3 > ( 2 + 750 / TICKS_LEN ) )
  264         goto _S_Error_Reset;
  265 
  266       goto ExitMachine;
  267 
  268       // --------------
  269 _S_CmdReadTemp:
  270       // OneWire: Read scratchpad
  271       OneWireWriteByte( CMD_RSCRATCHPAD );
  272       goto NextState;
  273 
  274       // --------------
  275 _S_Byte1ReadTemp:
  276       temperatureByteLow = OneWireReadByte();
  277       goto NextState;
  278 
  279       // --------------
  280 NextState:
  281       ++state;
  282 
  283 ExitMachine:
  284 #endif
  285       break;
  286 
  287       // -------------------------------------------------
  288     case DpaEvent_Init:
  289       // Do a one time initialization work before main loop starts
  290 
  291       // Initialize ticks
  292       startCapture();
  293 
  294       // Initialize sensors
  295       // C5 (AN4) as input 
  296       moduleInfo();
  297       // Connected TR pins?
  298       if ( !bufferINFO[5].7 )
  299       {
  300         TRISC.6 = 1;
  301         TRISB.4 = 1;
  302       }
  303       TRISA.5 = 1;
  304 
  305       // C1 (AN0) as input 
  306       TRISA.0 = 1;
  307 
  308 #ifdef DALLASnotMCP
  309       // Setup DS18B20 for 9bit precision, conversion takes 94ms (see datasheet)
  310       Ds18B20WriteConfig( 0b0.00.00000 );
  311 #else
  312       // Expect MCP9802 is enabled
  313       i2c_init();
  314 #endif
  315       break;
  316 
  317       // -------------------------------------------------
  318     case DpaEvent_AfterSleep:
  319       // Called after woken up after sleep
  320 #ifndef DALLASnotMCP
  321       i2c_init();
  322 #endif
  323 
  324       break;
  325 
  326       // -------------------------------------------------
  327     case DpaEvent_BeforeSleep:
  328       // Called before going to sleep
  329 #ifndef DALLASnotMCP
  330       i2c_shutdown();
  331 #endif
  332       break;
  333 
  334       // -------------------------------------------------
  335     case DpaEvent_DpaRequest:
  336       // Called to interpret DPA request for peripherals
  337       // -------------------------------------------------
  338       // Peripheral enumeration
  339       IfDpaEnumPeripherals_Else_PeripheralInfo_Else_PeripheralRequest()
  340       {
  341         // We implement 2 standard peripherals
  342         _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1;
  343         FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_STD_SENSORS );
  344         _DpaMessage.EnumPeripheralsAnswer.HWPID = HWPID_IQRF_TECH__DEMO_DDC_SE01_LP;
  345         _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0x0000;
  346 
  347 DpaHandleReturnTRUE:
  348         return TRUE;
  349       }
  350       // -------------------------------------------------
  351       // Get information about peripherals
  352       else
  353       {
  354         switch ( _DpaMessage.PeripheralInfoAnswer.PerT = _PNUM )
  355         {
  356           case PNUM_STD_SENSORS:
  357             // Set standard version
  358             _DpaMessage.PeripheralInfoAnswer.Par1 = 15;
  359             _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE;
  360             goto DpaHandleReturnTRUE;
  361         }
  362 
  363         break;
  364       }
  365 
  366       {
  367         // -------------------------------------------------
  368         // Handle peripheral command
  369 
  370         // Supported peripheral number?
  371         switch ( _PNUM )
  372         {
  373           case PNUM_STD_SENSORS:
  374           {
  375             // Supported commands?
  376             switch ( _PCMD )
  377             {
  378               // Invalid command
  379               default:
  380               {
  381                 // Return error
  382 _ERROR_PCMD:
  383                 W = ERROR_PCMD;
  384 _ERROR_W:
  385                 DpaApiReturnPeripheralError( W );
  386               }
  387 
  388               // Sensor enumeration
  389               case PCMD_STD_ENUMERATE:
  390                 if ( _DpaDataLength != 0 )
  391                 {
  392 _ERROR_DATA_LEN:
  393                   W = ERROR_DATA_LEN;
  394                   goto _ERROR_W;
  395                 }
  396 
  397                 _DpaMessage.Response.PData[0] = STD_SENSOR_TYPE_TEMPERATURE;
  398                 _DpaMessage.Response.PData[1] = STD_SENSOR_TYPE_BINARYDATA7;
  399                 _DpaMessage.Response.PData[2] = STD_SENSOR_TYPE_BINARYDATA7;
  400                 W = SENSORS_COUNT;
  401                 goto _W2_DpaDataLength;
  402 
  403                 // Supported commands. They are handled the same way except one "if" at StoreValue() method
  404               case PCMD_STD_SENSORS_READ_VALUES:
  405               case PCMD_STD_SENSORS_READ_TYPES_AND_VALUES:
  406               {
  407                 // No sensor bitmap specified? W = _DpaDataLength. Note: W is used to avoid MOVLB at next if
  408                 W = _DpaDataLength;
  409                 if ( W == 0 )   // Note: must not modify W
  410                 {
  411                   // Actually clears the bitmap
  412 #if &_DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap[0] != &bufferRF[0]
  413 #error Cannot use clearBufferRF for clearing bitmap
  414 #endif
  415                   clearBufferRF();
  416                   // Simulate 1st only sensor in the bitmap (states of the other unimplemented sensors do not care)
  417                   _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap[0].0 = 1;
  418                   // Bitmap is 32 bits long
  419                   _DpaDataLength = W = sizeof( _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap );
  420                 }
  421 
  422                 // Invalid bitmap (data) length (W = _DpaDataLength)?
  423                 if ( W != sizeof( _DpaMessageIqrfStd.PerStdSensorRead_Request.Bitmap ) )
  424                   goto _ERROR_DATA_LEN;
  425 
  426                 // Now read the sensors
  427 
  428                 // Prepare pointer (minus 1, see below) to store sensor (types and) values to
  429                 // 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...
  430                 // ... If it would be the case, then ERROR_FAIL must be returned
  431                 FSR1 = &_DpaMessage.Response.PData[-1];
  432 
  433                 // Store bitmap of sensors to get values from
  434                 uns8 sensorsBitmap = FSR1[1 + offsetof( TPerStdSensorRead_Request, Bitmap )];
  435 
  436                 // 1st sensor (index 0) selected?
  437                 if ( sensorsBitmap.0 )
  438                 {
  439                   Get0_Temperature();
  440                   StoreValue( STD_SENSOR_TYPE_TEMPERATURE );
  441                 }
  442 
  443                 // 2nd sensor (index 1) selected?
  444                 if ( sensorsBitmap.1 )
  445                 {
  446                   Get1_BinaryData_Light();
  447                   StoreValue( STD_SENSOR_TYPE_BINARYDATA7 );
  448                 }
  449 
  450                 // 3rd sensor (index 2) selected?
  451                 if ( sensorsBitmap.2 )
  452                 {
  453                   Get2_BinaryData_Potentiometer();
  454                   StoreValue( STD_SENSOR_TYPE_BINARYDATA7 );
  455                 }
  456 
  457                 // Compute returned data bytes count
  458                 W = FSR1L - ( (uns16)&_DpaMessageIqrfStd & 0xFF ) + 1;
  459                 // Optimization: return W long block of bytes at response
  460 _W2_DpaDataLength:
  461                 _DpaDataLength = W;
  462                 goto DpaHandleReturnTRUE;
  463               }
  464             }
  465           }
  466         }
  467 
  468         break;
  469       }
  470 
  471       // -------------------------------------------------
  472     case DpaEvent_FrcValue:
  473       // Called to get FRC value
  474 
  475       // FSR1 for optimization purposes (avoid MOVLB) will be used to point to DataOutBeforeResponseFRC[0...]
  476       FSR1 = (uns16)&PerStdSensorFrc;
  477 #if offsetof( TPerStdSensorFrc, Header ) != 0 || offsetof( TPerStdSensorFrc, SensorType ) != 1 || offsetof( TPerStdSensorFrc, Options ) != 3
  478 #error Cannot optimize
  479 #endif
  480       // Check for correct FRC user data
  481       if ( *FSR1++ /* PerStdSensorFrc.Header */ == PNUM_STD_SENSORS )
  482       {
  483         // Actually used sensor index
  484         uns8 sensorIndex = FSR1[offsetof( TPerStdSensorFrc, SensorIndex ) - 1] & 0x1f;
  485         // Test sensor type
  486         switch ( *FSR1++ /* PerStdSensorFrc.SensorType */ )
  487         {
  488           default:
  489             goto DpaHandleReturnFALSE;
  490 
  491             // No type specified, use specified index value
  492           case 0x00:
  493             goto _KeepSensorIndex;
  494 
  495             // For other types make the index value based on the requested index value and sensor type
  496           case STD_SENSOR_TYPE_TEMPERATURE:
  497             if ( sensorIndex > 0 )
  498               goto DpaHandleReturnFALSE;
  499             W = 0 + sensorIndex;
  500             break;
  501 
  502           case STD_SENSOR_TYPE_BINARYDATA7:
  503             if ( sensorIndex > 1 )
  504               goto DpaHandleReturnFALSE;
  505             W = 1 + sensorIndex;
  506             break;
  507         }
  508 
  509         // New sensor index based on type and requested index
  510         sensorIndex = W;
  511 _KeepSensorIndex:
  512 
  513         // Test for supported FRC commands
  514         switch ( _PCMD )
  515         {
  516           default:
  517             goto DpaHandleReturnFALSE;
  518 
  519           case FRC_STD_SENSORS_BIT:
  520           case FRC_STD_SENSORS_1B:
  521           case FRC_STD_SENSORS_2B:
  522             switch ( sensorIndex )
  523             {
  524               default:
  525                 goto DpaHandleReturnFALSE;
  526 
  527               case 0:
  528                 Carry = Get0_Temperature();
  529                 break;
  530 
  531               case 1:
  532                 Carry = Get1_BinaryData_Light();
  533                 break;
  534 
  535               case 2:
  536                 Carry = Get2_BinaryData_Potentiometer();
  537                 break;
  538             }
  539 
  540             // This type of FRC is not valid for the specified sensor
  541             if ( !Carry )
  542               goto DpaHandleReturnFALSE;
  543 
  544             break;
  545         }
  546 
  547         // Some sensor was measured by FRC, check if there is a sleep request
  548         FSR1++;
  549         if ( INDF1.0 ) // Note: same as PerStdSensorFrc.Options.0
  550         {
  551           // Remember sleep parameters to go to sleep at the Idle event later
  552           PerOSSleep_Request.Time.low8 = FSR1[offsetof( TPerOSSleep_Request, Time ) + 0 + offsetof( TPerStdSensorFrc, SleepParameters ) - 3];
  553           PerOSSleep_Request.Time.high8 = FSR1[offsetof( TPerOSSleep_Request, Time ) + 1 + offsetof( TPerStdSensorFrc, SleepParameters ) - 3];
  554           PerOSSleep_Request.Control = FSR1[offsetof( TPerOSSleep_Request, Control ) + offsetof( TPerStdSensorFrc, SleepParameters ) - 3];
  555         }
  556         }
  557 
  558       break;
  559 
  560       // -------------------------------------------------
  561     case DpaEvent_FrcResponseTime:
  562       // Called to get FRC response time
  563 
  564       // In this example the FRC commands are fast 
  565       switch ( DataOutBeforeResponseFRC[0] )
  566       {
  567         case FRC_STD_SENSORS_BIT:
  568         case FRC_STD_SENSORS_1B:
  569         case FRC_STD_SENSORS_2B:
  570           responseFRCvalue = _FRC_RESPONSE_TIME_40_MS;
  571           break;
  572       }
  573       break;
  574       }
  575 DpaHandleReturnFALSE:
  576   return FALSE;
  577   }
  578 
  579 //############################################################################################
  580 bit returnTRUE()
  581 //############################################################################################
  582 {
  583   return TRUE;
  584 }
  585 
  586 //############################################################################################
  587 bit returnFALSE()
  588 //############################################################################################
  589 {
  590   return FALSE;
  591 }
  592 
  593 //############################################################################################
  594 // Increases FSR1 and then stores the byte
  595 void setPlusPlusINDF1( uns8 data @ W )
  596 //############################################################################################
  597 {
  598   FSR1++; // Note: must not modify W
  599   setINDF1( data );
  600 }
  601 
  602 //############################################################################################
  603 // Stores measured sensor value byte(s) and optionally sensor type to the FSR[+1...]
  604 void StoreValue( uns8 sensorType )
  605 //############################################################################################
  606 {
  607   // Is the sensor type to be stored too?
  608   if ( _PCMD == PCMD_STD_SENSORS_READ_TYPES_AND_VALUES )
  609     setPlusPlusINDF1( sensorType );
  610 
  611   // Store lower value byte
  612   setPlusPlusINDF1( sensorValue.low8 );
  613 
  614   // No more value bytes to store?
  615   if ( sensorType.7 != 0 )
  616     return;
  617 
  618   // Store higher value byte
  619   setPlusPlusINDF1( sensorValue.high8 );
  620 
  621   // 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.
  622 }
  623 
  624 //############################################################################################
  625 bit setFRCerror()
  626 //############################################################################################
  627 {
  628   responseFRCvalue2B = 2;
  629   return returnTRUE();
  630 }
  631 
  632 //############################################################################################
  633 bit sensorError;
  634 bit AdjustFrcTemperature()
  635 //############################################################################################
  636 {
  637   // Test for supported FRC commands
  638   switch ( _PCMD )
  639   {
  640     default:
  641       return returnFALSE();
  642 
  643     case FRC_STD_SENSORS_1B:
  644       // Return sensor FRC value 1B
  645       // Check for out of limits
  646       if ( sensorError || (int16)sensorValue > (int16)( 105.5 * 16 ) || (int16)sensorValue < ( (int16)-20 * 16 ) )
  647         return setFRCerror();
  648 
  649       // Convert to the "F = ( T + 22 ) * 2 " from 1/16 resolution
  650       uns16 _sensorValue = sensorValue + 4; // Note: do rounding when /8
  651       responseFRCvalue = (uns8)( _sensorValue / 8 ) + 44;
  652       break;
  653 
  654     case FRC_STD_SENSORS_2B:
  655       // Return sensor FRC value 2B
  656       if ( sensorError )
  657         return setFRCerror();
  658 
  659       responseFRCvalue2B = sensorValue ^ 0x8000;
  660       break;
  661   }
  662 
  663   return returnTRUE();
  664 }
  665 
  666 //############################################################################################
  667 // Sensor index 1: measure temperature using one of the DDC-SE-01 sensors
  668 bit Get0_Temperature()
  669 //############################################################################################
  670 {
  671   // Make sure FSR1 is not modified
  672 
  673   // Measure temperature using DDC-SE-01 sensors
  674   // Read temperature and check for an error
  675 
  676   // Reads temperature from an enabled sensor
  677 #ifdef DALLASnotMCP
  678   sensorError = FALSE;
  679   // Temperature is ready at the background
  680   sensorValue = temperature;
  681   // When error, return standard (FRC) error value(s)
  682   if ( STD_SENSOR_TYPE_TEMPERATURE_IS_ERROR( sensorValue ) )
  683     sensorError = TRUE;
  684 #else
  685   sensorError = TRUE;
  686   // Temperature value must be read from I2C sensor
  687   STD_SENSOR_TYPE_TEMPERATURE_SET_ERROR( sensorValue );
  688   i2c_start();
  689   if ( !i2cTimeout )
  690   {
  691     // MCP9802 address
  692     i2c_write( I2C_ADR );
  693     // pointer: 1 = configuration register
  694     i2c_write( 0x01 );
  695     // configuration: 9-bit ADC
  696     i2c_write( 0x00 );
  697     i2c_stop();
  698 
  699     i2c_start();
  700     // MCP9802 address
  701     i2c_write( I2C_ADR );
  702     // pointer: 0 = temperature
  703     i2c_write( 0 );
  704     i2c_stop();
  705 
  706     i2c_start();
  707     // MCP9802 address + read
  708     i2c_write( 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 writeToSSPCON2( uns8 value )
  971 //############################################################################################
  972 {
  973   writeToRAM( &SSPCON2, value );
  974 }
  975 
  976 //############################################################################################
  977 void writeOredToSSPCON2( uns8 value )
  978 //############################################################################################
  979 {
  980   writeToSSPCON2( SSPCON2 | value );
  981 }
  982 
  983 //############################################################################################
  984 // I2C routines
  985 //############################################################################################
  986 
  987 //############################################################################################
  988 void i2c_init()
  989 //############################################################################################
  990 {
  991   // SCL as input (SIM C6)
  992   TRISC.3 = 1;
  993   // SDA as input (SIM C7)
  994   TRISC.4 = 1;
  995 
  996   // I2C master mode     SSPCON = 0b00111000
  997   writeToRAM( &SSPCON1, 0x38 );
  998   writeToSSPCON2( 0x00 );
  999 
 1000   // 50 kHz SCL frequency
 1001   SSPADD = ( F_OSC / 50000 / 4 ) - 2;
 1002   // Disable slew rate control
 1003   SMP = 1;
 1004 }
 1005 
 1006 //############################################################################################
 1007 void i2c_shutdown()
 1008 //############################################################################################
 1009 {
 1010   // I2C master mode     SSPCON = 0
 1011   writeToRAM( &SSPCON1, 0x00 );
 1012 }
 1013 
 1014 //############################################################################################
 1015 void i2c_waitForIdle()
 1016 //############################################################################################
 1017 {
 1018   i2cTimeout = FALSE;
 1019   uns8 timeout;
 1020   // Wait for idle and not writing
 1021   timeout = 0;
 1022   while ( ( SSPCON2 & 0b0001.1111 ) != 0 || RW_ )
 1023     if ( ++timeout == 0 )
 1024     {
 1025       i2cTimeout = TRUE;
 1026       break;
 1027     }
 1028 }
 1029 
 1030 //############################################################################################
 1031 void i2c_start()
 1032 //############################################################################################
 1033 {
 1034   i2c_waitForIdle();
 1035   // SEN = 1
 1036   writeOredToSSPCON2( 0x01 );
 1037 }
 1038 
 1039 //############################################################################################
 1040 void i2c_stop()
 1041 //############################################################################################
 1042 {
 1043   i2c_waitForIdle();
 1044   // PEN = 1
 1045   writeOredToSSPCON2( 0x04 );
 1046 }
 1047 
 1048 //############################################################################################
 1049 uns8 i2c_read( bit ack )
 1050 //############################################################################################
 1051 {
 1052   i2c_waitForIdle();
 1053   // RCEN = 1
 1054   writeOredToSSPCON2( 0x08 );
 1055 
 1056   i2c_waitForIdle();
 1057 
 1058   uns8 i2cReadData @ userReg0;
 1059   i2cReadData = SSPBUF;
 1060 
 1061   i2c_waitForIdle();
 1062 
 1063   if ( ack )
 1064     // Acknowledge, ACKDT = 0
 1065     writeToSSPCON2( SSPCON2 & 0xDF );
 1066   else
 1067     // Not acknowledge, ACKDT = 1 
 1068     writeOredToSSPCON2( 0x20 );
 1069 
 1070   // Send acknowledge sequence, ACKEN = 1 
 1071   writeOredToSSPCON2( 0x10 );
 1072   return i2cReadData;
 1073 }
 1074 
 1075 //############################################################################################
 1076 void i2c_write( uns8 i2cWriteData )
 1077 //############################################################################################
 1078 {
 1079   i2c_waitForIdle();
 1080   SSPBUF = i2cWriteData;
 1081 }
 1082 
 1083 #endif
 1084 
 1085 //############################################################################################
 1086 // 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) 
 1087 #include "DPAcustomHandler.h"
 1088 //############################################################################################