/** 
 * \file uart.h
 * \brief uart header file
 * \details File contains structures, enumerations and functions declarations for UART module
 *
 * \author Juraj Golej
 * \version 1.0
 */


#ifndef UART_H_
#define UART_H_

#include "sam.h"
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <clocks/clocks/clocks.h>
#include <utils/circbuffer/circbuff.h>
#include <utils/retcode/retcode.h>
#include <utils/assert/arm_assert.h>

/** 
 * \brief Baud rates enumeration
 */
enum UART_BAUD {
	UART_BAUD_1200 = 1200,		///< Baud rate 1200
	UART_BAUD_2400 = 2400,		///< Baud rate 2400
	UART_BAUD_4800 = 4800,		///< Baud rate 4800
	UART_BAUD_9600 = 9600,		///< Baud rate 9600
	UART_BAUD_19200 = 19200,	///< Baud rate 19200
	UART_BAUD_38400 = 38400,	///< Baud rate 38400
	UART_BAUD_57600 = 57600,	///< Baud rate 57600
	UART_BAUD_115200 = 115200,	///< Baud rate 115200
}; /* enum UART_BAUD */

/** 
 * \brief Parity type enumeration
 */
enum UART_PARITY {
	UART_PARITY_EVEN,		///< Even parity
	UART_PARITY_ODD,		///< Odd parity
	UART_PARITY_SPACE,		///< Space parity (forced to 0)
	UART_PARITY_MARK,		///< Space parity (forced to 1)
	UART_PARITY_NONE,		///< No parity
}; /* enum UART_PARITY */

/** 
 * \brief UART test modes
 */
enum UART_TEST {
	UART_TEST_NORMAL,		///< Normal mode 
	UART_TEST_AUTOMATIC,	///< Automatic echo (bit-by-bit retransmission, transmitted not connected to TXD pin)
	UART_TEST_LOCAL_LOOP,	///< Local loopback (transmitter directly connected to receiver, RXD and TXD pins unconnected)
	UART_TEST_REMOTE_LOOP,	///< Remote loopback (RXD pin connected directly to RXD pin, transmitter and receiver disconnected)
}; /* enum UART_TEST */

struct UART_module;

/**
 * \brief UART one byte received user defined function (callback)
 * 
 * \param[in] module Pointer on UART module
 */
typedef void (*uart_rx_byte_cb)(struct UART_module* const module);

/**
 * \brief UART line received user defined function (callback)
 * 
 * \param[in] module Pointer on UART module
 */
typedef void (*uart_rx_line_cb)(struct UART_module* const module);

/**
 * \brief UART data transferred user defined function (callback)
 * 
 * \param[in] module Pointer on UART module
 */
typedef void (*uart_tx_cb)(struct UART_module* const module);

/** 
 * \brief UART module structure
 */
struct UART_module {
	uint8_t ID;							///< Register status (if >0, module is initialized)
	Uart* periphery;					///< Pointer on UART periphery

	volatile struct circbuff read;		///< Circular buffer for received data
	const uint8_t *writeBuff;			///< Pointer on data array for transfer
	volatile uint16_t writeLen;			///< Number of bytes to be transferred
	volatile uint16_t writeIndex;		///< Actual index in write buffer array

	uart_rx_byte_cb callback_rxByte;	///< Pointer on byte received callback function
	uart_rx_line_cb callback_rxLine;	///< Pointer on line received callback function
	volatile uart_tx_cb callback_tx;	///< Pointer on all data transferred callback function
}; /* struct UART_module */

/**
 * \brief Get UART peripheral hardware ID
 * 
 * \param[in] periphery Pointer on UART periphery
 * 
 * \return \b int16_t Peripheral ID or -1, if can't find this \c periphery
 */
static inline int16_t UART_getPeripheralHWID(Uart* periphery)
{
	switch((uint32_t)periphery) {
		case (uint32_t)UART0:
			return ID_UART0;
		case (uint32_t)UART1:
			return ID_UART1;
		case (uint32_t)UART2:
			return ID_UART2;
		case (uint32_t)UART3:
			return ID_UART3;
		case (uint32_t)UART4:
			return ID_UART4;
		default:
			return -1;
	}
}

/**
 * \brief Initialize UART module
 * 
 * \param[in] module Pointer on UART module
 * \param[in] periphery Pointer on UART periphery
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone everything OK
 * \retval EDenied Periphery is already in use
 * \retval EInvalidParameter Invalid \c periphery parameter
 *
 * \note Call this function before anything else
 */
