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

void (*uart1_recv_callback)(void) = NULL;

/************************************************************************
 * function   : UART1_IRQHandler
 * description: uart1 interrupt handling
 * input 	  : none
 * return     : none
 ************************************************************************/
void UART1_IRQHandler(void)
{
	if( (REG_UART1_IIR & 0x0f)==0x04 )   
	{		
		if(uart1_recv_callback!= NULL)
		{
			(*uart1_recv_callback)(); 		                                           //uart1的接收处理回调函数
		}	
	}
}

/************************************************************************
 * 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 uart1_set_baud_rate(uint32_t clk_hz, uint32_t baud_rate)
{
	uint32_t integer,fraction;
	uint8_t MSbyte, LSbyte;	
	
	integer = (clk_hz)/(16*baud_rate);						                            //波特率整数部分
	fraction = (((clk_hz)%(baud_rate*16))/baud_rate);									//波特率小数部分
	
	MSbyte = integer>>8;
	LSbyte = integer;
	
	REG_UART1_DLF = fraction&0x3f;
	REG_UART1_LCR |= 0x80;     													        //需要动态调整波特率
	REG_UART1_DLH = MSbyte;
	REG_UART1_DLL = LSbyte;
	REG_UART1_LCR &= ~0x80;     													    //需要动态调整波特率
}

/************************************************************************
 * function   : uart_init
 * description: uart initial for  baud_rate
 * input 	  : uint32_t baud_rate：  Series rate
 *				uint32_t sys_clk_hz：system frequency
 * return	  : none
 ************************************************************************/
void uart1_init(uint32_t sys_clk_hz,uint32_t baud_rate)
{
	REG_SCU_PERICLKEN |= (1<<10);		                      							//开UART时钟使能	
	REG_SCU_PERIRESET |= (1<<10);		                      							//UART正常工作
								
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A; 												//清除IO写保护							
								
	REG_SCU_PCSEL = (REG_SCU_PCSEL&(~(0xF<<4)))|(2<<4);		  							//PC1复用为 UART1_TX
	REG_SCU_PCSEL = (REG_SCU_PCSEL&(~(0xF<<8)))|(2<<8);		  							//PC2复用为 UART1_RX	
    REG_SCU_PADIE0 |= (0x1<<18);                              							//PC2 输入使能
							
	while((REG_SCU_IOCTRLPROTECT & 0x01) == 0x01)             							//读IO控制保护寄存器的写使能状态
	{								
		REG_SCU_IOCTRLPROTECT = 0xffffffff;                   							//开启IO写保护
	}							
								
	REG_UART1_MCR = 0x00;     	                              							//流控制不使能  
	uart1_set_baud_rate(sys_clk_hz, baud_rate);		          							//设置波特率
	REG_UART1_FCR = 0x01;  		                              							//接收FIFO 1字节触发非空中断，发送FIFO空中断,使能FIFO
    REG_UART1_LCR = 0x03;		                              							//无校验位，1位停止位，8bits数据，

}

/************************************************************************
 * function   : uart1_irq_init
 * Description: uart1 irq init
 * input 	  : uint8_t irq_enable: interrupt enable/disable
 *              void (*uart_recv)(): interrupt callback function    
 * return	  : none
 ************************************************************************/
void uart1_irq_init(uint8_t irq_enable, void (*uart_recv)())  
{
	if(irq_enable == UART1_IRQ_ENABLE)
	{
		REG_UART1_IER |= 0x01;															//开启接收FIFO非空中断
		uart1_recv_callback = uart_recv;
	
		NVIC_ClearPendingIRQ(UART1_IRQn);
		NVIC_EnableIRQ(UART1_IRQn);
	}
	else
	{
		REG_UART1_IER &= ~0x01;															//关闭接收FIFO非空中断
		uart1_recv_callback =NULL;
	}	
}


/************************************************************************
 * function   : uart1_9bit_config
 * description: uart1_9bit_config
 * input      : uint8_t enable_addr_match: enable address match mode
 *              uint8_t addr_recv: address
 *              uint8_t mode: send or receive mode
 * return	  : none
 ************************************************************************/
