/***********************************************************************
 * Copyright (c)  2017 - 2020, Unicmicro Co.,Ltd .
 * All rights reserved.
 * Filename    : uart.c
 * Description : uart driver source file
 * Author(s)   : Dan
 * version     : V1.0
 * Modify date : 2019-04-10
 ***********************************************************************/
#include  "uart0.h"
uint8_t uart0_tx_flag = 0;
void (*uart0_recv_callback)(void) = NULL;


void UART0_IRQHandler(void)
{
	if(REG_UART0_ISR & 0x20)       // Rx int 
	{
		if(uart0_recv_callback!= NULL)
		{
			(*uart0_recv_callback)();
		}	
		REG_UART0_ISR &= ~(1<<5);	//清除FIFO_NE非空标志位
	}
#ifdef UART0_TX_INT_MODE		//中断方式
	else if(REG_UART0_ISR & 0x02)  // Tx int 发送中断
	{
		uart0_tx_flag =1;
		REG_UART0_ISR &= ~(1<<1);	//清除发送完成标志位
	}
#endif
	else
	{
		REG_UART0_ISR = 0x00; //  清除中断状态
	}
	
}

void uart0_init(uint32_t sys_clk_hz, uint32_t baud_rate)
{
	REG_SCU_PERICLKEN |= (1<<0);		//开UART时钟使能	
	REG_SCU_PERIRESET |= (1<<0);		//UART正常工作
	
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A; //清除IO写保护
	
	REG_SCU_PDSEL = (REG_SCU_PDSEL&(~(0x7<<24)))|(0x1<<24);		//PD6复用为UART0_TX
	REG_SCU_PDSEL = (REG_SCU_PDSEL&(~(0x7<<28)))|(0x7<<28);	    //PD7复用为UART0_RX	
  
	REG_SCU_IOCTRLPROTECT = 0xffffffff; //开启IO写保护
	while((REG_SCU_IOCTRLPROTECT & 0x01) == 0x01)      //读IO控制保护寄存器的写使能状态
	{	
		REG_SCU_IOCTRLPROTECT = 0xffffffff; //开启IO写保护
	}

	uart0_tx_flag = 0;
	
	REG_UART0_CR = 0x00;	  			//归零该寄存
	REG_UART0_CR|= (1 << 2);  			//清除接收FIFO中数据和指针
	REG_UART0_CR&= ~(1 << 2);   		//清空fifo完成后，还原状态（避免fifo一直处在清空状态，无法接收数据）
	REG_UART0_CR|= (1 << 1)|(1 << 3); 	//无奇偶校验 | 发送数据使能
	
	uart0_set_baud_rate(sys_clk_hz, baud_rate);		//设置波特率
	
	REG_UART0_ISR = 0x00; 		//中断状态清除
	REG_UART0_IER = 0x00;       //
			
}

 
/************************************************************************
 * function   : uart0_irq_init
 * Description: uart0 irq init
 * input : 
 *         uint8_t irq_enable: interrupt enable/disable
		   void (*uart_recv)(): interrupt callback function 
 * return: none
 ************************************************************************/
void uart0_irq_init(uint8_t irq_enable,void (*uart_recv)()) 
{
	if(irq_enable == UART0_IRQ_ENABLE)
	{
		NVIC_ClearPendingIRQ(UART0_IRQn);
		NVIC_EnableIRQ(UART0_IRQn);
		
	#ifdef UART0_TX_INT_MODE		//发送采用中断方式
		REG_UART0_IER |= (1 << 1);        //发送中断使能
	#endif	
		REG_UART0_IER |= (1 << 5);        //接收FIFO非空中断使能
		uart0_recv_callback = uart_recv;
	}
	else
	{
	#ifdef UART0_TX_INT_MODE		//发送采用中断方式
		REG_UART0_IER &= ~(1 << 1);        //发送中断使能
	#endif	
		REG_UART0_IER &= ~(1 << 5);        //接收FIFO非空中断使能
		
		uart0_recv_callback = NULL;
	}
}


/************************************************************************
 * function   : uart_set_baud_rate
 * Description: uart set baud rate
 * input : 
 *         uint32_t clk_hz: cpu frequency
 *         uint32_t baud_rate: Series rate
 * return: none
 ************************************************************************/
void uart0_set_baud_rate(uint32_t sys_clk_hz, uint32_t baud_rate)
{
//1.计算波特率高、低位；
//2.设置波特率寄存器
	
	uint16_t temp;
	uint8_t MSbyte, LSbyte;

	temp = sys_clk_hz / baud_rate;

	MSbyte = temp>>8;
	LSbyte = temp;
	
	REG_UART0_BRPH = MSbyte;
	REG_UART0_BRPL = LSbyte;
}

/************************************************************************
 * function   : outbyte
 * Description: uart out byte
 * input : 
 *         char c: out byte
 * return: none
 ************************************************************************/
void uart0_send_byte(uint8_t c)	
{
	REG_UART0_TDR = c;    //	1.输出一个字符
	
#ifdef UART0_TX_INT_MODE		//中断方式
	uint16_t timeout;
	timeout = 65535;
	while(uart0_tx_flag == 0) //等待数据发送完成
	{
		if((timeout--)==0)   //超时等待退出
		break;
	}
	uart0_tx_flag = 0;
#else	
	uint16_t timeout;
	timeout = 65535;
	//查询方式
	while((REG_UART0_ISR & 0x02) != 0x02) //等待数据发送完成
	{
		if((timeout--)==0)   //超时等待退出
		{
			break;
		}
	}
	REG_UART0_ISR &= ~(1<<1);			   //清除发送完成标志位
#endif	

}

/************************************************************************
 * function   : uart0_recv_byte
 * Description: uart0 read one byte's data
 * input : none
 *         
 * return: data from uart
 ************************************************************************/
uint8_t uart0_recv_byte(void)	
{
	return REG_UART0_RDR;
}

/************************************************************************
 * function   : uart_send_bytes
 * Description: uart send bytes
 * input : 
 *         uint8_t* buff: out buffer
 *         uint32_t length: buffer length
 * return: none
 ************************************************************************/
void uart0_send_bytes(uint8_t *buff, uint32_t length)
{
	uint32_t i;

	for(i = 0; i < length; i++)
	{
		uart0_send_byte(*buff++);
	}
}

/************************************************************************
 * function   : uart0_rec_bytes 
 * Description: uart0 receive bytes by polling mode
 * input : 
 *         uint8_t* buff: receive buffer
 *         uint32_t length: buffer length
 * return: none
 ************************************************************************/
void uart0_rec_bytes(uint8_t *buff, uint32_t length)
{
	while(length--)
	{
		while(!( REG_UART0_ISR & 0x20 ));	//wait rx not empty
		*buff++ = REG_UART0_TDR;	
	}	
		
}
