
#include "EEPROM_24Cxx.h"

EEPROMRWStruct  EEPROMRW;

EEPROMErrEnum EEPROM_Instant_Byte_Write(uint8_t DeviceAddr, uint16_t DataAddr, uint8_t Data)
{
  uint8_t i;
  uint8_t ACK;
  uint8_t AddrLen;
  uint8_t Addr[3];

  //准备地址
  if (EEPROMRW.State != EEPROM_IDLE)
    return EEPROM_BUSY;

  if (DeviceAddr > 0x07)
    return EEPROM_INVALID_DEVICE_ADDR;

  if (DataAddr > EEPROM_MAX_DATA_ADDR)
    return EEPROM_INVALID_DATA_ADDR;

#if   defined EEPROM_DATA_ADDR_2_BYTE
  AddrLen = 3;
  Addr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  Addr[1] = (uint8_t)(DataAddr >> 8);
  Addr[2] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_2_BYTE_MIXED
  #if   defined EEPROM_24C04    //24C04只有A2和A1引脚  
    DeviceAddr &= 0x06;
  #elif defined EEPROM_24C08    //24C08只有A2引脚
    DeviceAddr &= 0x04;
  #elif defined EEPROM_24C16    //24C16没有外置地址引脚
    DeviceAddr  = 0x00;
  #else
    #error Incorrect EEPROM device definition
  #endif

  AddrLen = 2;
  Addr[0] = EEPROM_DEVICE_ADDR_WR | (((uint8_t)(DataAddr >> 8) | DeviceAddr) << 1);
  Addr[1] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_1_BYTE
  AddrLen = 2;
  Addr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  Addr[1] = (uint8_t)DataAddr;

#else
  #error Incorrect EEPROM device definition

#endif

  //启动IIC
  IIC_Start();

  //发送地址
  for (i = 0; i < AddrLen; i++)
  {
    IIC_Transmit_Data(Addr[i]);

    do
    {
      ACK = IIC_Receive_ACK();
    }
    while (ACK == IIC_INVALID_ACK);

    if (ACK != IIC_ACK)
    {
      IIC_Stop();
      return EEPROM_NO_RESPONSE;
    }
  }

  //写入数据
  IIC_Transmit_Data(Data);

  do
  {
    ACK = IIC_Receive_ACK();
  }
  while (ACK == IIC_INVALID_ACK);

  //停止IIC
  IIC_Stop();

  //返回写入结果
  if (ACK == IIC_ACK)
    return EEPROM_OK;
  else
    return EEPROM_NO_RESPONSE;
}

EEPROMErrEnum EEPROM_Instant_Page_Write(uint8_t DeviceAddr, uint16_t DataAddr, uint8_t *pData, uint8_t Len)
{
  uint8_t i;
  uint8_t ACK;
  uint8_t AddrLen;
  uint8_t Addr[3];

  //准备地址
  if (EEPROMRW.State != EEPROM_IDLE)
    return EEPROM_BUSY;

  if (DeviceAddr > 0x07)
    return EEPROM_INVALID_DEVICE_ADDR;

  if (DataAddr > EEPROM_MAX_DATA_ADDR)
    return EEPROM_INVALID_DATA_ADDR;

  if ((Len > EEPROM_PAGE_SIZE) || (Len == 0))
    return EEPROM_DATA_LENGTH_ERR;

#if   defined EEPROM_DATA_ADDR_2_BYTE
  AddrLen = 3;
  Addr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  Addr[1] = (uint8_t)(DataAddr >> 8);
  Addr[2] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_2_BYTE_MIXED
  #if   defined EEPROM_24C04    //24C04只有A2和A1引脚  
    DeviceAddr &= 0x06;
  #elif defined EEPROM_24C08    //24C08只有A2引脚
    DeviceAddr &= 0x04;
  #elif defined EEPROM_24C16    //24C16没有外置地址引脚
    DeviceAddr  = 0x00;
  #else
    #error Incorrect EEPROM device definition
  #endif

  AddrLen = 2;
  Addr[0] = EEPROM_DEVICE_ADDR_WR | (((uint8_t)(DataAddr >> 8) | DeviceAddr) << 1);
  Addr[1] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_1_BYTE
  AddrLen = 2;
  Addr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  Addr[1] = (uint8_t)DataAddr;

#else
  #error Incorrect EEPROM device definition

#endif

  //启动IIC
  IIC_Start();

  //发送地址
  for (i = 0; i < AddrLen; i++)
  {
    IIC_Transmit_Data(Addr[i]);

    do
    {
      ACK = IIC_Receive_ACK();
    }
    while (ACK == IIC_INVALID_ACK);

    if (ACK != IIC_ACK)
    {
      IIC_Stop();
      return EEPROM_NO_RESPONSE;
    }
  }

  //写入数据
  for (i = 0; i < Len; i++)
  {
    IIC_Transmit_Data(pData[i]);

    do
    {
      ACK = IIC_Receive_ACK();
    }
    while (ACK == IIC_INVALID_ACK);

    if (ACK != IIC_ACK)
    {
      IIC_Stop();
      return EEPROM_NO_RESPONSE;
    }
  }

  //停止IIC
  IIC_Stop();

  //返回写入结果
  return EEPROM_OK;
}

