//===========================================================================
//文件名称：uart.c
//功能概要：UART底层驱动构件源文件
//版权所有：苏州大学飞思卡尔嵌入式中心(sumcu.suda.edu.cn)
//更新记录：2012-10-30   V2.0
//===========================================================================
#include "uart.h"

// UART IO引脚配置命令
#define IO_UART_PIN_MUX_ENABLE                (0x01)
#define IO_UART_PIN_MUX_DISABLE               (0x02)
#define IO_UART_CLOCK_ENABLE                  (0x04)   
#define IO_UART_CLOCK_DISABLE                 (0x08)   
#define IO_UART_MODULE_ENABLE                 (0x10)   
#define IO_UART_WAKEUP_ENABLE                 (0x20)   
#define IO_UART_WAKEUP_SLEEPONEXIT_DISABLE    (0x40) 

// 从串口号到串口寄存器组指针的映射
const UART_MemMapPtr UART_PTR[UART_MAX_NUM] = 
{
    UART0_BASE_PTR,
    UART1_BASE_PTR,
    UART2_BASE_PTR,
    UART3_BASE_PTR,
    UART4_BASE_PTR,
    UART5_BASE_PTR
};

// 串口中断irq号映射表
const uint_8 table_irq_uart[UART_MAX_NUM] = {45, 47, 49, 51, 53, 55};

// 内部函数声明
static void uart_enable (uint_8 uartNo);
static void uart_disable(uint_8 uartNo);

//=========================================================================
//函数名称：uart_init                                                        
//功能概要：初始化uartx模块。                                                
//参数说明：uartNo:串口号:0 ~ 5   
//          clk_khz:模块总线频率，如bus总线频率48000Khz
//          baud_rate:波特率，如9600，38400等，一般来说，速度越慢，通信越稳       
//函数返回：函数执行状态：0=正常；非0=异常
//=========================================================================
uint_8  uart_init (uint_8 uartNo, uint_32 clk_khz, uint_32 baud_rate)
{
    register uint_16 sbr, brfa;
    uint_8 temp;
    uint_32 sysClk = clk_khz;
    UART_MemMapPtr uartch = UART_PTR[uartNo];

    //使能引脚功能并启动引脚时钟
    switch (uartNo)
    {
    case UART_0:
        PORTD_PCR6 = PORT_PCR_MUX(0x3); //使能UART0_TXD
        PORTD_PCR7 = PORT_PCR_MUX(0x3); //使能UART0_RXD
        BSET(SIM_SCGC4_UART0_SHIFT, SIM_SCGC4);//启动串口0时钟
        break;
    case UART_1:
        PORTC_PCR4 = PORT_PCR_MUX(0x3); //使能UART1_TXD
        PORTC_PCR3 = PORT_PCR_MUX(0x3); //使能UART1_RXD
        BSET(SIM_SCGC4_UART1_SHIFT, SIM_SCGC4); //启动串口1时钟
        break;
    case UART_2:
        PORTD_PCR3 = PORT_PCR_MUX(0x3); //使能UART2_TXD
        PORTD_PCR2 = PORT_PCR_MUX(0x3); //使能UART2_RXD
        BSET(SIM_SCGC4_UART2_SHIFT, SIM_SCGC4);//启动串口2时钟
        break;
    case UART_3:
        PORTB_PCR11 = PORT_PCR_MUX(0x3); //使能UART3_TXD
        PORTB_PCR10 = PORT_PCR_MUX(0x3); //使能UART3_RXD
        BSET(SIM_SCGC4_UART3_SHIFT, SIM_SCGC4);//启动串口3时钟
        break;
    case UART_4:
        PORTE_PCR24 = PORT_PCR_MUX(0x3); //使能UART4_TXD
        PORTE_PCR25 = PORT_PCR_MUX(0x3); //使能UART4_RXD
        BSET(SIM_SCGC1_UART4_SHIFT, SIM_SCGC1); //启动串口4时钟
        break;
    case UART_5:
        PORTD_PCR9 = PORT_PCR_MUX(0x3); //使能UART5_TXD
        PORTD_PCR8 = PORT_PCR_MUX(0x3); //使能UART5_RXD
        BSET(SIM_SCGC1_UART5_SHIFT, SIM_SCGC1);  //启动串口5时钟
        break;
    default:
        return 1;  //传参错误，返回
    }
    
    //暂时关闭串口发送与接收功能
    UART_C2_REG(uartch) &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK);

    //配置串口工作模式
    //8位无校验模式
    UART_C1_REG(uartch) = 0;
    //配置波特率
    //串口0、1使用的内核时钟是其它串口使用外设时钟频率的2倍
    if (UART_0 == uartNo || UART_1 == uartNo)
        sysClk+=sysClk;  
    
    sbr = (uint_16)((sysClk*1000)/(baud_rate * 16));
    temp = UART_BDH_REG(uartch) & ~(UART_BDH_SBR(0x1F));
    UART_BDH_REG(uartch) = temp |  UART_BDH_SBR(((sbr & 0x1F00) >> 8));
    UART_BDL_REG(uartch) = (uint_8)(sbr & UART_BDL_SBR_MASK);
    
    brfa = (((sysClk*32000)/(baud_rate * 16)) - (sbr * 32));
    temp = UART_C4_REG(uartch) & ~(UART_C4_BRFA(0x1F));
    UART_C4_REG(uartch) = temp |  UART_C4_BRFA(brfa);    

    //启动发送接收
    UART_C2_REG(uartch) |= (UART_C2_TE_MASK | UART_C2_RE_MASK );
    return 0;
}

