/*!
 * \file      dc5v_uart.c
 * \brief     DC5V_UART driver interface
 * \details
 * \author    
 * \date
 * \copyright Actions
 */

#include "dc5v_uart.h"


dc5v_uart_context_t  dc5v_uart_context;


static void debug_dump_reg(void)
{
	printk("rst: 0x%x\n", sys_read32((0x40000000)));
	printk("clk: 0x%x\n", sys_read32((0x40001004)));

    //dump uart1 reg
    printk("ctl: 0x%x\n", sys_read32((0x4003c000 + 0x0)));
	printk("rx: 0x%x\n", sys_read32((0x4003c000 + 0x4)));
	printk("tx: 0x%x\n", sys_read32((0x4003c000 + 0x8)));
	printk("stat: 0x%x\n", sys_read32((0x4003c000 + 0x0c)));
	printk("br: 0x%x\n", sys_read32((0x4003c000 + 0x10)));

	//dump pmu reg
	printk("gdc5v: 0x%x\n", sys_read32((0x40068000 + 0x310)));
    printk("sys_set: 0x%x\n", sys_read32((0x40004000 + 0x108)));	

#if 1
	printk("pmu_det: 0x%x\n", sys_read32((0x40004000 + 0x10)));
	printk("ch_ctl: 0x%x\n", sys_read32((0x40004000 + 0x100)));
    printk("pmu sys_set: 0x%x\n", sys_read32((0x40004000 + 0x108)));
	printk("wk_ctl: 0x%x\n", sys_read32((0x40004000 + 0x110)));
	printk("wk_pd: 0x%x\n", sys_read32((0x40004000 + 0x114)));
	printk("cmu_s1: 0x%x\n", sys_read32((0x40001000 + 0xd0)));
#endif

}


static u32_t get_diff_time(u32_t end_time, u32_t begin_time)
{
    u32_t  diff_time;
    
    if (end_time >= begin_time)
    {
        diff_time = (end_time - begin_time);
    }
    else
    {
        diff_time = ((u32_t)-1 - begin_time + end_time + 1);
    }

    return diff_time;
}


/**
**	set register in pmusvcc 
**/
void sys_svcc_reg_write(u32_t reg_addr, u32_t mask, u32_t value)
{
    u32_t  tmp = sys_read32(reg_addr);
    int    i;

    tmp = (tmp & ~mask) | (value & mask);

    for (i = 0; i < 10; i++)
    {
        sys_write32(tmp, reg_addr);

        os_delay(200);

        if ((sys_read32(reg_addr) & mask) == (tmp & mask))
        {
            break;
        }
    }
}

/**
**	设置DC5V Uart切换电压
**/
void dc5v_uart_set_switch_volt(u32_t switch_volt)
{
    if (switch_volt != DC5V_UART_SWITCH_VOLT_NA)
    {
        sys_svcc_reg_write
        (
            (u32_t)PMU_WKUP_CTL_REG, 
            ((WKEN_CTL_DC5V_LHV_VOL_MASK) | 
             WKEN_CTL_DC5VLV_WKEN
            ), 
            ((switch_volt << WKEN_CTL_DC5V_LHV_VOL_SHIFT) | 
             WKEN_CTL_DC5VLV_WKEN)
        );
    }
    else
    {
        sys_svcc_reg_write
        (
            (u32_t)PMU_WKUP_CTL_REG,  
            WKEN_CTL_DC5VLV_WKEN, 
            (0 << WKEN_CTL_DC5VLV_WKEN_SHIFT)
        );
    }
    
    /* Must delay some time to take effect?
     */
    os_sleep(10);

	printk("wkup_ctl: 0x%x", sys_read32(PMU_WKUP_CTL_REG));
}

