// I2S接口驱动
// 杭州秒寻科技有限公司
// 周涛
// 2023-09-13

#include "includes.h"
volatile int16 g_awBuffer0[DRIVERI2S_BUFFER_LEN] = {0}; // 一次DMA发送的数量
volatile int16 g_awBuffer1[DRIVERI2S_BUFFER_LEN] = {0}; // 一次DMA发送的数量
volatile int16 g_awBuffer2[DRIVERI2S_BUFFER_LEN] = {0}; // 测试用缓存，正式发布后要删除

volatile uint8 g_I2s_byCpldStatus = 0;        // CPLD使能状态
volatile uint8 g_I2s_byCpldTestFlag = 1;      // 1：cpld测试数据，0：正常信号数据
volatile uint32 *g_pdwSingnalSendList = NULL; // 信号发送队列，队列中存储的是数据的首地址
volatile uint16 g_wDmaSendCounter = 0;        // 发送次数计数器
volatile uint8 g_byDmaSendFlag = 0;           // DMA发送状态，0：发送完成，1：正在发送

// 模块初始化
void driver_i2s_init()
{
    driver_i2s_init_cpld();
    driver_i2s_init_i2s(); // 初始化I2S接口
}

// 初始化CPLD使能管脚
void driver_i2s_init_cpld()
{
    GPIO_InitTypeDef stGpio = {0};

    // 开启管脚时钟
    RCC_AHB1PeriphClockCmd(DRIVER_I2S_CPLD_START_GPIO_CLK, ENABLE);

    // 管脚初始化
    stGpio.GPIO_Mode = GPIO_Mode_OUT;
    stGpio.GPIO_OType = GPIO_OType_PP;
    stGpio.GPIO_Speed = GPIO_Speed_50MHz;
    stGpio.GPIO_PuPd = GPIO_PuPd_DOWN;
    stGpio.GPIO_Pin = DRIVER_I2S_CPLD_START_GPIO_PIN;
    GPIO_Init(DRIVER_I2S_CPLD_START_GPIO_PORT, &stGpio); // 初始化GPIO管脚

    // 拉低，默认是低
    driver_i2s_cpld_cmd(0);
}

// 使能或者失能CPLD
// byBitValue:开关值，0：低，1：高
void driver_i2s_cpld_cmd(uint8 byBitValue)
{
    g_I2s_byCpldStatus = byBitValue;
    GPIO_WriteBit(DRIVER_I2S_CPLD_START_GPIO_PORT, DRIVER_I2S_CPLD_START_GPIO_PIN, (BitAction)byBitValue);
}

// 初始化I2S接口
void driver_i2s_init_i2s()
{
    GPIO_InitTypeDef stGpio = {0};
    I2S_InitTypeDef stI2sTxHandle = {0};

    ////初始化管脚
    // 管脚复用映射
    // GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource3, GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);

    // 初始化I2S接口GPIO
    stGpio.GPIO_Mode = GPIO_Mode_AF;
    stGpio.GPIO_OType = GPIO_OType_PP;
    stGpio.GPIO_Speed = GPIO_Speed_50MHz;
    stGpio.GPIO_PuPd = GPIO_PuPd_NOPULL;

    // 初始化LRCK
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    stGpio.GPIO_Pin = GPIO_Pin_12;
    GPIO_Init(GPIOB, &stGpio);

    // 初始化BCK
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
    stGpio.GPIO_Pin = GPIO_Pin_3;
    GPIO_Init(GPIOD, &stGpio);

    // 初始化SD
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    stGpio.GPIO_Pin = GPIO_Pin_15;
    GPIO_Init(GPIOB, &stGpio);

    //// 初始化I2S接口
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); // 使能I2S接口时钟
    SPI_I2S_DeInit(SPI2);
    stI2sTxHandle.I2S_Mode = I2S_Mode_MasterTx;
    stI2sTxHandle.I2S_Standard = I2S_Standard_Phillips;
    stI2sTxHandle.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
    stI2sTxHandle.I2S_AudioFreq = I2S_AudioFreq_48k;
    stI2sTxHandle.I2S_DataFormat = I2S_DataFormat_32b;
    stI2sTxHandle.I2S_CPOL = I2S_CPOL_Low;
    I2S_Init(SPI2, &stI2sTxHandle);

    // 设置I2S时钟分频器
    SPI2->I2SPR |= 0x000A;

    // 使能DMA功能
    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
    // I2S_Cmd(SPI2, ENABLE); // 使能I2S(开始转运数据)

    return;
}

