
#include "main.h"



#ifndef NULL
#define NULL 0
#endif

#define SZ24(size)  size >> 24
#define SZ16(size)  size >> 16
#define SZ8(size)  size >> 8
uint16_t flag = 0;
uint8_t flag2 = 0;

typedef enum {WR,RD}tI2Cdir_en; // запись/чтение
typedef enum {IDLE,START,DEV_ADDR,WRITE_READ,RESTART,RE_DEV_ADDR,DATA_WR,DATA_RD,STOP}tI2C_state_en; // состояния шины

typedef struct {                  // настройки пакета
    uint8_t dev_addr;             // адресс устройства
    uint32_t start_adr;           // адресс в который писать/читать
    uint8_t size_adr;             // размер адресса
    uint16_t data_length;         // длина пакета
    uint8_t* buf;                 // буфер передачи
    tI2Cdir_en RD_WR;             // чтение/запись
    uint8_t end_fg;               // интерфейс свободен/занят
    I2C_TypeDef *i2c_periph;      // какая перерия 1/2
    tI2C_state_en state;          // статус передачи
    uint8_t in_error;             // ошибки?
}tI2C_transfer_st;

static tI2C_transfer_st I2C2_struct={   // инициализация
    .dev_addr = 0,
	.start_adr = 0,
	.size_adr = 0,
    .data_length = 0,
    .RD_WR=RD,
    .buf=NULL,
    .end_fg=1,
    .i2c_periph=I2C2,
    .state=IDLE,
    .in_error=0
};
/** \brief Initialize I2C periphery in SDANDARD speed mode
 *
 * \param i2c I2C_TypeDef* select I2C1 or I2C2 module
 * \param f_bus int desired bus speed in kHz. Notice to set speed not more 100kHz
 * \return void
 *
 */
void I2C_Init(I2C_TypeDef *i2c,int f_bus_kHz){

	//Настройки тактирования
	SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPBEN); //Запуск тактирование порта B
	SET_BIT(RCC->APB2ENR, RCC_APB2ENR_AFIOEN); //Запуск тактирования альтернативных функций
	SET_BIT(RCC->APB1ENR, RCC_APB1ENR_I2C2EN); //Запуск тактирования I2C1

	//Настройки ножек SDA и SCL
	//PB7 SDA (I2C Data I/O) Alternate function open drain
	MODIFY_REG(GPIOB->CRH, GPIO_CRH_CNF10_Msk, 0b11 << GPIO_CRH_CNF10_Pos); //Alternate function open drain
	MODIFY_REG(GPIOB->CRH, GPIO_CRH_MODE10_Msk, 0b11 << GPIO_CRH_MODE10_Pos); //Maximum output speed 50 MHz
	//PB6 SCL (I2C clock) Alternate function open drain
	MODIFY_REG(GPIOB->CRH, GPIO_CRH_CNF11_Msk, 0b11 << GPIO_CRH_CNF11_Pos); //Alternate function open drain
	MODIFY_REG(GPIOB->CRH, GPIO_CRH_MODE11_Msk, 0b11 << GPIO_CRH_MODE11_Pos); //Maximum output speed 50 MHz

    i2c->CR1= 0;
    i2c->CCR= 0 | ((((SystemCoreClock+1000*f_bus_kHz)/1000/f_bus_kHz/2)<<I2C_CCR_CCR_Pos)&I2C_CCR_CCR_Msk); //скорость из даташита
    i2c->CR1= 0 | I2C_CR1_PE;
    i2c->CR2=(((SystemCoreClock/1000000ul)<<I2C_CR2_FREQ_Pos)&I2C_CR2_FREQ_Msk) | I2C_CR2_ITERREN | I2C_CR2_ITEVTEN;// | I2C_CR2_ITBUFEN;
    i2c->OAR1=0 ;
    i2c->OAR2= 0;
    i2c->TRISE=SystemCoreClock/1000000ul+1;//< 1000ns for Standard mode->1000000

    NVIC_SetPriority(I2C2_EV_IRQn,0);  //Включим прерывания по I2C
	NVIC_EnableIRQ(I2C2_EV_IRQn);      // наивысший приоритет

}

static void I2C_SetError(tI2C_transfer_st *i2c){   // обработка ошибки
    i2c->in_error=1;
    i2c->i2c_periph->CR1=I2C_CR1_SWRST;            // сбросить шину
    I2C2_struct.end_fg=1;

     	//SET_BIT(GPIOC -> BSRR, GPIO_BSRR_BR13);
}

