/**
************************************************************************************************
* @文件    : uart3.c
* @作者    : 樊春春
* @版本    : V1.0
* @时间    : 2022/05/31 20:15:29
* @邮箱    : fanchcho@gmail.com
* @说明    : 485底层驱动
************************************************************************************************
**/

#include "uart3.h"

static uint8_t uart3_tx_buf[UART3_TX_LEN]  = {0};
static uint8_t uart3_rx_buf[UART3_REC_LEN] = {0};

UartFrame_TypeDef Uart3FrameStruct[UART3_MAX_MSG_NUM];

extern OS_EVENT *uart3_mbox;

void uart3_nvic_config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    // Usart3 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel                   = USART3_IRQn; //串口3中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;           //抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;           //子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;      // IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);
}

void uart3_dma_init(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    if ((uint32_t)UART3_DMA_TXCH > (uint32_t)DMA2)
    {
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); // DMA2时钟使能
    }
    else
    {
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); // DMA1时钟使能
    }
    DMA_DeInit(UART3_DMA_TXCH);
    while (DMA_GetCmdStatus(UART3_DMA_TXCH) != DISABLE)
    {
    } //等待DMA可配置
    /* 配置 DMA Stream */
    DMA_InitStructure.DMA_Channel            = UART3_DMA;                   //通道选择
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART3->DR;       // DMA外设地址
    DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)uart3_tx_buf;      // DMA 存储器0地址
    DMA_InitStructure.DMA_DIR                = DMA_DIR_MemoryToPeripheral;  //存储器到外设模式
    DMA_InitStructure.DMA_BufferSize         = UART3_TX_LEN;                //数据传输量
    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;   //外设非增量模式
    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;        //存储器增量模式
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据长度:8位
    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;     //存储器数据长度:8位
    DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;             // 使用普通模式
    DMA_InitStructure.DMA_Priority           = DMA_Priority_Medium;         //中等优先级6
    DMA_InitStructure.DMA_FIFOMode           = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold      = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst        = DMA_MemoryBurst_Single;     //存储器突发单次传输
    DMA_InitStructure.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single; //外设突发单次传输
    DMA_Init(UART3_DMA_TXCH, &DMA_InitStructure);                          //初始化DMA Stream

    if ((uint32_t)UART3_DMA_RXCH > (uint32_t)DMA2) //得到当前stream是属于DMA2还是DMA1
    {
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); // DMA2时钟使能
    }
    else
    {
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); // DMA1时钟使能
    }

    DMA_DeInit(UART3_DMA_RXCH);
    while (DMA_GetCmdStatus(UART3_DMA_RXCH) != DISABLE)
    {
    } //等待DMA可配置
    /* 配置 DMA Stream */
    DMA_InitStructure.DMA_Channel            = UART3_DMA;                   //通道选择
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART3->DR;       // DMA外设地址
    DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)uart3_rx_buf;      // DMA 存储器0地址
    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralToMemory;  //外设到存储器模式
    DMA_InitStructure.DMA_BufferSize         = UART3_REC_LEN;               //数据传输量
    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;   //外设非增量模式
    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;        //存储器增量模式
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据长度:8位
    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;     //存储器数据长度:8位
    DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular;           // 使用循环模式
    DMA_InitStructure.DMA_Priority           = DMA_Priority_Medium;         //中等优先级
    DMA_InitStructure.DMA_FIFOMode           = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold      = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst        = DMA_MemoryBurst_Single;     //存储器突发单次传输
    DMA_InitStructure.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single; //外设突发单次传输
    DMA_Init(UART3_DMA_RXCH, &DMA_InitStructure);
}

void uart3_config(void)
{
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate            = 115200;                         //波特率设置
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;            //字长为8位数据格式
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;               //一个停止位
    USART_InitStructure.USART_Parity              = USART_Parity_No;                //无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
    USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;  //收发模式
    USART_Init(USART3, &USART_InitStructure);                                       //初始化串口1

    USART_Cmd(USART3, ENABLE); //使能串口3
}

