/* Includes ------------------------------------------------------------------*/
#include "drv_eeprom_24c02.h"
#include "FE82160_i2c.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define I2C_SPEED_RATE        100   // uint khz

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
I2CStatus I2C_MasterTransmit(uint16_t DevAddress, uint8_t *pData, uint16_t Size);
I2CStatus I2C_MasterReceive(uint16_t DevAddress, uint8_t *pData, uint16_t Size);
/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Checks whether the last I2C module  status flag is get or not in timeout.
  * @param  I2C_flag: Pointer to I2C flag.
  * @retval An ErrorStatus enumeration value:
  *         - I2C_OK: Get the status flag
  *         - I2C_ERROR: Can't get the status flag
  */
I2CStatus I2C_WaitFlag(uint32_t *I2C_flag)
{
  uint32_t time_cnt = 0;
  I2CStatus ret = I2C_WAITING;
  
  /* Wait flag for 10 ms */
  do
  {
    /* Insert a delay time to get the status correctly */
    SysTick_DelayUs(10);
    /* I2C_SUCCESS: Get the i2c module status */
    ret = I2C_CheckFlag(I2C_flag);
    time_cnt++;
  } while ((time_cnt < 1000) && (ret == I2C_WAITING));
  
  if (ret == I2C_SUCCESS)
      return I2C_OK;
  else
      return I2C_ERROR;
}

/**
  * @brief  Initializes eeprom_24c02.
  * @param  None
  * @retval None
  */
void eeprom_24c02_init(void) 
{
  I2C_InitTypeDef I2C_InitStruct;
  
  I2C_DeInit();
  
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
  RCC_APBPeriphClockCmd(RCC_APBPeriph_I2C, ENABLE);
  
  /*
    PC3 (I2C_SDA)
    PC4 (I2C_SCL)
  */
  GPIO_Init(GPIOC, GPIO_Pin_3 | GPIO_Pin_4, GPIO_SPEED_LOW | GPIO_PUPD_NOPULL | GPIO_OTYPE_OD | GPIO_DRV_LOW);
  GPIO_SetAFPin(GPIOC, GPIO_Pin_3 | GPIO_Pin_4, GPIO_AF4);

  // I2C configurtion
  I2C_InitStruct.broadack = I2C_BROAD_ACK_DISABLE;
  I2C_InitStruct.master = I2C_MASTER_MODE_ENABLE;
  I2C_InitStruct.slave = I2C_SLAVE_MODE_DISABLE;
  I2C_InitStruct.speedclock = I2C_SPEED_RATE;
  I2C_Init(&I2C_InitStruct);
  
  I2C_Cmd(ENABLE);
  I2C_ClearITPendingBit();
}

/**
  * @brief  Transmits in master mode an amount of data in blocking mode.
  * @param  DevAddress: Target device address: The device 7 bits address value
  *         in datasheet must be shift at right before call interface
  * @param  pData: Pointer to data buffer
  * @param  Size: Amount of data to be sent
  * @retval Status
  */
I2CStatus I2C_MasterTransmit(uint16_t DevAddress, uint8_t *pData, uint16_t Size)
{
  uint32_t transmit_size = 0;
  uint32_t i2c_flag = 0xFF;
      
  I2C_Start(ENABLE);
  I2C_WaitFlag(&i2c_flag);
  if (i2c_flag != I2C_FLAG_MASTER_TX_START)
  { 
    return I2C_ERROR;
  }
  i2c_flag = 0xFF;
  
  I2C_WriteAddress(DevAddress,I2C_Direction_Transmitter);
  I2C_SwitchStatus(I2C_STA_0, I2C_STO_0, I2C_AA_0);
  I2C_WaitFlag(&i2c_flag);
  if (i2c_flag != I2C_FLAG_MASTER_TX_SLAW_ACK)
  { 
    return I2C_ERROR;
  }
  
  while (transmit_size < Size)
  {
    i2c_flag = 0xFF;
    I2C_WriteByte(pData[transmit_size]);
    I2C_ClearITPendingBit();
    I2C_WaitFlag(&i2c_flag);
    if (i2c_flag != I2C_FLAG_MASTER_TX_DATA_ACK)
    { 
      return I2C_ERROR;
    }
    transmit_size++;
  } 
  return I2C_OK;
}

/**
  * @brief  Receives in master mode an amount of data in blocking mode.
  * @param  DevAddress: Target device address: The device 7 bits address value
  *         in datasheet must be shift at right before call interface
  * @param  pData: Pointer to data buffer
  * @param  Size: Amount of data to be sent
  * @retval Status
  */
I2CStatus I2C_MasterReceive(uint16_t DevAddress, uint8_t *pData, uint16_t Size)
{
  uint32_t receive_size = 0;
  uint32_t i2c_flag = 0xFF;
  
  i2c_flag = 0xFF;
  I2C_SwitchStatus(I2C_STA_1, I2C_STO_0, I2C_AA_0);  // Switching to restart status
  I2C_WaitFlag(&i2c_flag);
  
  if ((i2c_flag != I2C_FLAG_MASTER_RX_START) && (i2c_flag != I2C_FLAG_MASTER_RX_RESTART))
  { 
    return I2C_ERROR;
  }
  
  i2c_flag = 0xFF;
  I2C_WriteAddress(DevAddress,I2C_Direction_Receiver);
  I2C_SwitchStatus(I2C_STA_0, I2C_STO_0, I2C_AA_0);
  I2C_WaitFlag(&i2c_flag);
  if (i2c_flag != I2C_FLAG_MASTER_RX_SLAW_ACK)
  { 
    return I2C_ERROR;
  }
      
  while (receive_size < (Size-1))
  {
    I2C_ACK(ENABLE);
    i2c_flag = 0xFF;
    /* Clear interrupt flag */
    I2C_ClearITPendingBit();
    I2C_WaitFlag(&i2c_flag);
    if (i2c_flag != I2C_FLAG_MASTER_RX_DATA_ACK)
    { 
      return I2C_ERROR;
    }
    I2C_ReceiveByte(&pData[receive_size]);
    receive_size++;
  }
  if (receive_size == (Size-1))
  {
    I2C_ACK(DISABLE);
    i2c_flag = 0xFF;
    /* Clear interrupt flag */
    I2C_ClearITPendingBit();
    I2C_WaitFlag(&i2c_flag);
    if (i2c_flag != I2C_FLAG_MASTER_RX_DATA_NOACK)
    { 
      return I2C_ERROR;
    }
    I2C_ReceiveByte(&pData[receive_size]);
    receive_size++;
  }
  I2C_Stop(ENABLE);
  return I2C_OK;
}

uint32_t eeprom_24c02_read(uint8_t addr, uint8_t regaddr, uint8_t* pbuf, uint32_t len)
{
  I2CStatus  ret = I2C_ERROR;
  
  ret = I2C_MasterTransmit(addr, &regaddr, 1);
  ret = I2C_MasterReceive(addr, pbuf, len);
  
  return ret;
}

uint32_t eeprom_24c02_write(uint8_t addr, uint8_t regaddr, const uint8_t* pdata, uint8_t len)
{
  uint8_t data[17] = {0};
  uint8_t i = 0;
  I2CStatus  ret = I2C_ERROR;

  data[0] = regaddr;
  for(i=0; i<len; i++)
    data[i+1]= pdata[i];
  ret = I2C_MasterTransmit(addr, data, len+1);

  return ret;
}

