#include "yc11xx_uart.h"

typedef struct 
{
	uint16_t Baudrate;
	uint16_t RxSadr;
	uint16_t RxEadr;
	uint16_t RxRptr;
	uint16_t TxSadr;
	uint16_t TxEadr;
	uint16_t TxWptr;
}UartxRegDef;

typedef struct
{
	UartxRegDef rbu;
	uint8_t cbu;
}UartxRegControlBackup;

#define UART_PER_NUM 2

UartxRegControlBackup regBeck[UART_PER_NUM];

uint8_t uartA_tx_buf[uart_DMA_buf_len]={0};
uint8_t uartA_rx_buf[uart_DMA_buf_len]={0};
uint8_t uartB_tx_buf[uart_DMA_buf_len]={0};
uint8_t uartB_rx_buf[uart_DMA_buf_len]={0};

void USART_Init(USART_TypeDef USARTx, USART_InitTypeDef* USART_InitStruct)
{	
	
	uint8_t CtrValue = 0;
	void *Ptr = NULL;
	uint16_t UartxCtrlAdr = 0;
	UartxRegDef *UartAdr = NULL;		
	HWRITE(CORE_UART_CLKSEL, 1);
	HWCOR(CORE_CLKOFF + 1, 0x80);

#define UARTC_BIT_ENABLE (1<<0)
#define BAUD_USE_SETTING (1<<7)

	/*check parameter*/
	_ASSERT(USART_InitStruct != NULL);
	_ASSERT(IS_USARTAB(USARTx));
	_ASSERT(IS_UARTE_BAUDRATE(USART_InitStruct->USART_BaudRate));
	_ASSERT(IS_USART_WORD_LENGTH(USART_InitStruct->USART_WordLength));
	_ASSERT(IS_USART_STOPBITS(USART_InitStruct->USART_StopBits));
	_ASSERT(IS_USART_PARITY(USART_InitStruct->USART_Parity));
	_ASSERT(IS_USART_MODE(USART_InitStruct->USART_Mode));
	_ASSERT(IS_USART_HARDWARE_FLOW_CONTROL(USART_InitStruct->USART_HardwareFlowControl));
	_ASSERT(IS_USART_TXLen(USART_InitStruct->USART_TXLen));
	_ASSERT(IS_USART_RXLen(USART_InitStruct->USART_RXLen));

	/*init baud backup*/
	regBeck[USARTx].rbu.Baudrate = USART_InitStruct->USART_BaudRate;
	if(USARTx ==UARTA)
	{
		/*init tx ring buffer backup*/
		Ptr=uartA_tx_buf;
		regBeck[USARTx].rbu.TxSadr = (uint32_t)Ptr;
		regBeck[USARTx].rbu.TxEadr = (uint32_t)Ptr + USART_InitStruct->USART_TXLen;

 	   /*init rx ring buffer backup*/
		Ptr = uartA_rx_buf;
		regBeck[USARTx].rbu.RxSadr = (uint32_t)Ptr;
		regBeck[USARTx].rbu.RxEadr = (uint32_t)Ptr + USART_InitStruct->USART_RXLen;
	}
	else
	{
		/*init tx ring buffer backup*/
		Ptr = uartB_tx_buf;
		regBeck[USARTx].rbu.TxSadr = (uint32_t)Ptr;
		regBeck[USARTx].rbu.TxEadr = (uint32_t)Ptr + USART_InitStruct->USART_TXLen;

   		 /*init rx ring buffer backup*/
		Ptr = uartB_rx_buf;
		regBeck[USARTx].rbu.RxSadr = (uint32_t)Ptr;
		regBeck[USARTx].rbu.RxEadr = (uint32_t)Ptr + USART_InitStruct->USART_RXLen;		

	}
	CtrValue =  USART_InitStruct->USART_Mode | USART_InitStruct->USART_HardwareFlowControl |\
			  USART_InitStruct->USART_Parity |USART_InitStruct->USART_StopBits| \
			  USART_InitStruct->USART_WordLength|BAUD_USE_SETTING|UARTC_BIT_ENABLE;
	
	regBeck[USARTx].cbu = CtrValue;

	if(USARTx == UARTA) {
		UartxCtrlAdr = CORE_UART_CTRL;
		UartAdr = (UartxRegDef *)(reg_map(CORE_UART_BAUD));
	}
	else {
		UartxCtrlAdr = CORE_UARTB_CTRL;
		UartAdr = (UartxRegDef *)(reg_map(CORE_UARTB_BAUD));
	}

	HWCOR(UartxCtrlAdr, 1);

	/*init all reg by backup*/
	HW_REG_16BIT(((uint32_t)(&UartAdr->Baudrate)), regBeck[USARTx].rbu.Baudrate);
	HW_REG_16BIT(((uint32_t)(&UartAdr->TxSadr)), (uint32_t)regBeck[USARTx].rbu.TxSadr);
	HW_REG_16BIT(((uint32_t)(&UartAdr->TxEadr)), (uint32_t)regBeck[USARTx].rbu.TxEadr);
	HW_REG_16BIT(((uint32_t)(&UartAdr->TxWptr)), (uint32_t)regBeck[USARTx].rbu.TxSadr);
	HW_REG_16BIT(((uint32_t)(&UartAdr->RxSadr)), (uint32_t)regBeck[USARTx].rbu.RxSadr);
	HW_REG_16BIT(((uint32_t)(&UartAdr->RxEadr)), (uint32_t)regBeck[USARTx].rbu.RxEadr);
	HW_REG_16BIT(((uint32_t)(&UartAdr->RxRptr)), (uint32_t)regBeck[USARTx].rbu.RxSadr);
	HWOR(UartxCtrlAdr, regBeck[USARTx].cbu);

}


