//mqx_uart_polled.c

#include "mqx.h"
#include "bsp.h"
#include "fio.h"
#include "io.h"
#include "ioctl.h"

#include "uart.h"
#include "mqx_uart.h"
uint_8 UARTISR_NUM[6] = {61,63,65,67,69,71};

// 定义内部函数
static _mqx_int _io_uart_open(MQX_FILE_PTR, char_ptr, char_ptr);
static _mqx_int _io_uart_close(MQX_FILE_PTR);
static _mqx_int _io_uart_read(MQX_FILE_PTR, char_ptr, _mqx_int);
static _mqx_int _io_uart_write(MQX_FILE_PTR, char_ptr,_mqx_int);
static _mqx_int _io_uart_ioctl(MQX_FILE_PTR, _mqx_uint, pointer);

// 安装UART驱动
_mqx_uint _io_uart_install(char_ptr identifier, UART_POLLED_INIT_PTR uart_polled_ptr)   
{
    _mqx_uint result;
    
    result = _io_dev_install(identifier,
          _io_uart_open,
          _io_uart_close,
          _io_uart_read,
          _io_uart_write,
          _io_uart_ioctl,
          (pointer)uart_polled_ptr); 
    
    return result;
}

// 打开UART设备
_mqx_int _io_uart_open(MQX_FILE_PTR fd_ptr, char_ptr open_name_ptr, char_ptr flags)
{
    IO_DEVICE_STRUCT_PTR dev_ptr = fd_ptr->DEV_PTR;
    UART_POLLED_INIT_PTR init_ptr = (UART_POLLED_INIT_PTR)(dev_ptr->DRIVER_INIT_PTR);
    
    // 创建接收缓冲队列
    init_ptr->CHARQ = (CHARQ_STRUCT_PTR)_mem_alloc_system((_mem_size)(
            sizeof(CHARQ_STRUCT) - (4 * sizeof(char)) + init_ptr->QUEUE_SIZE));
    _mem_set_type(init_ptr->CHARQ,MEM_TYPE_IO_SERIAL_CHARQ);
    _CHARQ_INIT(init_ptr->CHARQ, init_ptr->QUEUE_SIZE);
    
    // 初始化硬件设备
    uart_init(init_ptr->UART_NO, init_ptr->CLK_KHZ/1000, init_ptr->BAUD_RATE);
    
	// 启动串口接收中断
	uart_enable_re_int(init_ptr->UART_NO);
	_bsp_int_init(UARTISR_NUM[init_ptr->UART_NO], 3, 0, TRUE);
    	
    return (MQX_OK);
}

_mqx_int _io_uart_close(MQX_FILE_PTR fd_ptr)
{
    IO_DEVICE_STRUCT_PTR dev_ptr = fd_ptr->DEV_PTR;
    UART_POLLED_INIT_PTR init_ptr = (UART_POLLED_INIT_PTR)(dev_ptr->DRIVER_INIT_PTR);
    
    // 关闭硬件设备
    uart_deinit(init_ptr->UART_NO);  
    
    // 释放保持资源
    _mem_free(init_ptr->CHARQ);
    init_ptr->CHARQ = NULL;
    
    return (MQX_OK);
}

// 从设备读数据
_mqx_int _io_uart_read(MQX_FILE_PTR fd_ptr, char_ptr data_ptr, _mqx_int num)
{
    IO_DEVICE_STRUCT_PTR dev_ptr = fd_ptr->DEV_PTR;
    UART_POLLED_INIT_PTR init_ptr = (UART_POLLED_INIT_PTR)(dev_ptr->DRIVER_INIT_PTR);
    _mqx_uint  i = num; 
    uchar      ch;
    uint_8 flag = 1;
    while (i)
    {
        while ((! _CHARQ_FULL(init_ptr->CHARQ)) )//&& uart_status(init_ptr->UART_NO)
        {
            ch = uart_re1(init_ptr->UART_NO,&flag);  
            if (CNTL_S == ch)
            {
                while (CNTL_Q != ch)
                {
                    ch = (uchar)uart_re1(init_ptr->UART_NO,&flag);      
                    if (CNTL_Q != ch)
                    {
                        _CHARQ_ENQUEUE(init_ptr->CHARQ, ch);
                    }
                }
            } // end_if
            else 
            {
                _CHARQ_ENQUEUE(init_ptr->CHARQ, ch);
            }
        } // end_while
      
        if ( _CHARQ_SIZE(init_ptr->CHARQ) ) 
        {
            _CHARQ_DEQUEUE(init_ptr->CHARQ, ch);
            if ('\r' == ch) 
            {  
                ch = '\n';
            } 
            *data_ptr++ = ch;
            --i;
        }
   }// end_while
   return num;
    
}

_mqx_int _io_uart_write(MQX_FILE_PTR fd_ptr, char_ptr data_ptr, _mqx_int num )
{
    IO_DEVICE_STRUCT_PTR dev_ptr = fd_ptr->DEV_PTR;
    UART_POLLED_INIT_PTR init_ptr = (UART_POLLED_INIT_PTR)(dev_ptr->DRIVER_INIT_PTR);
    uchar ch;
    _mqx_uint   i = num + 1;
    uint_8 flag = 1;
   while (--i) 
   {
        while ((! _CHARQ_FULL(init_ptr->CHARQ)) ) //2014.05.15&& uart_status(init_ptr->UART_NO)
        {
            ch = uart_re1(init_ptr->UART_NO,&flag);
            if (CNTL_S == ch) 
            {
                while (CNTL_Q != ch) 
                {
                    ch = (uchar)uart_re1(init_ptr->UART_NO,&flag); 
                    if (CNTL_Q != ch) 
                    {
                        _CHARQ_ENQUEUE(init_ptr->CHARQ, ch);
                    }
                } // end_while
            } 
            else 
            {
                _CHARQ_ENQUEUE(init_ptr->CHARQ,ch);
            } // end_if
        } // end_while
        
        if (*data_ptr == '\n') 
        {
            uart_send1(init_ptr->UART_NO, '\r');
        }
        uart_send1(init_ptr->UART_NO, *data_ptr++);
    } // end_while     
   return num;
}

_mqx_int _io_uart_ioctl(MQX_FILE_PTR fd_ptr, _mqx_uint cmd, pointer param_ptr)
{
	_mqx_int ret;
	switch (cmd)
	{
	    case IO_IOCTL_CHAR_AVAIL:  // 查看是否有数据未接收
	    	
	    	ret = IO_OK;
	    	break;
	    default:
	    	ret = IO_ERROR_INVALID_IOCTL_CMD;
	    	break;
	} // end_switch
	
	return ret;
}
