

#include "EEPROM_24Cxx.h"
#include "stdint.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();
}
