#include "usart.h"
#include "rcc.h"
#include "pin_names.h"
#include "pin.h"
#include "ringbuffer.h"
#include "nvic.h"
#include "serial_port.h"

// Status Register Definitions
enum {
	SR_CTS 				= (1 << 9),		// CTS Toggled
	SR_LBD 				= (1 << 8),		// LIN Break Detected
	SR_TXE				= (1 << 7),		// Transmit Data Register Empty
	SR_TC				= (1 << 6),		// Transmission Complete
	SR_RXNE				= (1 << 5), 	// Receive Data Register Not Empty
	SR_IDLE				= (1 << 4),		// IDLE line detected
	SR_ORE				= (1 << 3),		// Overrun Error
	SR_NF				= (1 << 2),		// Noise Detected
	SR_FE				= (1 << 1),		// Framing Error
	SR_PE				= (1 << 0)		// Parity Error
};

// Data Register Definitions
enum {
	DR_START			= 0,
	DR_END				= 7
};

// Baud Rate Register Register
enum {
	BRR_FRACTION_START	=  0,
	BRR_FRACTION_END	=  3,
	BRR_INTEGER_START	=  4,
	BRR_INTEGER_END		= 15
};

// Control Register 1 Definitions
enum {
	CR1_OVER8			= (1 << 15), 	// Oversampling (0=16X, 1=8X)
	CR1_UE				= (1 << 13),	// USART Enabled, when UE=1
	CR1_M				= (1 << 12),	// Word Length (0=8 Data Bits, 1=9 Data Bits)
	CR1_WAKE			= (1 << 11),	// Wakeup (0=Line IDLE, 1=Address Mark)
	CR1_PCE				= (1 << 10),	// Parity Control Enable
	CR1_PS				= (1 <<  9),	// Parity Selection
	CR1_PEIE			= (1 <<  8),	// PE Interrupt Enable
	CR1_TXEIE			= (1 <<  7),	// TXE Interrupt Enable
	CR1_TCIE			= (1 <<  6),	// TC Interrupt Enable
	CR1_RXNEIE			= (1 <<  5),	// RXNE interrupt Enable
	CR1_IDLEIE			= (1 <<  4),	// IDLE Interrupt Enable
	CR1_TE				= (1 <<  3),	// Transmitter Enable
	CR1_RE				= (1 <<  2),	// Receiver Enable
	CR1_RWU				= (1 <<  1),	// Receiver Wakeup
	CR1_SBK				= (1 <<  0)		// Send Break
};

// Control Register 2 Definitions
enum {
	CR2_LINEN			= (1 << 14),	// LIN Mode Enable
	CR2_STOP			= (3 << 12),	// Stop Bits (00=1, 01=0.5, 10=2, 11=1.5)
	CR2_CLKEN			= (1 << 11),	// Produce a clock on the SCLK pin(when 1)
	CR2_CPOL			= (1 << 10),	// Clock Polarity
	CR2_CPHA			= (1 <<  9),	// Clock Phase
	CR2_LBCL			= (1 <<  8),	// Last Bit Clock Pulse
	CR2_LBDIE			= (1 <<  6),	// LIN Break Detection Interrupt Enable
	CR2_LBDL			= (1 <<  5)		// LIN Break Detection Length
};

enum {
	CR2_ADD_START		= 0,
	CR2_ADD_END			= 3
};

// Control Register 3 Definitions
enum {
	CR3_ONEBIT			= (1 <<	11),	// Wakeup (0=Line IDLE, 1=Address Mark)
	CR3_CTSIE			= (1 << 10),	// CTS Toggled Interrupt Enable
	CR3_CTSE			= (1 <<  9),	// Enable CTS Output
	CR3_RTSE			= (1 <<  8),	// RTS Enable
	CR3_DMAT 			= (1 <<  7),	// Transmitter DMA enable
	CR3_DMAR			= (1 <<  6),	// Receiver DMA Enable
	CR3_SCEN			= (1 <<  5),	// Smartcard Mode Enable
	CR3_NACK			= (1 <<  4),	// Smartcard NACK Enable
	CR3_HDSEL			= (1 <<  3),	// Transmitter Enable
	CR3_IRLP			= (1 <<  2),	// IRDA Low Power
	CR3_IREN			= (1 <<  1),	// IRDA Mode Enable
	CR3_EIE				= (1 <<  0)		// Error Interrupt Enable
};

enum {
	GTPR_PSC_START		=  0,
	GTPR_PSC_END		=  7,
	GTPR_GT_START		=  8,
	GTPT_GT_END			= 15
};

enum { FIFO_Depth = 128 };
RingBuffer<char, FIFO_Depth>	_rxFIFO[8];
RingBuffer<char, FIFO_Depth>	_txFIFO[8];