EEPROMErrEnum EEPROM_Byte_Write(uint8_t DeviceAddr, uint16_t DataAddr, uint8_t Data)
{
  if (EEPROMRW.WRState != EEPROM_RW_IDLE)
    return EEPROM_BUSY;

  if (DeviceAddr > 0x07)
    return EEPROM_INVALID_DEVICE_ADDR;

  if (DataAddr > EEPROM_MAX_DATA_ADDR)
    return EEPROM_INVALID_DATA_ADDR;

#if   defined EEPROM_DATA_ADDR_2_BYTE
  EEPROMRW.WRAddrLen = 3;
  EEPROMRW.WRAddr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  EEPROMRW.WRAddr[1] = (uint8_t)(DataAddr >> 8);
  EEPROMRW.WRAddr[2] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_2_BYTE_MIXED
  #if   defined EEPROM_24C04    //24C04只有A2和A1引脚  
    DeviceAddr &= 0x06;
  #elif defined EEPROM_24C08    //24C08只有A2引脚
    DeviceAddr &= 0x04;
  #elif defined EEPROM_24C16    //24C16没有外置地址引脚
    DeviceAddr  = 0x00;
  #else
    #error Incorrect EEPROM device definition
  #endif

  EEPROMRW.WRAddrLen = 2;
  EEPROMRW.WRAddr[0] = EEPROM_DEVICE_ADDR_WR | (((uint8_t)(DataAddr >> 8) | DeviceAddr) << 1);
  EEPROMRW.WRAddr[1] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_1_BYTE
  EEPROMRW.WRAddrLen = 2;
  EEPROMRW.WRAddr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  EEPROMRW.WRAddr[1] = (uint8_t)DataAddr;

#else
  #error Incorrect EEPROM device definition

#endif

  EEPROMRW.WRDataLen = 1;
  EEPROMRW.WRData[0] = Data;

  EEPROMRW.WRResult = EEPROM_RW_IN_PROGRESS;

  EEPROMRW.WRState = EEPROM_RW_REQ;
  if ((EEPROMRW.State == EEPROM_IDLE) || (EEPROMRW.State == EEPROM_RD_START))   //写入优先级高于读出优先级
    EEPROMRW.State = EEPROM_WR_START;

  return EEPROM_OK;
}

