#include "i2c.h"

I2c :: I2c()
{
	
}

I2c :: I2c(GPIO_TypeDef* gpio, uint16_t scl_pin, uint16_t sda_pin) : 
	m_gpio(gpio), m_scl_pin(scl_pin), m_sda_pin(sda_pin)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //Periph clocking
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    
    GPIO_InitTypeDef param; //port B configuration
    param.GPIO_Mode = GPIO_Mode_OUT;
    //GPIO_Pin_10 | GPIO_Pin_11    i2c 
	param.GPIO_Pin = m_scl_pin | m_sda_pin;
    param.GPIO_PuPd = GPIO_PuPd_UP;
    param.GPIO_OType = GPIO_OType_OD;
    param.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(m_gpio, &param);
    
    m_sclHigh();
    m_sdaHigh();
}

void I2c :: m_delay()
{
    volatile uint8_t i=I2c_DELAY;
    while(i>0) i--;
}

void I2c :: m_sclHigh()
{
    GPIO_SetBits(m_gpio, m_scl_pin);
}

void I2c :: m_sclLow()
{
    GPIO_ResetBits(m_gpio, m_scl_pin);
}

void I2c :: m_sdaHigh()
{
    GPIO_SetBits(m_gpio, m_sda_pin);
}

void I2c :: m_sdaLow()
{
    GPIO_ResetBits(m_gpio, m_sda_pin);
}

bool I2c :: m_sclRead()
{
    bool a;
    a = GPIO_ReadInputDataBit(m_gpio, m_scl_pin);
    return a;
}

bool I2c :: m_sdaRead()
{
    bool a;
    a = GPIO_ReadInputDataBit(m_gpio, m_sda_pin);
    return a;
}

bool I2c :: begin()
{
    m_sdaHigh();
    m_sclHigh();
    m_delay();
    if(!m_sdaRead()) return 0;
    m_sdaLow();
    m_delay();
    if(m_sdaRead()) return 0;
    m_sclLow();
    m_delay();
    return 1;
}

bool I2c :: begin(uint8_t adress, bool dir)
{
    m_sdaHigh();
    m_sclHigh();
    m_delay();
    if(!m_sdaRead()) return 0;
    m_sdaLow();
    m_delay();
    if(m_sdaRead()) return 0;
    m_sclLow();
    m_delay();
    if(dir) writeByte((adress << 1) | 1);
    else writeByte((adress << 1) & 254);
    return 1;
}

bool I2c :: end()
{
    m_sdaLow();
    m_sclLow();
    m_delay();
    if(m_sclRead()) return 0;
    m_sclHigh();
    m_delay();
    if(!m_sclRead()) return 0;
    m_sdaHigh();
    m_delay();
    return 1;
}

void I2c :: writeByte(uint8_t byte)
{
    m_sclLow();
    m_delay();
    uint8_t a = 0x80;
    while(a > 0)
    {
        if(byte & a)
        {
            m_sdaHigh();
        }
        else
        {
            m_sdaLow();
        }
        m_delay();
        m_sclHigh();
        m_delay();
        m_sclLow();
        m_delay();
        m_sdaLow();
        m_delay();
        a = a >> 1;
    }
}

bool I2c :: readAck()
{
    m_sclLow();
    m_delay();
    m_sclHigh();
    m_delay();
    bool a;
    a = ~m_sdaRead();
    m_sclLow();
    m_delay();
    m_sdaLow();
    return a;
}

uint8_t I2c :: readByte()
{
    uint8_t byte = 0;
    volatile int8_t a = 7;
    m_sdaHigh();
    m_sclLow();
    m_delay();
    while (a >= 0)
    {
        m_sclHigh();
        m_delay();
        byte |= (m_sdaRead() << a);
        m_sclLow();
        m_delay();
        a--;
    }
    m_sdaLow();
    m_sclLow();
    return byte;
}

void I2c :: generateAck()
{
    m_sclLow();
    m_delay();
    m_sdaLow();
    m_delay();
    m_sclHigh();
    m_delay();
    m_sclLow();
    m_delay();
    m_sdaLow();
    m_delay();
}

void I2c :: generateNAck()
{
    m_sclLow();
    m_delay();
    m_sdaHigh();
    m_delay();
    m_sclHigh();
    m_delay();
    m_sclLow();
    m_delay();
    m_sdaLow();
    m_delay();
}
