#include "i2c.h"

volatile static uint8_t i2c_tx_buffer[BUFFER_SIZE];
volatile static uint8_t i2c_rx_buffer[BUFFER_SIZE];

volatile static uint8_t I2CMasterState = I2C_IDLE;
volatile static uint8_t I2CMasterMode;

volatile static uint8_t i2c_rx_counter = 0;
volatile static uint8_t i2c_tx_length = 0;

static uint8_t i2c_tx_index = 0;
uint8_t *i2c_rx_buffer_ptr = 0;                     

static void i2c_engine(void);

void i2c0_init(void)
{
//P3.1 TSC2013_SDA
//P3.2 TSC2013_SCL
  P3SEL |= 0x06;                            // Assign I2C pins to USCI_B0
 
  UCB0CTL1 |= UCSWRST;                      // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_1 + UCSWRST;            // Use ACLK, keep SW reset
  
  UCB0BR0 = 109;                           // fSCL = ACLK / 109 = ~100kHz
  UCB0BR1 = 0;
 
  UCB0I2CSA = 0x48;                         // Slave Address is 048h
  UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation

  IE2 |= UCB0TXIE;                          // Enable TX interrupt  
  IE2 |= UCB0RXIE;                          // Enable RX interrupt
}

#pragma vector = USCIAB0TX_VECTOR
__interrupt void i2c0_isr(void)
{
  if (I2CMasterMode == I2C_MASTER_WRITE)
  {
    if (i2c_tx_index < i2c_tx_length)               
    {
      UCB0TXBUF = i2c_tx_buffer[i2c_tx_index];
      i2c_tx_index++;
    }
    else
    {
      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
      IFG2 &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
      
      I2CMasterState = I2C_IDLE;
    }
  }
  else if (I2CMasterMode == I2C_MASTER_READ)
  {                                     
    i2c_rx_counter--;                              // Decrement RX byte counter
    if (i2c_rx_counter)
    {
      *i2c_rx_buffer_ptr++ = UCB0RXBUF;                 // Move RX data to address PRxData
         
      if (i2c_rx_counter == 1)                     // Only one byte left?
      {
        UCB0CTL1 |= UCTXSTP;                  // Generate I2C stop condition
      }
    }
    else
    {
      *i2c_rx_buffer_ptr = UCB0RXBUF;                   // Move final RX data to PRxData
      
      I2CMasterState = I2C_IDLE;
    }    
  }
}

void i2c0_write_register(uint8 reg_address, uint16 value)
{
  i2c_tx_length = 3;
  i2c_tx_index = 0;
  
  i2c_tx_buffer[0] = reg_address;
  i2c_tx_buffer[1] = (value >> 8);
  i2c_tx_buffer[2] = (value & 0xFF);
   
  I2CMasterMode = I2C_MASTER_WRITE;
  
  while (UCB0CTL1 & UCTXSTP);    // Ensure stop condition got sent

  I2CMasterState = I2C_BUSY;	
    
  UCB0CTL1 |= UCTR + UCTXSTT;    // I2C TX, start condition  
  
  i2c_engine();  
}

void i2c0_write_byte(uint8_t value)
{
  i2c_tx_length = 1;
  i2c_tx_index = 0;
  i2c_tx_buffer[0] = value;
  I2CMasterMode = I2C_MASTER_WRITE;
  
  while (UCB0CTL1 & UCTXSTP);    // Ensure stop condition got sent

  I2CMasterState = I2C_BUSY;	
    
  UCB0CTL1 |= UCTR + UCTXSTT;    // I2C TX, start condition  
  
  i2c_engine();
}

void i2c0_read_multi_byte(uint8 *data, uint8 length)
{
   uint8_t i;
     
   I2CMasterMode = I2C_MASTER_READ;
  
   i2c_rx_buffer_ptr = (uint8 *)i2c_rx_buffer;    
   i2c_rx_counter = length; 
   
   while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
   
   I2CMasterState = I2C_BUSY;	
      
   UCB0CTL1 &=(~UCTR);                     // Receiver Mode
   UCB0CTL1 |= UCTXSTT;                    // I2C start condition

   i2c_engine();
   
   for (i = 0;i < length; i++) 
   {
     data[i] = i2c_rx_buffer[i];	
   }
}

                         
void i2c_engine(void)
{
  while (I2CMasterState == I2C_BUSY)
  {
  }  
}