EEPROMErrEnum EEPROM_Page_Write(uint8_t DeviceAddr, uint16_t DataAddr, uint8_t *pData, uint8_t Len)
{
  uint8_t i;

  if (EEPROMRW.WRState != EEPROM_RW_IDLE)
    return EEPROM_BUSY;

  if (DeviceAddr > 0x07)
    return EEPROM_INVALID_DEVICE_ADDR;

  if (DataAddr > EEPROM_MAX_DATA_ADDR)
    return EEPROM_INVALID_DATA_ADDR;

  if ((Len > EEPROM_PAGE_SIZE) || (Len == 0))
    return EEPROM_DATA_LENGTH_ERR;

#if   defined EEPROM_DATA_ADDR_2_BYTE
  EEPROMRW.WRAddrLen = 3;
  EEPROMRW.WRAddr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  EEPROMRW.WRAddr[1] = (uint8_t)(DataAddr >> 8);
  EEPROMRW.WRAddr[2] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_2_BYTE_MIXED
  #if   defined EEPROM_24C04    //24C04只有A2和A1引脚  
    DeviceAddr &= 0x06;
  #elif defined EEPROM_24C08    //24C08只有A2引脚
    DeviceAddr &= 0x04;
  #elif defined EEPROM_24C16    //24C16没有外置地址引脚
    DeviceAddr  = 0x00;
  #else
    #error Incorrect EEPROM device definition
  #endif

  EEPROMRW.WRAddrLen = 2;
  EEPROMRW.WRAddr[0] = EEPROM_DEVICE_ADDR_WR | (((uint8_t)(DataAddr >> 8) | DeviceAddr) << 1);
  EEPROMRW.WRAddr[1] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_1_BYTE
  EEPROMRW.WRAddrLen = 2;
  EEPROMRW.WRAddr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  EEPROMRW.WRAddr[1] = (uint8_t)DataAddr;

#else
  #error Incorrect EEPROM device definition

#endif

  EEPROMRW.WRDataLen = Len;
  for (i = 0; i < Len; i++)
    EEPROMRW.WRData[i] = pData[i];

  EEPROMRW.WRResult = EEPROM_RW_IN_PROGRESS;

  EEPROMRW.WRState = EEPROM_RW_REQ;
  if ((EEPROMRW.State == EEPROM_IDLE) || (EEPROMRW.State == EEPROM_RD_START))   //写入优先级高于读出优先级
    EEPROMRW.State = EEPROM_WR_START;

  return EEPROM_OK;
}

EEPROMRWResultEnum EEPROM_Get_Write_Result(void)
{
  EEPROMRWResultEnum Result;

  if (EEPROMRW.WRState == EEPROM_RW_BUSY)
    return EEPROM_RW_IN_PROGRESS;
  else
  {
    Result = EEPROMRW.WRResult;
    if (Result != EEPROM_RW_IN_PROGRESS)
      EEPROMRW.WRResult = EEPROM_RW_NONE;
    return Result;
  }
}

void EEPROM_Write_In(void)
{
  uint8_t ACK;

  switch (EEPROMRW.State)
  {
  case EEPROM_WR_START  :
    IIC_Start();                                        //启动IIC
    EEPROMRW.WRState = EEPROM_RW_BUSY;                  //已开启写入过程
    EEPROMRW.State   = EEPROM_WR_ADDR;                  //接下来写地址
    EEPROMRW.Cnt     = 0;                               //清零字节计数器
    break;

  case EEPROM_WR_ADDR   :
    IIC_Transmit_Data(EEPROMRW.WRAddr[EEPROMRW.Cnt]);   //写入地址字节

    do
    {
      ACK = IIC_Receive_ACK();
    }
    while (ACK == IIC_INVALID_ACK);                     //获取写入结果

    if (ACK == IIC_ACK)                                 //地址字节写入成功
    {
      EEPROMRW.Cnt++;                                   //准备写入下一字节地址
      if (EEPROMRW.Cnt >= EEPROMRW.WRAddrLen)           //地址已全部写入
      {
        EEPROMRW.State   = EEPROM_WR_DATA;              //接下来写数据
        EEPROMRW.Cnt     = 0;                           //清零字节计数器
      }
    }
    else                                                //地址字节写入失败
    {
      EEPROMRW.State = EEPROM_WR_STOP;                  //停止写入过程
      EEPROMRW.WRResult = EEPROM_RW_FAIL;               //写入失败
    }
    break;

  case EEPROM_WR_DATA   :
    IIC_Transmit_Data(EEPROMRW.WRData[EEPROMRW.Cnt]);   //写入数据字节

    do
    {
      ACK = IIC_Receive_ACK();
    }
    while (ACK == IIC_INVALID_ACK);                     //获取写入结果

    if (ACK == IIC_ACK)                                 //数据字节写入成功
    {
      EEPROMRW.Cnt++;                                   //准备写入下一字节数据
      if (EEPROMRW.Cnt >= EEPROMRW.WRDataLen)           //数据已全部写入
      {
        EEPROMRW.State    = EEPROM_WR_STOP;             //发送停止停止信号即可完成整个写入过程
        EEPROMRW.WRResult = EEPROM_RW_DONE;             //写入成功
      }
    }
    else                                                //数据字节写入失败
    {
      EEPROMRW.State    = EEPROM_WR_STOP;               //停止写入过程
      EEPROMRW.WRResult = EEPROM_RW_FAIL;               //写入失败
    }
    break;

  case EEPROM_WR_STOP   :
    IIC_Stop();                                         //停止IIC
    EEPROMRW.WRState = EEPROM_RW_IDLE;                  //写入过程结束,回到空闲状态
    if (EEPROMRW.RDState == EEPROM_RW_REQ)              //如果有读请求则处理读请求
      EEPROMRW.State = EEPROM_RD_START;
    else                                                //否则EEPROM进入空闲状态
      EEPROMRW.State = EEPROM_IDLE;
    break;

  default               :
    EEPROM_Init();                                      //遇错误的写入过程,则重新初始化
    break;
  }
}

