/******************************************************************************
文 件 名：Simulated_IIC_Master.c
功能描述：IO端口模拟的IIC(I2C)主机函数库文件
作    者：张暄
版    本：V1.0
日    期：2016.12.21
******************************************************************************/
#include "Simulated_IIC_Master.h"
#include "GPIO.h"
#include "GPIO_Config.h"

uint8_t IICReceivedACK;



uint8_t IIC_SCL ( uint8_t x, uint8_t y );
uint8_t IIC_SDA ( uint8_t x, uint8_t y );
void IIC_SDA_DIR ( uint8_t x );
void IIC_SCL_DIR ( uint8_t x );

uint8_t IIC_SCL ( uint8_t x, uint8_t y )
{

    uint8_t value = 0;
    value = 0;

    if ( y == 0 )
    {
        value =  GPIO_PIDR1_PID8;        
    }
    else
    {
        MCU_EEPROM_SCL = x;
    }

    return value;
}

uint8_t IIC_SDA ( uint8_t x, uint8_t y )
{
    uint8_t value = 0;
    value = 0;
    if ( y == 0 ) //input
    {           
        value =  GPIO_PIDR1_PID9;
    }
    else        //output
    {
        MCU_EEPROM_SDA = x;
    }

    return value;
}

void IIC_SCL_DIR ( uint8_t x )
{
    if ( x == 1 )
    {   
        GPIO_Set_Pin_Direction ( 1, 8, GPIO_DIR_OUT );
    }
    else
    {
        GPIO_Set_Pin_Direction ( 1, 8, GPIO_DIR_IN );
        // Port_EnableInput();
    }

}
void IIC_SDA_DIR ( uint8_t x )
{

    if ( x == 1 )
    {
        GPIO_Set_Pin_Direction ( 1, 9, GPIO_DIR_OUT );
    }
    else
    {
        GPIO_Set_Pin_Direction ( 1, 9, GPIO_DIR_IN );
        // Port_EnableInput();
    }


}

/******************************************************************************
函数名：IIC_Init
功  能：初始化IIC总线
参  数：无
返回值：无
******************************************************************************/
void IIC_Init ( void )
{
    IIC_SCL_DIR ( 0 ); //SCL被设置为输入,IO口为高阻状态,总线上SCL信号由上拉电阻拉高,此时SCL = 1
    IIC_Delay();
    IIC_Delay();

    IIC_SDA_DIR ( 0 ); //SDA被设置为输入,IO口为高阻状态,总线上SDA信号由上拉电阻拉高,此时SDA = 1
    IIC_Delay();
    IIC_Delay();
    //    Port_EnableInput();
    IICReceivedACK = IIC_INVALID_ACK;
}

/******************************************************************************
函数名：IIC_Start
功  能：在IIC总线上发送起始信号,发起一次IIC通信
参  数：无
返回值：无
******************************************************************************/
void IIC_Start ( void )
{
    IICReceivedACK = IIC_INVALID_ACK;

    IIC_SDA_DIR ( 0 );  //SDA被设置为输入,IO口为高阻状态,总线上SDA信号由上拉电阻拉高,此时SDA = 1
    IIC_Delay();
    IIC_Delay();

    IIC_SCL_DIR ( 0 ); //SCL被设置为输入,IO口为高阻状态,总线上SCL信号由上拉电阻拉高,此时SCL = 1
    IIC_Delay();
    IIC_Delay();

    IIC_SDA_DIR ( 1 ); //SDA输出0,此时SDA = 0
    IIC_SDA ( 1, 0 );
    IIC_Delay();
    IIC_Delay();

    IIC_SCL_DIR ( 1 ); //SCL输出0,此时SCL = 0
    IIC_SCL ( 1, 0 );
    IIC_Delay();
    IIC_Delay();
}

/******************************************************************************
函数名：IIC_Stop
功  能：在IIC总线上发送停止信号,终止当前IIC通信
参  数：无
返回值：无
******************************************************************************/
void IIC_Stop ( void )
{
    IICReceivedACK = IIC_INVALID_ACK;

    IIC_SDA_DIR ( 1 ); //SDA输出0,此时SDA = 0
    IIC_SDA ( 1, 0 );
    IIC_Delay();
    IIC_Delay();

    IIC_SCL_DIR ( 0 ); //SCL被设置为输入,IO口为高阻状态,总线上SCL信号由上拉电阻拉高,此时SCL = 1
    IIC_Delay();
    IIC_Delay();

    IIC_SDA_DIR ( 0 ); //SDA被设置为输入,IO口为高阻状态,总线上SDA信号由上拉电阻拉高,此时SDA = 1
    IIC_Delay();
    IIC_Delay();
}