/**
**	将DC5V Uart 设置到RX模式
**/
void dc5v_uart_set_rx_mode(void)
{
    u32_t  key = irq_lock();

    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    printk("Switch to RX!");
	
    dc5v_uart->trx_mode = DC5V_UART_RX_MODE;

    //MFP
    dc5v_uart->bak_GPIO_DC5V_CTL &= ~DC5V_CTL_AD_SEL;
    dc5v_uart->bak_GPIO_DC5V_CTL &= ~DC5V_CTL_MFP_MASK;

    if(strcmp(CONFIG_UART_DC5V_ON_DEV_NAME, "UART_1") == 0)
    {
	    dc5v_uart->bak_GPIO_DC5V_CTL |= DC5V_CTL_MFP_UART1RX;
    }
	else
	{
	    dc5v_uart->bak_GPIO_DC5V_CTL |= DC5V_CTL_MFP_UART2RX;
	}
    //dc5v_uart->bak_GPIO_DC5V_CTL |= DC5V_CTL_10KPU_EN;

	sys_write32(dc5v_uart->bak_GPIO_DC5V_CTL, GPIO_DC5V_CTL_REG);

    irq_unlock(key);
}

/**
**	将DC5V Uart 设置到TX模式
**/
static inline void dc5v_uart_set_tx_mode(void)
{
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

	printk("Switch to TX!");

    k_timer_stop(&dc5v_uart->tx_context.tx_check_timer);

    if (dc5v_uart->trx_mode != DC5V_UART_TX_MODE)
    {
        dc5v_uart->trx_mode = DC5V_UART_TX_MODE;
        
        //MFP
        dc5v_uart->bak_GPIO_DC5V_CTL &= ~DC5V_CTL_AD_SEL;
        dc5v_uart->bak_GPIO_DC5V_CTL &= ~DC5V_CTL_MFP_MASK;

        if(strcmp(CONFIG_UART_DC5V_ON_DEV_NAME, "UART_1") == 0)
        {
	        dc5v_uart->bak_GPIO_DC5V_CTL |= DC5V_CTL_MFP_UART1TX;
        }
		else
		{
		    dc5v_uart->bak_GPIO_DC5V_CTL |= DC5V_CTL_MFP_UART2TX;
		}
		//dc5v_uart->bak_GPIO_DC5V_CTL |= DC5V_CTL_10KPU_EN;

	    sys_write32(dc5v_uart->bak_GPIO_DC5V_CTL, GPIO_DC5V_CTL_REG);		

        k_timer_stop(&dc5v_uart->tx_context.tx_switch_timer);

		dc5v_uart->tx_context.tx_switch_finish = false;
        k_timer_start(&dc5v_uart->tx_context.tx_switch_timer, K_USEC(200), K_NO_WAIT);
    }
}

/**
**	使能或关闭DC5V Uart功能
**/
void dc5v_uart_set_enable(bool enable)
{
    u32_t  key = irq_lock();

    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    if (enable)
    {
        printk("enable DC5V Uart!\n\n\n\n\n");

		#if 0
        dc5v_uart->bak_PMU_SYSTEM_SET_SVCC |= (SYSSET_UART_SW_SEL | SYSSET_UART_SW_MODE | SYSSET_UART_PWR_SEL);
        #else
		dc5v_uart->bak_PMU_SYSTEM_SET_SVCC &= (~SYSSET_UART_SW_MODE);
        dc5v_uart->bak_PMU_SYSTEM_SET_SVCC |= SYSSET_UART_SW_SEL;
        #endif
		
		sys_write32(dc5v_uart->bak_PMU_SYSTEM_SET_SVCC, PMU_SYS_SET_REG);
	
        /* Default set RX mode
         */
        dc5v_uart_set_rx_mode();
    }
    else
    {
        //switch to dc5v analog func
        printk("disable DC5V Uart!\n\n\n\n\n");
		
        dc5v_uart->bak_GPIO_DC5V_CTL |= DC5V_CTL_AD_SEL;
        sys_write32(dc5v_uart->bak_GPIO_DC5V_CTL, GPIO_DC5V_CTL_REG);
    }
    
    irq_unlock(key);
}