void uart1_9bit_config(uint8_t enable_addr_match,uint8_t addr_recv, uint8_t mode)
{
    if(mode)
    {                                                            //TX mode
        if(enable_addr_match)
        {
            REG_UART1_TAR = addr_recv;
            REG_UART1_LCRE = (REG_UART1_LCRE & (~0x0C)) | 0x04;  //由硬件决定发送地址
        }
        else
        {
            REG_UART1_LCRE = (REG_UART1_LCRE & (~0x0C)) | 0x08;  //由发送的数据决定发送的是地址还是数据
        }	
    }
    else
    {                                                            //RX mode
        if(enable_addr_match)
        {
            REG_UART1_LCRE |= 0x02;                              //使能从机地址接收匹配
            REG_UART1_RAR = addr_recv;                           //设置从机地址 
        }
    }
    REG_UART1_LCRE = (REG_UART1_LCRE & (~0x01)) | 0x01;          //使能9bit模式
	
}

/************************************************************************
 * function   : uart1_send_9bit_byte
 * description: uart out byte
 * input      : uint32_t c: out byte   
 * return     : none
 ************************************************************************/
void uart1_send_9bit_byte(uint32_t c)	
{
																	//输出一个字符
	uint16_t timeout;					
	timeout = 65535; 					
						
    c = c&0x01ff;					
	REG_UART1_THR = c;					
					
	 while((REG_UART1_LSR & 0x40) != 0x40)							//等待数据发送完成
	{					
		if((timeout--)==0)                      					//超时等待退出
		{
			break;
		}
	}
}

/************************************************************************
 * function   : uart1_recv_byte
 * description: uart1 read one byte's data
 * input 	  : none
 * return	  : data from uart
 ************************************************************************/
uint16_t uart1_recv_9bit_byte(void)	
{
	return REG_UART1_RBR;
}
/************************************************************************
 * function   : uart1_send_bytes
 * description: uart1 send bytes
 * input 	  : uint32_t* buff: out buffer
 *              uint32_t length: buffer length
 * return	  : none
 ************************************************************************/
void uart1_send_9bit_bytes(uint32_t *buff, uint32_t length)
{
	uint32_t i;

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

/************************************************************************
 * function   : uart1_rec_bytes 
 * description: uart1 receive bytes by polling mode
 * input      : uint32_t* buff: receive buffer
 *              uint32_t length: buffer length
 * return     : none
 ************************************************************************/
void uart1_rec_9bit_bytes(uint32_t *buff, uint32_t length)
{
	while(length--)
	{
		while((REG_UART1_IIR & 0x0f) !=0x04);							//wait rx not empty	
		*buff++ = REG_UART1_RBR;	
	}	
		
}

/************************************************************************
 * function   : uart1_send_byte
 * description: uart out byte
 * input      : uint8_t c: out byte   
 * return     : none
 ************************************************************************/
void uart1_send_byte(uint8_t c)	
{
																		//输出一个字符
	uint16_t timeout;							
	timeout = 65535;							
								
	REG_UART1_THR = c;							
							
	 while((REG_UART1_LSR & 0x40) != 0x40)								//等待数据发送完成
	{							
		if((timeout--)==0)                     							//超时等待退出
		{
			break;
		}
	}
}

/************************************************************************
 * function   : uart1_recv_byte
 * description: uart1 read one byte's data
 * input 	  : none
 * return	  : data from uart
 ************************************************************************/
uint8_t uart1_recv_byte(void)	
{
	return REG_UART1_RBR;
}

/************************************************************************
 * function   : uart1_send_bytes
 * description: uart1 send bytes
 * input      : uint8_t* buff: out buffer
 *              uint32_t length: buffer length
 * return     : none
 ************************************************************************/
void uart1_send_bytes(uint8_t *buff, uint32_t length)
{
	uint32_t i;

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

/************************************************************************
 * function   : uart1_rec_bytes 
 * description: uart1 receive bytes by polling mode
 * input      : uint8_t* buff: receive buffer
 *              uint32_t length: buffer length
 * return     : none
 ************************************************************************/
void uart1_rec_bytes(uint8_t *buff, uint32_t length)
{
	while(length--)
	{
		while((REG_UART1_IIR & 0x0f) !=0x04);							//wait rx not empty	
		*buff++ = REG_UART1_RBR;	
	}	
		
}



