#include "periphery.h"

void init_tim() {

    //-------TIM4-DELAAY--------------
    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
    TIM4->PSC = 71;
    TIM4->ARR = 50000;
    TIM4->CR1 |= TIM_CR1_CEN;
}

void init_gpio() {

    RCC->APB2ENR |= (RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN |
                     RCC_APB2ENR_AFIOEN); //--PORT-A:B:C:ALT-FUNC-CLOCK-ENABLE

    //-----PORT-A-RESET--
    GPIOA->CRL = 0UL;
    GPIOA->CRH = 0UL;
    //-----PORT-B-RESET--
    GPIOB->CRL = 0UL;
    GPIOB->CRH = 0UL;
    //-----PORT-C-RESET--
    GPIOC->CRL = 0UL;
    GPIOC->CRH = 0UL;

    //---------ON-BOARD-LED---------
    GPIOC->CRH |= GPIO_CRH_MODE13_0;

    //---------INT---------------
    GPIOB->CRL |= GPIO_CRL_CNF0_1;

    //---------USART3--------------
    //-PB10
    GPIOB->CRH |= GPIO_CRH_MODE10;
    GPIOB->CRH |= GPIO_CRH_CNF10_1;
    //-PB11

    GPIOB->CRH |= GPIO_CRH_CNF11_1;
    //---------I2C-----------------

    GPIOB->CRL |= GPIO_CRL_MODE6 | GPIO_CRL_CNF6; // I2C1 SCL
    GPIOB->CRL |= GPIO_CRL_MODE7 | GPIO_CRL_CNF7; // I2C1 SDA
    GPIOB->CRL &= ~(GPIO_CRL_MODE6 | GPIO_CRL_CNF6);
    GPIOB->CRL &= ~(GPIO_CRL_MODE7 | GPIO_CRL_CNF7);
    GPIOB->CRL |= GPIO_CRL_MODE6 | GPIO_CRL_CNF6;
    GPIOB->CRL |= GPIO_CRL_MODE7 | GPIO_CRL_CNF7;
}