/**
**	dc5v uart 将buffer数据输出
**/
int dc5v_uart_writedata(struct device *uart, const u8_t* buf, u32_t len, u32_t wait_end)
{
	dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    while(uart_acts_dma_send_complete((struct device *)dc5v_uart->tx_context.tx_dev) == 0)
    {
	    printk("wait tx dma finish!");
    }

	uart_dma_send((struct device *)dc5v_uart->tx_context.tx_dev, (char*)buf, len);

    if (wait_end != 0)
    {
        /* 等待 TX FIFO 所有数据传输完成 */
        while (uart_irq_tx_complete(dc5v_uart->tx_context.tx_dev) == 0)
            ;
    }

    return len;
}

/**
**	dc5v uart 切换到tx模式完成
**/
void dc5v_uart_tx_switch_complete(struct k_timer *timer)
{
    u32_t key = irq_lock();

    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

	k_timer_stop(&dc5v_uart->tx_context.tx_switch_timer);
	
    if (dc5v_uart->tx_context.tx_buf != NULL)
    {
        u8_t*  tx_buf = dc5v_uart->tx_context.tx_buf;
        u16_t  tx_len = dc5v_uart->tx_context.tx_len;

        dc5v_uart->tx_context.tx_buf = NULL;
        dc5v_uart->tx_context.tx_len = 0;
        
        dc5v_uart_writedata((struct device *)dc5v_uart->tx_context.tx_dev, tx_buf, tx_len, 0);
    }

	dc5v_uart->tx_context.tx_switch_finish = true;

    irq_unlock(key);
}

/**
**	延时到后,关闭dc5v uart
**/
void dc5v_uart_delay_disable(struct k_timer *timer)
{
    u32_t  key = irq_lock();

    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    dc5v_uart->enabled = NO;

    k_timer_stop(&dc5v_uart->disable_timer);

    dc5v_uart_set_enable(NO);

    irq_unlock(key);
}


/**
**	重启disable timer
**/
static inline void dc5v_uart_reset_delay_disable(void)
{
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    if (dc5v_uart->disable_delay_ms > 0)
    {
        k_timer_stop(&dc5v_uart->disable_timer);
        k_timer_start(&dc5v_uart->disable_timer, K_USEC(dc5v_uart->disable_delay_ms * 1000), K_NO_WAIT);
    }
}

static inline int dc5v_uart_tx_write(void* buf, int len)
{
    u32_t  key = irq_lock();
    
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;
    
    int  ret_val = 0;
    
	// last dma not finish
	if(uart_acts_dma_send_complete((struct device *)dc5v_uart->tx_context.tx_dev) == 0)	
    {
        goto end;
    }
    
    dc5v_uart_set_tx_mode();
    
    if (!dc5v_uart->tx_context.tx_switch_finish)
    {
        dc5v_uart->tx_context.tx_buf = (u8_t*)buf;
        dc5v_uart->tx_context.tx_len = (u16_t)len;
    }
    else
    {
        dc5v_uart_writedata((struct device *)dc5v_uart->tx_context.tx_dev, buf, len, 0);
    }

    dc5v_uart->last_io_time = k_uptime_get_32();
    
    dc5v_uart_reset_delay_disable();
    
    ret_val = len;

end:
    irq_unlock(key);

    return ret_val;
}


/**
**	检查DC5V Uart的写操作是否完成
**/
bool dc5v_uart_check_write_finish(void)
{
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

	if(uart_acts_dma_send_complete((struct device *)dc5v_uart->tx_context.tx_dev) == 0)
	{
	    return NO;
	}
	
    if(uart_irq_tx_complete(dc5v_uart->tx_context.tx_dev) == 0)
    {
        return NO;
    }
    
    return YES;
}


/**
**	DC5V Uart 写接口
**/
int dc5v_uart_api_write(struct device* uart, const u8_t* buf, u32_t len, u32_t flags)
{
    int   ret_val;
        
    if (buf == NULL || len == 0)
    {
        return 0;
    }
	
    do
    {
        ret_val = dc5v_uart_tx_write((void*)buf, len);
    }
    while (ret_val == 0 && (!k_is_in_isr()));

    if (ret_val != 0 &&
        flags   != 0)
    {
        while (!dc5v_uart_check_write_finish())
            ;
    }

    return ret_val;
}


