// This file has been prepared for Doxygen automatic documentation generation.
/*! \file ********************************************************************
*
* Atmel Corporation
*
* \li File:               main.c
* \li Compiler:           IAR EWAAVR 3.20a
* \li Support mail:       avr@atmel.com
*
* \li Supported devices:  All AVRs.
*
* \li Application Note:   AVR318 - Dallas 1-Wire(R) master.
*
*
* \li Description:        Example on how to use the 1-Wire(R) interface
*                         master.
*
*                         $Revision: 1.7 $
*                         $Date: Thursday, August 19, 2004 14:27:18 UTC $
****************************************************************************/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "OWImain.h"
#include "lcd.h"
#include "basis.h"

#define MAX_DEVICES  1

// Defines used only in code example.
#define DS1820_FAMILY_ID            0x10   // temeratur sensor 9 Bit
#define DS1822_FAMILY_ID            0x22   // temeratur sensor 12 Bit
#define DS1820_START_CONVERSION     0x44
#define DS1820_READ_SCRATCHPAD      0xbe
#define DS1820_READ_POWER_SUPPLY    0xb4
#define DS1820_ERROR               -1000   // Return code. Outside temperature range.

#define OWI_ROM_SKIP                0xcc  //!< SKIP ROM command code.

#define DS2890_FAMILY_ID            0x2c   // 100k einstellbarer Widerstand
#define DS2890_WRITE_CONTROL_REGISTER  0X55
#define DS2890_RELEASE_CODE            0x96
#define DS2890_WRITE_POSITION       0x0f

#define SEARCH_SUCCESSFUL           0x00
#define SEARCH_CRC_ERROR            0x01

/****************************************************************************
 ROM commands
****************************************************************************/
#define     OWI_ROM_READ    0x33    // READ ROM command code.
#define     OWI_ROM_SKIP    0xcc    // SKIP ROM command code.
#define     OWI_ROM_MATCH   0x55    // MATCH ROM command code.
#define     OWI_ROM_SEARCH  0xf0    // SEARCH ROM command code.

#define DS1820_READ_SCRATCHPAD 0xbe

/****************************************************************************
 Return codes
****************************************************************************/
#define     OWI_ROM_SEARCH_FINISHED 0x00    // Search finished return code
#define     OWI_CRC_OK              0x00    // CRC check succeded
#define     OWI_CRC_ERROR           0x01    // CRC check failed

#define FALSE     0
#define TRUE      1

#define     OWI_USE_INTERNAL_PULLUP         // geht nur mit dieser Option   
/****************************************************************************
 Macros
****************************************************************************/

/*! \def    OWI_RELEASE_BUS(bitMask)
 *
 *  \brief  Release the bus.
 *
 *  This macro releases the bus and enables the internal pull-up if
 *  it is used.
 *
 *  \param  bitMask A bitmask of the buses to release.

#ifdef OWI_USE_INTERNAL_PULLUP
// Set 1-Wire pin(s) to input and enable internal pull-up resistor.
#define OWI_RELEASE_BUS(bitMask) \
            OWI_DDR &= ~bitMask; \
            OWI_PORT |= bitMask;

#else
// Set 1-Wire pin(s) to input mode. No internal pull-up enabled.
#define OWI_RELEASE_BUS(bitMask) \
            OWI_DDR &= ~bitMask; \
            OWI_PORT &= ~bitMask;

#endif
 */
unsigned char OWI_ComputeCRC8 (unsigned char inData, unsigned char seed);
unsigned int  OWI_ComputeCRC16(unsigned char inData, unsigned int seed);
unsigned char OWI_CheckRomCRC (unsigned char * romValue);
unsigned char OWI_ComputeCRCn (unsigned char * romValue, unsigned char n);
void OWI_SendByte             (unsigned char data, unsigned char pins);
unsigned char OWI_ReceiveByte (unsigned char pin);
void OWI_SkipRom              (unsigned char pins);
void OWI_ReadRom              (unsigned char * romValue, unsigned char pins);
void OWI_ReadSCRATCHPAD       (unsigned char * romValue, unsigned char pin);
void OWI_Reset(unsigned char pins);
void OWI_WriteBit1(unsigned char pins);
void OWI_WriteBit0(unsigned char pins);
unsigned char OWI_ReadBit(unsigned char pins);
unsigned char OWI_DetectPresence(unsigned char pins);

