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