/*
 * remsdaq_uart.c
 *
 *  Created on: 22 Jul 2020
 *      Author: Nick Pelling
 */

#include "MIMXRT1062.h"		// for LPUART1/2/3/4/5/6/7/8
#include "fsl_lpuart.h"		// for NXP's low-level UART drivers

#include "remsdaq_uart.h"

/*
 * Map traditional Unix file descriptors onto physical UART base addresses
 */
static LPUART_Type * astLPUART[eUartIndex_MAX] =
{
	LPUART1,	// eUartIndex_STDIN
	LPUART1,	// eUartIndex_STDOUT
	LPUART1,	// eUartIndex_STDERR

	LPUART1,	// eUartIndex_UART1
	LPUART2,	// eUartIndex_UART2
	LPUART3,	// eUartIndex_UART3
	LPUART4,	// eUartIndex_UART4
	LPUART5,	// eUartIndex_UART5
	LPUART6,	// eUartIndex_UART6
	LPUART7,	// eUartIndex_UART7
	LPUART8,	// eUartIndex_UART8
};

/**
 * Initialise a Remsdaq UART (using NXP's fsl_lpuart.c driver)
 *
 * @param[in] eUartIndex Index of the UART to initialise
 * @param[in] uiSourceClock UART source clock (normally 80MHz)
 * @param[in] uiBaudRate Baud rate (e.g. 115200)
 *
 * @retval false Failed to initialise
 * @retval true Successfully initialised
 */
bool REMSDAQ_UART_Init(eUartIndex_t eUartIndex, uint32_t uiSourceClock, uint32_t uiBaudRate)
{
	lpuart_config_t stConfig;
	bool bRetVal = false;
	status_t eStatus;

	// If this is a valid UART index (i.e. eUartIndex_UART1..eUartIndex_UART8)
	if ((eUartIndex >= eUartIndex_UART1) && (eUartIndex <= eUartIndex_UART8))
	{
		// Get the default UART settings
		LPUART_GetDefaultConfig(&stConfig);

		// Set the requested baud rate
		stConfig.baudRate_Bps = uiBaudRate;

		// Enable transmit
		stConfig.enableTx = true;

		// Enable receive
		stConfig.enableRx = true;

		// Initialise the UART relative to a pre-known source clock
		eStatus = LPUART_Init(astLPUART[eUartIndex], &stConfig, uiSourceClock);

		// Only return true if UART was initialised successfully!
		if (eStatus == kStatus_Success)
		{
			bRetVal = true;
		}
	}

	return bRetVal;
}

/**
 * Implement newlib's weak _write() function to support printf()
 *
 * @param[in] fd	Unix file descriptor (e.g. stdin/stdout/stderr) or UART index
 * @param[in] buf	Base of buffer to write out to the UART
 * @param[in] count	Size of buffer to write out to the UART
 *
 * @retval -1		Call failed to execute
 * @return N		N bytes were written out
 */
int _write(int fd, const void *buf, size_t count)
{
	int iRetVal = -1;				// failure code
	eUartIndex_t eUartIndex = (eUartIndex_t)fd;
	LPUART_Type * pstLPUART;

	if (eUartIndex < eUartIndex_MAX)
	{
		pstLPUART = astLPUART[eUartIndex];
		LPUART_WriteBlocking(pstLPUART, (const uint8_t *) buf, count);
		iRetVal = count;
	}

	return iRetVal;
}

/**
 * Implement newlib's weak _read() function to support scanf()
 *
 * @param[in] fd	Unix file descriptor (e.g. stdin/stdout/stderr) or UART index
 * @param[in] count	Maximum number of bytes to hold bytes read in from the UART
 * @param[out] buf	Base of buffer to read bytes into from the UART
 *
 * @retval -1		Call failed to execute
 * @return N		N bytes were successfully read in (0 is a valid number)
 */
int _read(int fd, void *buf, size_t count)
{
	int iRetVal = -1;				// default to failure return code
	eUartIndex_t eUartIndex = (eUartIndex_t)fd;
	uint8_t * pu8Buf = (uint8_t *) buf;
	LPUART_Type * pstLPUART;
	size_t i;

	if (eUartIndex < eUartIndex_MAX)
	{
		pstLPUART = astLPUART[eUartIndex];

		for (i = 0; i < count; i++)
		{
			if ((kLPUART_RxDataRegFullFlag & LPUART_GetStatusFlags(pstLPUART)) == 0U)
				break;
			pu8Buf[i] = (uint8_t) LPUART_ReadByte(pstLPUART);
		}
		iRetVal = i;	// return number of bytes received
	}

	return iRetVal;
}