/****************************************************
*  Temperatur aufbereiten, 5 stellig
*  xxx,x
*  - x,x
*/
void edit_temperatur( DALLAS *pdallas, char *ziel )
{
   int x,r,rr;
   unsigned char negativ = 0;

   if ( pdallas->flag & DS_TEMP_DA )  // temperatur da
   {  
      x = pdallas->tempwert;
      if ( x < 0 )
      {
         negativ = 1;
         x *= -1;
      }
   
      if ( pdallas->kennung == 0x22 )     // DS1822
      {
         r = x & 0x000F ;
         x >>= 4;        // temperatur
         r *= 100;       //
         r /= 16;
         rr = r % 10;    // 0,0x ermitteln
         r /= 10 ;       // 0,x
         if ( rr > 5 )   // rest > 5
         {
            r++;         // aufrunden
            if ( r > 9 )    // 0,9 ??
            {
               r = 0;
               x++;
            }
         }
         ziel[4] = r + 0x30 ;
         ziel[3] = ',';
         ziel[2] = (x % 10) + 0x30 ;
         x /= 10;
         if ( x )
         {
            ziel[1] = (x % 10) + 0x30 ;
            x /= 10;
            if ( x )
               ziel[0] = (x % 10) + 0x30 ;
         }
         if ( negativ )
            ziel[0] = '-' ;
      }
   }
   else
   {
      edit_hex( 2, pdallas->flag, ziel );
      ziel[2] = 'b' ;       
      edit_hex( 2, pdallas->busbit, ziel+3 ); 
   }
}



/****************************************************
*  init dallas struktur
*  read ds1820/ds1822  Rom = serial number
*/
void OWI_Init(DALLAS *pdallas, unsigned char bit, char korr_wert )
{
   unsigned char i,n;
   unsigned char id[8];

   for( i=0; i < 8; i++)
   {
      pdallas->sim_eeprom[i] = 0xFF;           // clear serial number
   }
   for( i=0; i < 9; i++)
   {
      pdallas->mdata[i] = 0xFF;                // clear messung
   }
   pdallas->busbit = bit;                      // bit number
   pdallas->tempwert = 1;                      // clear
   pdallas->korrektur = korr_wert;             // korrektur Bits
   pdallas->kennung = 0xFF;                    //
   
   // OWI_Reset( bit );   
   i = OWI_DetectPresence( bit );              // reset pulse inter da
   if ( i )
   {
      OWI_ReadRom( id, bit);                   // read serial number
      
      i = OWI_ComputeCRCn( id, 7);             // compute CRC
      if ( i ==  id[7] )                       // CRC equ ??
      {
         for ( n=0; n < 7; n++)
         {
            pdallas->sim_eeprom[n] = id[n];
         }
         pdallas->kennung = id[0];             // family code merken
         if ( pdallas->kennung == 0x22 )
            pdallas->flag = DS_INIT_OK;          
      }
   }
   else
      pdallas->flag = DS_NICHT_DA;             //
}



/*********************************************************************
 *  This function will start a conversion and read back the temperature
 *  from a DS1820 temperature sensor.
 *  04.01.2010 li example3: nur ein DS1820 angeschlossen
 *  danach 800ms warten
 */
void DS1820_ReadTempStep1(DALLAS *pdallas)
{
   unsigned char bus, i=0;

   if ( pdallas->kennung == 0x22 )
   {
      bus = pdallas->busbit;
      i = OWI_DetectPresence( bus );           // Reset und hole precense code
      if ( i )
      {
         pdallas->flag |= DS_TEMP_S1;          // flag start messung setzen
         pdallas->flag &= ~DS_CRC_DATA_ERROR;  // reset Error  
         OWI_SkipRom( bus);
         OWI_SendByte(DS1820_START_CONVERSION, bus);  // Send start conversion command.
                                               // strong pullup on.
         OWI_DDR |= bus;                       // Port auf output 
         OWI_PORT |= bus;                      // port high
      }
   }
}