//===========================================================================
//函数名称：uart_deinit
//参数说明：uartNo:串口号:0 ~ 5   
//函数返回：无
//功能概要：关闭串口功能，让出硬件资源
//===========================================================================
void uart_deinit(uint_8 uartNo)
{
    //UART_MemMapPtr sci_ptr = UART_PTR[uartNo];
    
    //uart_disable(uartNo);
   // uart_io_init(uartNo, IO_UART_PIN_MUX_DISABLE);
}

//===========================================================================
//函数名称：uart_send1
//参数说明：uartNo:串口号:0 ~ 5   
//         ch：发送字符
//函数返回：无
//功能概要：通过串口发送1字节数据
//===========================================================================
uint_8 uart_send1(uint_8 uartNo, uint_8 ch)
{
    uint_32 t;
    UART_MemMapPtr uartch = UART_PTR[uartNo];

    for (t = 0; t < 0xFBBB; t++)
    {
        //判断发送缓冲区是否为空
        if (BGET(SendTestBit, ReSendStatusR(uartch)))
        {
            ReSendDataR(uartch) = ch;
            break;
        }
    }//end for
    if (t >= 0xFBBB)
        return 1; //发送超时
    else
        return 0; //成功发送
}

//=========================================================================
//函数名称：uart_sendN
//参数说明：uartNo:串口号:0 ~ 5   
//          buff: 发送缓冲区
//          len:发送长度
//函数返回： 函数执行状态：0=正常；1=异常。
//功能概要：串行 接收n个字节   
//=========================================================================
uint_8 uart_sendN (uint_8 uartNo ,uint_16 len ,uint_8* buff)
{
    uint_16 i;
    
    for (i = 0; i < len; i++)
        if (uart_send1(uartNo, buff[i]))
            break;
    if (i >= len)
        return 1;
    else 
        return 0;

}

//=========================================================================
//函数名称：uart_send_string
//参数说明：uartNo:串口号:0 ~ 5   
//          buff:要发送的字符串的首地址
//函数返回： 函数执行状态：0=正常；非0=异常。
//功能概要：从指定UART端口发送一个以'\0'结束的字符串
//=========================================================================
uint_8 uart_send_string(uint_8 uartNo, void *buff)
{
    uint_16 i = 0;
    uint_8 *buff_ptr = (uint_8 *)buff;
    for(i = 0; buff_ptr[i] != '\0'; i++)
    {
        if (uart_send1(uartNo,buff_ptr[i]))
            return 1;
    }
    return 0;
}

