#include "IIC3_Software.h"

//#define _IIC3_MAX_FREQ_ //2Mhz

#ifdef _IIC3_MAX_FREQ_
#define IIC3_SPEED 0
#endif

//{Freq}: 96Mhz
//#define IIC3_SPEED   7    //800khz
//#define IIC3_SPEED   10    //600khz
//#define IIC3_SPEED   13    //500khz
//#define IIC3_SPEED   18    //400khz
#define IIC3_SPEED   25   //300kHz
//#define IIC3_SPEED   43   //200khz
//#define IIC3_SPEED   80   //110khz

u8 iic3_speed_us = 0; //235kHz 默认

//修改IIC速度:
void IIC3_Set_Speed(u8 i2c_speed)
{
    //修改iic延时时间
    iic3_speed_us = i2c_speed;
}

void IIC3_sf_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure={0};
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );

    GPIO_InitStructure.GPIO_Pin = SENSOR_SDA | SENSOR_SCL;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    IIC3_SCL(1);
    IIC3_SDA(1);
    IIC3_Set_Speed(IIC3_SPEED);
    //test();
}

#pragma GCC optimize(1)
void IIC3_Delay(u8 time)
{
    u8 i;
    for (i = 0; i < time; i++)
    {__NOP();}
}

//产生IIC起始信号
void IIC3_Start(void)
{
    SDA3_OUT();     //sda线输出
    IIC3_SDA(1);
    IIC3_SCL(1);
    IIC3_Delay(iic3_speed_us);
    IIC3_SDA(0);//START:when CLK is high,DATA change form high to low
    IIC3_Delay(iic3_speed_us);
    IIC3_SCL(0);//钳住I2C总线，准备发送或接收数据
}

//产生IIC停止信号
void IIC3_Stop(void)
{
    SDA3_OUT();//sda线输出
    IIC3_SCL(0);
    IIC3_SDA(0);//STOP:when CLK is high DATA change form low to high
    IIC3_Delay(iic3_speed_us); //至少4us 表示空闲
    IIC3_SCL(1);
    IIC3_SDA(1);//发送I2C总线结束信号
    IIC3_Delay(iic3_speed_us); //至少4us 表示空闲
}

//等待应答信号到来
//返回值：1，接收应答失败
//        0，接收应答成功
u8 IIC3_Wait_Ack(void)
{
    u8 ucErrTime=0;
    SDA3_IN();      //SDA设置为输入
    IIC3_SDA(1);IIC3_Delay(iic3_speed_us);
    IIC3_SCL(1);IIC3_Delay(iic3_speed_us);
    while(READ3_SDA)
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            IIC3_Stop();//等待从机应答超时,发送stop
            return 1;
        }
    }
    IIC3_SCL(0);//时钟输出0
    return 0;
}

//产生ACK应答
void IIC3_Ack(void)
{
    IIC3_SCL(0);
    SDA3_OUT();
    IIC3_SDA(0);
    IIC3_Delay(iic3_speed_us);
    IIC3_SCL(1);
    IIC3_Delay(iic3_speed_us);
    IIC3_SCL(0);
}

//不产生ACK应答
void IIC3_NAck(void)
{
    IIC3_SCL(0);
    SDA3_OUT();
    IIC3_SDA(1);
    IIC3_Delay(iic3_speed_us);
    IIC3_SCL(1);
    IIC3_Delay(iic3_speed_us);
    IIC3_SCL(0);
}

//IIC发送一个字节
//返回从机有无应答: 1，有应答 0，无应答
#pragma GCC optimize(1)
void IIC3_Send_Byte(u8 txd)
{
    u8 t;
    SDA3_OUT();
    IIC3_SCL(0);//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {
        if((txd<<t)&0x80)
            IIC3_SDA(1);
        else
            IIC3_SDA(0);
        //IIC3_Delay(2);   //某些器件延时是必须的
        #ifdef _IIC3_MAX_FREQ_
            __NOP();
        #else
            IIC3_Delay(iic3_speed_us);
        #endif

        IIC3_SCL(1);

        #ifdef _IIC3_MAX_FREQ_
            __NOP();
        #else
            IIC3_Delay(iic3_speed_us);
        #endif
        IIC3_SCL(0);
        //IIC3_Delay(2);
    }
}

