/**
******************************************************************************************************************************************************************************************
*@file                       user_uart.c
*@author         
*@data                       
*@version                    v1.0
*@par Copyright(c):
*
*@par History:
*     version:author,date,desc
*     v1.0   :create this file
*
*******************************************************************************************************************************************************************************************
*/
#include "sdk_include.h"
#include "user_uart.h"
#include "cpu_uart.h"
#include "app_trace.h"
#include "app_config.h"
#include "cpu_deepsleep.h"
#if UART_USE_NUM
UART_PARAM   ui_uart_Param[UART_USE_NUM];
#endif

UART_PARAM *get_instance(ws_dev dev)
{
#if UART_USE_NUM
	if(dev == ws_uart0) return &ui_uart_Param[UART0_IDX];

	if(dev == ws_uart1) return &ui_uart_Param[UART1_IDX];
#endif
	return NULL;
}

void ui_uart_init(ws_dev dev)
{
    assert_param(is_uart_dev(dev));

	UART_PARAM * uart_param = get_instance(dev);
	
	if(NULL == uart_param)
		return;

	memset(uart_param,0,sizeof(UART_PARAM));
	uart_param->tx_transmit_stopped = 1; 
}

void set_uart_init(ws_dev dev)
{
    UART_PARAM * uart_param = NULL; 
    assert_param(is_uart_dev(dev));
    uart_param = get_instance(dev);
	
	if(NULL == uart_param)
		return;
	
	uart_param->init = 1;
}

void reg_uart_rx_callback(ws_dev dev,user_uart_cfg_parameter_t *p_parameter)
{
    UART_PARAM * uart_param = NULL; 
    uart_param = get_instance(dev);
	
	if(NULL == uart_param)
		return;

	if(uart_param){
		uart_param->uart_handler = p_parameter->uart_handler;
	}
}

uint32_t ui_get_uart_fifo_avaiable(ws_dev dev)
{    
	UART_PARAM * uart_param  = NULL; 
    uart_param 	= get_instance(dev);
	
	if(NULL == uart_param)
		return 0;

	return UART_SEND_BUF_SIZE - uart_param->Send.bytes;
}

void ui_uart_sendchar(ws_dev dev, uint8_t data)
{
    UART_PARAM * tmp_Uart_Param = NULL; 
	uart_typedef_t* uartx;
	
	if(dev == ws_uart0){
		uartx = UART0;
	}else if(dev == ws_uart1){
		uartx = UART1;
	}else{
		return;
	}
	
    tmp_Uart_Param 	= get_instance(dev);
	
	if(NULL == tmp_Uart_Param)
		return;
	
	if(0 == tmp_Uart_Param->init)
		return;
	
    while (UART_SEND_BUF_SIZE == tmp_Uart_Param->Send.bytes){
		tmp_Uart_Param->wait ++;
		if(tmp_Uart_Param->wait > 10000){
			tmp_Uart_Param->wait = 0;
			return;
		}
	}
 	//dbg_block_printf("ws_uart0 : UART0_TX_ONGOING\n");		
	if(dev == ws_uart0){
		cpu_prevent_sleep_set(UART0_TX_ONGOING);
	}
	if(dev == ws_uart1){
		cpu_prevent_sleep_set(UART1_TX_ONGOING);
	}

	tmp_Uart_Param->wait = 0;
    tmp_Uart_Param->Send.buf[tmp_Uart_Param->Send.write_index++] = data;

    if (tmp_Uart_Param->Send.write_index >= UART_SEND_BUF_SIZE)
    {
        tmp_Uart_Param->Send.write_index = 0;
    }

    __set_faultmask(1);

	if(tmp_Uart_Param->Send.bytes < UART_SEND_BUF_SIZE)
    	tmp_Uart_Param->Send.bytes++;
	else
		tmp_Uart_Param->Send.read_index  = tmp_Uart_Param->Send.write_index; 

	
    if (tmp_Uart_Param->Send.bytes && tmp_Uart_Param->tx_transmit_stopped)
    {
        tmp_Uart_Param->tx_transmit_stopped = 0;
        uart_it_config(uartx,UART_IT_ETBEI_TX, ENABLE);
    }
    __set_faultmask(0);
}