void init_usart(void) {

    RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
    USART3->CR1 = 0UL;

    USART3->BRR = 0x0138; //--9600BD = 0x0EA6; --115200BD = 0x0138;

    USART3->CR1 |= USART_CR1_RXNEIE;
    USART3->CR1 |= USART_CR1_TE;
    USART3->CR1 |= USART_CR1_RE;
    USART3->CR1 |= USART_CR1_UE;
    NVIC_EnableIRQ(USART3_IRQn);
}
void I2C1_Init(void) {
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
    I2C1->OAR1 = 0x00004000U;
    I2C1->OAR2 = 0x0U;
    I2C1->CR2 = 36;  // set FREQ = APB1 = 18MHz
    I2C1->CCR = 180; // 100 KHz
    I2C1->TRISE = 37;
    I2C1->CR1 |= I2C_CR1_ACK;
    I2C1->CR1 |= I2C_CR1_PE;
}
//------------------------------------------------------------------
void I2C_Master_Transmit(uint16_t DevAddress, uint8_t *pData, uint16_t Size) {
    while (I2C1->SR2 & I2C_SR2_BUSY)
        ;
    I2C1->CR1 &= ~I2C_CR1_POS;
    uint8_t *Buff = pData;
    uint16_t Count = Size;
    uint16_t rSize = Count;
    I2C1->CR1 |= I2C_CR1_ACK;
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB))
        ;
    I2C1->DR = ((uint8_t)DevAddress << 1);
    while (!(I2C1->SR1 & I2C_SR1_ADDR))
        ;
    (void)I2C1->SR1;
    (void)I2C1->SR2;
    while (rSize > 0U) {
        while (!(I2C1->SR1 & I2C_SR1_TXE))
            ;
        I2C1->DR = *Buff;
        Buff++;
        Count--;
        rSize--;
        if ((I2C1->SR1 & I2C_SR1_BTF) && (rSize != 0U)) {
            I2C1->DR = *Buff;
            Buff++;
            Count--;
            rSize--;
        }
        while (!(I2C1->SR1 & I2C_SR1_BTF))
            ;
    }
    I2C1->CR1 |= I2C_CR1_STOP;
}
//------------------------------------------------------------------
void I2C_Master_Receive(uint16_t DevAddress, uint8_t *pData, uint16_t Size) {
    while (I2C1->SR2 & I2C_SR2_BUSY)
        ;
    I2C1->CR1 &= ~I2C_CR1_POS;
    uint8_t *Buff = pData;
    uint16_t Count = Size;
    uint16_t rSize = Count;
    I2C1->CR1 |= I2C_CR1_ACK;
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB))
        ;
    I2C1->DR = ((uint8_t)((DevAddress << 1) | I2C_OAR1_ADD0));
    while (!(I2C1->SR1 & I2C_SR1_ADDR))
        ;
    if (rSize == 0U) {
        (void)I2C1->SR1;
        (void)I2C1->SR2;
        I2C1->CR1 |= I2C_CR1_STOP;
    } else if (rSize == 1U) {
        I2C1->CR1 &= ~I2C_CR1_ACK;
        (void)I2C1->SR1;
        (void)I2C1->SR2;
        I2C1->CR1 |= I2C_CR1_STOP;
    } else if (rSize == 2U) {
        I2C1->CR1 |= I2C_CR1_POS;
        (void)I2C1->SR1;
        (void)I2C1->SR2;
        I2C1->CR1 &= ~I2C_CR1_ACK;
    } else {
        I2C1->CR1 |= I2C_CR1_ACK;
        (void)I2C1->SR1;
        (void)I2C1->SR2;
    }
    while (rSize > 0U) {
        if (rSize <= 3U) {
            if (rSize == 1U) {
                while (!(I2C1->SR1 & I2C_SR1_RXNE))
                    ;
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
            } else if (rSize == 2U) {
                while (!(I2C1->SR1 & I2C_SR1_BTF))
                    ;
                I2C1->CR1 |= I2C_CR1_STOP;
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
            } else {
                while (!(I2C1->SR1 & I2C_SR1_BTF))
                    ;
                I2C1->CR1 &= ~I2C_CR1_ACK;
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
                while (!(I2C1->SR1 & I2C_SR1_BTF))
                    ;
                I2C1->CR1 |= I2C_CR1_STOP;
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
            }
        } else {
            while (!(I2C1->SR1 & I2C_SR1_RXNE))
                ;
            *Buff = (uint8_t)I2C1->DR;
            Buff++;
            Count--;
            rSize--;
            if (I2C1->SR1 & I2C_SR1_BTF) {
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
            }
        }
    }
}
//-----------------------------------------------------------------
void I2C_Mem_Write(uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData,
                   uint16_t Size) {
    while (I2C1->SR2 & I2C_SR2_BUSY)
        ;
    I2C1->CR1 &= ~I2C_CR1_POS;
    uint8_t *Buff = pData;
    uint16_t Count = Size;
    uint16_t rSize = Count;
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB))
        ;
    I2C1->DR = ((uint8_t)DevAddress << 1);
    while (!(I2C1->SR1 & I2C_SR1_ADDR))
        ;
    (void)I2C1->SR1;
    (void)I2C1->SR2;
    while (!(I2C1->SR1 & I2C_SR1_TXE))
        ;
    if (MemAddSize == 1) {
        I2C1->DR = ((uint8_t)MemAddress);
    } else {
        I2C1->DR = ((uint8_t)(((uint16_t)((MemAddress) & (uint16_t)0xFF00)) >> 8));
        while (!(I2C1->SR1 & I2C_SR1_TXE))
            ;
        I2C1->DR = ((uint8_t)MemAddress);
    }
    while (rSize > 0U) {
        while (!(I2C1->SR1 & I2C_SR1_TXE))
            ;
        I2C1->DR = *Buff;
        Buff++;
        Count--;
        rSize--;
        if ((I2C1->SR1 & I2C_SR1_BTF) && (rSize != 0U)) {
            I2C1->DR = *Buff;
            Buff++;
            Count--;
            rSize--;
        }
    }
    while (!(I2C1->SR1 & I2C_SR1_BTF))
        ;
    I2C1->CR1 |= I2C_CR1_STOP;
}
//-------------------------------------------------------------------------
void I2C_Mem_Read(uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData,
                  uint16_t Size) {
    while (I2C1->SR2 & I2C_SR2_BUSY)
        ;
    I2C1->CR1 &= ~I2C_CR1_POS;
    uint8_t *Buff = pData;
    uint16_t Count = Size;
    uint16_t rSize = Count;
    I2C1->CR1 |= I2C_CR1_ACK;
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB))
        ;
    I2C1->DR = ((uint8_t)DevAddress << 1);
    while (!(I2C1->SR1 & I2C_SR1_ADDR))
        ;
    (void)I2C1->SR1;
    (void)I2C1->SR2;
    while (!(I2C1->SR1 & I2C_SR1_TXE))
        ;
    if (MemAddSize == 1) {
        I2C1->DR = ((uint8_t)MemAddress);
    } else {
        I2C1->DR = ((uint8_t)(((uint16_t)((MemAddress) & (uint16_t)0xFF00)) >> 8));
        while (!(I2C1->SR1 & I2C_SR1_TXE))
            ;
        I2C1->DR = ((uint8_t)MemAddress);
    }
    while (!(I2C1->SR1 & I2C_SR1_TXE))
        ;
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB))
        ;
    I2C1->DR = ((uint8_t)((DevAddress << 1) | I2C_OAR1_ADD0));
    while (!(I2C1->SR1 & I2C_SR1_ADDR))
        ;
    if (rSize == 0U) {
        (void)I2C1->SR1;
        (void)I2C1->SR2;
        I2C1->CR1 |= I2C_CR1_STOP;
    } else if (rSize == 1U) {
        I2C1->CR1 &= ~I2C_CR1_ACK;
        (void)I2C1->SR1;
        (void)I2C1->SR2;
        I2C1->CR1 |= I2C_CR1_STOP;
    } else if (rSize == 2U) {
        I2C1->CR1 |= I2C_CR1_POS;
        (void)I2C1->SR1;
        (void)I2C1->SR2;
        I2C1->CR1 &= ~I2C_CR1_ACK;
    } else {
        I2C1->CR1 |= I2C_CR1_ACK;
        (void)I2C1->SR1;
        (void)I2C1->SR2;
    }
    while (rSize > 0U) {
        if (rSize <= 3U) {
            if (rSize == 1U) {
                while (!(I2C1->SR1 & I2C_SR1_RXNE))
                    ;
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
            } else if (rSize == 2U) {
                while (!(I2C1->SR1 & I2C_SR1_BTF))
                    ;
                I2C1->CR1 |= I2C_CR1_STOP;
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
            } else {
                while (!(I2C1->SR1 & I2C_SR1_BTF))
                    ;
                I2C1->CR1 &= ~I2C_CR1_ACK;
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
                while (!(I2C1->SR1 & I2C_SR1_BTF))
                    ;
                I2C1->CR1 |= I2C_CR1_STOP;
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
            }
        } else {
            while (!(I2C1->SR1 & I2C_SR1_RXNE))
                ;
            *Buff = (uint8_t)I2C1->DR;
            Buff++;
            Count--;
            rSize--;
            if (I2C1->SR1 & I2C_SR1_BTF) {
                *Buff = (uint8_t)I2C1->DR;
                Buff++;
                Count--;
                rSize--;
            }
        }
    }
}

