/*
* SCL -----------    ---.....---     ---------
*               |   |           |   |
*                ---             ---
* SDA --------    ---.....---------    ---------
*            |   |                 |   |
*             ---                   ---
*        start(SCL-H+SDA-falling)       stop(SCL-H+SDA-uping)
*/


#include "soft_iic.h"

void i2c_init(void)
{
    SDA_DIR_OUT();
    SCL_DIR_OUT();
    SDA_OUT_H();
    SCL_OUT_H();
    delay_ms(10);
}

void i2c_start(void)
{
    SDA_DIR_OUT();
    SDA_OUT_H();
    SCL_OUT_H();
    delay_us(5);
    SDA_OUT_L();
    delay_us(5);
    SCL_OUT_L();
}

void i2c_stop(void)
{
    SDA_DIR_OUT();
    SDA_OUT_L();
    SCL_OUT_L();
    delay_us(3);
    SCL_OUT_H();
    delay_us(3);
    SDA_OUT_H();
    delay_us(3);
}

void i2c_send_byte(u8 data)
{
    u8 i;

    SDA_DIR_OUT();
    SCL_OUT_L();

    for (i = 0; i < 8; i++) {
        if (data & BIT(7 - i)) {
            SDA_OUT_H();
        } else {
            SDA_OUT_L();
        }
        delay_us(3);
        SCL_OUT_H();
        delay_us(3);
        SCL_OUT_L();
        delay_us(3);
    }
}

u8 i2c_read_byte(u8 ack)
{
    u8 i, receive = 0;

    SDA_DIR_IN();

    for (i = 0; i < 8; i++) {
        SCL_OUT_L();
        delay_us(6);
        SCL_OUT_H();
        delay_us(2);
        receive <<= 1;
        if (SDA_STA()) {
            receive++;
        }
        delay_us(1);
    }

    if (ack) {
        i2c_ack();
    } else {
        i2c_nack();
    }

    return receive;
}

u8 i2c_wait_ack(void)
{
    u8 wait_time = 0;

    SDA_DIR_IN();
    delay_us(3);
    SCL_OUT_H();

    while (SDA_STA()) {
        wait_time++;
        if (wait_time > 250) {
            i2c_stop();
            return 0;
        }
        delay_us(1);
    }
    SCL_OUT_L();
    return 1;
}

void i2c_ack(void)
{
    SCL_OUT_L();
    SDA_DIR_OUT();
    SDA_OUT_L();
    delay_us(3);
    SCL_OUT_H();
    delay_us(3);
    SCL_OUT_L();
}

void i2c_nack(void)
{
    SCL_OUT_L();
    SDA_DIR_OUT();
    SDA_OUT_H();
    delay_us(3);
    SCL_OUT_H();
    delay_us(3);
    SCL_OUT_L();
}