uint8_t ui_uart_rx_fifo_empty(ws_dev dev)
{
    UART_PARAM * tmp_Uart_Param = NULL; 
    assert_param(is_uart_dev(dev));
    tmp_Uart_Param = get_instance(dev);
	return (tmp_Uart_Param->Recv.read_index == tmp_Uart_Param->Recv.write_index);
}


uint32_t ui_uart_recvchar(ws_dev dev, uint8_t *ch)
{
    UART_PARAM * tmp_Uart_Param = NULL; 
    assert_param(is_uart_dev(dev));
    tmp_Uart_Param = get_instance(dev);
	
	if(NULL == tmp_Uart_Param)
		return 0;

    if (0 == tmp_Uart_Param->Recv.bytes)
    {
        return 0;
    }

	__set_faultmask(1);
    *ch = tmp_Uart_Param->Recv.buf[tmp_Uart_Param->Recv.read_index++];
	if (tmp_Uart_Param->Recv.read_index >= UART_RECV_BUF_SIZE){
        tmp_Uart_Param->Recv.read_index = 0;
    }
    tmp_Uart_Param->Recv.bytes--;
    __set_faultmask(0);

	return 1;
}

int empty_cnt = 0;
static void put_uartx_2_fifo(uint8_t ch,UART_PARAM * tmp_Uart_Param)
{

	tmp_Uart_Param->Recv.buf[tmp_Uart_Param->Recv.write_index]= ch;
	tmp_Uart_Param->Recv.write_index += 1;
	if(tmp_Uart_Param->Recv.write_index >= UART_RECV_BUF_SIZE)
		tmp_Uart_Param->Recv.write_index = 0;

// fifo total data
	if(tmp_Uart_Param->Recv.bytes < UART_RECV_BUF_SIZE)
		tmp_Uart_Param->Recv.bytes++;
	else
		tmp_Uart_Param->Recv.read_index = tmp_Uart_Param->Recv.write_index;
		

}

static inline void read_all_fifo_data(uart_typedef_t* uartx,UART_PARAM * tmp_Uart_Param)
{
	uint8_t ch 		= 0;
	uint8_t recv 	= 0;
	while(uart_is_rx_fifo_no_empty(uartx))
	{
		ch = (uint8_t)(uartx->SEL0.RBR);
		if(tmp_Uart_Param){
			put_uartx_2_fifo(ch,tmp_Uart_Param);
		}
		recv = 1;
	}

	if(recv && tmp_Uart_Param &&tmp_Uart_Param->uart_handler){
		tmp_Uart_Param->uart_handler(tmp_Uart_Param,ch);
	}
}

/*****************************************************************************
 函 数 名  : flush_uartx_2_usr_fifo
 功能描述  : 进入低功耗之前查询
 输入参数  : uint8_t type  
 输出参数  : 无
 返 回 值  : 
*****************************************************************************/
void flush_uartx_2_usr_fifo(uint8_t type)
{
	uint8_t i 		= 0;
	UART_PARAM * 	tmp_Uart_Param;
	typedef struct _flush_uart{
		ws_dev device;
		uart_typedef_t* uartx;
	}flush_uart;

	flush_uart flush_uart_cfg[2]={
		{ws_uart0,UART0},
		{ws_uart1,UART1},
	};

	if(empty_cnt < 100000)
		empty_cnt ++;
		
	if(type == NORMAL_SLEEP){			//浅睡眠低功耗，查询间隔
		if(empty_cnt < 10000)
			return;
	}else if(type == NONE_SLEEP){		//正常模式
		if(empty_cnt < 20000)
			return;
	}
	
	empty_cnt = 0;
	__set_faultmask(1);
	for(i=0;i<2;i++){
		tmp_Uart_Param = get_instance(flush_uart_cfg[i].device);
		read_all_fifo_data(flush_uart_cfg[i].uartx,tmp_Uart_Param);
	}
	__set_faultmask(0);
}