void USART_DeInit(USART_TypeDef USARTx)
{
	_ASSERT(IS_USARTAB(USARTx));
	if(USARTx == UARTA) {
		HWOR(reg_map(CORE_UART_CTRL), (1<<0));
		HWOR(reg_map(CORE_UART_CTRL), (0<<0));
	}else {

		HWOR(reg_map(CORE_UARTB_CTRL), (1<<0));
		HWOR(reg_map(CORE_UARTB_CTRL), (0<<0));
	}
}

// void UartxInit(USART_TypeDef UARTx)
// {
// 	USART_InitTypeDef USART_InitStruct ;
	
// 	USART_InitStruct.USART_BaudRate = UARTE_BAUDRATE_BAUDRATE_Baud115200;
// 	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
// 	USART_InitStruct.USART_WordLength = USART_WordLength_8b;	
// 	USART_InitStruct.USART_StopBits = USART_StopBits_1;
// 	USART_InitStruct.USART_Mode =USART_Mode_duplex;
// 	USART_InitStruct.USART_Parity = USART_Parity_Even ;
// 	USART_InitStruct.USART_RXLen = UARTBUFSIZE;
// 	USART_InitStruct.USART_TXLen = UARTBUFSIZE;

// 	if(UARTA == UARTx){
// 	GPIO_SetGpioMultFunction(IO_TXA,GPCFG_UART_TXD);
// 	GPIO_SetGpioMultFunction(IO_RXA,GPCFG_UART_RXD);
// 	}else if (UARTB == UARTx){
// 	GPIO_SetGpioMultFunction(IO_TXB,GPCFG_UARTB_TXD);
// 	GPIO_SetGpioMultFunction(IO_RXB,GPCFG_UARTB_RXD);
// 	}

// 	USART_Init(UARTx,&USART_InitStruct);
// }


void USART_SendData(USART_TypeDef USARTx, uint8_t Data)
{
	UartxRegDef * UartAdr = NULL;
	uint16_t  WPtr = 0; 
	_ASSERT(IS_USARTAB(USARTx));
	
	if(USARTx == UARTA) {
		UartAdr = (UartxRegDef *)(reg_map(CORE_UART_BAUD));	
	}else {
		UartAdr = (UartxRegDef *)(reg_map(CORE_UARTB_BAUD));
	}
	_ASSERT((&UartAdr->TxSadr  != NULL));
	if(USARTx == UARTA) {
		while((HREADW(CORE_UART_TX_ITEMS)) > 0);
	}else {
		while((HREADW(CORE_UARTB_TX_ITEMS)) > 0);
	}	

	WPtr = HR_REG_16BIT((uint32_t)(&UartAdr->TxWptr));
	HW_REG_8BIT(WPtr|M0_MEMORY_BASE,Data);	
	RB_UPDATE_PTR(WPtr, HR_REG_16BIT((uint32_t)(&UartAdr->TxSadr)),  HR_REG_16BIT((uint32_t)(&UartAdr->TxEadr)));	
	HW_REG_16BIT((uint32_t)(&UartAdr->TxWptr),  WPtr); 
//	if(USARTx == UARTA) {
//		while((HREADW(CORE_UART_TX_ITEMS)) > 0);
//	}else {
//		while((HREADW(CORE_UARTB_TX_ITEMS)) > 0);
//	}		                                                                                            		
}