/*********************************************************************
 *  This function will start a conversion and read back the temperature
 *  from a DS1820 temperature sensor.
 *  04.01.2010 li example3: nur ein DS1820 angeschlossen
 */
void DS1820_ReadTempStep2(DALLAS *pdallas)
{
   unsigned char Feld[9],i, n, bus;
   int temp,x;
   bus = pdallas->busbit;
   
   if ( pdallas->flag & DS_TEMP_S1 )      // start Messung da gewesen ??
   {   
                                          // Berechnungen fuer DS18(s)20 durchfuehren
      i = OWI_DetectPresence(bus);        // Reset und hole precense code
      if ( i )
      {
         OWI_SkipRom( bus);
         OWI_ReadSCRATCHPAD(Feld, bus);    // Daten auslesen
         n = OWI_ComputeCRCn(Feld,8);      // CRC berechnen

         for (i=0; i < 9;i++)
         {
            pdallas->mdata[i] = Feld[i];   // save     
         }
         pdallas->flag &= ~(DS_TEMP_S1);
         if( n == Feld[8] )                // CRC equ ??
         {
            temp  = Feld[0] & 0xFF;
            x = Feld[1];
            x <<= 8;
            temp |= x;
            pdallas->tempwert = temp + pdallas->korrektur;  // 13.3.2010
            pdallas->flag |= DS_TEMP_DA;             
         }      
         else
         {
            pdallas->flag &= ~DS_TEMP_DA;   // reset 
            pdallas->flag |= DS_CRC_DATA_ERROR;         
         }
      }
   }
}



/*  
 *  pins    A bitmask of the buses to initialize.
 */
void OWI_Reset(unsigned char pins)
{
                           // The first rising edge can be interpreted by a slave as the end of a
   OWI_DDR &= ~pins;       // set input               
   OWI_PORT |= pins;       // use intern pullup  
   _delay_us(480);
}                          // sure that the real reset is interpreted correctly.


/*
 *  pins    A bitmask of the buses to write to.
 */
void OWI_WriteBit1(unsigned char pins)
{
   unsigned char intState;

   intState = SREG;        // save interrupts.
   cli();
                           // Drive bus low and delay.
   OWI_DDR |= pins;
   OWI_PORT &= ~pins;
   _delay_us(6);
                           // Release bus and delay.
   OWI_DDR &= ~pins;       // set input               
   OWI_PORT |= pins;       // use intern pullup  
   _delay_us(64);

   SREG = intState;
   sei();
}


/*
 *  param  pins    A bitmask of the buses to write to.
 */
void OWI_WriteBit0(unsigned char pins)
{
   unsigned char intState;

   intState = SREG;        // Disable interrupts.
   cli();
                           // Drive bus low and delay.
   OWI_DDR |= pins;
   OWI_PORT &= ~pins;
   _delay_us(60);
                           // Release bus and delay.
   OWI_DDR &= ~pins;       // set input               
   OWI_PORT |= pins;       // use intern pullup  
   _delay_us(10);

   SREG = intState;
   sei();
}


/*
 *  return A bitmask of the buses where a '1' was read.
 */
unsigned char OWI_ReadBit(unsigned char pins)
{
   unsigned char intState;
   unsigned char bitsRead;

   intState = SREG;        // save interrupts.
   cli();
                           // Drive bus low and delay.
   OWI_DDR |= pins;
   OWI_PORT &= ~pins;
   _delay_us(6);

                           // Release bus and delay.
   OWI_DDR &= ~pins;       // set input               
   OWI_PORT |= pins;       // use intern pullup  
   _delay_us(9);

   bitsRead = OWI_PIN & pins;          // Sample bus and delay.
   _delay_us(55);

   SREG = intState;
   sei();

   return bitsRead;
}


