/******************************************************************************
** Copyright 2015 MBARI - Monterey Bay Aquarium Research Institute
*******************************************************************************
*******************************************************************************
** Summary  : Routines to access DS2482 One-Wire Bridge via ISO-I2C 
** Filename : ds1683.c
** Author   : Luke Coletti
** Project  :
** Version  : 1.0
** Compiler : MetroWerks Code Warrior v8.3
** Created  : 12/15/14
** Archived :
*******************************************************************************
** Modification History:
** 01/02/15 : CF2 Port, LJC
*******************************************************************************/

#include	<cfxbios.h>		// Persistor BIOS and I/O Definitions
#include	<io_i2c.h>
#include	<ds2482.h>


/* DS2482 I2C I/O high level function prototypes */

//--------------------------------------------------------------------------
// DS2482 Detect routine that sets the I2C address and then performs a
// device reset followed by writing the configuration byte to default values:
//   1-Wire speed (c1WS) = standard (0)
//   Strong pullup (cSPU) = off (0)
//   Presence pulse masking (cPPM) = off (0)
//   Active pullup (cAPU) = on (CONFIG_APU = 0x01)
//
// Returns: TRUE if device was detected and written
//          FALSE device not detected or failure to write configuration byte
//
int DS2482_detect(void)
{
int c1WS, cSPU, cPPM, cAPU;

   // reset the DS2482 ON selected address
   if(!DS2482_reset())
     return FALSE;

   // default configuration
   c1WS = FALSE;                //bitval 0x08 to set else 0
   cSPU = FALSE;                //bitval 0x04 to set else 0
   cPPM = FALSE;                //bitval 0x02 to set else 0
   cAPU = 0x01;                 //bitval 0x01 to set else 0

   // write the default configuration setup
   if(!DS2482_write_config(c1WS | cSPU | cPPM | cAPU))
      return FALSE;

   return TRUE;
}

//--------------------------------------------------------------------------
// Perform a device reset on the DS2482
//
// Returns: TRUE if device was reset
//          FALSE device not detected or failure to perform reset
//
int DS2482_reset(void)
{
uchar ret;
uchar status;

   // Device Reset
   //   S AD,0 [A] DRST [A] Sr AD,1 [A] [SS] A\ P
   //  [] indicates from slave
   //  SS status byte to read to verify state

   I2C_Select( I2C_BUS_DURA );
   
   I2C_Start();
   ret =  I2C_WrByte( DS2482_ADDR_WR );
   ret &= I2C_WrByte( DS2482_CMD_DRST );
   I2C_Start();
   ret &= I2C_WrByte( DS2482_ADDR_RD );
   ret &= I2C_RdByte( &status );
   I2C_WrNak();
   I2C_Stop();
   
   I2C_Select( I2C_BUS_DISABLE );

   // DisplayByteVal("DS2482 Status", status);

   // check for failure due to incorrect read back of status
   // mask off LL bit and look for RST bit
   return ((status & 0xF7) == 0x10);
}

//--------------------------------------------------------------------------
// Write the configuration register in the DS2482. The configuration
// options are provided in the lower nibble of the provided config byte.
// The uppper nibble in bitwise inverted when written to the DS2482.
//
// Returns:  TRUE: config written and response correct
//           FALSE: response incorrect
//
int DS2482_write_config(uchar config)
{
uchar ret;
uchar read_config;

   // Write configuration (Case A)
   //   S AD,0 [A] WCFG [A] CF [A] Sr AD,1 [A] [CF] A\ P
   //  [] indicates from slave
   //  CF configuration byte to write

   I2C_Select( I2C_BUS_DURA );   
   
   I2C_Start();
   ret =  I2C_WrByte( DS2482_ADDR_WR );
   ret &= I2C_WrByte( DS2482_CMD_WCFG );
   ret &= I2C_WrByte( (config | (~config << 4)) );
   I2C_Start();
   ret &= I2C_WrByte( DS2482_ADDR_RD );
   ret &= I2C_RdByte( &read_config );
   I2C_WrNak();
   I2C_Stop();
   
   I2C_Select( I2C_BUS_DISABLE );   
   
// DisplayByteVal("DS2482 Config", read_config);

   // check for failure due to incorrect read back
   if (config != read_config)
   {
      // handle error
      // ...
      //printf("DS2482 Config Read Error\n");
      DS2482_reset();

      return FALSE;
   }

   return TRUE;
}

