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