void dev_isr(uart_typedef_t* uartx,UART_PARAM * tmp_Uart_Param)
{
	switch(uartx->SEL2.IIR & 0x0f)
	{
		case UART_IID_RECVD_DATA_AVAILABLE:
		case UART_IID_CHAR_TIMEOUT:
		{
			empty_cnt = 0;
		 	__set_faultmask(1);
			read_all_fifo_data(uartx,tmp_Uart_Param);
			__set_faultmask(0);
		}
		break;
		case UART_IID_THR_EMPTY:
		{
			__set_faultmask(1);
			if (0 == tmp_Uart_Param->Send.bytes)
			{
				uart_it_config(uartx,UART_IT_ETBEI_TX, DISABLE);
				tmp_Uart_Param->tx_transmit_stopped = 1;

				if(uartx == UART0){
					cpu_prevent_sleep_clear(UART0_TX_ONGOING);
				}
				if(uartx == UART1){
					cpu_prevent_sleep_clear(UART1_TX_ONGOING);
				}
			}

			if(tmp_Uart_Param->Send.bytes)
			{
				if(UART0 == uartx){
//					dbg_printf("%x ",tmp_Uart_Param->Send.buf[tmp_Uart_Param->Send.read_index]);
				}
				tmp_Uart_Param->Send.bytes--;
				uartx->SEL0.THR = tmp_Uart_Param->Send.buf[tmp_Uart_Param->Send.read_index++];
				if(tmp_Uart_Param->Send.read_index >= UART_SEND_BUF_SIZE)
				{
					tmp_Uart_Param->Send.read_index = 0;
				}				
			}
			__set_faultmask(0);
		}
		break;
		case UART_IID_MODEM_STATUS:
		{
			uint32_t msr = uartx->MSR;			
		}
		break;
		case UART_IID_RECEIVER_LINE_STATUS:
		{
			uint32_t lsr = uartx->LSR;			
		}	
		break;
		case UART_IID_BUSY_DETECT:
		{
			uint32_t usr = uartx->USR;			
		}	
		break;
		default:
			break;
	}
}

/*****************************************************************************
 函 数 名  : set_uart_recv_busy
 功能描述  : 设置UART接收工作状态
 输入参数  : ws_dev dev    
             uint8_t busy  
 输出参数  : 无
 返 回 值  : 

*****************************************************************************/
void set_uart_recv_busy(ws_dev dev,uint8_t busy)
{
	if(busy){
		if(dev == ws_uart0){
			cpu_prevent_sleep_set(UART0_RX_ONGOING);
		}
		if(dev == ws_uart1){
			cpu_prevent_sleep_set(UART1_RX_ONGOING);
		}
	}else{
		if(dev == ws_uart0){
			cpu_prevent_sleep_clear(UART0_RX_ONGOING);
		}
		if(dev == ws_uart1){
			cpu_prevent_sleep_clear(UART1_RX_ONGOING);
		}
	}
}
/*****************************************************************************
 函 数 名  : get_uart_recv_busy
 功能描述  : 设置UART接收工作状态
 输入参数  : ws_dev dev    
             uint8_t busy  
 输出参数  : 无
 返 回 值  : 

*****************************************************************************/
uint8_t get_uart_recv_busy(ws_dev dev)
{
	if(dev == ws_uart0){
		return (cpu_prevent_sleep_get() & UART0_RX_ONGOING);
	}
	if(dev == ws_uart1){
		return (cpu_prevent_sleep_get() & UART1_RX_ONGOING);
	}
	return 0;
}

uint32_t get_uart_tx_busy(ws_dev dev)
{
	if(dev == ws_uart0){
		return cpu_prevent_sleep_get() & UART0_TX_ONGOING;
	}
	if(dev == ws_uart1){
		return cpu_prevent_sleep_get() & UART1_TX_ONGOING;
	}
	return 0;
}

void UART0_IRQHandler(void)
{
    UART_PARAM * tmp_Uart_Param = get_instance(ws_uart0);
	
	if(NULL == tmp_Uart_Param)
		return;
	
	dev_isr(UART0,tmp_Uart_Param);
}


void UART1_IRQHandler(void)
{
    UART_PARAM * tmp_Uart_Param = get_instance(ws_uart1);
	
	if(NULL == tmp_Uart_Param)
		return;

	dev_isr(UART1,tmp_Uart_Param);
}

