#include "i2c_eeprom.h"
#include "soft_iic.h"

u8 eeprom_write_buf[256];
u8 eeprom_read_buf[256];

//Read EEPROM one byte
u8 at24c01_read_one_byte(u8 addr)
{
    u8 tmp = 0;

    #if SOFT_I2C_ENABLE
        i2c_start();
        i2c_send_byte(EEPROM_WRITE_ADDR);
        i2c_wait_ack();
        i2c_send_byte(addr);
        i2c_wait_ack();

        i2c_start();
        i2c_send_byte(EEPROM_READ_ADDR);
        i2c_wait_ack();
        tmp = i2c_read_byte(0);
        i2c_stop();
    #else
        tmp = iic_receive_data(EEPROM_WRITE_ADDR, addr, 1, EEPROM_READ_ADDR);
    #endif // SOFT_I2C_ENABLE

    return tmp;
}

//Write EEPROM one byte
void at24c01_write_one_byte(u8 addr,u8 data)
{
    #if SOFT_I2C_ENABLE
        i2c_start();
        i2c_send_byte(EEPROM_WRITE_ADDR);
        i2c_wait_ack();
        i2c_send_byte(addr);
        i2c_wait_ack();
        i2c_send_byte(data);
        i2c_wait_ack();
        i2c_stop();
        delay_ms(10);
    #else
        iic_send_data(EEPROM_WRITE_ADDR, addr, data, 1);
    #endif // SOFT_I2C_ENABLE
}

// Write EEPROM one data unit, maximum 4 bytes
u32 at24c01_read_len_byte(u16 addr,u8 len)
{
    u32 tmp = 0;

    #if SOFT_I2C_ENABLE
        u8 i;

        for (i = 0; i < len; i++) {
            tmp <<= 8;
            at24c01_read_one_byte(addr + len - i - 1);
        }
    #else
        tmp = iic_receive_data(EEPROM_WRITE_ADDR, addr, len, EEPROM_READ_ADDR);
    #endif // SOFT_I2C_ENABLE

    return tmp;
}

// Read EEPROM one data unit, maximum 4 bytes
void at24c01_write_len_byte(u16 addr,u32 data,u8 len)
{
    #if SOFT_I2C_ENABLE
        u8 i;

        for (i = 0; i < len; i++) {
            at24c01_write_one_byte(addr + i, (data >> (8 * i)) & 0xff);
        }
    #else
        iic_send_data(EEPROM_WRITE_ADDR, addr, data, len);
    #endif // SOFT_I2C_ENABLE
}

// Write EEPROM continuously
void at24c01_write(u16 addr,u8 *p,u16 num)
{
    while (num--) {
        at24c01_write_one_byte(addr, *p);
        addr++;
        p++;
    }
}

// Read EEPROM continuously
void at24c01_read(u16 addr,u8 *p,u16 num)
{
    while (num) {
        *p++ = at24c01_read_one_byte(addr);
        addr++;
        num--;
    }
}

// Hardware IIC initialization
void hardware_i2c_init(void)
{
    gpio_init_typedef gpio_init_structure;
    iic_init_typedef iic_init_struct;

    clock_gate2_cmd(CLOCK_GATE2_IIC, ENABLE);

    gpio_init_structure.gpio_pin = GPIO_PIN_1 | GPIO_PIN_2;
    gpio_init_structure.gpio_dir = GPIO_DIR_INPUT;
    gpio_init_structure.gpio_fen = GPIO_FEN_PER;
    gpio_init_structure.gpio_mode = GPIO_MODE_DIGITAL;
    gpio_init_structure.gpio_pupd = GPIO_PUPD_UP;
    gpio_init(GPIOB_REG, &gpio_init_structure);

    gpio_func_mapping(IICMAP_G3);

    iic_init_struct.clk_source = IIC_CLK_RC2M;
    iic_init_struct.scl_pose_div = 64;//3M/0-->93KHz,3M/64-->46.8KHz;---???
    iic_init_struct.sda_hold_cnt = 2;
    iic_init(&iic_init_struct);

    iic_cmd(ENABLE);
}


//Check whether EEPROM is online
//Success: 1
//Failed: 0
u8 at24c01_check(void)
{
    u8 tmp;

    tmp = at24c01_read_one_byte(CHECK_ADDR);
    if (tmp == CHECK_FLAG) {
        return 1;
    } else {
        at24c01_write_one_byte(CHECK_ADDR, CHECK_FLAG);
        delay_ms(10);
        tmp = at24c01_read_one_byte(CHECK_ADDR);
        if (tmp == CHECK_FLAG) {
            return 1;
        }
    }
    return 0;
}

//Initialize IIC
void IIC_AT24C01_init(void)
{
    #if SOFT_I2C_ENABLE
        i2c_init();
        printf("\n---> run with software iic <---\n");
    #else
        hardware_i2c_init();
        printf("\n---> run with hardware iic <---\n");
    #endif // SOFT_I2C_ENABLE
}

//Test function
void IIC_AT24C01_example(void)
{
    memset(eeprom_write_buf,'A',255);
    at24c01_write(0, eeprom_write_buf, 255);
    printf("write:\n%s\n",eeprom_write_buf);

    if (!at24c01_check()) {
        printf("---> eeprom init failed!\n");
    }
    else{
        printf("---> eeprom init success.\n");
        printf("EEPROM READ:\n");
        at24c01_read(0, eeprom_read_buf, 255);
        printf("%s\n",eeprom_read_buf);
    }
}