void Uart3DMA_Enable(DMA_Stream_TypeDef *DMA_Streamx, u16 count)
{
    DMA_Cmd(DMA_Streamx, DISABLE); //关闭DMA传输
    while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE)
    {
    } //确保DMA可以被设置

    DMA_SetCurrDataCounter(DMA_Streamx, count); //数据传输量
    DMA_Cmd(DMA_Streamx, ENABLE);               //开启DMA传输
}

void uart3_init(void)
{
    uart3_config();
    uart3_dma_init();
    uart3_nvic_config();
    /* USART DMA enable*/
    USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE); // 使能串口DMA接收数据
    Uart3DMA_Enable(UART3_DMA_RXCH, UART3_REC_LEN);

    /*configure DMA interrupt*/
    USART_ITConfig(USART3, USART_IT_IDLE, ENABLE); //开启空闲中断
    USART_ITConfig(USART3, USART_IT_TC, ENABLE);

    UART3_RX_ENABLE;
}

/****************************************************
 *  函 数 名：Uart3_Send_Data
 *  函数功能：串口3发送数据
 *  入口参数：buf 待发送数据  len 数据长度
 *  说    明：
 *****************************************************/
void Uart3_Send_Data(const uint8_t *buf, uint16_t len)
{
    uint8_t i;

    UART3_TX_ENABLE;          // 485 发送使能
    for (i = 0; i < len; i++) //循环发送数据
    {
        while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET)
            ;
        USART_SendData(USART3, buf[i]);
    }
    while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET)
        ;

    UART3_RX_ENABLE; // 接收使能
}

void uart3_dma_send(const uint8_t *buf, uint16_t len)
{
    if (DMA_GetFlagStatus(UART3_DMA_TXCH, DMA_FLAG_TCIF3) != RESET)
    {
        DMA_ClearFlag(UART3_DMA_TXCH, DMA_FLAG_TCIF3);
    }

    UART3_TX_ENABLE; // 485 发送使能
    if (len > UART3_TX_LEN)
    {
        len = UART3_TX_LEN;
    }
    memcpy(uart3_tx_buf, buf, len);
    USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);
    Uart3DMA_Enable(UART3_DMA_TXCH, len);
}

void USART3_IRQHandler(void)
{
    static uint8_t   u3_index = 0;
    volatile uint8_t clear    = 0;
    uint8_t          rec_cnt  = 0;
    if (RESET != USART_GetITStatus(USART3, USART_IT_IDLE))
    {
        clear = USART3->SR;
        clear = USART3->DR; // 先读SR, 再读DR, 就是为了消除IDLE中断
        DMA_Cmd(UART3_DMA_RXCH, DISABLE);
        DMA_ClearFlag(UART3_DMA_RXCH, DMA_FLAG_TCIF1);
        rec_cnt = UART3_REC_LEN - DMA_GetCurrDataCounter(UART3_DMA_RXCH);

        memcpy(Uart3FrameStruct[u3_index].buf, uart3_rx_buf, rec_cnt);
        Uart3FrameStruct[u3_index].len = rec_cnt;

        OSMboxPost(uart3_mbox, &Uart3FrameStruct[u3_index]);
        if (u3_index < UART3_MAX_MSG_NUM - 1)
        {
            u3_index++;
        }
        else
        {
            u3_index = 0;
        }
        DMA_SetCurrDataCounter(UART3_DMA_RXCH, UART3_REC_LEN);
        DMA_Cmd(UART3_DMA_RXCH, ENABLE);
    }
    else if (RESET != USART_GetITStatus(USART3, USART_IT_TC))
    {
        USART_ClearITPendingBit(USART3, USART_IT_TC);
        UART3_RX_ENABLE;
        Uart3DMA_Enable(UART3_DMA_RXCH, UART3_REC_LEN); // DMA接收使能
        DMA_Cmd(UART3_DMA_TXCH, DISABLE);               // 关闭发送DMA
        DMA_SetCurrDataCounter(UART3_DMA_TXCH, 0);      // 清除发送数据长度
    }
}