/********************************************************************
 *  Send a Reset signal and listen for Presence signal
 *
 *  Generates the waveform for transmission of a Reset pulse on the
 *  1-Wire(R) bus and listens for presence signals.
 *
 *  pins    A bitmask of the buses to send the Reset signal on.
 *
 *  return  A bitmask of the buses where a presence signal was detected.
 */
unsigned char OWI_DetectPresence(unsigned char pins)
{
   unsigned char intState;
   unsigned char presenceDetected;

   intState = SREG;
   cli();                  // disable ints
                           // Drive bus low and delay.
   OWI_DDR |= pins;
   OWI_PORT &= ~pins;
   _delay_us(480);
                           // Release bus and delay.
   OWI_DDR &= ~pins;       // set input               
   OWI_PORT |= pins;       // use intern pullup   
   _delay_us(70);

   presenceDetected = OWI_PIN & pins ;       // Sample bus to detect presence signal and delay.
   _delay_us(410);

   SREG = intState;
   sei();
   
   return (presenceDetected ^= pins);        // aus 0 wird 1  
}


/*! \brief  Compute the CRC8 value of a data set.
 *
 *  This function will compute the CRC8 or DOW-CRC of inData using seed
 *  as inital value for the CRC.
 *
 *  \param  inData  One byte of data to compute CRC from.
 *
 *  \param  seed    The starting value of the CRC.
 *
 *  \return The CRC8 of inData with seed as initial value.
 *
 *  \note   Setting seed to 0 computes the crc8 of the inData.
 *
 *  \note   Constantly passing the return value of this function
 *          As the seed argument computes the CRC8 value of a
 *          longer string of data.
 */
unsigned char OWI_ComputeCRC8(unsigned char inData, unsigned char seed)
{
   unsigned char bitsLeft;
   unsigned char temp;

   for (bitsLeft = 8; bitsLeft > 0; bitsLeft--)
   {
      temp = ((seed ^ inData) & 0x01);
      if (temp == 0)
         seed >>= 1;
      else
      {
         seed ^= 0x18;
         seed >>= 1;
         seed |= 0x80;
      }
      inData >>= 1;
   }
   return seed;
}


/*! \brief  Compute the CRC16 value of a data set.
 *
 *  This function will compute the CRC16 of inData using seed
 *  as inital value for the CRC.
 *
 *  \param  inData  One byte of data to compute CRC from.
 *
 *  \param  seed    The starting value of the CRC.
 *
 *  \return The CRC16 of inData with seed as initial value.
 *
 *  \note   Setting seed to 0 computes the crc16 of the inData.
 *
 *  \note   Constantly passing the return value of this function
 *          As the seed argument computes the CRC16 value of a
 *          longer string of data.
 */
unsigned int OWI_ComputeCRC16(unsigned char inData, unsigned int seed)
{
    unsigned char bitsLeft;
    unsigned char temp;

    for (bitsLeft = 8; bitsLeft > 0; bitsLeft--)
    {
        temp = ((seed ^ inData) & 0x01);
        if (temp == 0)
        {
            seed >>= 1;
        }
        else
        {
            seed ^= 0x4002;
            seed >>= 1;
            seed |= 0x8000;
        }
        inData >>= 1;
    }
    return seed;
}


/*! \brief  Calculate and check the CRC of a 64 bit ROM identifier.
 *
 *  This function computes the CRC8 value of the first 56 bits of a
 *  64 bit identifier. It then checks the calculated value against the
 *  CRC value stored in ROM.
 *
 *  \param  romvalue    A pointer to an array holding a 64 bit identifier.
 *
 *  \retval OWI_CRC_OK      The CRC's matched.
 *  \retval OWI_CRC_ERROR   There was a discrepancy between the calculated and the stored CRC.
 */
