/**
  *****************************************************************************
  *                           系统串口设置相关的函数
  *
  *                       (C) Copyright 2000-2020, ***
  *                            All Rights Reserved
  *****************************************************************************
  *
  * @File    : usart.c
  * @By      : 陈桂东
  * @Version : V1.0
  * @Date    : 2012 / 10 / 20
  *
  *****************************************************************************
  *                                   Update
  * @Version : V1.0.1
  * @By      : 陈桂东
  * @Date    : 2014 / 05 / 24
  * @Brief   : 增加对C++环境支持
  *
  * @Version : V1.1
  * @By      : 陈桂东
  * @Date    : 2015 / 10 / 03
  * @Brief   : 增加103和407之间切换宏定义
  *
  * @Version : V1.2
  * @By      : 陈桂东
  * @Date    : 2016 / 04 / 27
  * @Brief   : A、增加对STM32F0系列支持
  *            B、增加对IAR环境支持
  *
  *****************************************************************************
**/

#include "usart.h"


#if _SYSTEM_SUPPORT_ROTS == 1
#if _RTOS_Type_Support == 1  // RAW-OS
#include "raw_api.h"
#else  // uCOS
#include "includes.h"
#endif
#endif

#if Printf_Support_En == 0
#include <stdarg.h>
#endif


/******************************************************************************
           加入以下代码，支持printf函数，而不需要选择use MicroLIB
******************************************************************************/

#if Printf_Support_En == 1

#ifdef __ICCARM__  //IAR支持

/**
  *****************************************************************************
  * @Name   : 重定义out_char函数
  *
  * @Brief  : none
  *
  * @Input  : ch：发送字符
  *
  * @Output : none
  *
  * @Return : none
  *****************************************************************************
**/
int putchar ( int c )
{
    uint16_t timeout = 0;


    USART_SendData ( USART1, ( uint16_t ) c ); //发送数据

    while ( USART_GetFlagStatus ( USART1, USART_FLAG_TC ) == RESET ) //循环发送，直到发送完毕
    {
        timeout++;

        if ( timeout > 800 )
        {
            timeout = 0;
            break;
        }
    }

    return c;
}


#else  //MDK支持

#pragma import(__use_no_semihosting)
//
//标准库需要的支持函数
//
struct __FILE
{
    int handle;

};
/* FILE is typedef’ d in stdio.h. */
FILE __stdout;
//
//定义_sys_exit()以避免使用半主机模式
//
_sys_exit ( int x )
{
    x = x;
}

/**
  *****************************************************************************
  * @Name   : 重定义fputc函数
  *
  * @Brief  : none
  *
  * @Input  : ch：发送字符
  *           *f: FILE指针
  *
  * @Output : none
  *
  * @Return : none
  *****************************************************************************
**/
int fputc ( int ch, FILE *f )
{
    uint16_t timeout = 0;

    while ( USART_GetFlagStatus ( USART1, USART_FLAG_TC ) == RESET ) //循环发送，直到发送完毕
    {
        timeout++;

        if ( timeout > 800 )
        {
            timeout = 0;
            break;
        }
    }

    USART_SendData ( USART1, ( uint16_t ) ch ); //发送数据

    return ch;
}

#endif

#else

/**
  *****************************************************************************
  * @Name   : 串口发送一个字节
  *
  * @Brief  : none
  *
  * @Input  : byte：发送字符
  *
  * @Output : none
  *
  * @Return : none
  *****************************************************************************
**/
void uart_sendbyte ( uint8_t byte )
{
    while ( USART_GetFlagStatus ( USART1, USART_FLAG_TC ) == RESET );

    USART_SendData ( USART1, byte );

    while ( USART_GetFlagStatus ( USART1, USART_FLAG_TC ) == RESET );
}

