#include "drv_usart.h"
#include "app_rs485_1.h"
#include "app_can.h"
#include "drv_can.h"

static u16 shark_uart_poll_ticks;
static u8 shark_uart_poll_index;

static void shark_uart_gpio_init(void)
{
	/* enable GPIO clock */
	rcu_periph_clock_enable(RCU_GPIOA);
	rcu_periph_clock_enable(RCU_AF);
	rcu_periph_clock_enable(RCU_USART0);
	rcu_periph_clock_enable(RCU_USART1);

	/* connect port to USARTx_Tx */
	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2 | GPIO_PIN_9);

	/* connect port to USARTx_Rx */
	gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_3 | GPIO_PIN_10);
}

static void shark_uart_irq_init(void)
{
	nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
	nvic_irq_enable(USART0_IRQn, 1, 0);
	nvic_irq_enable(USART1_IRQn, 1, 0);
}

static void shark_uart_dev_init(SUB_BMS_INFO *info)
{
	usart_deinit(info->uart);
	usart_baudrate_set(info->uart, USART_BAUND);
	usart_word_length_set(info->uart, USART_WL_8BIT);
	usart_stop_bit_set(info->uart, USART_STB_1BIT);
	usart_parity_config(info->uart, USART_PM_NONE);
	usart_hardware_flow_rts_config(info->uart, USART_RTS_DISABLE);
	usart_hardware_flow_cts_config(info->uart, USART_CTS_DISABLE);
	usart_receive_config(info->uart, USART_RECEIVE_ENABLE);
	usart_transmit_config(info->uart, USART_TRANSMIT_ENABLE);
	usart_interrupt_enable(info->uart, USART_INT_RBNE);
	usart_enable(info->uart);
}

static void shark_uart_isr(SUB_BMS_INFO *info)
{
	if (usart_flag_get(info->uart, USART_FLAG_RBNE) != RESET) {
		u8 value = usart_data_receive(info->uart);

		if (info->rx_length < sizeof(info->rx_buff)) {
			info->rx_buff[info->rx_length] = value;
			info->rx_length++;
			info->rx_busy = 5;
		} else {
			info->rx_busy = 0;
			info->rx_pending = shark_true;
		}
	}

	if (usart_flag_get(info->uart, USART_FLAG_TC) != RESET) {
		if (info->tx_index < info->tx_length) {
			usart_data_transmit(info->uart, info->tx_buff[info->tx_index]);
			info->tx_index++;
		} else {
			usart_interrupt_disable(info->uart, USART_INT_TC);
		}
	}
}

void shark_uart_init(void)
{
	shark_uart_gpio_init();
	shark_uart_dev_init(&sub_bms_info_1);
	shark_uart_dev_init(&sub_bms_info_2);
	shark_uart_irq_init();
}

u16 shark_uart_read(SUB_BMS_INFO *info, u8 *buff, u8 length)
{
	if (info->rx_length == 0) {
		return 0;
	}

	if (length > info->rx_length) {
		length = info->rx_length;
	}

	memcpy(buff, info->rx_buff, length);
	info->rx_pending = shark_false;
	info->rx_length = 0;

	return length;
}

void shark_uart_write(SUB_BMS_INFO *info, u16 size)
{
	info->tx_index = 0;
	info->tx_length = size;
	info->tx_busy = CONFIG_UART_TIMEOUT;
	usart_interrupt_enable(info->uart, USART_INT_TC);
}

shark_bool shark_uart_write2(SUB_BMS_INFO *info, const u8 *buff, u16 size)
{
	if (size > sizeof(info->tx_buff)) {
		return shark_false;
	}

	memcpy(info->tx_buff, buff, size);
	shark_uart_write(info, size);

	return shark_true;
}

int8_t Send_Data_RS485(uint8_t *data, uint16_t size)
{
	return shark_uart_write2(&sub_bms_info_1, data, size);
}

uint16_t Get_RS485_Data(uint8_t * dbuf, uint16_t dbuf_len)
{
	return shark_uart_read(&sub_bms_info_1, dbuf, dbuf_len);
}

static void shark_uart_disconnect(SUB_BMS_INFO *info)
{
	shark_battery_clear(info);
}

static void shark_uart_tick_raw(SUB_BMS_INFO *info)
{
	if (info->rx_busy > 0) {
		if (info->rx_busy > 1) {
			info->rx_busy--;
		} else {
			info->rx_busy = 0;
			info->rx_pending = shark_true;
		}
	}

	if (info->send_state == SHARK_SEND_PENDING) {
		if (info->tx_busy > 0) {
			info->tx_busy--;
		} else {
			info->send_state = SHARK_SEND_TIMEOUT;

			if (info->connected > 0) {
				if (info->connected > 1) {
					info->connected--;
					info->tx_pending = shark_true;
				} else {
					info->connected = 0;
					shark_uart_disconnect(info);
				}
			}
		}
	}

	if (info->update_ticks == 0 && info->connected) {
		info->update_mask = 0xFF;
	}

	info->update_ticks++;
}

void shark_uart_tick(void)
{
	if (shark_uart_poll_ticks < (CONFIG_UART_POLL_DELAY / 2)) {
		shark_uart_poll_ticks++;
	} else {
		shark_uart_poll_ticks = 0;
		shark_uart_poll_index++;

		if ((shark_uart_poll_index & 1) == 0) {
			sub_bms_info_1.tx_pending = shark_true;
		} else {
			sub_bms_info_2.tx_pending = shark_true;
		}
	}

	shark_uart_tick_raw(&sub_bms_info_1);
	shark_uart_tick_raw(&sub_bms_info_2);
}

void shark_uart_poll_raw(SUB_BMS_INFO *info)
{
	if (info->rx_pending) {
		info->rx_pending = shark_false;
		shark_battery_process(info, info->rx_buff, info->rx_length);
		info->rx_length = 0;
	}

	if (info->tx_pending) {
		info->tx_pending = shark_false;

		if (!shark_battery_switch_busy) {
			shark_battery_send_command(info);
		}
	}
}

void shark_uart_poll(void)
{
	shark_uart_poll_raw(&sub_bms_info_1);
	shark_uart_poll_raw(&sub_bms_info_2);
}

void shark_uart_poll_safe(void)
{
	fwdgt_counter_reload();
	Handle_Can_Data();
	shark_uart_poll();
	shark_can_tx_flush();
}

void USART0_IRQHandler(void)
{
	shark_uart_isr(&sub_bms_info_1);
}

void USART1_IRQHandler(void)
{
	shark_uart_isr(&sub_bms_info_2);
}