//=========================================================================
//函数名称：uart_re1
//参数说明：uartNo:串口号:0 ~ 5   
//          fp:接收成功标志的指针:*fp=0，成功接收；*fp=1，接收失败
//函数返回：接收返回字节
//功能概要：串行接收1个字节
//=========================================================================
uint_8 uart_re1 (uint_8 uartNo,uint_8 *fp)
{   
    uint_32 t;
    uint_8  dat;
    UART_MemMapPtr uartch = UART_PTR[uartNo];

    for (t = 0; t < 0xFBBB; t++)//查询指定次数
    {
        //判断接收缓冲区是否满
        if (BGET(ReTestBit, ReSendStatusR(uartch)))
        {
            dat = ReSendDataR(uartch);
            *fp= 0;  //收到数据 
            break;
        }
    }//end for
    if(t >= 0xFBBB) 
    {
        dat = 0xFF;
        *fp = 1;  //未收到数据
    }
    return dat;    //返回接收到的数据
    
}

//=========================================================================
//函数名称：uart_reN
//参数说明：uartNo:串口号:0 ~ 5                                                    
//          buff: 接收缓冲区
//          len:接收长度
//函数返回：函数执行状态 0=正常;非0=异常
//功能概要：串行 接收n个字节
//=========================================================================
uint_8 uart_reN (uint_8 uartNo ,uint_16 len ,uint_8* buff)
{
    uint_16 i;
    uint_8 flag = 0;
    
    for (i = 0; i < len && 0 == flag; i++)
    {
        buff[i] = uart_re1(uartNo, &flag);
    }
    if (i >= len)
        return 1; //接收失败
    else
        return 0; //接收成功

}

//=========================================================================
//函数名称：uart_enable_re_int
//参数说明：uartNo:串口号:0 ~ 5   
//函数返回：无
//功能概要：开串口接收中断
//=========================================================================
void uart_enable_re_int(uint_8 uartNo)
{
    UART_MemMapPtr sci_ptr = UART_PTR[uartNo];
    sci_ptr->C2 |= UART_C2_RIE_MASK;
    enable_irq(table_irq_uart[uartNo]);          //开接收引脚的IRQ中断
}

//=========================================================================
//函数名称：uart_disable_re_int
//参数说明：uartNo:串口号:0 ~ 5   
//函数返回：无
//功能概要：关串口接收中断
//=========================================================================
void uart_disable_re_int(uint_8 uartNo)
{
    UART_MemMapPtr sci_ptr = UART_PTR[uartNo];
    sci_ptr->C2 &= ~(UART_C2_RIE_MASK);
    disable_irq(table_irq_uart[uartNo]);          //开接收引脚的IRQ中断
}


//=========================================================================
//                             内部静态函数
//=========================================================================
//函数名称：uart_enable
//参数说明：uartNo：串口号，由宏定义，例如UART_0
//函数返回：无
//功能概要：内部函数
//         使能UART外设功能
//=========================================================================
static void uart_enable(uint_8 uartNo)
{
    UART_MemMapPtr sci_ptr = UART_PTR[uartNo];
    /* Transmitter and receiver enable */
    sci_ptr->C2 |= UART_C2_RE_MASK | UART_C2_TE_MASK;
}

//=========================================================================
//函数名称：uart_disable
//参数说明：uartNo：串口号，由宏定义，例如UART_0
//函数返回：无
//功能概要：内部函数
//         关闭UART外设功能
//=========================================================================
static void uart_disable(uint_8 uartNo)
{
    UART_MemMapPtr sci_ptr = UART_PTR[uartNo];
    /* Transmitter and receiver disable */
    sci_ptr->C2 &= (~ (UART_C2_RE_MASK | UART_C2_TE_MASK));
}