// 初始化DMA测试接口
void driver_i2s_init_dma_test()
{
    DMA_InitTypeDef stDmaTxHandle = {0};
    NVIC_InitTypeDef stNvic = {0};

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); // 开启时钟
    DMA_DeInit(DMA1_Stream4);                            // 初始化为默认复位值
    while (DMA_GetCmdStatus(DMA1_Stream4) != DISABLE)    // 等待复位成功
    {                                                    // 等待DMA1_Stream4可配置
    }
    DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_FEIF4 | DMA_IT_DMEIF4 | DMA_IT_TEIF4 | DMA_IT_HTIF4 | DMA_IT_TCIF4); // 清空DMA1_Stream4上所有中断标志

    // 初始化DMA
    DMA_StructInit(&stDmaTxHandle);
    stDmaTxHandle.DMA_Channel = DMA_Channel_0; // 0号通道
    stDmaTxHandle.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    stDmaTxHandle.DMA_PeripheralBaseAddr = (uint32)(&SPI2->DR);
    stDmaTxHandle.DMA_Memory0BaseAddr = (uint32)g_awBuffer0; // 缓存0
    stDmaTxHandle.DMA_BufferSize = 64;                       // 64个数据项
    stDmaTxHandle.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    stDmaTxHandle.DMA_MemoryInc = DMA_MemoryInc_Enable;
    stDmaTxHandle.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    stDmaTxHandle.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    stDmaTxHandle.DMA_Mode = DMA_Mode_Normal;
    stDmaTxHandle.DMA_Priority = DMA_Priority_High;
    stDmaTxHandle.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_Init(DMA1_Stream4, &stDmaTxHandle); // 初始化DMA

    // 使能中断
    DMA_ITConfig(DMA1_Stream4, DMA_IT_TC, ENABLE);

    // 使能DMA功能
    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);

    // 配置NVIC
    stNvic.NVIC_IRQChannel = DMA1_Stream4_IRQn;
    stNvic.NVIC_IRQChannelPreemptionPriority = 1;
    stNvic.NVIC_IRQChannelSubPriority = 0;
    stNvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&stNvic);

    return;
}

// 发送CPLD初始化数据
void driver_i2s_start_send_cpld_test_data()
{
    g_I2s_byCpldTestFlag = 1; // CPLD测试数据

    // 组织测试数据
    SYS_MEMSET(g_awBuffer0, 0, sizeof(uint16) * DRIVERI2S_BUFFER_LEN);
    for (uint16 i = 0; i < 64; i++)
    {
        g_awBuffer0[i] = 0x55AA;
    }

    g_byDmaSendFlag = 1;   // DMA开始发送(0:发送完成，1：发送中)
    g_wDmaSendCounter = 0; // DMA发送次数计数器置0

    driver_i2s_init_dma_test(); // 初始化DMA

    // 使能DMA和I2S
    I2S_Cmd(SPI2, ENABLE);
    DMA_Cmd(DMA1_Stream4, ENABLE);
}

// 初始化DMA接口(双缓存)
void driver_i2s_init_dma()
{
    DMA_InitTypeDef stDmaTxHandle = {0};
    NVIC_InitTypeDef stNvic = {0};

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);                                                            // 开启时钟
    DMA_DeInit(DMA1_Stream4);                                                                                       // 初始化为默认复位值                                                                                  // 复位
    DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_FEIF4 | DMA_IT_DMEIF4 | DMA_IT_TEIF4 | DMA_IT_HTIF4 | DMA_IT_TCIF4); // 清空DMA1_Stream4上所有中断标志

    // 初始化DMA
    DMA_StructInit(&stDmaTxHandle);
    stDmaTxHandle.DMA_Channel = DMA_Channel_0; // 0号通道
    stDmaTxHandle.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    stDmaTxHandle.DMA_PeripheralBaseAddr = (uint32)(&SPI2->DR);
    stDmaTxHandle.DMA_Memory0BaseAddr = (uint32_t)g_awBuffer0; // 缓存0
    stDmaTxHandle.DMA_BufferSize = DRIVERI2S_BUFFER_LEN;       // 缓存大小
    stDmaTxHandle.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    stDmaTxHandle.DMA_MemoryInc = DMA_MemoryInc_Enable;
    stDmaTxHandle.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    stDmaTxHandle.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    stDmaTxHandle.DMA_Mode = DMA_Mode_Circular; // 循环模式
    stDmaTxHandle.DMA_Priority = DMA_Priority_High;
    stDmaTxHandle.DMA_FIFOMode = DMA_FIFOMode_Disable;
    stDmaTxHandle.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    stDmaTxHandle.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    stDmaTxHandle.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_Init(DMA1_Stream4, &stDmaTxHandle); // 初始化DMA

    // 双缓冲
    DMA_DoubleBufferModeConfig(DMA1_Stream4, (uint32_t)g_awBuffer1, DMA_Memory_0); // 配置缓存1地址，同时将当前可用缓存配置为缓存0
    DMA_DoubleBufferModeCmd(DMA1_Stream4, ENABLE);                                 // 双缓冲模式开启

    // 使能中断
    DMA_ITConfig(DMA1_Stream4, DMA_IT_TC, ENABLE);

    // 使能DMA功能
    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);

    // 配置NVIC
    stNvic.NVIC_IRQChannel = DMA1_Stream4_IRQn;
    stNvic.NVIC_IRQChannelPreemptionPriority = 1;
    stNvic.NVIC_IRQChannelSubPriority = 0;
    stNvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&stNvic);

    return;
}

