#include "callback.h"
#include "variables.h"
#include "esp8266.h"
#include "gas_sensor.h"

typedef enum
{
    UART_RX_WAIT_HEAD = 0,
    UART_RX_WAIT_LEFT,
    UART_RX_WAIT_RIGHT,
    UART_RX_WAIT_TAIL
} UartRxState_t;

static osThreadId_t uart1TaskHandle = NULL;
static uint8_t rx1 = 0U;
static uint8_t rx2 = 0U;
static uint8_t rx3 = 0U;
static uint8_t rx4 = 0U;
static uint8_t frame[4] = {0U, 0U, 0U, 0U};
static UartRxState_t rx_state = UART_RX_WAIT_HEAD;

static uint8_t speed_level_is_valid(uint8_t level)
{
    return ((level >= 0x01U) && (level <= 0x04U)) ? 1U : 0U;
}

static void uart1_reset_parser(void)
{
    rx_state = UART_RX_WAIT_HEAD;
}

static void uart1_commit_frame(void)
{
    receive[0] = frame[0];
    receive[1] = frame[1];
    receive[2] = frame[2];
    receive[3] = frame[3];

    UART1[0] = frame[1];
    UART1[1] = frame[2];
    motor_ctrl_buffer[0] = frame[1];
    motor_ctrl_buffer[1] = frame[2];

    uart_frame_valid = 1U;
    uart_frame_ok_count++;

    if (uart1TaskHandle != NULL)
    {
        (void)osThreadFlagsSet(uart1TaskHandle, 0x01U);
    }
}

void UART1_RegisterTaskHandle(osThreadId_t tid)
{
    uart1TaskHandle = tid;
}

void UART1_StartRxIT(void)
{
    uart1_reset_parser();
    (void)HAL_UART_Receive_IT(&huart1, &rx1, 1U);
}

void UART2_StartRxIT(void)
{
    (void)HAL_UART_Receive_IT(&huart2, &rx2, 1U);
}

void UART3_StartRxIT(void)
{
    (void)HAL_UART_Receive_IT(&huart3, &rx3, 1U);
}

void UART4_StartRxIT(void)
{
    (void)HAL_UART_Receive_IT(&huart4, &rx4, 1U);
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART1)
    {
        const uint8_t b = rx1;

        switch (rx_state)
        {
            case UART_RX_WAIT_HEAD:
                if (b == 0x0FU)
                {
                    frame[0] = b;
                    rx_state = UART_RX_WAIT_LEFT;
                }
                break;

            case UART_RX_WAIT_LEFT:
                if (b == 0x0FU)
                {
                    frame[0] = b;
                }
                else
                {
                    frame[1] = b;
                    rx_state = UART_RX_WAIT_RIGHT;
                }
                break;

            case UART_RX_WAIT_RIGHT:
                if (b == 0x0FU)
                {
                    frame[0] = b;
                    rx_state = UART_RX_WAIT_LEFT;
                }
                else
                {
                    frame[2] = b;
                    rx_state = UART_RX_WAIT_TAIL;
                }
                break;

            case UART_RX_WAIT_TAIL:
                if ((b == 0xF0U) && speed_level_is_valid(frame[1]) && speed_level_is_valid(frame[2]))
                {
                    frame[3] = b;
                    uart1_commit_frame();
                }
                else
                {
                    uart_frame_valid = 0U;
                    uart_frame_err_count++;

                    if (b == 0x0FU)
                    {
                        frame[0] = b;
                        rx_state = UART_RX_WAIT_LEFT;
                        (void)HAL_UART_Receive_IT(&huart1, &rx1, 1U);
                        return;
                    }
                }
                uart1_reset_parser();
                break;

            default:
                uart1_reset_parser();
                break;
        }

        (void)HAL_UART_Receive_IT(&huart1, &rx1, 1U);
        return;
    }

    if (huart->Instance == USART2)
    {
        GasSensor_RxByteIRQ(&huart2, rx2);
        (void)HAL_UART_Receive_IT(&huart2, &rx2, 1U);
        return;
    }

    if (huart->Instance == USART3)
    {
        GasSensor_RxByteIRQ(&huart3, rx3);
        (void)HAL_UART_Receive_IT(&huart3, &rx3, 1U);
        return;
    }

    if (huart->Instance == UART4)
    {
        ESP8266_RxByteIRQ(rx4);
        (void)HAL_UART_Receive_IT(&huart4, &rx4, 1U);
    }
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART1)
    {
        uart_frame_valid = 0U;
        uart1_reset_parser();
        (void)HAL_UART_Receive_IT(&huart1, &rx1, 1U);
        return;
    }

    if (huart->Instance == USART2)
    {
        GasSensor_RxErrorIRQ(&huart2);
        (void)HAL_UART_Receive_IT(&huart2, &rx2, 1U);
        return;
    }

    if (huart->Instance == USART3)
    {
        GasSensor_RxErrorIRQ(&huart3);
        (void)HAL_UART_Receive_IT(&huart3, &rx3, 1U);
        return;
    }

    if (huart->Instance == UART4)
    {
        ESP8266_RxErrorIRQ();
        (void)HAL_UART_Receive_IT(&huart4, &rx4, 1U);
    }
}
