#include "iic.h"

static inline void iic_Start(SW_Dev_IIC dev) {
    dev.SDA_MODE(OUT);
    dev.SDA_SET(HIGH);
    dev.CLK_SET(HIGH);DELAY1US();
    dev.SDA_SET(LOW);DELAY1US();
    dev.CLK_SET(LOW);
}

//结束信号
static inline void iic_Stop(SW_Dev_IIC dev) {
    dev.SDA_MODE(OUT);
    dev.CLK_SET(LOW);
    dev.SDA_SET(LOW);DELAY1US();
    dev.CLK_SET(HIGH);
    dev.SDA_SET(HIGH);
}

//等待信号响应
static inline uint8_t iic_WaitAck(SW_Dev_IIC dev, uint16_t timeout) {
    uint16_t time = 0;
    dev.SDA_MODE(IN);
    dev.SDA_SET(HIGH);DELAY1US();
    dev.CLK_SET(HIGH);DELAY1US();
    while (dev.SDA()) {
        time++;DELAY1US();
        if (time > timeout) {
            iic_Stop(dev);
            return 1;
        }
    }
    dev.CLK_SET(LOW);
    return 0;
}

static inline void iic_Ack(SW_Dev_IIC dev) {
    dev.CLK_SET(LOW);
    dev.SDA_MODE(OUT);
    dev.SDA_SET(LOW);DELAY1US();DELAY1US();
    dev.CLK_SET(HIGH);DELAY1US();DELAY1US();
    dev.CLK_SET(LOW);
}

static inline void iic_NAck(SW_Dev_IIC dev) {
    dev.CLK_SET(LOW);
    dev.SDA_MODE(OUT);
    dev.SDA_SET(HIGH);DELAY1US();DELAY1US();
    dev.CLK_SET(HIGH);DELAY1US();DELAY1US();
    dev.CLK_SET(LOW);
}

//写入一个字节
static inline void iic_W(SW_Dev_IIC dev, uint8_t date) {
    dev.SDA_MODE(OUT);
    uint8_t i;
    for (i = 0; i < 8; i++) {
        dev.CLK_SET(LOW);
        if (date & 0x80) {
            dev.SDA_SET(HIGH);
        } else {
            dev.SDA_SET(LOW);
        }DELAY1US();DELAY1US();
        dev.CLK_SET(HIGH);DELAY1US();DELAY1US();
        dev.CLK_SET(LOW);DELAY1US();DELAY1US();
        date <<= 1;
    }
}

static inline uint8_t iic_R(SW_Dev_IIC dev, uint8_t ack) {
    unsigned char i, read = 0;
    dev.SDA_MODE(IN);
    for (i = 0; i < 8; i++) {
        dev.CLK_SET(LOW);DELAY1US();DELAY1US();
        dev.CLK_SET(HIGH);
        read <<= 1;
        if (dev.SDA())read++;DELAY1US();
    }
    if (ack)
        iic_Ack(dev);        //发送ACK
    else
        iic_NAck(dev);       //发送NACK
    return read;
}

void SW_IIC_WL(SW_Dev_IIC Dev, uint8_t InternalAddress, uint8_t *Write_Data, uint32_t Len) {
    iic_Start(Dev);
    iic_W(Dev, Dev.ADD);
    iic_WaitAck(Dev, 200);
    iic_W(Dev, InternalAddress);
    iic_WaitAck(Dev, 200);
    for (uint32_t i = 0; i < Len; i++) {
        iic_W(Dev, Write_Data[i]);
        iic_WaitAck(Dev, 200);
    }
    iic_Stop(Dev);
}

void SW_IIC_RL(SW_Dev_IIC Dev, uint8_t InternalAddress, uint8_t *Read_Data, uint32_t Len, uint8_t Ack) {
    iic_Start(Dev);
    iic_W(Dev, Dev.ADD);
    iic_WaitAck(Dev, 200);
    iic_W(Dev, InternalAddress);
    iic_WaitAck(Dev, 200);
    for (uint32_t i = 0; i < Len; i++) {
        Read_Data[i] = iic_R(Dev, Ack);
    }
    iic_Stop(Dev);
}