uint16_t USART_ReceiveData(USART_TypeDef USARTx)
{	
	UartxRegDef *UartAdr = NULL;
	uint16_t  RPtr = 0;
	uint16_t  RdData = 0;
	_ASSERT(IS_USARTAB(USARTx)); 

	if(USARTx == UARTA) {
		UartAdr = (UartxRegDef *)(reg_map(CORE_UART_BAUD));	
	}else {
		UartAdr = (UartxRegDef *)(reg_map(CORE_UARTB_BAUD));
	}
	RPtr = HR_REG_16BIT((uint32_t)(&UartAdr->RxRptr));
	
	RdData = HR_REG_16BIT(RPtr|M0_MEMORY_BASE);

	RB_UPDATE_PTR(RPtr, HR_REG_16BIT((uint32_t)(&UartAdr->RxSadr)), HR_REG_16BIT((uint32_t)(&UartAdr->RxEadr)));
	HW_REG_16BIT((uint32_t)(&UartAdr->RxRptr), RPtr);	
	return RdData;
}


uint16_t USART_GetRxCount(USART_TypeDef USARTx)
{
	_ASSERT(IS_USARTAB(USARTx));
	if(USARTx == UARTA) {
		return HR_REG_16BIT(reg_map(CORE_UART_RX_ITEMS));
	}else {
		return HR_REG_16BIT(reg_map(CORE_UARTB_RX_ITEMS));
	}
}


uint16_t USART_ReadDatatoBuff(USART_TypeDef USARTx, uint8_t* RxBuff, uint16_t RxSize)
{
	uint16_t RxLen = 0;	
	uint16_t RPtr = 0;
   	uint16_t RdataLen = 0;
   	uint32_t RxITEMS = 0;
	UartxRegDef *UartAdr = NULL;
	_ASSERT(IS_USARTAB(USARTx));
	_ASSERT(RxBuff != NULL);
	
	if(USARTx == UARTA) {
		UartAdr = (UartxRegDef *)(reg_map(CORE_UART_BAUD));
		RxITEMS = reg_map(CORE_UART_RX_ITEMS);
	}else {
		UartAdr = (UartxRegDef *)(reg_map(CORE_UARTB_BAUD));
		RxITEMS = reg_map(CORE_UARTB_RX_ITEMS);
	}
	RxLen = HR_REG_16BIT(RxITEMS); 
	if (RxSize!=0) {
		if (RxLen < RxSize) 
			return 0; 
		else 
		RxLen = RxSize;
	}
	if (0 == RxLen) {
    	return 0;
    } else {
		RPtr = HR_REG_16BIT((uint32_t)(&UartAdr->RxRptr));
		for(RdataLen = 0; RdataLen<RxLen; RdataLen++ )
		{           			 
   			RxBuff[RdataLen] = HR_REG_8BIT(RPtr|M0_MEMORY_BASE);   
			RB_UPDATE_PTR(RPtr, HR_REG_16BIT((uint32_t)(&UartAdr->RxSadr)), HR_REG_16BIT((uint32_t)(&UartAdr->RxEadr)));
		}
	}
	HW_REG_16BIT((uint32_t)(&UartAdr->RxRptr), (RPtr));
	return RdataLen;
}


uint16_t USART_SendDataFromBuff(USART_TypeDef USARTx, uint8_t* TxBuff, uint16_t TxLen)
{
	uint16_t  WPtr = 0;
	uint16_t  SDataLen = 0;	
	uint16_t i;
	UartxRegDef *UartAdr = NULL;
	_ASSERT(IS_USARTAB(USARTx));
	_ASSERT(TxBuff != 0);
	_ASSERT(TxLen > 0);
	
	if(USARTx == UARTA) {
		UartAdr = (UartxRegDef *)(reg_map(CORE_UART_BAUD));	
	}else {
		UartAdr = (UartxRegDef *)(reg_map(CORE_UARTB_BAUD));
	}
	_ASSERT((&UartAdr->TxSadr  != NULL));
	if(USARTx == UARTA) {
		while((HREADW(CORE_UART_TX_ITEMS)) > 0);
	}else {
		while((HREADW(CORE_UARTB_TX_ITEMS)) > 0);
	}	
   	WPtr = HR_REG_16BIT((uint32_t)(&UartAdr->TxWptr));
   	for ( i=0; i<TxLen; i++)  {	
		
		HW_REG_8BIT(WPtr|M0_MEMORY_BASE,TxBuff[i]);	
		RB_UPDATE_PTR(WPtr, HR_REG_16BIT((uint32_t)(&UartAdr->TxSadr)),  HR_REG_16BIT((uint32_t)(&UartAdr->TxEadr)));	   
		SDataLen++;	
	}
	HW_REG_16BIT((uint32_t)(&UartAdr->TxWptr),  WPtr);  
//	if(USARTx == UARTA) {
//		while(HREADW(CORE_UART_TX_ITEMS) > 0);
//	}else {
//		while(HREADW(CORE_UARTB_TX_ITEMS) > 0);
//	}			
	return SDataLen;
}

//int fputc(int ch, FILE *f)
//{
//	USART_SendData(UARTB, (unsigned char) ch);
//	while (!(HR_REG_16BIT(reg_map(CORE_UARTB_TX_ITEMS))));
//	return (ch);
//}