#ifndef __USART_H__
#define __USART_H__

#include "types.h"
#include "base_addresses.h"
#include "register.h"

class USART
{
	public:

		void *operator new(size_t base_address) {
			return reinterpret_cast<void *> (base_address);
		}
		void Send(const char* string);
		void Send(char ch);
		char Receive(void);
		bool TransmitterEmpty(void);
		bool ReceiverNonEmpty(void);
		void EnableTransmitInterrupt(void);
		void DisableTransmitInterrupt(void);
		void EnableReceiveInterrupt(void);
		void DisableReceiveInterrupt(void);

	protected:

		void SetBaudRate(uint32_t clockRate, uint32_t baudRate);

		Register<uint32_t>	SR;         // USART Status register,		   Address offset: 0x00
		Register<uint32_t>	DR;         // USART Data register,     	   Address offset: 0x04
		Register<uint32_t>	BRR;        // USART Baud rate register,	   Address offset: 0x08
		Register<uint32_t>	CR1;        // USART Control register 1,       Address offset: 0x0C
		Register<uint32_t>	CR2;        // USART Control register 2,       Address offset: 0x10
		Register<uint32_t>	CR3;        // USART Control register 3,       Address offset: 0x14
		Register<uint32_t>	GTPR;       // USART Guard time and prescaler, Address offset: 0x18
};

class USART_1 : public USART
{
	public:
		enum {address = USART1_BASE };
		void *operator new(size_t) { return reinterpret_cast<void *> (address); }
};

class USART_2 : public USART
{
	public:
		enum { address = USART2_BASE };
};

class USART_3 : public USART
{
	public:
		enum {address = USART3_BASE };
		void *operator new(size_t) { return reinterpret_cast<void *> (address); }
		void Open(uint32_t baudRate);
		void Close(void);
		void Put(const char* str);
		void Write(char* str, uint32_t length);
		void Read(char* str, uint32_t length);
		char Get(void);
};

class UART_4 : public USART
{
	public:
		enum { address = UART4_BASE };
		void *operator new(size_t) { return reinterpret_cast<void *> (address); }
};

class UART_5 : public USART
{
	public:
		enum { address = UART5_BASE };
		void *operator new(size_t) { return reinterpret_cast<void *> (address); }
};

class USART_6 : public USART
{
	public:
		enum {address = USART6_BASE };
		void *operator new(size_t) { return reinterpret_cast<void *> (address); }
		void Open(uint32_t baudRate);
		void Close(void);
		void Put(const char* str);
		void Write(char* str, uint32_t length);
		void Read(char* str, uint32_t length);
		char Get(void);
		static void InterruptHandler(void);
};

#endif // __USART_H__