/******************************************************************************
函数名：IIC_Transmit_Data
功  能：向IIC总线上发送1字节数据
参  数：Data：发送的数据
返回值：总线上器件的确认(ACK)  0 - ACK  1 - NAK
******************************************************************************/
void IIC_Transmit_Data ( uint8_t Data )
{
    uint8_t i;

    IICReceivedACK = IIC_INVALID_ACK;

    for ( i = 0; i < 8; i++ )
    {
        if ( Data & 0x80 )
            IIC_SDA_DIR ( 0 ); //SDA被设置为输入,IO口为高阻状态,总线上SDA信号由上拉电阻拉高,此时SDA = 1
        else
        {
            IIC_SDA_DIR ( 1 ); //SDA输出0,此时SDA = 0
            IIC_SDA ( 1, 0 );
        }
        IIC_Delay();
        IIC_Delay();
        IIC_Delay();

        IIC_SCL_DIR ( 0 );   //SCL被设置为输入,IO口为高阻状态,总线上SCL信号由上拉电阻拉高,此时SCL = 1
        IIC_Delay();
        IIC_Delay();

        IIC_SCL_DIR ( 1 );   //SCL输出0,此时SCL = 0
        IIC_SCL ( 1, 0 );
        IIC_Delay();
        IIC_Delay();
        IIC_Delay();

        Data <<= 1;
    }

    IIC_SDA_DIR ( 0 );     //设置SDA为输入状态
    IIC_Delay();
    IIC_Delay();

    IIC_SCL_DIR ( 0 );     //SCL被设置为输入,IO口为高阻状态,总线上SCL信号由上拉电阻拉高,此时SCL = 1
    IIC_Delay();
    IIC_Delay();

    IICReceivedACK = IIC_SDA ( 0, 0 );

    IIC_SCL_DIR ( 1 );     //SCL输出0,此时SCL = 0
    IIC_SCL ( 1, 0 );
    IIC_Delay();
    IIC_Delay();
}

/******************************************************************************
函数名：IIC_Receive_Data
功  能：从IIC总线上接收1字节数据
参  数：无
返回值：接收到的数据
******************************************************************************/
uint8_t IIC_Receive_Data ( void )
{
    uint8_t i;
    uint8_t Data;

    Data = 0;

    IIC_SDA_DIR ( 0 );     //设置SDA为输入状态
    IIC_Delay();
    IIC_Delay();

    for ( i = 0; i < 8; i++ )
    {
        Data <<= 1;

        IIC_SCL_DIR ( 0 );  //SCL被设置为输入,IO口为高阻状态,总线上SCL信号由上拉电阻拉高,此时SCL = 1
        IIC_Delay();
        IIC_Delay();
        IIC_Delay();

        Data |= IIC_SDA ( 0, 0 );

        IIC_SCL_DIR ( 1 );   //SCL输出0,此时SCL = 0
        IIC_SCL ( 1, 0 );
        IIC_Delay();
        IIC_Delay();
        IIC_Delay();
    }

    return Data;
}

/******************************************************************************
函数名：IIC_Transmit_ACK
功  能：向IIC总线上发送确认信号
参  数：ACK：确认信号的类型： IIC_ACK  肯定应答
                              IIC_NAK  否定应答
返回值：无
******************************************************************************/
void IIC_Transmit_ACK ( uint8_t ACK )
{
    IICReceivedACK = IIC_INVALID_ACK;

    if ( ACK > IIC_NAK )
        return;

    if ( ACK )
        IIC_SDA_DIR ( 0 );   //SDA被设置为输入,IO口为高阻状态,总线上SDA信号由上拉电阻拉高,此时SDA = 1
    else
    {
        IIC_SDA_DIR ( 1 );   //SDA输出0,此时SDA = 0
        IIC_SDA ( 1, 0 );
    }
    IIC_Delay();
    IIC_Delay();

    IIC_SCL_DIR ( 0 );     //SCL被设置为输入,IO口为高阻状态,总线上SCL信号由上拉电阻拉高,此时SCL = 1
    IIC_Delay();
    IIC_Delay();

    IIC_SCL_DIR ( 1 );     //SCL输出0,此时SCL = 0
    IIC_SCL ( 1, 0 );
    IIC_Delay();
    IIC_Delay();
}

/******************************************************************************
函数名：IIC_Receive_ACK
功  能：获取从总线上接收到的确认信号
参  数：无
返回值：总线上器件的确认信号类型：IIC_ACK         肯定应答
                                  IIC_NAK         否定应答
                                  IIC_INVALID_ACK 无效的应答信号(应答信号还未收到)
******************************************************************************/
uint8_t IIC_Receive_ACK ( void )
{
    uint8_t ACK;

    ACK = IICReceivedACK;
    IICReceivedACK = IIC_INVALID_ACK;

    return ACK;
}

/******************************************************************************
函数名：IIC_Delay
功  能：延时5us,用于收发过程中的时序控制
        注意：必须调整IIC_5us_DELAY_CALIBRATION参数校准延时时间在5us左右
参  数：ACK：确认信号的类型  0 - ACK  1 - NAK
返回值：无
******************************************************************************/
void IIC_Delay ( void )
{
    uint8_t i;

    for ( i = 0; i < IIC_FREQ_CALIBRATION; i++ )
        asm ( "nop" );
}