void re_config_uart_param(u32_t baudrate)
{
	struct uart_config uart_cfg;
	dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    uart_cfg.baudrate = baudrate;
	uart_cfg.parity = dc5v_uart->cfg.DC5V_UART_Parity_Select;
    uart_cfg.stop_bits = UART_CFG_STOP_BITS_1;
	uart_cfg.data_bits = UART_CFG_DATA_BITS_8;
	uart_cfg.flow_ctrl = UART_CFG_FLOW_CTRL_NONE;	

	printk("config DC5V Uart BR: %d\n", uart_cfg.baudrate);

    uart_configure(dc5v_uart->tx_context.tx_dev, &uart_cfg);

	dc5v_uart->baud_rate = uart_cfg.baudrate;
}


int dc5v_uart_api_ioctl(struct device* uart, u32_t mode, void* param1, void* param2)
{
    int ret = 0;
	dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    if (dc5v_uart->dc5v_uart_init == 0)
    {
        return 0;
    }

    switch (mode)
    {
        case UART_SET_BAUDRATE:
		if(param1 == (void*)0)
		{
		    param1 = (void*)dc5v_uart->cfg.DC5V_UART_Comm_Baudrate;
		}
		if((u32_t)param1 != dc5v_uart->baud_rate)
		{
            re_config_uart_param((u32_t)param1);
		}
        break;

        case UART_CHECK_WRITE_FINISH:
        ret = dc5v_uart_check_write_finish();
        break;

        case UART_IS_RX_FIFO_EMPTY:
        if(uart_irq_rx_ready(dc5v_uart->rx_context.rx_dev))
		{
			ret = 0;
		}
		else
		{
		    ret = 1;
		}
        break;

        case UART_RX_DMA_ACCESS_SWITCH:
        if ((u32_t)param1)
        {
            uart_rx_dma_switch((struct device *)dc5v_uart->rx_context.rx_dev, TRUE, NULL, NULL);
        }
        else
        {
            uart_rx_dma_switch((struct device *)dc5v_uart->rx_context.rx_dev, FALSE, NULL, NULL);
        }
        break;

        default:
        break;
    }

    return ret;
}


/**
**	tx finish check timer
**/
void dc5v_uart_check_tx_complete(struct k_timer *timer)
{
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;
    
	k_timer_stop(&dc5v_uart->tx_context.tx_check_timer);

    if(uart_irq_tx_complete(dc5v_uart->tx_context.tx_dev) != 0)
    {
        dc5v_uart_set_rx_mode();
    }
    else
    {
		k_timer_start(&dc5v_uart->tx_context.tx_check_timer, K_USEC(200), K_NO_WAIT);	
    }
}


/**
**	tx dma handle
**/
void dc5v_uart_tx_dma_handler(const struct device *dev, void *user_data,
					   u32_t channel, int status)
{
    if (status == DC5V_UART_DMA_IRQ_TC)
    {
		u32_t key = irq_lock();
        
        dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

		k_timer_stop(&dc5v_uart->tx_context.tx_check_timer);
		k_timer_start(&dc5v_uart->tx_context.tx_check_timer, K_USEC(200), K_NO_WAIT);

        irq_unlock(key);
    }
}

/**
**	start dma to receive data
**/
void uart_ctrl_rx_dma_start(struct device *dev)
{
    uart_rx_dma_switch(dev, TRUE, NULL, NULL);
    uart_dma_receive(dev, dc5v_uart_context.rx_context.dma_buf, UART_CTRL_RX_DMA_BUF_SIZE);

    /* 定时一小段时间后将 DMA 接收的数据保存至 data_buf
     */
    k_timer_start(&dc5v_uart_context.rx_context.rx_timer, K_USEC(UART_CTRL_RX_DMA_TIMER_US), K_NO_WAIT);
}