void USART3_IRQHandler(void) {
    if (USART3->SR & USART_SR_RXNE) {
        USART3->SR &= ~USART_SR_RXNE;
        usart3_rx_buf[usart3_rx_inc] = USART3->DR;
        usart3_rx_inc++;
        usart3_rx_timeout = 50;
    }
}

void USART_TX(char *array) {
    while (*array != 0) {
        while (!(USART3->SR & USART_SR_TXE))
            ;
        USART3->DR = *array++;
    }
}

void sys_clocking(void) {
    RCC->CR |= RCC_CR_HSEON;
    while (!(RCC->CR & RCC_CR_HSERDY))
        ;
    FLASH->ACR &= ~FLASH_ACR_PRFTBE;
    FLASH->ACR |= FLASH_ACR_PRFTBE;
    FLASH->ACR |= FLASH_ACR_LATENCY_2;
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV1 | RCC_CFGR_PPRE1_DIV2;
    RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL);
    RCC->CFGR |= RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9;
    RCC->CR |= RCC_CR_PLLON;
    while (!(RCC->CR & RCC_CR_PLLRDY))
        ;
    RCC->CFGR &= ~RCC_CFGR_SW_PLL;
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    while (!(RCC->CFGR & RCC_CFGR_SWS_PLL))
        ;
    SystemCoreClockUpdate();
    SysTick_Config(SystemCoreClock / 1000);
}

void SysTick_Handler(void) {
    if (wto > 0) {
        wto--;
    }
    if (usart3_rx_timeout > 0) {
        usart3_rx_timeout--;
        if (usart3_rx_timeout <= 1) {
            usart3_rx_done = 1;
            usart3_rx_timeout = 0;
        }
    }
    if (!mpu_read_flag) {
        if (mpu_flag_time < 100) {
            mpu_flag_time++;
        } else {
            mpu_read_flag = 1;
            mpu_flag_time = 0;
        }
    }
}

void init_all() {
    sys_clocking();
    init_gpio();
    init_tim();
    init_usart();
    I2C1_Init();
}