void I2C_transfer(tI2C_transfer_st *i2c){          // инициализация передачи
    if(i2c->i2c_periph->SR2 & I2C_SR2_BUSY)I2C_SetError(i2c);// проверка не сломана ли шина
    if(i2c->in_error){
        I2C_Init(i2c->i2c_periph,I2C_BUS_FREQ_KHZ);    // переинициализация переферии
        i2c->in_error=0;                               // сброс флага ошибки
    }
    i2c->state=START;                                  // статус старт
    //i2c->i2c_periph->CR2|=I2C_CR2_ITBUFEN;//I2C_CR2_ITBUFEN включим прерывание от TxE,RxNE , так как было сброшено
    i2c->i2c_periph->CR1|=I2C_CR1_START;               // формируем старт

}

void I2C2_EV_IRQHandler(void){                         // прерывание от и2с

    uint16_t status1=I2C2->SR1;                        // считываем статусный регистр в переменную
    static uint8_t*buf_ptr;                            // указатель на буффер данных
    static uint16_t length;                            // длина отправляемого/принимаемого буфера
   volatile uint32_t r1;
   volatile uint32_t r2;
   volatile uint32_t r3;
   volatile uint32_t r4;

	   if (status1&I2C_SR1_ADDR) {
		   SET_BIT(GPIOC -> BSRR, GPIO_BSRR_BS13);
	   } else {
		   SET_BIT(GPIOC -> BSRR, GPIO_BSRR_BR13);
	   }
	  /* if (status1&I2C_SR1_BTF) {
		   SET_BIT(GPIOC -> BSRR, GPIO_BSRR_BS14);
	   } else {
		   SET_BIT(GPIOC -> BSRR, GPIO_BSRR_BR14);
	   }*/
  // SET_BIT(GPIOC -> BSRR, GPIO_BSRR_BS13);
   	if (flag2 == 0){ flag2 = 1; SET_BIT(GPIOC -> BSRR, GPIO_BSRR_BS14); goto ends;}
   	if (flag2 == 1){ flag2 = 0; SET_BIT(GPIOC -> BSRR, GPIO_BSRR_BR14); goto ends;}
 ends:

    switch (I2C2_struct.state){                        // в зависимости от статуса выполняем действия
    case START://SB
        if(!(status1&I2C_SR1_SB)){I2C_SetError(&I2C2_struct); break;}  // если по факту не был сгенерирован старт - ошибка
        buf_ptr=I2C2_struct.buf;                       // получаем указатель на передаваемый буфер
        I2C2_struct.state=DEV_ADDR;                    // устанавливаем статус отправили адресс
        if (I2C2_struct.size_adr) I2C2->DR=(I2C2_struct.dev_addr<<1) | 0;   // смещаем адресс на один в лево и добавляем бит  записи
        if (!I2C2_struct.size_adr) I2C2->DR=(I2C2_struct.dev_addr<<1) | (I2C2_struct.RD_WR==RD?1:0);   // смещаем адресс на один в лево и добавляем бит чтения или  записи
        break;

    case DEV_ADDR://ADDR                               // адресс был отправлен
        if(!(status1&I2C_SR1_ADDR)){I2C_SetError(&I2C2_struct); break;}  // если это не так то ошибка
        (void)I2C2->SR2;                               // читаем в пустоту SR2 для сброса, SR1 был уже считан выше для сброса ADDR
        if (I2C2_struct.size_adr) {                    // если размер адресса доступа больше 0
        	I2C2_struct.size_adr --;                   // отнимаем кусок переданного адреса
        	switch (I2C2_struct.size_adr + 1) {        // передадим старший байт адресса регистра
            case (1): I2C2->DR = I2C2_struct.start_adr; // тут выбираем макрос в зависимости от размера адреса
        	if (I2C2_struct.RD_WR==RD) {                 // если передаем данные
        		I2C2_struct.state = WRITE_READ;          // установим статус перехода
        		goto out;
        	}
            break;
            case (2): I2C2->DR = SZ8(I2C2_struct.start_adr); break;
            case (3): I2C2->DR = SZ16(I2C2_struct.start_adr); break;
            case (4): I2C2->DR = SZ24(I2C2_struct.start_adr); break;
            }
            I2C2_struct.state=DATA_WR;                 // устанавливаем статус передачи байта
            length=I2C2_struct.data_length;            // узнаем размер отправляемоых данных
        } else {                                       // если адресс доступа к регистру не используеться
            if(I2C2_struct.RD_WR==WR){                 // если пишем в устройство
                length=I2C2_struct.data_length-1;      // узнаем размер отправляемоых данных - 1, так как 1 мы щас передадим
                I2C2_struct.state=DATA_WR;             // устанавливаем статус передачи данных
                I2C2->DR=*buf_ptr++;                   // отправляем нулевой байт
            }else{                                     // если у нас чтение
                length=I2C2_struct.data_length;        // узнаем сколько нужно считать
                if(length>1)I2C2->CR1|=I2C_CR1_ACK;    // если больше 1 то генерируем аск ( после этого начинается снова генерация на считывание)
              //  if(length==1)I2C2->CR1|=I2C_CR1_STOP;  // если нужно считать только 1 то после него генерим стоп
                I2C2_struct.state=DATA_RD;             // устанавливаем статус чтения
            }
        }
            break;

    case DATA_WR:                                       // передача байта завершена
        if(status1&I2C_SR1_AF){I2C_SetError(&I2C2_struct); break;}  // если не было подтверждение значит ошибка
        if (I2C2_struct.size_adr) {                     // если мы еще не передали адрес регистра, передаем
            I2C2_struct.size_adr --;                    // уменьшаем переменную   счетчика кусков адреса
        	switch (I2C2_struct.size_adr + 1) {             // передадим оставшиеся куски адреса регистра + 1 так как отняли перед этим
             case (1): I2C2->DR = I2C2_struct.start_adr; // тут выбираем макрос в зависимости от размера адреса
         	  if (I2C2_struct.RD_WR==RD) {               // если принимаем данные
         		I2C2_struct.state = WRITE_READ;          // установим статус перехода
         		//I2C2->CR1 |= I2C_SR1_AF;
         		//I2C2->CR1|=I2C_CR1_START;
         	  }goto out;
             case (2): I2C2->DR = SZ8(I2C2_struct.start_adr); goto out;
             case (3): I2C2->DR = SZ16(I2C2_struct.start_adr); goto out;
            }
        }
        if(length > 1){                                     // если длина 1 или более
            length--;                                   // уменьшаем ее
            I2C2->DR=*buf_ptr++;                        // увеличиваем буффер, статус не меняем
        }
        if(length == 1){                                          // передача последнего или предпоследнего байта
        	    length--;                                   // уменьшаем ее
        	    I2C2->DR=*buf_ptr++;
                I2C2->CR1|=I2C_CR1_STOP;                // отправить стоп после последнего байта
                I2C2_struct.end_fg=1;                   // говорим что передача завершена
                I2C2_struct.state=IDLE;                 // ставим статус свободен
        }
        out:
        break;

    case WRITE_READ:                                    // переходной блок для перехода между записью регистра и подальшим чтением
    	if((status1&I2C_SR1_AF)){I2C_SetError(&I2C2_struct); break;}  // если передача данных завершена
		I2C2_struct.state = RESTART;                    // установим статус повторный старт
      //  I2C2->CR2&=~I2C_CR2_ITBUFEN;                    // отключим прерывание на прием? непонятный момент, почему именно так?
	/*	for (int i = 0; i < 100; i ++){
			asm("NOP");
		}*/

		r1 = I2C2->CR1;
		r2 = I2C2->CR2;
		r3 = I2C2->SR1;
		r4 = I2C2->SR2;
       // I2C2->DR=0x55;//dummy fill register to reset TxE and TBF until 'start' finished?
	//(void)I2C2->DR;
		flag = 1;
		r1 = I2C2->CR1;
		r2 = I2C2->CR2;
		r3 = I2C2->SR1;
		r4 = I2C2->SR2;

		I2C2->CR1|=I2C_CR1_START;                       // сформируем повторный старт

		//I2C2->DR=0x55;
          //(void)I2C2->DR;
    	break;

    case RESTART:                                       // рестарт чтоб не отправлять стоп а потом опять старт
    //	if (flag2 == 0){ flag2 = 1; SET_BIT(GPIOC -> BSRR, GPIO_BSRR_BR13);break; }
    //	if (flag2 == 1){ flag2 = 0; SET_BIT(GPIOC -> BSRR, GPIO_BSRR_BS13); break;}
    	if(!(status1&I2C_SR1_SB)){I2C_SetError(&I2C2_struct); break;}// если это не так то ошибка

        I2C2_struct.state=RE_DEV_ADDR;                  // статус повторная отправка адреcа
      //  I2C2->CR2|=I2C_CR2_ITBUFEN;                     // включим прерывание
        if(length>1)I2C2->CR1|=I2C_CR1_ACK;             // если длина больше 1 формируем аск
        I2C2->DR=(I2C2_struct.dev_addr<<1) | 1;         // передаем адресс смещенный на 1 и бит чтения, так как повторный рестарт для чтения
        break;

    case RE_DEV_ADDR://ADDR                             // после отправки повторного старта сюда
        if(!(status1&I2C_SR1_ADDR)){I2C_SetError(&I2C2_struct); break;}  // если адрес не был отправлен то ошибка
        I2C2_struct.state=DATA_RD;                      // меняем статус на чтение
        (void)I2C2->SR2;                                // читаем в пустоту SR2 для сброса, SR1 был уже считан выше для сброса ADDR
       // if(length==1)I2C2->CR1|=I2C_CR1_STOP;           // если длина равная 1 то формируем стоп, аск автоматом становиться ноаск
        break;

    case DATA_RD://RxNE or BTF                          // чтение байтов
        *buf_ptr++=I2C2->DR;                            // считываем и увеличиваем значение указателя
        length--;                                       // уменьшаем счетчик количества итераций
        if(!length){                                    // больше читать не нужно
            I2C2_struct.state=IDLE;                     // ставим статус свободен
            I2C2->CR1|=I2C_CR1_STOP;                    // выставим стоп
        }else if(length==1){                            // если это последний байт
            I2C2->CR1&=~I2C_CR1_ACK;                    // аск включен до тех пор пока мы его тут не выключим
            I2C2->CR1|=I2C_CR1_STOP;                    // выставим стоп
            I2C2_struct.end_fg=1;                   // говорим что передача завершена
        }
        break;
    default:
        I2C_SetError(&I2C2_struct);
        break;
    }//END switch
}