//读1个字节，ack=1时，发送ACK，ack=0，发送nACK
u8 IIC3_Read_Byte(unsigned char ack)
{
    unsigned char i,receive=0;
    SDA3_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
    {
        IIC3_SCL(0);
        #ifdef _IIC3_MAX_FREQ_
            __NOP();
        #else
            IIC3_Delay(iic3_speed_us);
        #endif
        IIC3_SCL(1);
        receive<<=1;
        if(READ3_SDA)receive++;
        #ifdef _IIC3_MAX_FREQ_
            __NOP();
        #else
            IIC3_Delay(iic3_speed_us);
        #endif
    }
    if (!ack)
        IIC3_NAck();//发送nACK 1
    else
        IIC3_Ack(); //发送ACK 0
    return receive;
}

//测试IIC地址: 1，成功 0，失败
u8 IIC3_Check_Address(u8 Address)
{
    IIC3_Start();
    IIC3_Send_Byte(Address);
    if(IIC3_Wait_Ack())
    {
        IIC3_Stop();
        return (0);
    }
    IIC3_Stop();
    return (1);
}

//发送多个字节: 8bit address + 8bit register + n bytes data
u8 IIC3_Send_8bitMultiBytes(u8 address, u8 reg, u8 *str, u8 num)
{
    u8 i;
    IIC3_Start();
    IIC3_Send_Byte(address);
    if(IIC3_Wait_Ack()) return (0);
    IIC3_Send_Byte(reg);
    if(IIC3_Wait_Ack()) return (0);

    for(i=0; i<num; i++)
    {
        IIC3_Send_Byte(*str);
        if(IIC3_Wait_Ack()) return (0);
        str++;
    }
    IIC3_Stop();
    return (1);
}

//读取多个字节: 8bit address + 8bit register + n bytes data
u8 IIC3_Read_8bitMultiBytes(u8 address, u8 reg, u8 *str, u8 num)
{
    u8 i;
    IIC3_Start();
    IIC3_Send_Byte(address);
    if(IIC3_Wait_Ack()) return (0);
    IIC3_Send_Byte(reg);
    if(IIC3_Wait_Ack()) return (0);

    IIC3_Start();
    IIC3_Send_Byte(address+1);
    if(IIC3_Wait_Ack()) return (0);
    for(i=0; i<num; i++)
    {
        *str = IIC3_Read_Byte(i == (num-1) ? 0 : 1);
        str++;
    }

    IIC3_Stop();
    return (1);
}

//fix 读取多个字节: 8bit address + 8bit register + n bytes data
u8 IIC3_Read_8bitMultiBytes_sgm832(u8 address, u8 reg, u16 *str, u8 num)
{
    IIC3_Start();
    IIC3_Send_Byte(address);//8a
    if(IIC3_Wait_Ack()) return (0);

    IIC3_Send_Byte(reg);//fe
    if(IIC3_Wait_Ack()) return (0);

    IIC3_Delay(1);
    IIC3_Start();
    IIC3_Send_Byte(address+1);
    if(IIC3_Wait_Ack()) return (0);

    u8 bit0 = IIC3_Read_Byte(1);
    IIC3_Delay(10);

    u8 bit1 = IIC3_Read_Byte(0);

    *str = (bit0 << 8) | bit1;

    IIC3_Stop();
    return (1);
}
// //fix 写取多个字节: 8bit address + 8bit register + n bytes data
// u8 IIC3_Read_8bitMultiBytes_sgm832(u8 address, u8 reg, u16 *str, u8 num)
// {
//     u8 i;
//     IIC3_Start();
//     IIC3_Send_Byte(address);
//     if(IIC3_Wait_Ack()) return (0);

