#include "led.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_tim.h"

void led_init(uint16_t led)
{
    GPIO_InitTypeDef  GPIO_InitStructure = {
        .GPIO_Pin = led,
        .GPIO_Mode = GPIO_Mode_OUT,
        .GPIO_OType = GPIO_OType_PP,
        .GPIO_Speed = GPIO_Speed_2MHz,
        .GPIO_PuPd = GPIO_PuPd_NOPULL,
    };
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    GPIO_Init(PORT_LED, &GPIO_InitStructure);
    led_off(led);

    /* TIM3 16bit for delay time calculation */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period = 42000; /* 84MHz, 0.5ms */
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV4;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
    /* Prescaler configuration */
    TIM_PrescalerConfig(TIM3, 0, TIM_PSCReloadMode_Immediate);
    /* TIM3 disable counter, start when ltc1867 need delay */
    TIM_Cmd(TIM3, DISABLE);
}

void led_off(uint16_t led)
{
    GPIO_SetBits(PORT_LED, led);
}

void led_on(uint16_t led)
{
    GPIO_ResetBits(PORT_LED, led);
}

void led_toggle(uint16_t led)
{
    GPIO_ToggleBits(PORT_LED, led);
}

void led_delay_ms(uint16_t ms)
{
    FlagStatus sts;

    TIM_SetCounter(TIM3, 0);
    TIM_PrescalerConfig(TIM3, ms * 2 - 1, TIM_PSCReloadMode_Immediate);
    TIM_ClearFlag(TIM3, TIM_FLAG_Update);
    TIM_Cmd(TIM3, ENABLE);
    while (1) {
        sts = TIM_GetFlagStatus(TIM3, TIM_FLAG_Update);
        if (sts != RESET) {
            break;
        }
    }
    TIM_Cmd(TIM3, DISABLE);
}

void led_indicate_error(void)
{
    while (1) {
        led_delay_ms(100);
        led_on(LED1 | LED2);
        led_delay_ms(100);
        led_off(LED1 | LED2);
    }
}

void led_deinit(void)
{
    TIM_DeInit(TIM3);
}