EEPROMErrEnum EEPROM_Instant_Byte_Read(uint8_t DeviceAddr, uint16_t DataAddr, uint8_t *pData)
{
  uint8_t i;
  uint8_t ACK;
  uint8_t AddrLen;
  uint8_t Addr[3];

  //准备地址
  if (EEPROMRW.State != EEPROM_IDLE)
    return EEPROM_BUSY;

  if (DeviceAddr > 0x07)
    return EEPROM_INVALID_DEVICE_ADDR;

  if (DataAddr > EEPROM_MAX_DATA_ADDR)
    return EEPROM_INVALID_DATA_ADDR;

#if   defined EEPROM_DATA_ADDR_2_BYTE
  AddrLen = 3;
  Addr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  Addr[1] = (uint8_t)(DataAddr >> 8);
  Addr[2] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_2_BYTE_MIXED
  #if   defined EEPROM_24C04    //24C04只有A2和A1引脚  
    DeviceAddr &= 0x06;
  #elif defined EEPROM_24C08    //24C08只有A2引脚
    DeviceAddr &= 0x04;
  #elif defined EEPROM_24C16    //24C16没有外置地址引脚
    DeviceAddr  = 0x00;
  #else
    #error Incorrect EEPROM device definition
  #endif

  AddrLen = 2;
  Addr[0] = EEPROM_DEVICE_ADDR_WR | (((uint8_t)(DataAddr >> 8) | DeviceAddr) << 1);
  Addr[1] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_1_BYTE
  AddrLen = 2;
  Addr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  Addr[1] = (uint8_t)DataAddr;

#else
  #error Incorrect EEPROM device definition

#endif

  //启动IIC
  IIC_Start();

  //发送地址
  for (i = 0; i < AddrLen; i++)
  {
    IIC_Transmit_Data(Addr[i]);

    do
    {
      ACK = IIC_Receive_ACK();
    }
    while (ACK == IIC_INVALID_ACK);

    if (ACK != IIC_ACK)
    {
      IIC_Stop();
      return EEPROM_NO_RESPONSE;
    }
  }

  //重新启动IIC
  IIC_Start();

  //请求读取EEPROM
  Addr[0] |= EEPROM_DEVICE_ADDR_RD;
  IIC_Transmit_Data(Addr[0]);

  do
  {
    ACK = IIC_Receive_ACK();
  }
  while (ACK == IIC_INVALID_ACK);

  if (ACK != IIC_ACK)
  {
    IIC_Stop();
    return EEPROM_NO_RESPONSE;
  }

  //读取数据
  *pData = IIC_Receive_Data();
  IIC_Transmit_ACK(IIC_NAK);

  //停止IIC
  IIC_Stop();

  //返回写入结果
  return EEPROM_OK;
}