// 开始发送数据
// pdwSingnalSendList:信号发送队列
void driver_i2s_start_send_data(uint32 *pdwSingnalSendList)
{
    uint16 wExpiryCounter = 0;
    uint32 *pTmp = NULL;
    uint32 dwTmp = 0;

    if (pdwSingnalSendList == NULL)
    {
        return;
    }
    g_pdwSingnalSendList = pdwSingnalSendList;

    // 准备缓存0初始数据
    if (pdwSingnalSendList[0] != 0)
    {
        SYS_MEMCPY((void *)g_awBuffer0, (void *)pdwSingnalSendList[0], sizeof(int16) * DRIVERI2S_BUFFER_LEN);
    }
    else
    {
        SYS_MEMSET(g_awBuffer0, 0, sizeof(int16) * DRIVERI2S_BUFFER_LEN);
    }

    // 准备缓存1中初始数据
    if (pdwSingnalSendList[1] != 0)
    {
        SYS_MEMCPY(g_awBuffer1, (void *)pdwSingnalSendList[1], sizeof(int16) * DRIVERI2S_BUFFER_LEN);
    }
    else
    {
        SYS_MEMSET(g_awBuffer1, 0, sizeof(int16) * DRIVERI2S_BUFFER_LEN);
    }

    // 等待上一次DMA发送完成，复位各控制变量
    do
    {
        wExpiryCounter++;
        if (wExpiryCounter >= 10000)
        {
            break; // 超时10000后强制退出
        }
    } while (g_byDmaSendFlag);

    g_I2s_byCpldTestFlag = 0; // 非cpld测试信号
    g_byDmaSendFlag = 1;      // DMA开始发送(0:发送完成，1：发送中)
    g_wDmaSendCounter = 0;    // DMA发送次数计数器置0

    // 初始化DMA
    driver_i2s_init_dma();

    // 使能cpld
    driver_i2s_cpld_cmd(1);

    // 使能DMA和I2S，开始发送数据
    I2S_Cmd(SPI2, ENABLE);
    DMA_Cmd(DMA1_Stream4, ENABLE);

    return;
}

// 停止发送数据
void driver_i2s_stop_send_data()
{
    uint16 wCounter = 0;

    // DMA停止转运数据
    DMA_Cmd(DMA1_Stream4, DISABLE);
    while (DMA_GetCmdStatus(DMA1_Stream4) != DISABLE) // 等待复位成功
    {
    }

    // 等待SPI发送寄存器为空
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
    {
        if (wCounter >= 50000)
        {
            break;
        }
        wCounter++;
    }

    // 等待移位寄存器发送完成
    wCounter = 0;
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET)
    { // SET:表示还有数据待发送
        if (wCounter >= 50000)
        {
            break;
        }
        wCounter++;
    }

    // I2S停止发送
    I2S_Cmd(SPI2, DISABLE); // 失能I2S;

    g_byDmaSendFlag = 0;         // 本次DMA发送完成，状态置0
    g_wDmaSendCounter = 0;       // 本次DMA发送次数清0
    g_pdwSingnalSendList = NULL; // 发送信号队列清0

    return;
}

