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