1 // *********************************************************************
    2 //   Custom DPA Handler code example - DDC-SE-01 and/or DDC-RE-01      *
    3 // *********************************************************************
    4 // Copyright (c) MICRORISC s.r.o.
    5 //
    6 // File:    $RCSfile: CustomDpaHandler-DDC-Core.c,v $
    7 // Version: $Revision: 1.24 $
    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 //   2017/03/13  Release for DPA 3.00
   14 //   2016/12/22  Release for DPA 2.28
   15 //
   16 // *********************************************************************
   17 
   18 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/
   19 
   20 /* This example implements HWP for DDC-SE-01 and/or DDC-RE-01
   21 
   22 DDC-SE-01: HWPID=0x001F
   23 DDC-RE-01: HWPID=0x002F
   24 DDC-SE-01 & DDC-RE-01: HWPID=0x003F
   25 
   26 ----------- DDC-SE-01
   27 Request: PNUM = 0x20, PCMD = 0x31
   28 Response:
   29  PData[0]=Temperature at [C]
   30  PData[1]=Photoresistor value 0x00-0xFF
   31  PData[2]=Potentiometer value 0x00-0xFF
   32  returns ERROR_FAIL when error reading temperature
   33 
   34 FRC=0xC0, returns temperature at C, 127 for 0 C, 0x80 for error reading temperature
   35 FRC=0xC1, returns photoresistor value, returns 1 instead of 0
   36 FRC=0xC2, returns potentiometer value, returns 1 instead of 0
   37 
   38 ----------- DDC-RE-01
   39 Request: PNUM = 0x20, PCMD = 0x32
   40  PData[0]=Relay1Ctrl
   41  PData[1]=Relay2Ctrl
   42 
   43 Response:
   44  PData[0]=Relay1State
   45  PData[1]=Relay2State
   46 
   47 RelayCtrl: 0=Switch the Relay off, 1=Switch the Relay on, Other=Do not control the Relay
   48 RelayState: 0=Relay was off, 1=Relay was on
   49 */
   50 
   51 // *********************************************************************
   52 
   53 // Default IQRF include (modify the path according to your setup)
   54 #include "IQRF.h"
   55 
   56 // Default DPA header (modify the path according to your setup)
   57 #include "DPA.h"
   58 // Default Custom DPA Handler header (modify the path according to your setup)
   59 #include "DPAcustomHandler.h"
   60 
   61 #if defined( DDC_SE_01 ) && defined( DDC_RE_01 )
   62 #define ThisHWPID 0x003F
   63 #elif defined( DDC_SE_01 )
   64 #define ThisHWPID 0x001F
   65 #elif defined( DDC_RE_01 )
   66 #define ThisHWPID 0x002F
   67 #else
   68 #error Symbol(s) DDC_SE_01 and/or DDC_RE_01 must be defined
   69 #endif
   70 
   71 //############################################################################################
   72 
   73 #if defined( DDC_SE_01 )
   74 
   75 // Special temperature value to indicate a sensor error
   76 #define ERROR_TEMPERATURE 0xF800
   77 
   78 // Sensor connected to PORT C.3 (compatible with DDC-SE-01)
   79 #define OneWire_TRIS         TRISC.3
   80 #define OneWire_IO_IN        PORTC.3
   81 #define OneWire_IO_OUT       LATC.3
   82 
   83 // Writes sensor configuration (resolution)
   84 bit Ds18B20WriteConfig( uns8 value );
   85 
   86 // Resets OneWire
   87 bit OneWireReset();
   88 // Reads OneWire byte
   89 uns8 OneWireReadByte();
   90 // Writes OneWire byte
   91 void OneWireWriteByte( uns8 byte );
   92 
   93 // DS18B20 commands
   94 #define CMD_READROM       0x33
   95 #define CMD_CONVERTTEMP   0x44
   96 #define CMD_CPYSCRATCHPAD 0x48
   97 #define CMD_WSCRATCHPAD   0x4e
   98 #define CMD_MATCHROM      0x55
   99 #define CMD_RPWRSUPPLY    0xb4
  100 #define CMD_RECEEPROM     0xb8
  101 #define CMD_RSCRATCHPAD   0xbe
  102 #define CMD_SKIPROM       0xcc
  103 #define CMD_ALARMSEARCH   0xec
  104 #define CMD_SEARCHROM     0xf0
  105 
  106 // I2C SCL frequency [Hz]
  107 #define I2Cfrequency      50000
  108 
  109 // MCP9802 address
  110 #define I2C_ADR             0b10010110
  111 // Power pin
  112 #define PWR_SENSOR_TRIS     TRISC.7
  113 #define PWR_SENSOR_IO       LATC.7
  114 
  115 // Sensors read routines
  116 uns16 GetTemperature();
  117 uns8  ReadAdcPhotoresistor();
  118 uns8  ReadAdcPotentiometer();
  119 
  120 // TRUE if DS18B20 is enabled, FALSE in case of MCP9802
  121 bit isDS18B20;
  122 // Final DS18B20 temperature value
  123 static uns16 temperature;
  124 
  125 #endif
  126 
  127 #if defined( DDC_RE_01 )
  128 
  129 // C.5 = C8 = Relay#1
  130 #define RELAY1_LAT  LATC.5
  131 #define RELAY1_TRIS TRISC.5
  132 
  133 // C.2 = C2 = Relay#2
  134 #define RELAY2_LAT  LATC.2
  135 #define RELAY2_TRIS TRISC.2
  136 
  137 #endif
  138 
  139 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location!
  140 //############################################################################################
  141 bit CustomDpaHandler()
  142 //############################################################################################
  143 {
  144 #if defined( DDC_SE_01 )
  145   // Finite machine states
  146   typedef enum
  147   {
  148     S_ResetConvertT = 0,
  149     S_SkipRomConvertT,
  150     S_CmdConvertT,
  151 
  152     S_WaitConvertT,
  153 
  154     S_ResetReadTemp,
  155     S_SkipRomReadTemp,
  156     S_CmdReadTemp,
  157     S_Byte1ReadTemp,
  158     S_Byte2ReadTemp
  159   } TState;
  160 
  161 #endif
  162 
  163   // Handler presence mark
  164   clrwdt();
  165 
  166 #if defined( DDC_SE_01 )
  167   // Finite machine state
  168   static uns8 state; // = S_ResetConvertT = 0
  169   // Pre-read lower temperature byte
  170   static uns8 temperatureByteLow;
  171   // Conversion timeout counter
  172   static uns8 timeout;
  173 #endif
  174 
  175   // Detect DPA event to handle
  176   switch ( GetDpaEvent() )
  177   {
  178     // -------------------------------------------------
  179     case DpaEvent_Interrupt:
  180       // Do an extra quick background interrupt work
  181       // ! 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.
  182       // ! 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.
  183       // ! 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.
  184       // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy.
  185       // ! Make sure race condition does not occur when accessing those variables at other places.
  186       // ! 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.
  187       // ! Do not call any OS functions except setINDFx().
  188       // ! Do not use any OS variables especially for writing access.
  189       // ! 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.
  190 
  191 #if defined( DDC_SE_01 )
  192 #define TICKS_LEN  10
  193 
  194 //  If TMR6 interrupt occurred
  195       if ( TMR6IF )
  196       {
  197         // Unmask interrupt
  198         TMR6IF = 0;
  199         // Decrement count
  200         if ( timeout != 0 )
  201           timeout--;
  202       }
  203 #endif
  204       return Carry;
  205 
  206 #if defined( DDC_SE_01 )
  207       // -------------------------------------------------
  208     case DpaEvent_Idle:
  209       // Do a quick background work when RF packet is not received
  210 
  211       // Run finite state machine to read temperature from DS18B20 at background so the temperature value is immediately ready for FRC
  212       if ( !isDS18B20 )
  213         break;
  214 
  215       // Make sure 1Wire data pin at LATX.y is low as it might be set by another PORTX.? pin manipulation
  216       OneWire_IO_OUT = 0;
  217 
  218       skip( state );
  219 #pragma computedGoto 1
  220       goto _S_ResetConvertT;
  221       goto _S_SkipRomConvertT;
  222       goto _S_CmdConvertT;
  223       goto _S_WaitConvertT;
  224       goto _S_ResetReadTemp;
  225       goto _S_SkipRomReadTemp;
  226       goto _S_CmdReadTemp;
  227       goto _S_Byte1ReadTemp;
  228       goto _S_Byte2ReadTemp;
  229 #pragma computedGoto 0
  230       ;
  231       // --------------
  232 _S_Byte2ReadTemp:
  233       temperature.high8 = OneWireReadByte();
  234       temperature.low8 = temperatureByteLow;
  235 
  236 ResetMachine:
  237       state = S_ResetConvertT;
  238       goto ExitMachine;
  239 
  240       // --------------
  241 _S_ResetConvertT:
  242 _S_ResetReadTemp:
  243       if ( !OneWireReset() )
  244       {
  245 _S_Error_Reset:
  246         temperature = ERROR_TEMPERATURE;
  247         goto ResetMachine;
  248       }
  249       goto NextState;
  250 
  251       // --------------
  252 _S_SkipRomConvertT:
  253 _S_SkipRomReadTemp:
  254       // OneWire: Skip ROM
  255       OneWireWriteByte( CMD_SKIPROM );
  256       goto NextState;
  257 
  258       // --------------
  259 _S_CmdConvertT:
  260       // OneWire: Convert temperature
  261       OneWireWriteByte( CMD_CONVERTTEMP );
  262       // Setup timeout for approx 750 ms (the longest conversion time)
  263       timeout = 2 + 750 / TICKS_LEN;
  264       goto NextState;
  265 
  266       // --------------
  267 _S_WaitConvertT:
  268       if ( OneWireReadByte() == 0xff )
  269         goto NextState;
  270 
  271       // Timeout?
  272       if ( timeout == 0 )
  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       break;
  294 
  295       // -------------------------------------------------
  296     case DpaEvent_FrcValue:
  297       // Called to get FRC value
  298 
  299       // Which FRC command?
  300       switch ( _PCMD )
  301       {
  302         case FRC_USER_BYTE_FROM + 0:
  303           // Returns temperature
  304           uns16 curTemperature = GetTemperature();
  305           if ( curTemperature == ERROR_TEMPERATURE )
  306             responseFRCvalue = 0x80;
  307           else
  308           {
  309             responseFRCvalue = curTemperature.low8;
  310             if ( responseFRCvalue == 0 )
  311               responseFRCvalue = 127;
  312           }
  313           break;
  314 
  315         case FRC_USER_BYTE_FROM + 1:
  316           // Returns photoresistor value
  317           responseFRCvalue = ReadAdcPhotoresistor();
  318 _Zero2One:
  319           if ( responseFRCvalue == 0 )
  320             responseFRCvalue |= 1;
  321           break;
  322 
  323         case FRC_USER_BYTE_FROM + 2:
  324           // Returns potentiometer value
  325           responseFRCvalue = ReadAdcPotentiometer();
  326           goto _Zero2One;
  327       }
  328       break;
  329 
  330       // -------------------------------------------------
  331     case DpaEvent_FrcResponseTime:
  332       // Called to get FRC response time
  333 
  334       if ( DataOutBeforeResponseFRC[0] >= ( FRC_USER_BYTE_FROM + 0 ) && DataOutBeforeResponseFRC[0] <= ( FRC_USER_BYTE_FROM + 2 ) )
  335         responseFRCvalue = _FRC_RESPONSE_TIME_40_MS;
  336       break;
  337 #endif
  338 
  339       // -------------------------------------------------
  340     case DpaEvent_DpaRequest:
  341     {
  342       // Called to interpret DPA request for peripherals
  343       // -------------------------------------------------
  344       // Peripheral enumeration
  345       if ( IsDpaEnumPeripheralsRequest() )
  346       {
  347         // We implement 1 user peripheral
  348         _DpaMessage.EnumPeripheralsAnswer.UserPerNr = 1;
  349 #ifdef FlagUserPer  // Get ready for upcoming DPA 3.00
  350         FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 );
  351 #endif
  352         _DpaMessage.EnumPeripheralsAnswer.HWPID = ThisHWPID;
  353         _DpaMessage.EnumPeripheralsAnswer.HWPIDver = 0x0000;
  354 
  355 DpaHandleReturnTRUE:
  356         return TRUE;
  357       }
  358       // -------------------------------------------------
  359       // Get information about peripheral
  360       else if ( IsDpaPeripheralInfoRequest() )
  361       {
  362         if ( _PNUM == PNUM_USER + 0 )
  363         {
  364           _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA;
  365 #if !defined( DDC_RE_01 )
  366           _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ;
  367 #else
  368           _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE;
  369 #endif
  370           goto DpaHandleReturnTRUE;
  371         }
  372 
  373         break;
  374       }
  375       // -------------------------------------------------
  376       else
  377       {
  378         // Handle peripheral command
  379         if ( _PNUM == PNUM_USER + 0 )
  380         {
  381           switch ( _PCMD )
  382           {
  383 #if defined( DDC_SE_01 )
  384             case 0x31:
  385               // Read sensors
  386               if ( _DpaDataLength != 0 )
  387                 DpaApiReturnPeripheralError( ERROR_DATA_LEN );
  388 
  389               // Read temperature and check for an error
  390               uns16 temperature = GetTemperature();
  391               if ( temperature == ERROR_TEMPERATURE )
  392                 DpaApiReturnPeripheralError( ERROR_FAIL );
  393               _DpaMessage.Response.PData[0] = temperature.low8;
  394 
  395               // Read other sensors
  396               _DpaMessage.Response.PData[1] = ReadAdcPhotoresistor();
  397               _DpaMessage.Response.PData[2] = ReadAdcPotentiometer();
  398 
  399               // Return 3 bytes
  400               _DpaDataLength = 3;
  401               goto DpaHandleReturnTRUE;
  402 #endif
  403 
  404 #if defined( DDC_RE_01 )
  405             case 0x32:
  406               // Control and return state of relays
  407               if ( _DpaDataLength != 2 )
  408                 DpaApiReturnPeripheralError( ERROR_DATA_LEN );
  409 
  410               // Relay #1
  411               // Get
  412               userReg0 = 0;
  413               if ( RELAY1_LAT )
  414                 userReg0.0 = 1;
  415 
  416               // Set
  417               switch ( _DpaMessage.Request.PData[0] )
  418               {
  419                 case 0:
  420                   RELAY1_LAT = 0;
  421                   break;
  422                 case 1:
  423                   RELAY1_LAT = 1;
  424                   break;
  425               }
  426               _DpaMessage.Response.PData[0] = userReg0;
  427 
  428               // Relay #2
  429               // Get
  430               userReg0 = 0;
  431               if ( RELAY2_LAT )
  432                 userReg0.0 = 1;
  433 
  434               // Set
  435               switch ( _DpaMessage.Request.PData[1] )
  436               {
  437                 case 0:
  438                   RELAY2_LAT = 0;
  439                   break;
  440                 case 1:
  441                   RELAY2_LAT = 1;
  442                   break;
  443               }
  444               _DpaMessage.Response.PData[1] = userReg0;
  445               // Receives and returns 2 bytes
  446               goto DpaHandleReturnTRUE;
  447 #endif
  448 
  449               // Invalid command
  450             default:
  451               DpaApiReturnPeripheralError( ERROR_PCMD );
  452               break;
  453           }
  454         }
  455       }
  456 
  457       break;
  458     }
  459 
  460     // -------------------------------------------------
  461     case DpaEvent_Init:
  462       // Do a one time initialization before main loop starts
  463 
  464 #if defined( DDC_SE_01 )
  465       // Initialize sensors
  466 
  467       // C5 (AN4) as input
  468       moduleInfo();
  469       // Connected TR pins?
  470       if ( !bufferINFO[5].7 )
  471       {
  472         TRISC.6 = 1;
  473         TRISB.4 = 1;
  474       }
  475       TRISA.5 = 1;
  476 
  477       // C1 (AN0) as input
  478       TRISA.0 = 1;
  479 
  480       // Setup TMR6 to generate ticks on the background (ticks every 10ms)
  481 #if F_OSC == 16000000
  482       PR6 = 250 - 1;
  483       T6CON = 0b0.1001.1.10;    // Prescaler 16, Postscaler 10, 16 * 10 * 250 = 40000 = 4MHz * 10ms
  484 #else
  485 #error Unsupported oscillator frequency
  486 #endif
  487 
  488       // Setup DS18B20 for 9bit precision, conversion takes 94ms (see datasheet)
  489       if ( Ds18B20WriteConfig( 0b0.00.00000 ) )
  490         // DS18B20 is enabled
  491         isDS18B20 = TRUE;
  492       else
  493       {
  494         // Expect MCP9802 is enabled
  495         I2Ctimeout = 0xFF;
  496         _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) );
  497   }
  498 #endif
  499 
  500 #if defined( DDC_RE_01 )
  501       // Initialize relays
  502       RELAY1_LAT = 0;
  503       RELAY2_LAT = 0;
  504       RELAY1_TRIS = 0;
  505       RELAY2_TRIS = 0;
  506 
  507 #endif
  508       break;
  509 
  510 #if defined( DDC_SE_01 )
  511       // -------------------------------------------------
  512     case DpaEvent_AfterSleep:
  513       // Called after woken up after sleep
  514       if ( !isDS18B20 )
  515         _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) );
  516 
  517       // Called on wake-up from sleep
  518       TMR6IE = TRUE;
  519       TMR6ON = TRUE;
  520       break;
  521 
  522       // -------------------------------------------------
  523     case DpaEvent_BeforeSleep:
  524       // Called before going to sleep
  525       if ( !isDS18B20 )
  526         _DpaApiI2Cshutdown();
  527 
  528       // -------------------------------------------------
  529     case DpaEvent_DisableInterrupts:
  530       // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond, and Run RFPGM)
  531       // Must not use TMR6 any more
  532       TMR6ON = FALSE;
  533       TMR6IE = FALSE;
  534       break;
  535 #endif
  536 }
  537   return FALSE;
  538 }
  539 
  540 //############################################################################################
  541 #if defined( DDC_SE_01 )
  542 
  543 //############################################################################################
  544 // OneWire and Dallas 18B20 routines
  545 //############################################################################################
  546 
  547 //############################################################################################
  548 void Delay5us( uns8 val @ W ) // Absolutely precise timing but val != 0
  549 //############################################################################################
  550 {
  551   // 16 MHz
  552   // + 0.75us ( W=val, Call )
  553   for ( ;; )
  554   {         // loop time
  555     nop2(); // 0.50us
  556     nop2(); // 1.00us
  557     nop2(); // 1.50us
  558     nop2(); // 2.00us
  559     nop2(); // 2.50us
  560     nop2(); // 3.00us
  561     nop();  // 3.25us
  562     if ( --val == 0 ) // + 0.75us (W--, BTFS )
  563       return;         // + 0.25us
  564     nop2(); // 4.50us
  565   }         // 5.00us (Goto)
  566 }
  567 //############################################################################################
  568 
  569 #define OneWireData0()  { OneWire_TRIS = 0; }     // 0.5us @ 16MHz
  570 #define OneWireData1()  { OneWire_TRIS = 1; }     // 0.5us @ 16MHz
  571 
  572 //############################################################################################
  573 void OneWireWriteByte( uns8 byte )
  574 //############################################################################################
  575 {
  576   uns8 bitLoop = 8;
  577   do
  578   {
  579     // Next sequence is time precision critical
  580     GIE = FALSE;
  581 
  582     OneWireData0();
  583     nop2();         // 1 us [0.5 us]
  584     nop2();         // [1.0 us]
  585     if ( byte.0 )   // 2.5 us [1.75us]
  586       OneWireData1();
  587 
  588     // End of time precision critical sequence
  589     GIE = TRUE;
  590 
  591     // 60us minimum in total, does not have to be precise
  592     Delay5us( ( 60 - 3 ) / 5 + 1 );
  593 
  594     OneWireData1();
  595 
  596     byte >>= 1;
  597   } while ( --bitLoop != 0 );
  598 }
  599 
  600 //############################################################################################
  601 uns8 OneWireReadByte()
  602 //############################################################################################
  603 {
  604   uns8 result;
  605   uns8 bitLoop = 8;
  606   do
  607   {
  608     // Next sequence is time precision critical
  609     GIE = FALSE;
  610 
  611     OneWireData0();
  612     nop2();         // 1 us [0.5 us]
  613 #if F_OSC == 16000000
  614     nop2();         // [1.0 us]
  615 #endif
  616     OneWireData1();         // 2 us [1.5 us]
  617     Delay5us( 15 / 5 );     // 17 us [16.5 us]
  618 
  619     Carry = 0;              // 17.5 us [16.75 us]
  620     if ( OneWire_IO_IN )    // 18.5 us [ 17.25 us] (condition must not modify Carry)
  621       Carry = 1;
  622 
  623     // End of time precision critical sequence
  624     GIE = TRUE;             // must not modify Carry
  625     result = rr( result );
  626 
  627     // 60us minimum in total, does not have to be precise
  628     Delay5us( ( 60 - 20 ) / 5 + 1 );
  629   } while ( --bitLoop != 0 );
  630 
  631   return result;
  632 }
  633 
  634 //############################################################################################
  635 bit OneWireReset()
  636 //############################################################################################
  637 {
  638   // Setting the pin once to low is enough
  639   OneWire_IO_OUT = 0;
  640   // Reset pulse
  641   OneWireData0();
  642   Delay5us( 500 / 5 );
  643   // Reset pulse end
  644   OneWireData1();
  645   // Next sequence is time precision critical
  646   GIE = FALSE;
  647   // Wait for presence pulse
  648   Delay5us( 70 / 5 );
  649   // End of time precision critical sequence
  650   GIE = TRUE;
  651   // Presence pulse?
  652   if ( OneWire_IO_IN )
  653   {
  654     // No presence, finish initialization sequence
  655     Delay5us( ( 500 - 70 ) / 5 );
  656     return FALSE;
  657   }
  658   else
  659   {
  660     // Presence OK, finish initialization sequence
  661     Delay5us( ( 500 - 70 ) / 5 );
  662     return TRUE;
  663   }
  664 }
  665 
  666 //############################################################################################
  667 void OneWireCmd( uns8 cmd )
  668 //############################################################################################
  669 {
  670   // OneWire: Skip ROM
  671   OneWireWriteByte( CMD_SKIPROM );
  672   // OneWire: Send command
  673   OneWireWriteByte( cmd );
  674 }
  675 
  676 //############################################################################################
  677 bit Ds18B20WriteConfig( uns8 value )
  678 //############################################################################################
  679 {
  680   if ( OneWireReset() )
  681   {
  682     // Write Scratchpad
  683     OneWireCmd( CMD_WSCRATCHPAD );
  684 
  685     // Write TL = ? (we dot not care the value)
  686     OneWireWriteByte( W );
  687     // Write TH = ? (we dot not care the value)
  688     OneWireWriteByte( W );
  689     // Write Config byte
  690     OneWireWriteByte( value );
  691 
  692     if ( OneWireReset() )
  693     {
  694       //  Copy Scratchpad
  695       OneWireCmd( CMD_CPYSCRATCHPAD );
  696       return TRUE;
  697     }
  698   }
  699   return FALSE;
  700 }
  701 
  702 //############################################################################################
  703 uns16 MCP9802GetTemp()
  704 //############################################################################################
  705 {
  706   // MCP9802 address
  707   _DpaApiI2Cstart( I2C_ADR );
  708   if ( I2CwasTimeout )
  709     return ERROR_TEMPERATURE;
  710 
  711   // pointer: 1 = configuration register
  712   _DpaApiI2Cwrite( 0x01 );
  713   // configuration: 9-bit ADC
  714   _DpaApiI2CwriteAndStop( 0x00 );
  715 
  716   // MCP9802 address
  717   _DpaApiI2Cstart( I2C_ADR );
  718   // pointer: 0 = temperature
  719   _DpaApiI2CwriteAndStop( 0 );
  720 
  721   // MCP9802 address + read
  722   _DpaApiI2Cstart( I2C_ADR | 1 );
  723   uns16 temperature;
  724   // store the result
  725   temperature.high8 = _DpaApiI2Cread( TRUE );
  726   temperature.low8 = _DpaApiI2Cread( FALSE );
  727   _DpaApiI2Cstop();
  728   return temperature;
  729 }
  730 
  731 //############################################################################################
  732 uns16 GetTemperature()
  733 //############################################################################################
  734 {
  735   // Reads temperature from an enabled sensor
  736   uns16 temperatureResult;
  737 
  738   if ( isDS18B20 )
  739   {
  740     // Temperature is ready at the background
  741     temperatureResult = temperature;
  742     if ( temperatureResult != ERROR_TEMPERATURE )
  743     {
  744       temperatureResult += 0x08;
  745       temperatureResult /= 0x10;
  746     }
  747   }
  748   else
  749   {
  750     // Temperature value must be read from I2C sensor
  751     temperatureResult = MCP9802GetTemp();
  752     if ( temperatureResult != ERROR_TEMPERATURE )
  753     {
  754       temperatureResult += 0x80;
  755       temperatureResult /= 0x100;
  756     }
  757   }
  758 
  759   return temperatureResult;
  760 }
  761 
  762 //############################################################################################
  763 uns8 ReadAdc()
  764 //############################################################################################
  765 {
  766   // ADC result - left justified, Fosc/8
  767   ADCON1 = 0b0001.0000;
  768   // start ADC
  769   GO = 1;
  770   // wait for ADC finish
  771   while ( GO );
  772   return ADRESH;
  773 }
  774 
  775 //############################################################################################
  776 uns8  ReadAdcPhotoresistor()
  777 //############################################################################################
  778 {
  779   // ADC initialization (for more info see PIC datasheet) pin C1 (AN0) as analog input
  780   ANSELA.0 = 1;
  781   // ADC setting (AN0 channel)
  782   ADCON0 = 0b0.00000.01;
  783   return ReadAdc();
  784 }
  785 
  786 //############################################################################################
  787 uns8  ReadAdcPotentiometer()
  788 //############################################################################################
  789 {
  790   // ADC initialization (for more info see PIC datasheet) pin C5 (AN4) as analog input
  791   ANSELA.5 = 1;
  792   // ADC setting (AN4 channel)
  793   ADCON0 = 0b0.00100.01;
  794   return ReadAdc();
  795 }
  796 //############################################################################################
  797 #endif
  798 //############################################################################################
  799 // 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)
  800 #include "DPAcustomHandler.h"
  801 //############################################################################################