void USART::Send(char ch)
{
	DR = ch;
	// DR = '1';
}

char USART::Receive(void)
{
	char foo = DR & 0xFF;
	return foo;
}

bool USART::TransmitterEmpty(void)
{
	return SR.MaskTest(SR_TXE);
}

bool USART::ReceiverNonEmpty(void)
{
	return SR.MaskTest(SR_RXNE);
}

void USART::EnableTransmitInterrupt(void)
{
	CR1.MaskSet(CR1_TXEIE);
}

void USART::DisableTransmitInterrupt(void)
{
	CR1.MaskClear(CR1_TXEIE);
}

void USART::EnableReceiveInterrupt(void)
{
	CR1.MaskSet(CR1_RXNEIE);
}

void USART::DisableReceiveInterrupt(void)
{
	CR1.MaskClear(CR1_RXNEIE);
}

void USART::SetBaudRate(uint32_t clockRate, uint32_t baudRate)
{
	uint32_t divider;
	uint32_t integer;
	uint32_t fraction;

	if (CR1.MaskTest(CR1_OVER8) == true) {
		divider = (25 * clockRate) / (2 * baudRate);
	} else {
		divider = (25 * clockRate) / (4 * baudRate);
	}
	integer = divider / 100;
	BRR.InsertBits(BRR_INTEGER_END, BRR_INTEGER_START, integer);
	fraction = divider - (100 * integer);
	if (CR1.MaskTest(CR1_OVER8) == true) {
		fraction = (((fraction *  8) + 50) / 100);
	} else {
		fraction = (((fraction * 16) + 50) / 100);
	}
	BRR.InsertBits(BRR_FRACTION_END, BRR_FRACTION_START, fraction);
}

void USART::Send(const char* string)
{
	int i = 0;
	// loop through until reach string's zero terminator
	while (string[i] != 0) {
		Send(string[i]); // print each character
		i++;
	}
}

void USART_1::Open(uint32_t baudRate)
{
	RCC&    	rcc(*new RCC);
	uint32_t	SYS_Clock;
	uint32_t	AHB_Clock;
	uint32_t	APB1_Clock;
	uint32_t	APB2_Clock;

	AlternateFunction<PA_9> usart_1_tx(GPIO::USART1_USART2_USART3_I2SEXT);
	AlternateFunction<PA_10> usart_1_rx(GPIO::USART1_USART2_USART3_I2SEXT);

	// USART_1 is an APB 2 peripheral
	rcc.GetClocks(SYS_Clock, AHB_Clock, APB1_Clock, APB2_Clock);
	rcc.EnableClocks(USART1_EN, ASSERT);
	rcc.ResetPeripherals(USART1_RST, ASSERT);
	rcc.ResetPeripherals(USART1_RST, NEGATE);
	SetBaudRate(APB2_Clock, baudRate);
	CR1.MaskSet(CR1_UE | CR1_TE | CR1_RE);
	// nvic.EnableIRQ(NVIC::USART1_IRQn);
	// EnableReceiveInterrupt();
}

void USART_1::Close(void)
{
	RCC&    rcc(*new RCC);
	NVIC&	nvic(*new NVIC);
	DisableReceiveInterrupt();
	nvic.EnableIRQ(NVIC::USART1_IRQn);
	CR1.MaskClear(CR1_UE | CR1_TE | CR1_RE);
	rcc.EnableClocks(USART1_EN, NEGATE);
}

#if 0
void USART_1::Put(const char* str)
{
	while (*str) {
		while (!TransmitterEmpty()) ;
		Send(*str++);
	};
}

void USART_1::Write(char* str, uint32_t length)
{
	for (uint32_t i; i < length; i++) {
		while (!TransmitterEmpty()) ;
		Send(*str++);
	}
}

char USART_1::Get(void){
	while (!ReceiverNonEmpty()) ;
	return Receive();
}

void USART_1::Read(char* str, uint32_t length)
{
	for (uint32_t i; i < length; i++) {
		*str++ = Get();
	}
}
#endif

void USART_3::Open(uint32_t baudRate)
{
	RCC&    	rcc(*new RCC);
	// NVIC&		nvic(*new NVIC);
	uint32_t	SYS_Clock;
	uint32_t	AHB_Clock;
	uint32_t	APB1_Clock;
	uint32_t	APB2_Clock;

	AlternateFunction<PD_8> usart_3_tx(GPIO::USART1_USART2_USART3_I2SEXT);
	AlternateFunction<PD_9> usart_3_rx(GPIO::USART1_USART2_USART3_I2SEXT);
	// USART_3 is an APB 1 peripheral
	rcc.GetClocks(SYS_Clock, AHB_Clock, APB1_Clock, APB2_Clock);
	rcc.EnableClocks(USART3_EN, ASSERT);
	rcc.ResetPeripherals(USART3_RST, ASSERT);
	rcc.ResetPeripherals(USART3_RST, NEGATE);
	SetBaudRate(APB1_Clock, baudRate);
	CR1.MaskSet(CR1_UE | CR1_TE | CR1_RE);
	// nvic.EnableIRQ(NVIC::USART3_IRQn);
	// EnableReceiveInterrupt();
}