/**
**	dc5v uart rx irq handle
**/
void dc5v_uart_rx_irq_handler(struct device *dev, void *user_data)
{
    u32_t  key = irq_lock();
	
    /* 暂时禁止 RX 中断
     */
    uart_irq_rx_disable(dev);

    /* 启用 DMA 进行数据接收
     */
    uart_ctrl_rx_dma_start(dev);

    irq_unlock(key);
}

/**
**	dc5v uart irq handle
**/
static void dc5v_uart_irq_callback(const struct device *dev, void *user_data)
{
    //printk("rx irq!\n");

	uart_irq_update(dev);

	if (uart_irq_rx_ready(dev)) {
		dc5v_uart_rx_irq_handler((struct device *)dev, user_data);
	}
}

void uart_ctrl_rx_timer_handler(struct k_timer *timer)
{
    u32_t  key = irq_lock();

	dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;
	struct device* dev = (struct device *)dc5v_uart->rx_context.rx_dev;

    int   len, count;


    /* 读取 DMA 接收到的数据之前先禁止 DRQ ?
     */
	uart_dma_receive_drq_switch(dev, FALSE);

    /* 等待当前正在进行的 DMA 传输完成?
     */
    k_busy_wait(1);

    k_timer_stop(&dc5v_uart->rx_context.rx_timer);

	count = uart_dma_receive_stop(dev);

    /* DMA 当前已接收到的数据?
     */
	len = UART_CTRL_RX_DMA_BUF_SIZE - count;

    if (len > 0)
    {
        /* 保存至 data_buf
         */
        //printk("put: 0x%x--%d\n", dc5v_uart->rx_context.dma_buf[0], len);
		ring_buf_put(&dc5v_uart->rx_context.rx_rbuf, dc5v_uart->rx_context.dma_buf, len);
    }
    /* RX_FIFO 中还有剩余数据时使用 CPU 进行读取
     */
    else
    {
        uart_rx_dma_switch(dev, FALSE, NULL, NULL);
        count = uart_fifo_read(dev, dc5v_uart->rx_context.dma_buf, UART_CTRL_RX_DMA_BUF_SIZE);

        if(count > 0)
        {
		    //printk("put2: 0x%x--%d\n", dc5v_uart->rx_context.dma_buf[0],count);
            ring_buf_put(&dc5v_uart->rx_context.rx_rbuf, dc5v_uart->rx_context.dma_buf, count);
			len += count;
        }
    }

    if (len > 0)
    {
        /* 重新使能 DRQ
        */
        uart_dma_receive_drq_switch(dev, TRUE);
        /* 重新启用 DMA 接收数据
         */
        uart_ctrl_rx_dma_start(dev);
    }
    else
    {
        /* 重新使能 RX 中断
         */
        uart_irq_rx_enable(dev);
    }

    irq_unlock(key);
}


/**
**	rx timer handle
**/
void dc5v_uart_rx_timer_handler(struct k_timer *timer)
{
    u32_t  key = irq_lock();
    
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    u32_t  data_count = UART_CTRL_RX_DATA_BUF_SIZE - ring_buf_space_get(&dc5v_uart->rx_context.rx_rbuf);

    uart_ctrl_rx_timer_handler(timer);

    if ((UART_CTRL_RX_DATA_BUF_SIZE - ring_buf_space_get(&dc5v_uart->rx_context.rx_rbuf)) > data_count)
    {
        dc5v_uart->last_io_time = k_uptime_get_32();
        dc5v_uart_reset_delay_disable();
    }

    irq_unlock(key);
}


/**
**	read data by dc5v uart
**/
int dc5v_uart_rx_timed_read(void* buf, u32_t len, u32_t timeout_ms)
{
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    int    count = 0;
    u32_t  t;

    if (dc5v_uart->dc5v_uart_init == 0)
    {
        return 0;
    }

    printk("DC5V Uart Read!");

    t = k_uptime_get_32();

    while (count < len)
    {
        u8_t*  ptr;
        int    n;

        if (buf != NULL)
        {
            ptr = (u8_t*)buf + count;
        }
        else
        {
            ptr = NULL;
        }
        
        n = ring_buf_get(&dc5v_uart->rx_context.rx_rbuf, ptr, len - count);
        
        if (n <= 0)
        {
            os_sleep(1);
        
            n = ring_buf_get(&dc5v_uart->rx_context.rx_rbuf, ptr, len - count);
        }
        
        if (n > 0)
        {
            count += n;
            t = k_uptime_get_32();
        }
        else
        {
            if (get_diff_time(k_uptime_get_32(), t) >= timeout_ms)
            {
                break;
            }
        }
    }

    return count;
}

