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.33 $
    8 // Date:    $Date: 2022/02/25 09:41:25 $
    9 //
   10 // Revision history:
   11 //   2022/02/24  Release for DPA 4.17
   12 //   2021/08/20  Release for DPA 4.16
   13 //   2020/01/02  Release for DPA 4.11
   14 //   2017/03/13  Release for DPA 3.00
   15 //   2016/12/22  Release for DPA 2.28
   16 //
   17 // *********************************************************************
   18 
   19 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/
   20 
   21 /* This example implements HWP for DDC-SE-01 and/or DDC-RE-01
   22 
   23 DDC-SE-01: HWPID=0x001F
   24 DDC-RE-01: HWPID=0x002F
   25 DDC-SE-01 & DDC-RE-01: HWPID=0x003F
   26 
   27 ! Make sure embedded UART DPA peripheral is not enabled to avoid a collision of peripherals
   28 
   29 ----------- DDC-SE-01
   30 Request: PNUM = 0x20, PCMD = 0x31
   31 Response:
   32  PData[0]=Temperature at [C]
   33  PData[1]=Photoresistor value 0x00-0xFF
   34  PData[2]=Potentiometer value 0x00-0xFF
   35  returns ERROR_FAIL when error reading temperature
   36 
   37 FRC=0xC0, returns temperature at C, 127 for 0 C, 0x80 for error reading temperature
   38 FRC=0xC1, returns photoresistor value, returns 1 instead of 0
   39 FRC=0xC2, returns potentiometer value, returns 1 instead of 0
   40 
   41 ----------- DDC-RE-01
   42 Request: PNUM = 0x20, PCMD = 0x32
   43  PData[0]=Relay1Ctrl
   44  PData[1]=Relay2Ctrl
   45 
   46 Response:
   47  PData[0]=Relay1State
   48  PData[1]=Relay2State
   49 
   50 RelayCtrl: 0=Switch the Relay off, 1=Switch the Relay on, Other=Do not control the Relay
   51 RelayState: 0=Relay was off, 1=Relay was on
   52 */
   53 
   54 // *********************************************************************
   55 
   56 // Default IQRF include (modify the path according to your setup)
   57 #include "IQRF.h"
   58 
   59 // Default DPA header (modify the path according to your setup)
   60 #include "DPA.h"
   61 // Default Custom DPA Handler header (modify the path according to your setup)
   62 #include "DPAcustomHandler.h"
   63 
   64 #if defined( DDC_SE_01 ) && defined( DDC_RE_01 )
   65 #define ThisHWPID 0x003F
   66 #elif defined( DDC_SE_01 )
   67 #define ThisHWPID 0x001F
   68 #elif defined( DDC_RE_01 )
   69 #define ThisHWPID 0x002F
   70 #else
   71 #error Symbol(s) DDC_SE_01 and/or DDC_RE_01 must be defined
   72 #endif
   73 
   74 //############################################################################################
   75 
   76 #if defined( DDC_SE_01 )
   77 
   78 // Special temperature value to indicate a sensor error
   79 #define ERROR_TEMPERATURE 0xF800
   80 
   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 // Writes sensor configuration (resolution)
   87 bit Ds18B20WriteConfig( uns8 value );
   88 
   89 // Resets OneWire
   90 bit OneWireReset();
   91 // Reads OneWire byte
   92 uns8 OneWireReadByte();
   93 // Writes OneWire byte
   94 void OneWireWriteByte( uns8 byte );
   95 
   96 // DS18B20 commands
   97 #define CMD_READROM       0x33
   98 #define CMD_CONVERTTEMP   0x44
   99 #define CMD_CPYSCRATCHPAD 0x48
  100 #define CMD_WSCRATCHPAD   0x4e
  101 #define CMD_MATCHROM      0x55
  102 #define CMD_RPWRSUPPLY    0xb4
  103 #define CMD_RECEEPROM     0xb8
  104 #define CMD_RSCRATCHPAD   0xbe
  105 #define CMD_SKIPROM       0xcc
  106 #define CMD_ALARMSEARCH   0xec
  107 #define CMD_SEARCHROM     0xf0
  108 
  109 // I2C SCL frequency [Hz]
  110 #define I2Cfrequency      50000
  111 
  112 // MCP9802 address
  113 #define I2C_ADR           0b1001.0110
  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 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               {
  388                 W = ERROR_DATA_LEN;
  389                 goto _ERROR_W;
  390               }
  391 
  392               // Read temperature and check for an error
  393               uns16 temperature = GetTemperature();
  394               if ( temperature == ERROR_TEMPERATURE )
  395               {
  396                 W = ERROR_FAIL;
  397                 goto _ERROR_W;
  398               }
  399 
  400               _DpaMessage.Response.PData[0] = temperature.low8;
  401 
  402               // Read other sensors
  403               _DpaMessage.Response.PData[1] = ReadAdcPhotoresistor();
  404               _DpaMessage.Response.PData[2] = ReadAdcPotentiometer();
  405 
  406               // Return 3 bytes
  407               _DpaDataLength = 3;
  408               goto DpaHandleReturnTRUE;
  409 #endif
  410 
  411 #if defined( DDC_RE_01 )
  412             case 0x32:
  413               // Control and return state of relays
  414               if ( _DpaDataLength != 2 )
  415               {
  416                 W = ERROR_DATA_LEN;
  417                 goto _ERROR_W;
  418               }
  419 
  420               // Relay #1
  421               // Get
  422               userReg0 = 0;
  423               if ( RELAY1_LAT )
  424                 userReg0.0 = 1;
  425 
  426               // Set
  427               switch ( _DpaMessage.Request.PData[0] )
  428               {
  429                 case 0:
  430                   RELAY1_LAT = 0;
  431                   break;
  432                 case 1:
  433                   RELAY1_LAT = 1;
  434                   break;
  435               }
  436               _DpaMessage.Response.PData[0] = userReg0;
  437 
  438               // Relay #2
  439               // Get
  440               userReg0 = 0;
  441               if ( RELAY2_LAT )
  442                 userReg0.0 = 1;
  443 
  444               // Set
  445               switch ( _DpaMessage.Request.PData[1] )
  446               {
  447                 case 0:
  448                   RELAY2_LAT = 0;
  449                   break;
  450                 case 1:
  451                   RELAY2_LAT = 1;
  452                   break;
  453               }
  454               _DpaMessage.Response.PData[1] = userReg0;
  455               // Receives and returns 2 bytes
  456               goto DpaHandleReturnTRUE;
  457 #endif
  458 
  459               // Invalid command
  460             default:
  461               W = ERROR_PCMD;
  462 _ERROR_W:
  463               DpaApiReturnPeripheralError( W );
  464           }
  465         }
  466       }
  467 
  468       break;
  469     }
  470 
  471     // -------------------------------------------------
  472     case DpaEvent_Init:
  473       // Do a one time initialization before main loop starts
  474 
  475 #if defined( DDC_SE_01 )
  476       // Initialize sensors
  477 
  478       // C5 as input
  479       moduleInfo();
  480       // Connected TR pins?
  481       if ( !bufferINFO[5].7 )
  482       {
  483         TRISC.6 = 1;
  484         TRISB.4 = 1;
  485       }
  486       // C5 as input
  487       TRISA.5 = 1;
  488       // C1 as input
  489       TRISA.0 = 1;
  490 
  491       // Setup TMR6 to generate ticks on the background (ticks every 10ms)
  492       _PR6 = 250 - 1;
  493       // Prescaler 16, Postscaler 10, 16 * 10 * 250 = 40000 = 4MHz * 10ms
  494 #if defined( TR7xG )
  495       TMR6MD = 0;
  496       T6CON = 0b1.100.1001;
  497       //  Timer2/4/6 Clock Select bits = FOSC/4
  498       T6CLKCON |= 0b0000.0001;
  499 #else
  500       T6CON = 0b0.1001.1.10;
  501 #endif
  502 
  503       TMR6IE = TRUE;
  504 
  505       // Setup DS18B20 for 9bit precision, conversion takes 94ms (see datasheet)
  506       if ( Ds18B20WriteConfig( 0b0.00.00000 ) )
  507         // DS18B20 is enabled
  508         isDS18B20 = TRUE;
  509       else
  510       {
  511         // Expect MCP9802 is enabled
  512         I2Ctimeout = 0xFF;
  513 
  514 #if defined( TR7xG )
  515         // Do PPS for I2C
  516         unlockPPS();
  517         SSP1CLKPPS = 0x13;  // RC3
  518         SSP1DATPPS = 0x14;  // RC4
  519         RC3PPS = 0x14;      // SCK1/SCL1
  520         RC4PPS = 0x15;      // SD01/SDA1
  521         lockPPS();
  522 #endif
  523 
  524         _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) );
  525       }
  526 #endif
  527 
  528 #if defined( DDC_RE_01 )
  529       // Initialize relays
  530       RELAY1_LAT = 0;
  531       RELAY2_LAT = 0;
  532       RELAY1_TRIS = 0;
  533       RELAY2_TRIS = 0;
  534 
  535 #endif
  536       break;
  537 
  538 #if defined( DDC_SE_01 )
  539       // -------------------------------------------------
  540     case DpaEvent_AfterSleep:
  541       // Called after woken up after sleep
  542       if ( !isDS18B20 )
  543         _DpaApiI2Cinit( I2CcomputeFrequency( I2Cfrequency ) );
  544 
  545       // Called on wake-up from sleep
  546       TMR6IE = TRUE;
  547       _TMR6ON = TRUE;
  548       break;
  549 
  550       // -------------------------------------------------
  551     case DpaEvent_BeforeSleep:
  552       // Called before going to sleep
  553       if ( !isDS18B20 )
  554         _DpaApiI2Cshutdown();
  555 
  556       // -------------------------------------------------
  557     case DpaEvent_DisableInterrupts:
  558       // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond, and Run RFPGM)
  559       // Must not use TMR6 any more
  560       _TMR6ON = FALSE;
  561       TMR6IE = FALSE;
  562       break;
  563 #endif
  564   }
  565   return FALSE;
  566 }
  567 
  568 //############################################################################################
  569 #if defined( DDC_SE_01 )
  570 
  571 //############################################################################################
  572 // OneWire and Dallas 18B20 routines
  573 //############################################################################################
  574 
  575 //############################################################################################
  576 void Delay5us( uns8 val @ W ) // Absolutely precise timing but val != 0
  577 //############################################################################################
  578 {
  579   // 16 MHz
  580   // + 0.75us ( W=val, Call )
  581   for ( ;; )
  582   {         // loop time
  583     nop2(); // 0.50us
  584     nop2(); // 1.00us
  585     nop2(); // 1.50us
  586     nop2(); // 2.00us
  587     nop2(); // 2.50us
  588     nop2(); // 3.00us
  589     nop();  // 3.25us
  590     if ( --val == 0 ) // + 0.75us (W--, BTFS )
  591       return;         // + 0.25us
  592     nop2(); // 4.50us
  593   }         // 5.00us (Goto)
  594 }
  595 //############################################################################################
  596 
  597 #define OneWireData0()  { OneWire_TRIS = 0; }     // 0.5us @ 16MHz
  598 #define OneWireData1()  { OneWire_TRIS = 1; }     // 0.5us @ 16MHz
  599 
  600 //############################################################################################
  601 void OneWireWriteByte( uns8 byte )
  602 //############################################################################################
  603 {
  604   uns8 bitLoop = 8;
  605   do
  606   {
  607     // Next sequence is time precision critical
  608     GIE = FALSE;
  609 
  610     OneWireData0();
  611     nop2();         // 1 us [0.5 us]
  612     nop2();         // [1.0 us]
  613     if ( byte.0 )   // 2.5 us [1.75us]
  614       OneWireData1();
  615 
  616     // End of time precision critical sequence
  617     GIE = TRUE;
  618 
  619     // 60us minimum in total, does not have to be precise
  620     Delay5us( ( 60 - 3 ) / 5 + 1 );
  621 
  622     OneWireData1();
  623 
  624     byte >>= 1;
  625   } while ( --bitLoop != 0 );
  626 }
  627 
  628 //############################################################################################
  629 uns8 OneWireReadByte()
  630 //############################################################################################
  631 {
  632   uns8 result;
  633   uns8 bitLoop = 8;
  634   do
  635   {
  636     // Next sequence is time precision critical
  637     GIE = FALSE;
  638 
  639     OneWireData0();
  640     nop2();         // 1 us [0.5 us]
  641 #if F_OSC == 16000000
  642     nop2();         // [1.0 us]
  643 #endif
  644     OneWireData1();         // 2 us [1.5 us]
  645     Delay5us( 15 / 5 );     // 17 us [16.5 us]
  646 
  647     Carry = 0;              // 17.5 us [16.75 us]
  648     if ( OneWire_IO_IN )    // 18.5 us [ 17.25 us] (condition must not modify Carry)
  649       Carry = 1;
  650 
  651     // End of time precision critical sequence
  652     GIE = TRUE;             // must not modify Carry
  653     result = rr( result );
  654 
  655     // 60us minimum in total, does not have to be precise
  656     Delay5us( ( 60 - 20 ) / 5 + 1 );
  657   } while ( --bitLoop != 0 );
  658 
  659   return result;
  660 }
  661 
  662 //############################################################################################
  663 bit OneWireReset()
  664 //############################################################################################
  665 {
  666   // Setting the pin once to low is enough
  667   OneWire_IO_OUT = 0;
  668   // Reset pulse
  669   OneWireData0();
  670   Delay5us( 500 / 5 );
  671   // Reset pulse end
  672   OneWireData1();
  673   // Next sequence is time precision critical
  674   GIE = FALSE;
  675   // Wait for presence pulse
  676   Delay5us( 70 / 5 );
  677   // End of time precision critical sequence
  678   GIE = TRUE;
  679   // Presence pulse?
  680   if ( OneWire_IO_IN )
  681   {
  682     // No presence, finish initialization sequence
  683     Delay5us( ( 500 - 70 ) / 5 );
  684     return FALSE;
  685   }
  686   else
  687   {
  688     // Presence OK, finish initialization sequence
  689     Delay5us( ( 500 - 70 ) / 5 );
  690     return TRUE;
  691   }
  692 }
  693 
  694 //############################################################################################
  695 void OneWireCmd( uns8 cmd )
  696 //############################################################################################
  697 {
  698   // OneWire: Skip ROM
  699   OneWireWriteByte( CMD_SKIPROM );
  700   // OneWire: Send command
  701   OneWireWriteByte( cmd );
  702 }
  703 
  704 //############################################################################################
  705 bit Ds18B20WriteConfig( uns8 value )
  706 //############################################################################################
  707 {
  708   if ( OneWireReset() )
  709   {
  710     // Write Scratchpad
  711     OneWireCmd( CMD_WSCRATCHPAD );
  712 
  713     // Write TL = ? (we dot not care the value)
  714     OneWireWriteByte( W );
  715     // Write TH = ? (we dot not care the value)
  716     OneWireWriteByte( W );
  717     // Write Config byte
  718     OneWireWriteByte( value );
  719 
  720     if ( OneWireReset() )
  721     {
  722       //  Copy Scratchpad
  723       OneWireCmd( CMD_CPYSCRATCHPAD );
  724       return TRUE;
  725     }
  726   }
  727   return FALSE;
  728 }
  729 
  730 //############################################################################################
  731 uns16 MCP9802GetTemp()
  732 //############################################################################################
  733 {
  734   // MCP9802 address
  735   _DpaApiI2Cstart( I2C_ADR );
  736   if ( I2CwasTimeout )
  737     return ERROR_TEMPERATURE;
  738 
  739   // pointer: 1 = configuration register
  740   _DpaApiI2Cwrite( 0x01 );
  741   // configuration: 9-bit ADC
  742   _DpaApiI2CwriteAndStop( 0x00 );
  743 
  744   // MCP9802 address
  745   _DpaApiI2Cstart( I2C_ADR );
  746   // pointer: 0 = temperature
  747   _DpaApiI2CwriteAndStop( 0 );
  748 
  749   // MCP9802 address + read
  750   _DpaApiI2Cstart( I2C_ADR | 1 );
  751   uns16 temperature;
  752   // store the result
  753   temperature.high8 = _DpaApiI2Cread( TRUE );
  754   temperature.low8 = _DpaApiI2Cread( FALSE );
  755   _DpaApiI2Cstop();
  756   return temperature;
  757 }
  758 
  759 //############################################################################################
  760 uns16 GetTemperature()
  761 //############################################################################################
  762 {
  763   // Reads temperature from an enabled sensor
  764   uns16 temperatureResult;
  765 
  766   if ( isDS18B20 )
  767   {
  768     // Temperature is ready at the background
  769     temperatureResult = temperature;
  770     if ( temperatureResult != ERROR_TEMPERATURE )
  771     {
  772       temperatureResult += 0x08;
  773       temperatureResult /= 0x10;
  774     }
  775   }
  776   else
  777   {
  778     // Temperature value must be read from I2C sensor
  779     temperatureResult = MCP9802GetTemp();
  780     if ( temperatureResult != ERROR_TEMPERATURE )
  781     {
  782       temperatureResult += 0x80;
  783       temperatureResult /= 0x100;
  784     }
  785   }
  786 
  787   return temperatureResult;
  788 }
  789 
  790 #if defined( TR7xG )
  791 //############################################################################################
  792 // Might not be needed if ADC registers are kept default
  793 void resetADCregs()
  794 //############################################################################################
  795 {
  796   // Start reseting ADC registers from ADCON0 to ADPCH
  797   FSR0 = &ADCON0;
  798   do
  799   {
  800     setINDF0( 0 );
  801     FSR0++;
  802     // Stop reseting at 1st GPR register, ADPCH is the last implemented register before GPR
  803   } while ( !FSR0L.5 );
  804 }
  805 #endif
  806 
  807 //############################################################################################
  808 uns8 ReadAdc()
  809 //############################################################################################
  810 {
  811 #if defined( TR7xG )
  812   // ADC is enabled, ADGO is cleared upon completion, Clock supplied according to ADCLK register, left-justified
  813   ADCON0 = 0b1000.0000;
  814   // ADC Conversion Clock = FOSC/8
  815   ADCLK = 8 / 2 - 1;
  816 #else
  817   // ADC result - left justified, Fosc/8
  818   ADCON1 = 0b0001.0000;
  819 #endif
  820 
  821   // Short delay to stabilize
  822   updateCRC16( W );
  823 
  824   // start ADC
  825   _GO = 1;
  826   // wait for ADC finish
  827   while ( _GO );
  828   return ADRESH;
  829 }
  830 
  831 //############################################################################################
  832 uns8  ReadAdcPhotoresistor()
  833 //############################################################################################
  834 {
  835 #if defined( TR7xG )
  836   // Enable ADC
  837   ADCMD = 0;
  838   // Resets all ADC registers
  839   // VREF- is connected to AVSS, VREF+ is connected to VDD
  840   resetADCregs();
  841   //  ADC Positive Input Channel = ANA0
  842   setADPCH( 0x00 );
  843 #else
  844   // ADC setting (AN0 channel)
  845   ADCON0 = 0b0.00000.01;
  846 #endif
  847   // ADC initialization (for more info see PIC datasheet) pin C1 (AN0-D/ANA0-G) as analog input
  848   ANSELA.0 = 1;
  849   return ReadAdc();
  850 }
  851 
  852 //############################################################################################
  853 uns8  ReadAdcPotentiometer()
  854 //############################################################################################
  855 {
  856 #if defined( TR7xG )
  857   // Enable ADC
  858   ADCMD = 0;
  859   // Resets all ADC registers
  860   // VREF- is connected to AVSS, VREF+ is connected to VDD
  861   resetADCregs();
  862   //  ADC Positive Input Channel = ANA5
  863   setADPCH( 0x05 );
  864 #else
  865   // ADC setting (AN4 channel)
  866   ADCON0 = 0b0.00100.01;
  867 #endif
  868   // ADC initialization (for more info see PIC datasheet) pin C5 (AN4-D/ANA5-G) as analog input
  869   ANSELA.5 = 1;
  870   return ReadAdc();
  871 }
  872 //############################################################################################
  873 #endif
  874 //############################################################################################
  875 // Default Custom DPA Handler header; 2nd include implementing a Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup)
  876 #include "DPAcustomHandler.h"
  877 //############################################################################################