// 填充缓存数据
// byCounter:信号发送队列索引
void driver_i2s_fill_buf_data(uint16 wCounter)
{
    uint8 byBufferNo = 0; // 缓存编号
    uint32 dwAddress = 0;
    uint32 *pTmp = NULL;
    uint32 dwTmp = 0;

    // 当前正在使用的缓存编号
    byBufferNo = DMA_GetCurrentMemoryTarget(DMA1_Stream4);

    // DMA正在使用buf0，MCU可以操作buf1
    if (0 == byBufferNo)
    {
        dwAddress = g_pdwSingnalSendList[wCounter + 1];
        if (dwAddress == 0)
        {
            SYS_MEMSET(g_awBuffer1, 0, sizeof(int16) * DRIVERI2S_BUFFER_LEN);
        }
        else
        {
            SYS_MEMCPY(g_awBuffer1, (void *)dwAddress, sizeof(int16) * DRIVERI2S_BUFFER_LEN);
        }
    }
    else
    { // DMA正在使用buf1，MCU可以操作buf0
        dwAddress = g_pdwSingnalSendList[wCounter + 1];
        if (dwAddress == 0)
        {
            SYS_MEMSET(g_awBuffer0, 0, sizeof(int16) * DRIVERI2S_BUFFER_LEN);
        }
        else
        {
            SYS_MEMCPY(g_awBuffer0, (void *)dwAddress, sizeof(int16) * DRIVERI2S_BUFFER_LEN);
        }
    }
}

// DMA1中断服务程序
void DMA1_Stream4_IRQHandler(void)
{
    // DMA一个buf发送完成(注意：最后一次中断不要处理，直接丢弃)
    if (DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4) == SET)
    {
        // 信号发送中才处理业务逻辑，否则不做任何业务处理，直接清除中断标志位
        if (g_byDmaSendFlag)
        {
            g_wDmaSendCounter++; // 发送次数加1

            // CPLD测试信号
            if (g_I2s_byCpldTestFlag == 1)
            {
                // 停止发送
                if (g_wDmaSendCounter >= 1)
                {
                    driver_i2s_stop_send_data(); // 停止发送数据(停止发送数据后，还会产生一次发生完成中断，该中断一定忽略掉)
                }
            }
            // 正常信号
            else
            {
                // 数据已发完
                if (g_wDmaSendCounter >= DRIVERI2S_SEND_TIMES)
                {
                    driver_i2s_stop_send_data(); // 停止发送数据(停止发送数据后，还会产生一次发生完成中断，该中断要忽略掉)

                    ////发送完成后向处理
                    driver_i2s_cpld_cmd(0);                 // 失能CPLD
                    driver_i2s_start_send_cpld_test_data(); // 发送测试数据初始化cpld
                }
                // 数据尚未发完
                else
                {
                    driver_i2s_fill_buf_data(g_wDmaSendCounter); // 组织缓存数据
                }
            }
        }

        // 清除中断标识符
        DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);
    }
    else if (DMA_GetITStatus(DMA1_Stream4, DMA_IT_HTIF4) == SET)
    {
        DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_HTIF4); // 清除中断标识符
    }
    else if (DMA_GetITStatus(DMA1_Stream4, DMA_IT_TEIF4) == SET)
    {
        DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TEIF4); // 清除中断标识符
    }
    else if (DMA_GetITStatus(DMA1_Stream4, DMA_IT_DMEIF4) == SET)
    {
        DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_DMEIF4); // 清除中断标识符
    }
    else if (DMA_GetITStatus(DMA1_Stream4, DMA_IT_FEIF4) == SET)
    {
        DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_FEIF4); // 清除中断标识符
    }
}

// 发送数据到测试窗口以便观察
void driver_i2s_send_data_to_gui(uint32 dwAddress)
{
    uint8 abyData[2] = {0};
    uint8 byTmp = 0;
    uint16 wData = 0;

    SYS_MEMCPY(g_awBuffer2, dwAddress, sizeof(int16) * DRIVERI2S_BUFFER_LEN);

    for (uint16 i = 0; i < DRIVERI2S_BUFFER_LEN; i++)
    {
        wData = g_awBuffer2[i];
        SYS_MEMCPY(abyData, &wData, 2);
        // byTmp = abyData[0];
        // abyData[0] = abyData[1];
        // abyData[1] = byTmp;
        driver_gui_send_data(abyData, 2);
    }
}

// 查询CPLD使能状态
uint8 driver_i2s_query_cpld_status()
{
    return g_I2s_byCpldStatus;
}

uint8 driver_i2s_query_send_status()
{
    return g_byDmaSendFlag;
}