//     IIC3_Send_Byte(reg >> 8);   // Send the high byte of reg
//     if(IIC3_Wait_Ack()) return (0);
//     IIC3_Send_Byte(reg & 0xFF); // Send the low byte of reg
//     if(IIC3_Wait_Ack()) return (0);

//     for(i=0; i<num; i++)
//     {
//         IIC3_Send_Byte(*str);
//         if(IIC3_Wait_Ack()) return (0);
//         str++;
//     }
//     IIC3_Stop();
//     return (1);
// }

//发送多个字节(先发送低字节): 8bit address + 16bit register + n bytes data
u8 IIC3_Send_16bit_LE_MultiBytes(u8 address, u16 reg, u8 *str, u16 num)
{
    u8 i;
    IIC3_Start();
    IIC3_Send_Byte(address);
    if(IIC3_Wait_Ack()) return (0);

    IIC3_Send_Byte(reg & 0xFF); // Send the low byte of reg
    if(IIC3_Wait_Ack()) return (0);
    IIC3_Send_Byte(reg >> 8);   // Send the high byte of reg
    if(IIC3_Wait_Ack()) return (0);

    for(i=0; i<num; i++)
    {
        IIC3_Send_Byte(*str);
        if(IIC3_Wait_Ack()) return (0);
        str++;
    }
    IIC3_Stop();
    return (1);
}

//读取多个字节(先发送低字节): 8bit address + 16bit register + n bytes data
u8 IIC3_Read_16bit_LE_MultiBytes(u8 address, u16 reg, u8 *str, u8 num)
{
    u8 i;
    IIC3_Start();
    IIC3_Send_Byte(address);
    if(IIC3_Wait_Ack()) return (0);

    IIC3_Send_Byte(reg & 0xFF); // Send the low byte of reg
    if(IIC3_Wait_Ack()) return (0);
    IIC3_Send_Byte(reg >> 8);   // Send the high byte of reg
    if(IIC3_Wait_Ack()) return (0);

    IIC3_Start();
    IIC3_Send_Byte(address+1);
    if(IIC3_Wait_Ack()) return (0);
    for(i=0; i<num; i++)
    {
        *str = IIC3_Read_Byte(i == (num-1) ? 0 : 1);
        str++;
    }

    IIC3_Stop();
    return (1);
}

//发送多个字节(先发送高字节): 8bit address + 16bit register + n bytes data
u8 IIC3_Send_16bit_BE_MultiBytes(u8 address, u16 reg, u8 *str, u8 num)
{
    u8 i;
    IIC3_Start();
    IIC3_Send_Byte(address);
    if(IIC3_Wait_Ack()) return (0);

    IIC3_Send_Byte(reg >> 8);   // Send the high byte of reg
    if(IIC3_Wait_Ack()) return (0);
    IIC3_Send_Byte(reg & 0xFF); // Send the low byte of reg
    if(IIC3_Wait_Ack()) return (0);

    for(i=0; i<num; i++)
    {
        IIC3_Send_Byte(*str);
        if(IIC3_Wait_Ack()) return (0);
        str++;
    }
    IIC3_Stop();
    return (1);
}

//读取多个字节(先发送高字节): 8bit address + 16bit register + n bytes data
u8 IIC3_Read_16bit_BE_MultiBytes(u8 address, u16 reg, u8 *str, u8 num)
{
    u8 i;
    IIC3_Start();
    IIC3_Send_Byte(address);
    if(IIC3_Wait_Ack()) return (0);

    IIC3_Send_Byte(reg >> 8);   // Send the high byte of reg
    if(IIC3_Wait_Ack()) return (0);
    IIC3_Send_Byte(reg & 0xFF); // Send the low byte of reg
    if(IIC3_Wait_Ack()) return (0);

    IIC3_Start();
    IIC3_Send_Byte(address+1);
    if(IIC3_Wait_Ack()) return (0);
    for(i=0; i<num; i++)
    {
        *str = IIC3_Read_Byte(i == (num-1) ? 0 : 1);
        str++;
    }

    IIC3_Stop();
    return (1);
}