EEPROMErrEnum EEPROM_Instant_Sequential_Read(uint8_t DeviceAddr, uint16_t DataAddr, uint8_t *pData, uint8_t Len)
{
  uint8_t i;
  uint8_t ACK;
  uint8_t AddrLen;
  uint8_t Addr[3];

  //准备地址
  if (EEPROMRW.State != EEPROM_IDLE)
    return EEPROM_BUSY;

  if (DeviceAddr > 0x07)
    return EEPROM_INVALID_DEVICE_ADDR;

  if (DataAddr > EEPROM_MAX_DATA_ADDR)
    return EEPROM_INVALID_DATA_ADDR;

  if ((EEPROM_MAX_DATA_ADDR - DataAddr + 1 < Len) || (Len == 0))
    return EEPROM_DATA_LENGTH_ERR;

#if   defined EEPROM_DATA_ADDR_2_BYTE
  AddrLen = 3;
  Addr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  Addr[1] = (uint8_t)(DataAddr >> 8);
  Addr[2] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_2_BYTE_MIXED
  #if   defined EEPROM_24C04    //24C04只有A2和A1引脚  
    DeviceAddr &= 0x06;
  #elif defined EEPROM_24C08    //24C08只有A2引脚
    DeviceAddr &= 0x04;
  #elif defined EEPROM_24C16    //24C16没有外置地址引脚
    DeviceAddr  = 0x00;
  #else
    #error Incorrect EEPROM device definition
  #endif

  AddrLen = 2;
  Addr[0] = EEPROM_DEVICE_ADDR_WR | (((uint8_t)(DataAddr >> 8) | DeviceAddr) << 1);
  Addr[1] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_1_BYTE
  AddrLen = 2;
  Addr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  Addr[1] = (uint8_t)DataAddr;

#else
  #error Incorrect EEPROM device definition

#endif

  //启动IIC
  IIC_Start();

  //发送地址
  for (i = 0; i < AddrLen; i++)
  {
    IIC_Transmit_Data(Addr[i]);

    do
    {
      ACK = IIC_Receive_ACK();
    }
    while (ACK == IIC_INVALID_ACK);

    if (ACK != IIC_ACK)
    {
      IIC_Stop();
      return EEPROM_NO_RESPONSE;
    }
  }

  //重新启动IIC
  IIC_Start();

  //请求读取EEPROM
  Addr[0] |= EEPROM_DEVICE_ADDR_RD;
  IIC_Transmit_Data(Addr[0]);

  do
  {
    ACK = IIC_Receive_ACK();
  }
  while (ACK == IIC_INVALID_ACK);

  if (ACK != IIC_ACK)
  {
    IIC_Stop();
    return EEPROM_NO_RESPONSE;
  }

  //读取数据
  for (i = 0; i < Len - 1; i++)
  {
    pData[i] = IIC_Receive_Data();
    IIC_Transmit_ACK(IIC_ACK);
  }

  pData[i] = IIC_Receive_Data();
  IIC_Transmit_ACK(IIC_NAK);

  //停止IIC
  IIC_Stop();

  //返回写入结果
  return EEPROM_OK;
}

EEPROMErrEnum EEPROM_Byte_Read(uint8_t DeviceAddr, uint16_t DataAddr)
{
  if (EEPROMRW.RDState != EEPROM_RW_IDLE)
    return EEPROM_BUSY;

  if (DeviceAddr > 0x07)
    return EEPROM_INVALID_DEVICE_ADDR;

  if (DataAddr > EEPROM_MAX_DATA_ADDR)
    return EEPROM_INVALID_DATA_ADDR;

#if   defined EEPROM_DATA_ADDR_2_BYTE
  EEPROMRW.RDAddrLen = 3;
  EEPROMRW.RDAddr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  EEPROMRW.RDAddr[1] = (uint8_t)(DataAddr >> 8);
  EEPROMRW.RDAddr[2] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_2_BYTE_MIXED
  #if   defined EEPROM_24C04    //24C04只有A2和A1引脚  
    DeviceAddr &= 0x06;
  #elif defined EEPROM_24C08    //24C08只有A2引脚
    DeviceAddr &= 0x04;
  #elif defined EEPROM_24C16    //24C16没有外置地址引脚
    DeviceAddr  = 0x00;
  #else
    #error Incorrect EEPROM device definition
  #endif

  EEPROMRW.RDAddrLen = 2;
  EEPROMRW.RDAddr[0] = EEPROM_DEVICE_ADDR_WR | (((uint8_t)(DataAddr >> 8) | DeviceAddr) << 1);
  EEPROMRW.RDAddr[1] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_1_BYTE
  EEPROMRW.RDAddrLen = 2;
  EEPROMRW.RDAddr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  EEPROMRW.RDAddr[1] = (uint8_t)DataAddr;

#else
  #error Incorrect EEPROM device definition

#endif

  EEPROMRW.RDDataLen = 1;

  EEPROMRW.RDResult = EEPROM_RW_IN_PROGRESS;

  EEPROMRW.RDState = EEPROM_RW_REQ;
  if (EEPROMRW.State == EEPROM_IDLE)
    EEPROMRW.State = EEPROM_RD_START;

  return EEPROM_OK;
}

