
#include <i2c.h>

uint8_t i2c_error;

void i2c_init(void) {
    switch (PSC_I2C) {
    case 4:
        TWSR = 0x1;
        break;
    case 16:
        TWSR = 0x2;
        break;
    case 64:
        TWSR = 0x3;
        break;
    default:
        TWSR = 0x00;
        break;
    }
    TWBR = (uint8_t) SET_TWBR;
    TWCR = (1 << TWEN);
}

void i2c_send_addr(uint8_t i2c_addr) {
    TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
    uint16_t timeout = F_CPU / F_I2C * 2.0;

    while ((TWCR & (1 << TWINT)) == 0 && timeout != 0) {
        timeout--;
        if (timeout == 0) {
            i2c_error |= (1 << I2C_ERR_START);
            return;
        }
    };
    TWDR = i2c_addr;
    TWCR = (1 << TWINT) | (1 << TWEN);
    timeout = F_CPU / F_I2C * 2.0;
    while ((TWCR & (1 << TWINT)) == 0 && timeout != 0) {
        timeout--;
        if (timeout == 0) {
            i2c_error |= (1 << I2C_ERR_SENDADRESS);
            return;
        }
    };
}

void i2c_stop(void) {
    TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
}

void i2c_send_data(uint8_t byte) {
    TWDR = byte;
    TWCR = (1 << TWINT) | (1 << TWEN);
    uint16_t timeout = F_CPU / F_I2C * 2.0;

    while ((TWCR & (1 << TWINT)) == 0 && timeout != 0) {
        timeout--;
        if (timeout == 0) {
            i2c_error |= (1 << I2C_ERR_BYTE);
            return;
        }
    };
}

uint8_t i2c_read_ack(void) {
    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
    uint16_t timeout = F_CPU / F_I2C * 2.0;

    while ((TWCR & (1 << TWINT)) == 0 && timeout != 0) {
        timeout--;
        if (timeout == 0) {
            i2c_error |= (1 << I2C_ERR_READACK);
            return 0;
        }
    };
    return TWDR;
}


uint8_t i2c_read_nack(void) {
    TWCR = (1 << TWINT) | (1 << TWEN);
    uint16_t timeout = F_CPU / F_I2C * 2.0;

    while ((TWCR & (1 << TWINT)) == 0 && timeout != 0) {
        timeout--;
        if (timeout == 0) {
            i2c_error |= (1 << I2C_ERR_READNACK);
            return 0;
        }
    };
    return TWDR;
}