void USART_3::Close(void)
{
	RCC&    rcc(*new RCC);
	NVIC&	nvic(*new NVIC);
	DisableReceiveInterrupt();
	nvic.EnableIRQ(NVIC::USART3_IRQn);
	CR1.MaskClear(CR1_UE | CR1_TE | CR1_RE);
	rcc.EnableClocks(USART3_EN, NEGATE);
}


#if 0
void USART_3::Put(const char* str)
{
	while (*str) {
		while (!TransmitterEmpty()) ;
		Send(*str++);
	};
}

void USART_3::Write(char* str, uint32_t length)
{
	for (uint32_t i; i < length; i++) {
		while (!TransmitterEmpty()) ;
		Send(*str++);
	}
}

char USART_3::Get(void){
	while (!ReceiverNonEmpty()) ;
	return Receive();
}

void USART_3::Read(char* str, uint32_t length)
{
	for (uint32_t i; i < length; i++) {
		*str++ = Get();
	}
}
#endif

void USART_6::Open(uint32_t baudRate)
{
	RCC&    	rcc(*new RCC);
	NVIC&		nvic(*new NVIC);
	uint32_t	SYS_Clock;
	uint32_t	AHB_Clock;
	uint32_t	APB1_Clock;
	uint32_t	APB2_Clock;

	// Connect peripheral signals to pins
	AlternateFunction<PC_6> usart_6_tx(GPIO::UART4_UART5_USART6);
	AlternateFunction<PG_9> usart_6_rx(GPIO::UART4_UART5_USART6);

	// USART_6 is an APB 2 peripheral
	rcc.GetClocks(SYS_Clock, AHB_Clock, APB1_Clock, APB2_Clock);
	rcc.EnableClocks(USART6_EN, ASSERT);
	rcc.ResetPeripherals(USART6_RST, ASSERT);
	rcc.ResetPeripherals(USART6_RST, NEGATE);
	SetBaudRate(APB2_Clock, baudRate);
	CR1.MaskSet(CR1_UE | CR1_TE | CR1_RE);
#if 0
	nvic.EnableIRQ(NVIC::USART6_IRQn);
	EnableReceiveInterrupt();
#endif
}

void USART_6::Close(void)
{
	RCC&    rcc(*new RCC);
	NVIC&	nvic(*new NVIC);
	DisableReceiveInterrupt();
	nvic.EnableIRQ(NVIC::USART6_IRQn);
	CR1.MaskClear(CR1_UE | CR1_TE | CR1_RE);
	rcc.EnableClocks(USART6_EN, NEGATE);
}

#if 0

void USART_6::Put(const char* str)
{
	while (*str) {
		while (!TransmitterEmpty()) ;
		Send(*str++);
	};

#if 0
	while (*str) {
		_txFIFO[5].Push(*str++);
	}
	EnableTransmitInterrupt();
#endif
}

void USART_6::Write(char* str, uint32_t length)
{
	for (uint32_t i; i < length; i++) {
		while (!TransmitterEmpty()) ;
		Send(*str++);
	}
#if 0
	for (uint32_t i; i < length; i++) {
		_txFIFO[5].Push(*str++);
	}
	EnableTransmitInterrupt();
#endif
}

char USART_6::Get(void)
{
	while (!ReceiverNonEmpty()) ;
	return Receive();
#if 0
	while (_rxFIFO[5].Empty()) ;
	char ch = _rxFIFO[5].Front();
	_rxFIFO[5].Pop();
	return ch;
#endif
}

void USART_6::Read(char* str, uint32_t length)
{
	for (uint32_t i; i < length; i++) {
		*str++ = Get();
	}
}
#endif
void USART_6::InterruptHandler()
{
	USART& device = *reinterpret_cast<USART_6*> (USART6_BASE);

	if (device.ReceiverNonEmpty()) {
		// Received a new character
		if (!_rxFIFO[5].Full()) {
			_rxFIFO[5].Push(device.Receive());
		} else {
			for (;;) ;
			// TO DO:  Horrible System Crash
			// UART Overrun
		}
	} else if (device.TransmitterEmpty()){
		// Finished sending a character
		if (!_txFIFO[5].Empty()) {
			// More characters are waiting to be sent
			device.Send(_txFIFO[5].Front());
			_txFIFO[5].Pop();
		} else {
			device.DisableTransmitInterrupt();
		}
	} else {
		// TO DO:  Deal with this stuff later....
		for (;;) ;
	}
}