EEPROMErrEnum EEPROM_Sequential_Read(uint8_t DeviceAddr, uint16_t DataAddr, uint8_t Len)
{
  if (EEPROMRW.RDState != EEPROM_RW_IDLE)
    return EEPROM_BUSY;

  if (DeviceAddr > 0x07)
    return EEPROM_INVALID_DEVICE_ADDR;

  if (DataAddr > EEPROM_MAX_DATA_ADDR)
    return EEPROM_INVALID_DATA_ADDR;

  if ((EEPROM_MAX_DATA_ADDR - DataAddr + 1 < Len) || (Len == 0))
    return EEPROM_DATA_LENGTH_ERR;

#if   defined EEPROM_DATA_ADDR_2_BYTE
  EEPROMRW.RDAddrLen = 3;
  EEPROMRW.RDAddr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  EEPROMRW.RDAddr[1] = (uint8_t)(DataAddr >> 8);
  EEPROMRW.RDAddr[2] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_2_BYTE_MIXED
  #if   defined EEPROM_24C04    //24C04只有A2和A1引脚  
    DeviceAddr &= 0x06;
  #elif defined EEPROM_24C08    //24C08只有A2引脚
    DeviceAddr &= 0x04;
  #elif defined EEPROM_24C16    //24C16没有外置地址引脚
    DeviceAddr  = 0x00;
  #else
    #error Incorrect EEPROM device definition
  #endif

  EEPROMRW.RDAddrLen = 2;
  EEPROMRW.RDAddr[0] = EEPROM_DEVICE_ADDR_WR | (((uint8_t)(DataAddr >> 8) | DeviceAddr) << 1);
  EEPROMRW.RDAddr[1] = (uint8_t)DataAddr;

#elif defined EEPROM_DATA_ADDR_1_BYTE
  EEPROMRW.RDAddrLen = 2;
  EEPROMRW.RDAddr[0] = EEPROM_DEVICE_ADDR_WR | (DeviceAddr << 1);
  EEPROMRW.RDAddr[1] = (uint8_t)DataAddr;

#else
  #error Incorrect EEPROM device definition

#endif

  EEPROMRW.RDDataLen = Len;

  EEPROMRW.RDResult = EEPROM_RW_IN_PROGRESS;

  EEPROMRW.RDState = EEPROM_RW_REQ;
  if (EEPROMRW.State == EEPROM_IDLE)
    EEPROMRW.State = EEPROM_RD_START;

  return EEPROM_OK;
}

EEPROMRWResultEnum EEPROM_Get_Read_Result(void)
{
  EEPROMRWResultEnum Result;

  if (EEPROMRW.RDState == EEPROM_RW_BUSY)
    return EEPROM_RW_IN_PROGRESS;
  else
  {
    Result = EEPROMRW.RDResult;
    if ((Result != EEPROM_RW_DONE) && (Result != EEPROM_RW_IN_PROGRESS))
      EEPROMRW.RDResult = EEPROM_RW_NONE;
    return Result;
  }
}

uint8_t EEPROM_Get_Read_Out_Byte(void)
{
  if (EEPROMRW.RDResult == EEPROM_RW_DONE)
    EEPROMRW.RDResult = EEPROM_RW_NONE;

  return EEPROMRW.RDData[0];
}

void EEPROM_Get_Read_Out(uint8_t *pData, uint8_t Len)
{
  uint8_t i;

  if (EEPROMRW.RDResult == EEPROM_RW_DONE)
    EEPROMRW.RDResult = EEPROM_RW_NONE;

  if (Len > EEPROMRW.RDDataLen)
    Len = EEPROMRW.RDDataLen;

  for (i = 0; i < Len; i++)
    pData[i] = EEPROMRW.RDData[i];
}