/**
**	clear dc5v uart rx buffer
**/
void dc5v_uart_clear_rx_buf(u32_t wait_ms)
{
    u32_t  key;
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;
    struct ring_buf*  rx_buf = &dc5v_uart->rx_context.rx_rbuf;

    if (wait_ms > 0)
    {
        os_sleep(wait_ms);
    }

    key = irq_lock();

	ring_buf_reset(rx_buf);

    irq_unlock(key);
}

/**
**	dc5v uart suspend
**/
void dc5v_uart_ctrl_suspend(void)
{
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    if (!dc5v_uart->suspended)
    {
        dc5v_uart->suspended = YES;
    
        while (!dc5v_uart_check_write_finish())
            ;

        dc5v_uart_set_enable(NO);
        dc5v_uart_set_switch_volt(DC5V_UART_SWITCH_VOLT_NA);

    }
}


void dc5v_uart_ctrl_resume(void)
{
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    if (dc5v_uart->suspended)
    {
        dc5v_uart->suspended = NO;
    
        dc5v_uart_set_switch_volt(dc5v_uart->cfg.DC5V_UART_Switch_Voltage);
        dc5v_uart_set_enable(dc5v_uart->enabled);
        
        dc5v_uart_clear_rx_buf(10);
    }
}

void dc5v_uart_set_rx_buf_size(u32_t buf_size)
{
    u32_t  key = irq_lock();

    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    if ((u32_t)dc5v_uart->rx_context.rx_rbuf.buf.buf32 != (u32_t)dc5v_uart->rx_context.data_buf)
    {
        app_mem_free((void*)dc5v_uart->rx_context.rx_rbuf.buf.buf32);
    }

    if (buf_size <= UART_CTRL_RX_DATA_BUF_SIZE)
    {
        ring_buf_init(&dc5v_uart->rx_context.rx_rbuf, UART_CTRL_RX_DATA_BUF_SIZE, dc5v_uart->rx_context.data_buf);
    }
    else
    {
        void*  data_buf = app_mem_malloc(buf_size);
        
        ring_buf_init(&dc5v_uart->rx_context.rx_rbuf, buf_size, data_buf);
    }

    irq_unlock(key);
}


void dc5v_uart_set_enable_ex(bool enable, u32_t delay_disable)
{
    u32_t  key = irq_lock();

    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    if (enable)
    {
        //dc5v_uart->disable_delay_ms = 0;
        k_timer_stop(&dc5v_uart->disable_timer);

        if (!dc5v_uart->enabled)
        {
            dc5v_uart->enabled = YES;
            dc5v_uart_set_enable(YES);
        }
    }
    else
    {
        dc5v_uart->disable_delay_ms = delay_disable;		
        k_timer_stop(&dc5v_uart->disable_timer);
        k_timer_start(&dc5v_uart->disable_timer, K_USEC(dc5v_uart->disable_delay_ms * 1000), K_NO_WAIT);
    }

    irq_unlock(key);
}

bool dc5v_uart_check_io_time(u32_t ms)
{
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    if (dc5v_uart->disable_delay_ms > 0)
    {
        return YES;
    }

    if (dc5v_uart->redirect_console_print &&
        dc5v_uart->enabled &&
        dc5v_uart->suspended == NO)
    {
        return YES;
    }

    if (dc5v_uart->last_io_time != 0 &&
        get_diff_time(k_uptime_get_32(), dc5v_uart->last_io_time) < ms)
    {
        return YES;
    }

    return NO;
}



