/***********************************************************************
 * Copyright (c)  2017 - 2022, Unicmicro Co.,Ltd .
 * All rights reserved.
 * Filename    : uart0.c
 * Description : uart0 driver source file
 * Author(s)   : zhilan
 * version     : V1.0
 * Modify date : 2022-08-04
 ***********************************************************************/
#include  "uart0.h"

uint8_t uart0_tx_flag = 0;
void (*uart0_recv_callback)(void) = NULL;

/************************************************************************
 * function   : UART0_IRQHandler
 * description: uart0 interrupt handling
 * input 	  : none
 * return     : none
 ************************************************************************/
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; 										//清除中断状态
	}
	
}
/************************************************************************
 * function   : uart0_init
 * description: uart0 initial for baud_rate
 * input      : uint32_t sys_clk_hz: system clock frequency
 *              uint32_t baud_rate: uart baud rare       
 * return     : none
 ************************************************************************/
void uart0_init(uint32_t sys_clk_hz, uint32_t baud_rate)
{
	REG_SCU_PERICLKEN |= (1<<0);									//开UART0时钟使能	
	REG_SCU_PERIRESET |= (1<<0);									//UART0正常工作
		
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A; 							//清除IO写保护
		
	REG_SCU_PDSEL = (REG_SCU_PDSEL&(~(0xF<<24)))|(0x1<<24);			//PD6复用为UART0_TX
	REG_SCU_PCSEL = (REG_SCU_PCSEL&(~(0xF<<16)))|(0x3<<16);	    	//PC4复用为UART0_RX	
    REG_SCU_PADIE0 |= (0x1<<20);                                	//PC4输入使能
		
	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   : uart0_set_baud_rate
 * description: uart0 set baud rate
 * input 	  : uint32_t sys_clk_hz: system clock frequency
 *       	    uint32_t baud_rate: Series rate        
 * return	  : none
 ************************************************************************/
void uart0_set_baud_rate(uint32_t sys_clk_hz, uint32_t baud_rate)
{
	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   : uart0_send_byte
 * description: uart0 out byte
 * input      : uint8_t c: out byte    
 * return     : none
 ************************************************************************/
void uart0_send_byte(uint8_t c)	
{
	REG_UART0_TDR = c;        									    //输出一个字符
										
#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   : uart0_send_bytes
 * description: uart0 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 
 * 0escription: 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;	
	}	
		
}