/**
  *****************************************************************************
  * @Name   : 串口发送字符串
  *
  * @Brief  : none
  *
  * @Input  : *str：发送字符串
  *
  * @Output : none
  *
  * @Return : none
  *****************************************************************************
**/
void uart_senfstring ( uint8_t * str )
{
    while ( USART_GetFlagStatus ( USART1, USART_FLAG_TC ) == RESET );

    while ( *str != '\0' )
    {
        USART_SendData ( USART1, * ( str++ ) );

        while ( USART_GetFlagStatus ( USART1, USART_FLAG_TC ) == RESET );
    }
}

/**
  *****************************************************************************
  * @Name   : 串口格式化打印
  *
  * @Brief  : none
  *
  * @Input  : *format：格式化字符串
  *           ...:     变长参数
  *
  * @Output : none
  *
  * @Return : none
  *****************************************************************************
**/
void uart_printf ( char *format, ... )
{
    va_list ap;
    char string[512];

    va_start ( ap, format );
    vsprintf ( string, format, ap );
    va_end ( ap );

    uart_senfstring ( ( uint8_t * ) string );
}

#endif

/*************************************   end   *******************************/

/**
  *****************************************************************************
  * @Name   : 初始化IO 串口
  *
  * @Brief  : none
  *
  * @Input  : bound：波特率
  *
  * @Output : none
  *
  * @Return : none
  *****************************************************************************
**/
void uart_init ( uint32_t bound )
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef  NVIC_InitStructure;

#if __CORTEX_M == 0x00  //Cortex-M0

    RCC_AHBPeriphClockCmd ( RCC_AHBPeriph_GPIOA, ENABLE );
    RCC_APB2PeriphClockCmd ( RCC_APB2Periph_USART1, ENABLE );

    //
    //管脚复用
    //
    GPIO_PinAFConfig ( GPIOA, GPIO_PinSource9,  GPIO_AF_1 );
#if EN_USART1_RX == 1  //使能接收
    GPIO_PinAFConfig ( GPIOA, GPIO_PinSource10, GPIO_AF_1 );
#endif
    //
    //初始化管脚
    //
#if EN_USART1_RX == 1  //使能接收
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9 | GPIO_Pin_10;
#else
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;
#endif
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_Init ( GPIOA, &GPIO_InitStructure );

#elif __CORTEX_M == 0x03  //Cortex-M3

    //
    //打开时钟
    //
    RCC_APB2PeriphClockCmd ( RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE );
    //
    //初始化管脚
    //
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;  //PA.9 TXD
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;  //复用推挽输出
    GPIO_Init ( GPIOA, &GPIO_InitStructure );

#if EN_USART1_RX == 1  //使能接收

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;  //PA.10 RXD
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //浮空输入
    GPIO_Init ( GPIOA, &GPIO_InitStructure );

#endif

#elif __CORTEX_M == 0x04  //Cortex-M4

    //
    //打开时钟
    //
    RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_GPIOA, ENABLE ); //使能GPIOA时钟
    RCC_APB2PeriphClockCmd ( RCC_APB2Periph_USART1, ENABLE ); //使能USART1时钟
    //
    //管脚复用
    //
    GPIO_PinAFConfig ( GPIOA, GPIO_PinSource9, GPIO_AF_USART1 ); //TXD管脚
#if EN_USART1_RX == 1  //使能接收
    GPIO_PinAFConfig ( GPIOA, GPIO_PinSource10, GPIO_AF_USART1 ); //RXD管脚
#endif
    //
    //初始化管脚
    //
#if EN_USART1_RX == 1  //使能接收
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9 | GPIO_Pin_10;
#else
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;  //只初始化TXD管脚
#endif
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;  //复用功能
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;  //推挽输出
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;  //上拉
    GPIO_Init ( GPIOA, &GPIO_InitStructure );

#endif  //end __CORTEX_M

    //
    //配置串口参数
    //
    USART_InitStructure.USART_BaudRate            = bound;  //波特率
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;  //数据长度8
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;  //停止位1
    USART_InitStructure.USART_Parity              = USART_Parity_No;  //无奇偶校验
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  //无数据流控制
#if EN_USART1_RX == 1  //使能接收
    USART_InitStructure.USART_Mode                = USART_Mode_Tx | USART_Mode_Rx;