uint16_t get_ui_uart_data_size(ws_dev  dev)
{
    UART_PARAM * tmp_Uart_Param = NULL; 
    tmp_Uart_Param = get_instance(dev);	
	
	if(NULL == tmp_Uart_Param)
		return 0;
	
    return tmp_Uart_Param->Recv.bytes;
}


uint32_t ui_uart_readbuf(ws_dev  dev,uint8_t *buf,uint32_t len)
{
	uint32_t read_len = 0;
	while((read_len < len) && ui_uart_recvchar(dev,&buf[read_len])){
		read_len ++;
	}
	return read_len;
}

/*****************************************************************************
 函 数 名  : ui_uart_flush
 功能描述  : 清掉缓冲区
 输入参数  : ws_dev  dev  
 输出参数  : 无
 返 回 值  : 
*****************************************************************************/
uint8_t ui_uart_flush(ws_dev  dev)
{
	uint8_t read_len = 0;
    UART_PARAM * tmp_Uart_Param = NULL; 
    assert_param(is_uart_dev(dev));
    tmp_Uart_Param = get_instance(dev);
	if(NULL == tmp_Uart_Param)
		return 0;
	
	tmp_Uart_Param->Recv.read_index 	= 0;
	tmp_Uart_Param->Recv.write_index 	= 0;
	tmp_Uart_Param->Recv.bytes 			= 0;	
	return read_len;
}

void ui_dbg_uart_writebuf(ws_dev dev,uint8_t * buf,uint32_t buf_len)
{
    uint32_t i = 0;
    for(i =0;i < buf_len;i++){
		
		if(buf[i]=='\n')
			ui_uart_sendchar(dev,'\r');

		ui_uart_sendchar(dev,buf[i]);
    }
}

void ui_uart_writebuf(ws_dev dev,uint8_t * buf,uint32_t buf_len)
{
    uint32_t i = 0;
    for(i =0;i < buf_len;i++){
		ui_uart_sendchar(dev,buf[i]);
    }
}

int uart_block_putchar (ws_dev dev,int ch)
{
	uart_typedef_t* 	uartx;
    UART_PARAM * tmp_Uart_Param = NULL; 
    assert_param(is_uart_dev(dev));
    tmp_Uart_Param = get_instance(dev);
	if(NULL == tmp_Uart_Param)
		return 0;
		
	if(tmp_Uart_Param->init == 0)
		return 0;	
		
	if(dev == ws_uart0){
		uartx = UART0;
	}else if(dev == ws_uart1){
		uartx = UART1;
	}else{
		return 0;
	}
	while(!uart_is_tx_empty(uartx));
	uart_send_data(uartx, (uint8_t) ch);
	return ch;
}

void ui_uart_block_writebuf(ws_dev dev,uint8_t * buf,uint32_t buf_len)
{
    uint32_t i = 0;
    for(i =0;i < buf_len;i++){
		uart_block_putchar(dev,buf[i]);
    }
}

