#include "uart_dev.h"
#include <stdarg.h>
#include <string.h>
#include <stdio.h>

device_handle g_gw485_uart2_handle;
device_handle g_bat485_uart3_handle;
device_handle g_debug_uart4_handle;

static uint8_t Debug_in_buff[200];
static uint8_t Gw485_in_buff[200];
static uint8_t Bat485_in_buff[200];

uint8_t rx_gw485_buf[1];
uint8_t rx_bat485_buf[1];

static uint8_t debug_out_buff[100];

/**
  * @brief  串口信息初始化,串口号及波特率.
  * @param  uart_index    对应的硬件串口号
  * @param  uart_baudrate 波特率
  */
uart_device_info uart_devices[]={
  [0] = {
      .init          = 0,
      .uart_index    = GW485_UART_INDEX,
      .uart_baudrate = 115200,
  },
  [1] = {
      .init          = 0,
      .uart_index    = BAT485_UART_INDEX,
      .uart_baudrate = 115200,
  },
  [2] = {
      .init          = 0,
      .uart_index    = DEBUG_UART_INDEX,
      .uart_baudrate = 115200,
  },
};

static device_handle uart_dev_init(uartIndex_e uart_index, uint8_t *buff, int buff_size);
static void uart_init(uartIndex_e uart_index, uint32_t baud);
static u_int8_t uart_putchar(device_handle device, char ch);


/**
  * @brief  初始化串口设备.
  * @param  uart_index 初始化串口号
  * @param  buff       串口循环buff地址
  * @param  buff_size  串口循环buff对应大小
  * @retval 串口句柄
  */
device_handle uart_dev_init(uartIndex_e uart_index, uint8_t *buff, int buff_size)
{
    int i = 0;
    for (; i < ELEMENT_OF(uart_devices); i++) {
        if (uart_devices[i].uart_index == uart_index) {
            if (!uart_devices[i].init) { 
                InitRingQueue(&uart_devices[i].uart_ring_queue, buff, buff_size); 
                uart_init(uart_index, uart_devices[i].uart_baudrate);  
                
                uart_devices[i].init = 1;
            }
            return (device_handle)(&uart_devices[i]);
        }
    }
    return 0;
}

/**
  * @brief  串口硬件初始化.
  * @param  uart_index 串口号
  * @param  baud 波特率
  * @retval None
  */
void uart_init(uartIndex_e uart_index, uint32_t baud)
{      
    if (uart_index == GW485_UART_INDEX) {
        HD_GW485_Init(baud);
    } else if (uart_index == BAT485_UART_INDEX) {
        HD_BAT485_Init(baud);
    } else if (uart_index == DEBUG_UART_INDEX) {
        HD_DEBUG_Uart_Init(baud);
    }
}

/**
  * @brief  关闭串口
  * @param  uart_index 串口号
  * @retval None
  */
void uart_close(uartIndex_e uart_index)
{      
    if(uart_index == GW485_UART_INDEX){
       HAL_UART_MspDeInit(&huart2);
    }else if(uart_index == BAT485_UART_INDEX){
       HAL_UART_MspDeInit(&huart3);
    }else if(uart_index == DEBUG_UART_INDEX){
       HAL_UART_MspDeInit(&huart4);
    }
}

/**
  * @brief  发送一个字节.
  * @param  uart_index 串口号
  * @param  ch 待发送字符
  * @retval 1 成功  0失败
  */
static u_int8_t uart_putchar(device_handle device, char ch)
{  
  
    int ret = HAL_ERROR;
    
    uart_device_info *device_info = (uart_device_info *)device; 
    if((!device) || (!device_info->init))
        return 0;
    
    if (device_info->uart_index == GW485_UART_INDEX) {
        ret = HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, 10); 
    } else if (device_info->uart_index == BAT485_UART_INDEX) {
        ret = HAL_UART_Transmit(&huart3, (uint8_t*)&ch, 1, 10);
    } else if (device_info->uart_index == DEBUG_UART_INDEX) {
        ret = HAL_UART_Transmit(&huart4, (uint8_t*)&ch, 1, 10);
    }
        
    if (ret == HAL_OK) {
        return 1;
    } else {
        return 0;
    }
}