void I2C2_ER_IRQHandler(void){

}



void Write_I2C_adr (uint8_t adr, uint8_t len, uint32_t adr_reg, uint8_t size_adr, uint8_t *buf){
	if (!I2C2_struct.end_fg) {while (!I2C2_struct.end_fg); }
	I2C2_struct.start_adr = adr_reg;
	I2C2_struct.size_adr = size_adr;
	I2C2_struct.end_fg=0;    // занимаем шину
    I2C2_struct.buf = buf;
    I2C2_struct.dev_addr = adr;
    I2C2_struct.data_length = len;
    I2C2_struct.RD_WR = WR;
    I2C_transfer(&I2C2_struct);
}

void Write_I2C (uint8_t adr, uint8_t len, uint8_t *buf){
	if (!I2C2_struct.end_fg) {while (!I2C2_struct.end_fg); }
	I2C2_struct.start_adr = 0;
	I2C2_struct.size_adr = 0;
	I2C2_struct.end_fg=0;    // занимаем шину
    I2C2_struct.buf = buf;
    I2C2_struct.dev_addr = adr;
    I2C2_struct.data_length = len;
    I2C2_struct.RD_WR = WR;
    I2C_transfer(&I2C2_struct);
}

void Read_I2C_adr (uint8_t adr, uint8_t len, uint32_t adr_reg, uint8_t size_adr, uint8_t *buf){
	if (!I2C2_struct.end_fg) {while (!I2C2_struct.end_fg); }
	//SET_BIT(GPIOC -> BSRR, GPIO_BSRR_BS13);
	I2C2_struct.start_adr = adr_reg;
	I2C2_struct.size_adr = size_adr;
	I2C2_struct.end_fg=0;    // занимаем шину
    I2C2_struct.buf = buf;
    I2C2_struct.dev_addr = adr;
    I2C2_struct.data_length = len;
    I2C2_struct.RD_WR = RD;
    I2C_transfer(&I2C2_struct);
}

void Read_I2C (uint8_t adr, uint8_t len, uint8_t *buf){
	if (!I2C2_struct.end_fg) {while (!I2C2_struct.end_fg); }
	I2C2_struct.start_adr = 0;
	I2C2_struct.size_adr = 0;
	I2C2_struct.end_fg=0;    // занимаем шину
    I2C2_struct.buf = buf;
    I2C2_struct.dev_addr = adr;
    I2C2_struct.data_length = len;
    I2C2_struct.RD_WR = RD;
    I2C_transfer(&I2C2_struct);
}

uint8_t data_ok (void){
	if (I2C2_struct.end_fg) return 1;
	else return 0;
}

/* замечания по И2С, если мы выставляем I2C2->CR1|=I2C_CR1_STOP; или допустим наск, то это примениться к
  следующему отправленному/принятому биту
  когда мы установили бит аск, то он будет постоянно после принятого байта передавать аск, пока мы не сбросим этот бит

  */