void EEPROM_Read_Out(void)
{
  uint8_t ACK;

  switch (EEPROMRW.State)
  {
  case EEPROM_RD_START    :
    IIC_Start();                                        //启动IIC
    EEPROMRW.RDState = EEPROM_RW_BUSY;                  //已开启写入过程
    EEPROMRW.State   = EEPROM_RD_ADDR1;                 //接下来设置读出数据地址
    EEPROMRW.Cnt     = 0;                               //清零字节计数器
    break;

  case EEPROM_RD_ADDR1    :
    IIC_Transmit_Data(EEPROMRW.RDAddr[EEPROMRW.Cnt]);   //写入地址字节

    do
    {
      ACK = IIC_Receive_ACK();
    }
    while (ACK == IIC_INVALID_ACK);                     //获取写入结果

    if (ACK == IIC_ACK)                                 //地址字节写入成功
    {
      EEPROMRW.Cnt++;                                   //准备写入下一字节地址
      if (EEPROMRW.Cnt >= EEPROMRW.RDAddrLen)           //地址已全部写入
        EEPROMRW.State   = EEPROM_RD_RESTART;           //接下来重新启动IIC
    }
    else                                                //地址字节写入失败
    {
      EEPROMRW.State = EEPROM_RD_STOP;                  //停止读出过程
      EEPROMRW.RDResult = EEPROM_RW_FAIL;               //读出失败
    }
    break;

  case EEPROM_RD_RESTART  :
    IIC_Start();                                        //重新启动IIC
    EEPROMRW.State = EEPROM_RD_ADDR2;                   //接下来设置器件地址并转为读模式
    EEPROMRW.RDAddr[0] |= EEPROM_DEVICE_ADDR_RD;
    break;

  case EEPROM_RD_ADDR2    :
    IIC_Transmit_Data(EEPROMRW.RDAddr[0]);              //写入器件读地址

    do
    {
      ACK = IIC_Receive_ACK();
    }
    while (ACK == IIC_INVALID_ACK);                     //获取写入结果

    if (ACK == IIC_ACK)                                 //地址字节写入成功
    {
      EEPROMRW.State = EEPROM_RD_DATA;                  //接下来读取数据
      EEPROMRW.Cnt   = 0;                               //清零字节计数器
    }
    else                                                //器件读地址写入失败
    {
      EEPROMRW.State = EEPROM_RD_STOP;                  //停止读出过程
      EEPROMRW.RDResult = EEPROM_RW_FAIL;               //读出失败
    }
    break;

  case EEPROM_RD_DATA    :
    EEPROMRW.RDData[EEPROMRW.Cnt] = IIC_Receive_Data(); //读出数据字节
    EEPROMRW.Cnt++;                                     //准备读出下一字节
    if(EEPROMRW.Cnt >= EEPROMRW.RDDataLen)              //已经是最后一字节了
    {
      IIC_Transmit_ACK(IIC_NAK);                        //最后一字节发NAK
      EEPROMRW.State    = EEPROM_RD_STOP;               //发送停止停止信号即可完成整个读出过程
      EEPROMRW.RDResult = EEPROM_RW_DONE;               //读出成功
    }
    else
      IIC_Transmit_ACK(IIC_ACK);                        //不是最后一字节则发ACK

    break;

  case EEPROM_RD_STOP     :
    IIC_Stop();                                         //停止IIC
    EEPROMRW.RDState = EEPROM_RW_IDLE;                  //读出过程结束,回到空闲状态
    if (EEPROMRW.WRState == EEPROM_RW_REQ)              //如果有写请求则处理写请求
      EEPROMRW.State = EEPROM_WR_START;
    else                                                //否则EEPROM进入空闲状态
      EEPROMRW.State = EEPROM_IDLE;
    break;

  default                 :
    EEPROM_Init();                                      //遇错误的读出过程,则重新初始化
    break;
  }
}

void EEPROM_Init(void)
{
  EEPROMRW.State    = EEPROM_IDLE;
  EEPROMRW.WRState  = EEPROM_RW_IDLE;
  EEPROMRW.WRResult = EEPROM_RW_NONE;
  EEPROMRW.RDState  = EEPROM_RW_IDLE;
  EEPROMRW.RDResult = EEPROM_RW_NONE;
}

void EEPROM_RW_Service(void)
{
  if (EEPROMRW.State == EEPROM_IDLE)
    return;
  else if (EEPROMRW.State & EEPROM_WR)
    EEPROM_Write_In();
  else if (EEPROMRW.State & EEPROM_RD)
    EEPROM_Read_Out();
  else
    EEPROM_Init();
}