/**
  * @brief  发送字符串.
  * @param  uart_index 串口号
  * @param  str 待发送字符串地址
  * @retval None
  */
void uart_sendstr(device_handle device, char *str)
{    
    while ((*str) != (char )0u) {
        if (*str == ASCII_CHAR_LINE_FEED){
            uart_putchar(device, (ASCII_CHAR_CARRIAGE_RETURN));
            uart_putchar(device, ASCII_CHAR_LINE_FEED);
            str++;
        }else{
            uart_putchar(device, *str++);
        }
    }
}

/**
  * @brief  调试串口 .
  * @param  可变参
  * @retval Null
  */
void debug_printf(char *format, ...)
{  
    memset(debug_out_buff, 0, sizeof(debug_out_buff));
    va_list va_ptr;  
    va_start(va_ptr, format);
    vsprintf((char*)debug_out_buff, (char const *)format, va_ptr);
    va_end(va_ptr);

    uart_sendstr(g_debug_uart4_handle, (char*)debug_out_buff);
}

/**
  * @brief  初始化调试串口.
  * @retval None
  */
void Init_debug_uart(void)
{    
	g_debug_uart4_handle = uart_dev_init(DEBUG_UART_INDEX, Debug_in_buff, sizeof(Debug_in_buff));     
}

/**
  * @brief  初始化向下通信对电池pack串口.
  * @retval None
  */
void Init_BAT485_uart(uint32_t baud)
{
    uart_devices[1].uart_baudrate = baud;
	g_bat485_uart3_handle = uart_dev_init(BAT485_UART_INDEX, Bat485_in_buff, sizeof(Bat485_in_buff));     
}

/**
  * @brief  初始化向上对网关通信485串口.
  * @retval None
  */
void Init_GW485_uart(uint32_t baud)
{
    uart_devices[0].uart_baudrate = baud;
	g_gw485_uart2_handle = uart_dev_init(GW485_UART_INDEX, Gw485_in_buff, sizeof(Gw485_in_buff));     
}

/**
  * @brief  从串口设备循环buff读取一个数据.
  * @param  device 串口句柄
  * @retval 读取到的字符
  */
uint8_t uart_dev_in_char(device_handle device)
{
    uart_device_info *device_info = (uart_device_info *)device;
    char c = 0;

    if (uart_dev_char_present(device))
        OutRingQueue(&device_info->uart_ring_queue, (u_int8_t*)&c);
    return c;
}

/**
  * @brief  判断串口设备循环buff是否有数据.
  * @param  device 串口句柄
  * @retval 0 空   1有数据
  */
int uart_dev_char_present(device_handle device)
{
    uart_device_info *device_info = (uart_device_info *)device;

    if((!device) || (!device_info->init))
        return 0;

    return !RingQueueEmpty(&device_info->uart_ring_queue);
}

/**
  * @brief  串口多字节堵塞发送.
  * @param  device 串口句柄
  * @param  data 待发送数据
  * @param  len  待发送数据长度
  * @retval None
  */
void uart_dev_write(device_handle device, void *data, int len)
{
   for (int i = 0; i < len; i++) {
       uart_putchar(device, ((char *)data)[i]);
   }
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART2) {
        gw485_RxIt();
    }
    else if (huart->Instance == USART3) {
        bat485_RxIt();   
    }
}


void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART2) {
        gw485_TxIt();
    }
    else if (huart->Instance == USART3) {
        bat485_TxIt();   
    }
}




/**
  * @brief  开启向上对网关通信485串口的中断接收.
  * @retval None
  */
void start_gw485Rx_It(void)
{
    HAL_UART_Receive_IT(&huart2, rx_gw485_buf, 1);
}

/**
  * @brief  开启向下通信对电池pack串口的中断接收.
  * @retval None
  */
void start_bat485Rx_It(void)
{
    HAL_UART_Receive_IT(&huart3, rx_bat485_buf, 1);
}