int dc5v_uart_rx_read_byte(u8_t* byte)
{
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;
	uart_ctrl_rx_context_t*  rx = &dc5v_uart->rx_context;

    if (ring_buf_get(&rx->rx_rbuf, byte, 1) != 0)
    {
        printk("Read 1byte: 0x%x\n", *byte);
        return 1;
    }

    return 0;
}


void dc5v_uart_rx_deal(void)
{
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;
	uart_ctrl_rx_context_t*  rx = &dc5v_uart->rx_context;
	u8_t  byte;

    while(dc5v_uart->rxdeal_need_quit == 0)
    {
        if(ring_buf_is_empty(&dc5v_uart->rx_context.rx_rbuf))
        {
            os_sleep(20);
            continue;
        }

        if (dc5v_uart_rx_read_byte(&byte) == 0)
        {
            continue;
        }

        if (rx->rx_data_handler != NULL)
        {
            //printk("Handle: %d", byte);
            rx->rx_data_handler(byte);
        }
    }

    dc5v_uart->rxdeal_quited = 1;

	printk("RX deal thread Exit!\n\n");
	
    return;
}


/**	init
**/
bool dc5v_uart_ctrl_init(CFG_Type_DC5V_UART_Comm_Settings* cfg)
{
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    if (dc5v_uart_context.dc5v_uart_init != 0)
    {
        return YES;
    }

    if (cfg->Enable_DC5V_UART_Comm_Mode == NO ||
        cfg->DC5V_UART_Switch_Voltage == DC5V_UART_SWITCH_VOLT_NA ||
        cfg->DC5V_UART_Comm_Baudrate < 1000)
    {
        return NO;
    }

    cfg->Redirect_Console_Print = 0;

    memset(dc5v_uart, 0, sizeof(dc5v_uart_context_t));

	dc5v_uart->bak_PMU_SYSTEM_SET_SVCC = sys_read32(PMU_SYS_SET_REG);
	dc5v_uart->bak_GPIO_DC5V_CTL = sys_read32(GPIO_DC5V_CTL_REG);	

    dc5v_uart->cfg = *cfg;

    /* DC5V_UART_DEV
     */
	dc5v_uart->tx_context.tx_dev = (struct device *)device_get_binding(CONFIG_UART_DC5V_ON_DEV_NAME);
    dc5v_uart->rx_context.rx_dev = (struct device *)device_get_binding(CONFIG_UART_DC5V_ON_DEV_NAME);

    /* tx config
     */
    k_timer_init(&dc5v_uart->tx_context.tx_check_timer, dc5v_uart_check_tx_complete, NULL);
	k_timer_init(&dc5v_uart->tx_context.tx_switch_timer, dc5v_uart_tx_switch_complete, NULL);
	k_timer_init(&dc5v_uart->disable_timer, dc5v_uart_delay_disable, NULL);

    uart_dma_send_init((struct device *)dc5v_uart->tx_context.tx_dev, dc5v_uart_tx_dma_handler, NULL);
	uart_tx_dma_switch((struct device *)dc5v_uart->tx_context.tx_dev, TRUE, NULL, NULL);

    /* rx config
     */
	ring_buf_init(&dc5v_uart->rx_context.rx_rbuf, UART_CTRL_RX_DATA_BUF_SIZE, dc5v_uart->rx_context.data_buf);	

    k_timer_init(&dc5v_uart->rx_context.rx_timer, dc5v_uart_rx_timer_handler, NULL);

	uart_dma_receive_init((struct device *)dc5v_uart->rx_context.rx_dev,	NULL, NULL);
	uart_rx_dma_switch((struct device *)dc5v_uart->rx_context.rx_dev, FALSE, NULL, NULL);

	uart_irq_callback_set(dc5v_uart->rx_context.rx_dev, dc5v_uart_irq_callback);
	uart_irq_rx_enable(dc5v_uart->rx_context.rx_dev);

    /* reconfig uart param
    */
	re_config_uart_param(dc5v_uart->cfg.DC5V_UART_Comm_Baudrate);
	
    /*	set switch volt
     */
    dc5v_uart_set_switch_volt(cfg->DC5V_UART_Switch_Voltage);
	
    if (cfg->Redirect_Console_Print)
    {
        dc5v_uart_set_enable((dc5v_uart->enabled = YES));
        dc5v_uart_clear_rx_buf(10);
    }
    else
    {
        dc5v_uart_set_enable((dc5v_uart->enabled = NO));
    }

	dc5v_uart->dc5v_uart_init = 1;

    return YES;
}