void ui_uart_configuration(ws_dev dev,uart_config *pConfig,uint8_t on)
{
	uart_init_struct 	UART_InitStructure;
	uart_fifo_struct 	UART_FIFOInitStruct;
	uart_typedef_t* 	uartx;
	char id = 0;
	
	typedef struct _uart_map{
		gpio_remap_type rtsnPin;
		gpio_remap_type ctsnPin;
		gpio_remap_type rxPin;
		gpio_remap_type txPin;
	}uart_map;
	
	uart_struct_init(&UART_InitStructure);
	uart_fifo_struct_init(&UART_FIFOInitStruct);

	const uart_map uartmap[2]={
		{GPIO_Remap_UART0_RTSN,GPIO_Remap_UART0_CTSN,GPIO_Remap_UART0_RX,GPIO_Remap_UART0_TX},
		{GPIO_Remap_UART1_RTSN,GPIO_Remap_UART1_CTSN,GPIO_Remap_UART1_RX,GPIO_Remap_UART1_TX},
	};
	if(dev == ws_uart0){
		id = 0;
		uartx = UART0;
	}else if(dev == ws_uart1){
		id = 1;
		uartx = UART1;
	}else{
		return;
	}
	
    if(pConfig->rtsnPin != GPIO_INVAILD){
		gpio_remap_config(pConfig->rtsnPin,(on == ON)?uartmap[id].rtsnPin:GPIO_Remap_GPIO);
		gpio_init(pConfig->rtsnPin,GPIO_Mode_Input);
	}
	
	if(pConfig->ctsnPin != GPIO_INVAILD){
		gpio_remap_config(pConfig->ctsnPin,(on == ON)?uartmap[id].ctsnPin:GPIO_Remap_GPIO);
		gpio_init(pConfig->ctsnPin,(on == ON)?GPIO_Mode_Output:GPIO_Mode_Input);
	}
	
	if(pConfig->rxPin != GPIO_INVAILD){
		gpio_remap_config(pConfig->rxPin,(on == ON)?uartmap[id].rxPin:GPIO_Remap_GPIO);
		gpio_init(pConfig->rxPin,GPIO_Mode_Input);
	}

	if(pConfig->txPin != GPIO_INVAILD){
		gpio_set(pConfig->txPin);
		gpio_remap_config(pConfig->txPin,(on == ON)?uartmap[id].txPin:GPIO_Remap_GPIO);
		gpio_init(pConfig->txPin,(on == ON)?GPIO_Mode_Output:GPIO_Mode_Input);
	}

	if(on == OFF){
		return;
	}

	UART_InitStructure.uart_baudrate	= pConfig->boaud_rate;
	UART_InitStructure.uart_word_len	= pConfig->length_bit;
	UART_InitStructure.uart_stop_bits	= pConfig->stop_bit;
	UART_InitStructure.uart_parity		= pConfig->parity_bit;

	if(pConfig->mode == APP_USART_IRQ){
		
		uart_init(uartx, &UART_InitStructure);
		uart_fifo_cmd(uartx,ENABLE);
		uart_fifo_set_trigger_level(uartx,0,0);
		uart_it_config(uartx,UART_IT_ERBFI_RX,ENABLE);
		
	}else if(pConfig->mode == APP_USART_FIFO_IRQ){
// FIFO 为16字节，	
		UART_FIFOInitStruct.FIFO_Enable 				= ENABLE;
		UART_FIFOInitStruct.FIFO_DMA_Mode				= UART_FIFO_DMA_Mode_1;
		UART_FIFOInitStruct.FIFO_RX_Trigger 			= UART_FIFO_RX_Trigger_1_2_Full;
		UART_FIFOInitStruct.FIFO_TX_Trigger 			= UART_FIFO_TX_Trigger_1_4_Full;
		UART_FIFOInitStruct.FIFO_TX_TriggerIntEnable	= ENABLE;

		uart_init(uartx,		&UART_InitStructure);
		uart_fifo_init(uartx,	&UART_FIFOInitStruct);
		uart_it_config(uartx,	UART_IT_RX_RECVD, ENABLE);
		
	}else{
		uart_init(uartx, &UART_InitStructure);
	}

	if(((pConfig->mode == APP_USART_FIFO_IRQ) || (pConfig->mode == APP_USART_IRQ))
		&& ((pConfig->ctsnPin != GPIO_INVAILD) || (pConfig->rtsnPin != GPIO_INVAILD)))
	{
		uart_auto_flow_ctrl_cmd(uartx, ENABLE);
		uart_set_rts(uartx);
	}
	else
	{
		uart_auto_flow_ctrl_cmd(uartx, DISABLE);
		uart_reset_rts(uartx);
	}
	set_uart_init(dev);
}

void user_uart_config(ws_dev dev,user_uart_cfg_parameter_t *p_parameter)
{
	UART_PARAM * uart_parm = get_instance(dev);
	
	if(NULL == uart_parm)
		return;

	uart_parm->uart_handler = p_parameter->uart_handler;
}

//=========================================================================
//****	串口应用举例
//****
//****
//=========================================================================
void user_uart_rcv_cbk(void *param,uint8_t ch)
{


}



