/*
 * uartio.c
 *
 *  Created on: Jan 21, 2022
 *      Author: radioman
 */

#include "main.h"
#include "uartio.h"
#include <string.h>

static uint8_t uart_rx_buffer[UART_RX_BUF_SIZE];
static uint8_t uart_tx_buffer[UART_TX_BUF_SIZE];

static uint32_t tail;
static uint8_t tx_cplt = 1;
static UART_HandleTypeDef *uart_handle;

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart == uart_handle)
		tx_cplt = 1;
}

void UARTIO_Init(UART_HandleTypeDef *huart)
{
	uart_handle = huart;
	tail = 0;
	HAL_UART_Receive_DMA(uart_handle, uart_rx_buffer, UART_RX_BUF_SIZE);
}

uint32_t UARTIO_DataAvailable(void)
{
	uint32_t head = UART_RX_BUF_SIZE - uart_handle->hdmarx->Instance->CNDTR;

	if(head >= tail)
		return (head - tail);
	else
		return (UART_RX_BUF_SIZE - tail + head);
}

int UARTIO_Receive(uint8_t *buf, uint32_t len)
{
	//uint32_t dma_ptr = (UART_RX_BUF_SIZE - huart->hdmarx->Instance->CNDTR);
	uint32_t head = UART_RX_BUF_SIZE - uart_handle->hdmarx->Instance->CNDTR;
	if(tail == head)
		return (-1);

	if(tail > head)
	{
		uint32_t cap_avail = UART_RX_BUF_SIZE - tail + head;
		if((UART_RX_BUF_SIZE - tail) >= len)
		{
			memcpy(buf, &uart_rx_buffer[tail], len);
			tail = (tail + len) % UART_RX_BUF_SIZE;
		}
		else
		{
			if(len > cap_avail)
				len = cap_avail;
			uint32_t blk1_sz = UART_RX_BUF_SIZE - tail;
			memcpy(buf, &uart_rx_buffer[tail], blk1_sz);
			tail = 0;
			memcpy(&buf[blk1_sz], &uart_rx_buffer[tail], (len - blk1_sz));
			tail = (len - blk1_sz) % UART_RX_BUF_SIZE;
		}
	}
	else
	{
		if(len > (head - tail))
			len = head - tail;
		memcpy(buf, &uart_rx_buffer[tail], len);
		tail = (tail + len) % UART_RX_BUF_SIZE;
	}

	return (len);
}

int UARTIO_Transmit(uint8_t *buf, uint32_t len)
{
	if(!tx_cplt)
		return (-1);

	memcpy(uart_tx_buffer, buf, len);
	HAL_UART_Transmit_DMA(uart_handle, uart_tx_buffer, len);
	tx_cplt = 0;
	return len;
}