enum retCode UART_init(struct UART_module* const module, Uart* periphery);

/**
 * \brief Deinitialize UART module
 * 
 * \param[in] module Pointer on UART module
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone everything OK
 * \retval EDenied Module isn't initialized
 */
enum retCode UART_deinit(struct UART_module* const module);

/**
 * \brief Configure and enable receiver
 * 
 * \param[in] module Pointer on UART module
 * \param[in] buffer Pointer on bytes array, used in internal circular buffer
 * \param[in] buffSize \c buffer size
 * \param[in] byte_cb Pointer on callback function (can be \c NULL)
 * \param[in] line_cb Pointer on callback function (can be \c NULL)
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone everything OK
 * \retval EDenied Module isn't initialized
 * \retval EInvalidParameter invalid \c buffer or \c buffSize parameter
 */
enum retCode UART_enable_receiver(struct UART_module* const module, uint8_t* buffer, const uint16_t buffSize, uart_rx_byte_cb byte_cb, uart_rx_line_cb line_cb);

/**
 * \brief Forced transfer termination
 * 
 * \param[in] module Pointer on UART module
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone everything OK
 * \retval EDenied Module isn't initialized
 */
enum retCode UART_stop_transmit(struct UART_module* const module);

/**
 * \brief Disable receiver
 * 
 * \param[in] module Pointer on UART module
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone everything OK
 * \retval EDenied Module isn't initialized
 */
enum retCode UART_disable_receiver(struct UART_module* const module);

/**
 * \brief Send data through transmitter
 * 
 * \param[in] module Pointer on UART module
 * \param[in] data Pointer on \c data array for transmit
 * \param[in] len Number of bytes in \c data array
 * \param[in] cb Callback function (called when all data bytes are transmitted)
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone everything OK
 * \retval EDenied Module isn't initialized
 * \retval EBusy The transfer of data before has not yet been completed
 */
enum retCode UART_write(struct UART_module* const module, const uint8_t* const data, const uint16_t len, uart_tx_cb cb);

/**
 * \brief Read all received data (If there is any)
 * 
 * \param[in] module Pointer on UART module
 * \param[out] data Pointer on \c data array for reading
 * \param[in] maxlen Maximum bytes than can be read
 * 
 * \return \b uint16_t Number of read bytes
 */
uint16_t UART_read(struct UART_module* const module, uint8_t* const data, const uint16_t maxlen);

/**
 * \brief Read one line ended with '\n' or '\r' incl
 * 
 * \param[in] module Pointer on UART module
 * \param[out] data Pointer on \c data array for reading
 * \param[in] maxlen Maximum bytes than can be read
 * 
 * \return \b uint16_t Number of read bytes incl end line character
 */
uint16_t UART_readLine(struct UART_module* const module, uint8_t* const data, const uint16_t maxlen);

/**
 * \brief Set baud rate
 * 
 * \param[in] module Pointer on UART module
 * \param[in] baud Baud rate
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone everything OK
 * \retval EDenied Module isn't initialized
 * \retval EInvalidParameter Can't created this baud rate for actual peripheral frequency
 */
enum retCode UART_setBaudRate(struct UART_module* const module, const enum UART_BAUD baud);

/**
 * \brief Set parity
 * 
 * \param[in] module Pointer on UART module
 * \param[in] parity Parity
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone everything OK
 * \retval EDenied Module isn't initialized
 */
enum retCode UART_setParity(struct UART_module* const module, const enum UART_PARITY parity);

/**
 * \brief Set test mode
 * 
 * \param[in] module Pointer on UART module
 * \param[in] test Test mode
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone everything OK
 * \retval EDenied Module isn't initialized
 */
enum retCode UART_setTest(struct UART_module* const module, const enum UART_TEST test);

/**
 * \brief Enable/disable filter
 * 
 * \param[in] module Pointer on UART module
 * \param[in] filter \c true for enable, \c false for disable filter
 * 
 * \return \b enum \b retCode Return code value
 * \retval ENone everything OK
 * \retval EDenied Module isn't initialized
 *
 * \note UART filters the receive line using a three-sample filter (16x-bit clock) (2 over 3 majority)
 */
enum retCode UART_setFilter(struct UART_module* const module, const bool filter);

#endif /* UART_H_ */