/*****************************************************************************
 函 数 名  : user_timer_example
 功能描述  : 定时器应用举例
 输入参数  : void  
 输出参数  : 无
 返 回 值  : 
 调用函数  : 
 被调函数  : 
*****************************************************************************/
void user_uart_example(void)
{
	dbg_block_printf("app service initial timer ready\r\n");
	user_uart_cfg_parameter_t tmp_Uart_Param;
	uint32_t i;
	uint8_t buf[64];
	uint8_t rcv_buf[64];
	uint8_t sz;
//【1】 开启串口 0 时钟	
	system_clock_config(ws_uart1,ENABLE);

//【2】 开启串口 0 中断
	nvic_init_type_def nvic_init_structure;
	NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2);
	nvic_init_structure.nvic_irq_channel_preemption_priority	= 1;
	nvic_init_structure.nvic_irq_channel_subpriority			= 0;
	nvic_init_structure.nvic_irq_channel_cmd					= ENABLE; 
	nvic_init_structure.nvic_irq_channel 						= UART1_IRQn;
	nvic_init(&nvic_init_structure);

//【3】 初始化开串口参数以及注册回掉函数
	uart_config Config={
		.boaud_rate = 115200,
		.length_bit = UART_WordLength_8b,	   
		.stop_bit	= UART_StopBits_1,		  
		.parity_bit = UART_Parity_No, 
		.mode		= APP_USART_IRQ,
#if USART0_FlowCtrl_EN		
		.rtsnPin	= GPIOD_Pin0,					//串口接收流控脚
		.ctsnPin	= GPIOD_Pin1,					//串口发送流控脚
#else
		.rtsnPin	= GPIO_INVAILD, 				//串口接收流控脚
		.ctsnPin	= GPIO_INVAILD, 				//串口发送流控脚
#endif
		.rxPin		= GPIOD_Pin2,					//串口接收脚
		.txPin		= GPIOD_Pin3					//串口发送脚
	};


	Config.boaud_rate	= get_baudrate();
	ui_uart_configuration(ws_uart1,&Config,1);

	tmp_Uart_Param.uart_handler = user_uart_rcv_cbk;
	reg_uart_rx_callback(ws_uart1,&tmp_Uart_Param);
	ui_uart_block_writebuf(ws_uart1,"1234",strlen("1234") + 1);

	for(i=0;i<64;i++){
		buf[i] = (((i+1)*(i+2)) & 0xFF);
	}
	
//注意开了看门狗，此处要添加喂狗动作
	while(1){
		while(ui_get_uart_fifo_avaiable(ws_uart1) < 64);	
		
		ui_uart_writebuf(ws_uart1,buf,64);

		sz = ui_uart_readbuf(ws_uart1,rcv_buf,64);

		if(sz > 0){
			dbg_printf_hex("revice",(char *)rcv_buf,64);
		}
		
		for(i=0;i<1000000;i++);
	}

//【4】 备注:
//		串口 RX 为输入
//			 TX 为输出
//			在深度低功耗状态下，串口外设失电,串口控制寄存器数据丢失,RX 退化为悬浮输入的普通GPIO状态	
//			基于上述条件 需要注意:
//			A:退出低功耗串口外设需要重新初始化
//			B:不接负载，RX TX需要接3M上拉电阻
//			C:接入串口负载，串口默认电平为高电平，不影响。
}


/*****************************************************************************
 函 数 名  : app_uart_configuration
 功能描述  : 若用户没有定义，使用备用函数
 输入参数  : void  
 输出参数  : 无
 返 回 值  : 
 调用函数  : 
 被调函数  : 
*****************************************************************************/
__weak void app_uart_configuration(uint8_t on)
{

#if is_uart_dev(APP_UART)
	uart_config Config={
		.boaud_rate	= 115200,
		.length_bit	= UART_WordLength_8b,	   
		.stop_bit	= UART_StopBits_1,		  
		.parity_bit	= UART_Parity_No, 
		.mode		= APP_USART_FIFO_IRQ,
		
#if USART1_FlowCtrl_EN		
		.rtsnPin	= GPIOD_Pin0,					//串口接收流控脚
		.ctsnPin	= GPIOD_Pin1,					//串口发送流控脚
#else
		.rtsnPin	= GPIO_INVAILD, 				//串口接收流控脚
		.ctsnPin	= GPIO_INVAILD, 				//串口发送流控脚
#endif

		.rxPin		= GPIOD_Pin2,					//串口接收脚
		.txPin		= GPIOD_Pin3					//串口发送脚
	};
	Config.boaud_rate	= get_baudrate();
	ui_uart_configuration(APP_UART,&Config,on);
#endif

}
