/*
 * usart.c
 *
 *  Created on: Jun 23, 2023
 *      Author: true
 */


#include "hk32f030m.h"
#include "usart.h"

#include <string.h>


#define BAUDRATE			115200

#define USART_DEVICE		USART1

#define USART_TX_GPIO_CLK	RCC_AHBPeriph_GPIOD
#define USART_TX_PORT		GPIOD
#define USART_TX_PIN		1
#define USART_TX_PINSRC		GPIO_PinSource1

#define USART_RX_GPIO_CLK	RCC_AHBPeriph_GPIOB
#define USART_RX_PORT		GPIOB
#define USART_RX_PIN		4
#define USART_RX_PINSRC		GPIO_PinSource4



// inefficient, but we have time and space
#define RX_BUF_LEN		1040
uint8_t rxbuf[RX_BUF_LEN];
uint16_t rxptr = 0;
uint16_t rxlen = 0;



/**
 * @brief   Initializes USART peripheral at fixed baud rate.
 */
void comm_init()
{
	// enable GPIO clock
	// RCC_AHBPeriphClockCmd(USART_TX_GPIO_CLK | USART_RX_GPIO_CLK, ENABLE);

	// attach USART peripheral to pins
	// GPIO_PinAFConfig(USART_TX_PORT, USART_TX_PINSRC, GPIO_AF_1);
	// GPIO_PinAFConfig(USART_RX_PORT, USART_RX_PINSRC, GPIO_AF_1);
	GPIOB->AFR[0] = 0x00010000;
	GPIOD->AFR[0] = 0x00000010;

	/* these have been configured in user_io.c to save space
	USART_RX_PORT->MODER   &= ~(GPIO_MODER_MODER0     << 2 * USART_RX_PIN);
	USART_RX_PORT->MODER   |=  (GPIO_Mode_AF          << 2 * USART_RX_PIN);	// alt function

	USART_TX_PORT->MODER   &= ~(GPIO_MODER_MODER0     << 2 * USART_TX_PIN);
	USART_TX_PORT->OTYPER  &= ~(GPIO_OTYPER_OT_0      <<     USART_TX_PIN);	// push pull
	USART_TX_PORT->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEEDR0 << 2 * USART_TX_PIN);	// slow
	USART_TX_PORT->MODER   |=  (GPIO_Mode_AF          << 2 * USART_TX_PIN);	// alt function
	*/

	// enable USART clock
	// RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

	// configure USART peripheral manually
	// we do this as the library bloats flash space (division, verbose, ...)
	USART1->CR1 = 0;								// disable USART
	USART1->CR2 = 0;								// 1 stop bit
	USART1->CR3 = 0;
	USART1->CR1 = USART_Mode_Rx | USART_Mode_Tx;	// 8 bits, no parity, tx/rx enabled
	USART1->BRR = 0x45;								// 115200 baud rate @8MHz (per datasheet)

	// enable USART
	USART1->CR1 = USART_Mode_Rx | USART_Mode_Tx | USART_CR1_UE;
}

/**
 * @brief   Receives data from USART in a polling manner.
 * @param   *data: Array to save the received data.
 * @param   length:  Size of the data.
 * @return  status: Report about the success of the receiving.
 */
BL_comm_status comm_rx(uint8_t *data, uint16_t length)
{
	uint16_t i;
	uint16_t timeout;

	for (i = 0; i < length; i++) {
		timeout = COMM_TIMEOUT;
		while (!(USART1->ISR & USART_ISR_RXNE) && timeout) {
			timeout--;
		}

		if (timeout) {
			// we didn't time out and now there is new data waiting for us
			data[i] = USART1->RDR;
		} else {
			// no data returned in time
			return COMM_ERROR;
		}
	}

	return COMM_OK;
}

/**
 * @brief   Transmits a single char to UART.
 * @param   *data: The char.
 * @return  status: Report about the success of the transmission.
 */
BL_comm_status comm_tx_byte(uint8_t data)
{
	USART_SendData(USART1, data);

	while (!(USART1->ISR & USART_ISR_TXE));

	return COMM_OK;
}

/**
 * @brief   Transmits a null-terminated string over USART.
 * @param   *data: String array.
 * @return  status: Report about the success of the transmission.
 */
BL_comm_status comm_tx_str(char *data)
{
	uint8_t  i;
	uint16_t len = 0;

	len = strlen((const char *)data);

	for (i = 0; i < len; i++) {
		comm_tx_byte(data[i]);
	}

	while (!(USART1->ISR & USART_ISR_TC));

	return COMM_OK;
}

