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