#else
    USART_InitStructure.USART_Mode                = USART_Mode_Tx;
#endif
    USART_Init ( USART1, &USART_InitStructure );

    //
    //使能串口
    //
    USART_Cmd ( USART1, ENABLE );
    USART_ClearFlag ( USART1, USART_FLAG_TC );

    //
    //初始化串口中断优先级
    //
#if EN_USART1_RX == 1  //使能接收
    //
    //开启串口中断接收
    //
    USART_ITConfig ( USART1, USART_IT_RXNE, ENABLE );

    NVIC_InitStructure.NVIC_IRQChannel                   = USART1_IRQn;  //中断号
#if __CORTEX_M == 0x00  //Cortex-M0

    NVIC_InitStructure.NVIC_IRQChannelPriority           = 3;

#else

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  //抢先优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 3;  //响应优先级

#endif

    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init ( &NVIC_InitStructure );

#endif
}

#if EN_USART1_RX == 1  //使能接收

//注意,读取USARTx->SR能避免莫名其妙的错误

uint8_t USART_RX_BUF[USART_REC_LEN];  //接收缓冲,最大USART_REC_LEN个字节

//接收状态
//bit15：接收完成标志
//bit14：接收到0x0d
//bit13~0：接收到的有效字节数目，最大512字节

uint16_t USART_RX_STA = 0;	//接收状态标记

/**
  *****************************************************************************
  * @Name   : 串口1接收中断服务程序
  *
  * @Brief  : none
  *
  * @Input  : none
  *
  * @Output : none
  *
  * @Return : none
  *****************************************************************************
**/
void USART1_IRQHandler ( void )
{
    uint8_t res;

#if _SYSTEM_SUPPORT_ROTS == 1
#if _RTOS_Type_Support == 1  // RAW-OS
    raw_enter_interrupt();
#else  // uCOS
    OSIntEnter();
#endif
#endif

    if ( USART_GetITStatus ( USART1, USART_IT_RXNE ) != RESET ) //接收到数据
    {
        res = USART_ReceiveData ( USART1 );	//读取接收到的数据

        if ( ( USART_RX_STA & 0x8000 ) == 0 ) //接收未完成
        {
            if ( USART_RX_STA & 0x4000 ) //接收到了0x0d
            {
                /***********************************************
                                  修改内容如下
                    当用户数据当中有0x0d的时候修正的错误的判断
                ***********************************************/

                if ( res != 0x0a )
                {
                    USART_RX_BUF[USART_RX_STA & 0x3fff] = 0x0d;	//补上丢失的0x0d数据
                    USART_RX_STA++;
                    USART_RX_BUF[USART_RX_STA & 0x3fff] = res;	//继续接收数据
                    USART_RX_STA++;
                    USART_RX_STA &= 0xbfff;						//清除0x0d标志
                }

                /***********************************************
                                      修改完成
                ***********************************************/

                else	USART_RX_STA |= 0x8000;	//接收完成了
            }
            else //还没收到0x0d
            {
                if ( res == 0x0d )	USART_RX_STA |= 0x4000;
                else
                {
                    USART_RX_BUF[USART_RX_STA & 0x3fff] = res;
                    USART_RX_STA++;

                    if ( USART_RX_STA > ( USART_REC_LEN - 1 ) )	USART_RX_STA = 0; //接收数据错误,重新开始接收
                }
            }
        }	//end 接收未完成
    }	//end 接收到数据

#if _SYSTEM_SUPPORT_ROTS == 1
#if _RTOS_Type_Support == 1  // RAW-OS
    raw_finish_int();
#else  // uCOS
    OSIntExit();
#endif
#endif
}

#endif  //end EN_USART1_RX