static void dc5v_uart_start_rxdeal(void)
{
	dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;

    if (dc5v_uart->dc5v_uart_init != 0)
    {
        dc5v_uart->rxdeal_need_quit = 0;
		dc5v_uart->rxdeal_quited = 0;
	    dc5v_uart->rxdeal_thread_stack = app_mem_malloc(1024);

	    os_thread_create(dc5v_uart->rxdeal_thread_stack, UART_RX_DATADEAL_STACK,
			    (void *)dc5v_uart_rx_deal, NULL, NULL, NULL, UART_RX_THREAD_PRIO, 0, 0);

        #if 1
        dc5v_uart_set_enable((dc5v_uart->enabled = YES));
	    dc5v_uart_clear_rx_buf(10);	
        #endif

        debug_dump_reg();
    }
	else
	{
	    printk("Err: dc5v uart not init!\n");
	}
}

static void dc5v_uart_stop_rxdeal(void)
{
    dc5v_uart_context_t*  dc5v_uart = &dc5v_uart_context;
	
	if (!dc5v_uart->rxdeal_thread_stack)
	{
		return;
	}

	dc5v_uart->rxdeal_need_quit = 1;
	while (!dc5v_uart->rxdeal_quited)
		os_sleep(1);

	app_mem_free(dc5v_uart->rxdeal_thread_stack);
	dc5v_uart->rxdeal_thread_stack = NULL;
}

int dc5v_uart_operate(u32_t cmd, void* param1, u32_t param2, u32_t param3)
{
    int  ret_val = 0;
    
    if (cmd == DC5V_UART_INIT)
    {
        ret_val = dc5v_uart_ctrl_init(param1);
        return ret_val;
    }

    if (dc5v_uart_context.dc5v_uart_init == 0)
    {
        printk("not init yet!");
        return 0;
    }

    switch (cmd)
    {
        case DC5V_UART_SUSPEND:
        {
            dc5v_uart_ctrl_suspend();
            break;
        }
        
        case DC5V_UART_RESUME:
        {
            dc5v_uart_ctrl_resume();
            break;
        }
        
        case DC5V_UART_SET_RX_DATA_HANDLER:
        {
            dc5v_uart_context.rx_context.rx_data_handler = param1;
            break;
        }

        case DC5V_UART_SET_RX_BUF_SIZE:
        {
            dc5v_uart_set_rx_buf_size(param2);
            break;
        }
        
        case DC5V_UART_READ:          
        {
            ret_val = dc5v_uart_rx_timed_read(param1, param2, param3);
            break;
        }

        case DC5V_UART_WRITE:         
        {
            ret_val = dc5v_uart_api_write(NULL, param1, param2, param3);
            break;
        }

        case DC5V_UART_IOCTL:
        {
            ret_val = dc5v_uart_api_ioctl
            (
                NULL, (u32_t)param1, (void*)param2, (void*)param3
            );
            break;
        }

        case DC5V_UART_CHECK_IO_TIME:
        {
            ret_val = dc5v_uart_check_io_time(param2);
            break;
        }

        case DC5V_UART_SET_ENABLE:
        {
            dc5v_uart_set_enable_ex(param2, param3);
            break;
        }

		case DC5V_UART_RUN_RXDEAL:
		{
		    dc5v_uart_start_rxdeal();
			break;
		}

		case DC5V_UART_STOP_RXDEAL:
		{
		    dc5v_uart_stop_rxdeal();
			break;
		}		
    }
    
    return ret_val;
}