//--------------------------------------------------------------------------
// Reset all of the devices on the 1-Wire Net and return the result.
//
// Returns: TRUE(1):  presence pulse(s) detected, device(s) reset
//          FALSE(0): no presence pulses detected
//
int DS2482_OWReset(int *short_detected)
{
uchar ret;
uchar status;
int poll_count = 0;

   // 1-Wire reset (Case B)
   //   S AD,0 [A] 1WRS [A] Sr AD,1 [A] [Status] A [Status] A\ P
   //                                   \--------/
   //                       Repeat until 1WB bit has changed to 0
   //  [] indicates from slave

   I2C_Select( I2C_BUS_DURA );   
   
   I2C_Start();
   ret =  I2C_WrByte( DS2482_ADDR_WR );
   ret &= I2C_WrByte( DS2482_CMD_1WRS );
   I2C_Start();
   ret &= I2C_WrByte( DS2482_ADDR_RD );

   // loop checking 1WB bit for completion of 1-Wire operation
   // abort if poll limit reached
   do
   {
      I2C_RdByte( &status );
      if( status & STATUS_1WB )
        I2C_WrAck();
      else{
        I2C_WrNak();
        break;
        }
   }
   while( (poll_count++ < POLL_LIMIT) );

   I2C_Stop();
   
   I2C_Select( I2C_BUS_DISABLE );   

   // check for failure due to poll limit reached
   if (poll_count >= POLL_LIMIT)
   {
      // handle error
      // ...
      //printf("DS2482 Poll Limit Error\n");
      DS2482_reset();
      return FALSE;
   }

   // check for short condition
   if (status & STATUS_SD)
      *short_detected = TRUE;
   else
      *short_detected = FALSE;

   // check for presence detect
   if (status & STATUS_PPD)
      return TRUE;
   else
      return FALSE;
}

//--------------------------------------------------------------------------
// Send 8 bits of read communication to the 1-Wire Net and return the
// result 8 bits read from the 1-Wire Net.
//
// Returns:  8 bits read from 1-Wire Net
//
uchar DS2482_OWReadByte(void)
{
uchar ret;
uchar data, status;
int poll_count = 0;

   // 1-Wire Read Bytes (Case C)
   //   S AD,0 [A] 1WRB [A] Sr AD,1 [A] [Status] A [Status] A\
   //                                   \--------/
   //                     Repeat until 1WB bit has changed to 0
   //   Sr AD,0 [A] SRP [A] E1 [A] Sr AD,1 [A] DD A\ P
   //
   //  [] indicates from slave
   //  DD data read
   
   I2C_Select( I2C_BUS_DURA );  

   I2C_Start();
   ret =  I2C_WrByte( DS2482_ADDR_WR );
   ret &= I2C_WrByte( DS2482_CMD_1WRB );
   I2C_Start();
   ret &= I2C_WrByte( DS2482_ADDR_RD );

   // loop checking 1WB bit for completion of 1-Wire operation
   // abort if poll limit reached
   do
   {
      I2C_RdByte( &status );
      if( status & STATUS_1WB )
        I2C_WrAck();
      else{
        I2C_WrNak();
        break;
        }
   }
   while( (poll_count++ < POLL_LIMIT) );

   // check for failure due to poll limit reached
   if (poll_count >= POLL_LIMIT)
   {
      // handle error
      // ...
      //printf("DS2482 Poll Limit Error\n");
      DS2482_reset();
      return( 0 );
   }

   I2C_Start();
   ret =  I2C_WrByte( DS2482_ADDR_WR );
   ret &= I2C_WrByte( DS2482_CMD_SRP );
   ret &= I2C_WrByte( DS2482_PTR_DATA );
   I2C_Start();
   ret &= I2C_WrByte( DS2482_ADDR_RD );

   I2C_RdByte( &data );
   I2C_WrNak();

   I2C_Stop();

   I2C_Select( I2C_BUS_DISABLE );     
   
   return( data );
}

//--------------------------------------------------------------------------
// Send 8 bits of communication to the 1-Wire Net and verify that the
// 8 bits read from the 1-Wire Net are the same (write operation).
// The parameter 'sendbyte' least significant 8 bits are used.
//
// 'sendbyte' - 8 bits to send (least significant byte)
//
// Returns:  TRUE: bytes written and echo was the same
//           FALSE: echo was not the same
//
uchar DS2482_OWWriteByte(uchar sendbyte)
{
uchar ret;
uchar status;
int poll_count = 0;

   // 1-Wire Write Byte (Case B)
   //   S AD,0 [A] 1WWB [A] DD [A] Sr AD,1 [A] [Status] A [Status] A\ P
   //                                          \--------/
   //                             Repeat until 1WB bit has changed to 0
   //  [] indicates from slave
   //  DD data to write

   I2C_Select( I2C_BUS_DURA );  
   
   I2C_Start();
   ret =  I2C_WrByte( DS2482_ADDR_WR );
   ret &= I2C_WrByte( DS2482_CMD_1WWB );
   ret &= I2C_WrByte( sendbyte );
   I2C_Start();
   ret &= I2C_WrByte( DS2482_ADDR_RD );

   // loop checking 1WB bit for completion of 1-Wire operation
   // abort if poll limit reached
   do
   {
      I2C_RdByte( &status );
      if( status & STATUS_1WB )
        I2C_WrAck();
      else{
        I2C_WrNak();
        break;
        }
   }
   while( (poll_count++ < POLL_LIMIT) );

   I2C_Stop();
   
   I2C_Select( I2C_BUS_DISABLE );    

   // check for failure due to poll limit reached
   if (poll_count >= POLL_LIMIT)
   {
      // handle error
      // ...
      //printf("DS2482 Poll Limit Error\n");
      DS2482_reset();
   }

    return( ret );
}