unsigned char OWI_CheckRomCRC(unsigned char * romValue)
{
    unsigned char i;
    unsigned char crc8 = 0;

    for (i = 0; i < 7; i++)
    {
        crc8 = OWI_ComputeCRC8(*romValue, crc8);
        romValue++;
    }
    if (crc8 == (*romValue))
    {
        return OWI_CRC_OK;
    }
    return OWI_CRC_ERROR;
}

/*! \brief  Compute the CRC8 value of a data set of n bytes.
 *
 *  This function will compute the CRC8 or DOW-CRC of a data set with n bytes
 *
 *  \param  romvalue    A pointer to an array holding the data set.
 *
 *  \param  n    number of bytes for crc-check.
 *
 *  \return The CRC8 of n bytes starting with romvalue.
 */
unsigned char OWI_ComputeCRCn(unsigned char * romValue, unsigned char n)
{
   unsigned char crc;

   crc = 0;
   do
   {
      crc = OWI_ComputeCRC8(*romValue, crc);
      romValue++;
      n--;
   } while (n);

   return crc;
}

/*! \brief  Sends one byte of data on the 1-Wire(R) bus(es).
 *
 *  This function automates the task of sending a complete byte
 *  of data on the 1-Wire bus(es).
 *
 *  \param  data    The data to send on the bus(es).
 *
 *  \param  pins    A bitmask of the buses to send the data to.
 */
void OWI_SendByte(unsigned char data, unsigned char pins)
{
   unsigned char i;

   for (i = 0; i < 8; i++)         // Do once for each bit
   {
      if ( data & 0x01 )
         OWI_WriteBit1(pins);
      else
         OWI_WriteBit0(pins);
      data >>= 1;       // Right shift the data to get next bit.
   }
}



/*! \brief  Receives one byte of data from the 1-Wire(R) bus.
 *
 *  This function automates the task of receiving a complete byte
 *  of data from the 1-Wire bus.
 *
 *  \param  pin     A bitmask of the bus to read from.
 *
 *  \return     The byte read from the bus.
 */
unsigned char OWI_ReceiveByte(unsigned char pin)
{
   unsigned char data;
   unsigned char i;

   data = 0x00;               // Clear the temporary input variable.

   for (i = 0; i < 8; i++)    // Do once for each bit
   {
      data >>= 1;             // Shift temporary input variable right.
                              // Set the msb if a '1' value is read from the bus
      if ( OWI_ReadBit(pin) )
         data |= 0x80; // Set msb
   }
   return data;
}



/*! \brief  Sends the SKIP ROM command to the 1-Wire bus(es).
 *
 *  \param  pins    A bitmask of the buses to send the SKIP ROM command to.
 */
void OWI_SkipRom(unsigned char pins)
{
   OWI_SendByte(OWI_ROM_SKIP, pins);   // Send the SKIP ROM command on the bus.
}



/*! \brief  Sends the READ ROM command and reads back the ROM id.
 *
 *  \param  romValue    A pointer where the id will be placed.
 *
 *  \param  pin     A bitmask of the bus to read from.
 */
void OWI_ReadRom(unsigned char *romValue, unsigned char pin)
{
   unsigned char bytesLeft = 8;

   OWI_SendByte( OWI_ROM_READ, pin);      // Send the READ ROM command on the bus.

   while ( bytesLeft > 0)
   {                                      // Do 8 times.
      *romValue++ = OWI_ReceiveByte(pin); // Place the received data in memory.
      bytesLeft--;
   }
}



/*! \brief  Sends the READ SCRATCHPAD command and reads back the SCRATCHPAD.
 *
 *  \param  romValue    A pointer where the SRATCHPAD will be placed.
 *
 *  \param  pin     A bitmask of the bus to read from.
 */
void OWI_ReadSCRATCHPAD(unsigned char * romValue, unsigned char pin)
{
   unsigned char bytesLeft = 9;

   OWI_SendByte( DS1820_READ_SCRATCHPAD, pin);  // Send the READ SCRATCHPAD command on the bus.

   do
   {                                            // Do 9 times.
      *romValue++ = OWI_ReceiveByte(pin);      // Place the received data and crc in memory.
      bytesLeft--;
   } while (bytesLeft);
}

