#include "platform.h"
#include "brom_func.h"
#include "dspHandler.h"
#include "debug.h"

#define ALGO_UDSP_PARAM_CHANNEL (0)
#define ALGO_UDSP_CALC_CHANNEL (1)

static dspListener_s *gDspListener = NULL;

/*
 * fft计算输入参数结构体
 * */
typedef struct
{
    // 上边界和下边界虚拟连在一起，形成一个类似循环队列。上下边界确定后不需要再改变
    void *in_data_current;    // 输入缓存当前地址，当前地址必须在上下边界之间
    void *in_data_low;        // 输入缓存下边界地址
    void *in_data_upper;      // 输入缓存上边界地址
    void *out_data_current;   // 输出缓存当前地址，当前地址必须在上下边界之间
    void *out_data_low;       // 输出缓存下边界地址
    void *out_data_upper;     // 输出缓存上边界地址
    uint32_t input_size;      // 输入每个数据的宽度，例如 sizeof(int)
    uint32_t nmemb;           // 输入数据个数，长度只支持 32 64 128 256 512 1024
    uint32_t output_size;     // 输出每个数据的宽度，例如 sizeof(int)
    uint32_t win_enable;      // 是否对fft计算前加窗 加窗数据计算前加载到buffer1中
    uint32_t spectrum_enable; // 输出求能量
    //  uint32_t calculate_over;    //计算完成 需要在中断中调用才有效
} UDSP_FFT_InputStruct;

typedef struct
{
    // 上边界和下边界虚拟连在一起，形成一个类似循环队列。上下边界确定后不需要再改变
    void *in_data_current;  // 输入缓存当前地址，当前地址必须在上下边界之间
    void *in_data_low;      // 输入缓存下边界地址
    void *in_data_upper;    // 输入缓存上边界地址
    void *out_data_current; // 输出缓存当前地址，当前地址必须在上下边界之间
    void *out_data_low;     // 输出缓存下边界地址
    void *out_data_upper;   // 输出缓存上边界地址
    uint32_t input_size;    // 输入每个数据的宽度，例如 sizeof(int)
    uint32_t nmemb;         // 输入数据个数，长度只支持 32 64 128 256 512 1024
    uint32_t output_size;   // 输出每个数据的宽度，例如 sizeof(int)
    int32_t *complex_temp;  // 是否对fft计算前加窗
} UDSP_IRFFT_InputStruct;

void udsp_init()
{
    DEV_RMU->RSTEN0 &= ~DEV_RMU_RSTEN0_UDSP;
    DEV_CMU->CLKEN0 |= DEV_CMU_CLKEN0_UDSP;
    DEV_RMU->RSTEN0 |= DEV_RMU_RSTEN0_UDSP;
    DEV_UDSP->PD = DEV_UDSP_PD_END_MASK | DEV_UDSP_PD_FFT_BIT31_OF | DEV_UDSP_PD_FFT_BIT32_OF;
    DEV_UDSP->IE = 1 << ALGO_UDSP_CALC_CHANNEL;
}

/**
 * @brief        向buffer1中加载参数
 * @details      加载系数到buffer1中，用于协助udsp的主运算，如cos div hanning窗系数等
 * @param        @arg channel: 使用的usdp通道， 参数范围 0-7
 *               @arg coef: 需要加载的系数缓存地址
 *               @arg size: 系数每个成员的宽度，例如sizeof(int)
 *               @arg nmemb ：系数的个数
 *               @arg bur_addr ：系数放在usdp buffer1的地址偏移， buffer总大小4096word
 * @return       无
 * @note         注意udsp不能直接访问local memory和cache，但内部会处理
 */
void udsp_load_buffer1(int channel, void *coef, uint32_t size, uint32_t nmemb, uint32_t bur_addr)
{
    uint32_t addr_HSB, input_addr;
    input_addr = (uint32_t)coef;
    addr_HSB = input_addr >> 28;
    input_addr = addr_HSB ? input_addr : (input_addr | 0x61000000);
    DEV_UDSP->CHN[channel].SLA = (uint32_t)input_addr;
    DEV_UDSP->CHN[channel].SUA = (uint32_t)input_addr + size * nmemb;
    DEV_UDSP->CHN[channel].SCA = (uint32_t)input_addr;
    DEV_UDSP->CHN[channel].SMF = size << 16 | DEV_UDSP_CHNn_SMF_SRC_DATA_TYPE_REALINT32 | DEV_UDSP_CHNn_SMF_SRC_DATA_FORMAT_LOW_24BIT | ((size - 1) << 12) | (nmemb - 1);
    DEV_UDSP->CHN[channel].LMF0 = DEV_UDSP_CHNn_LMF0_SMA_WR_BUF1_SEL_ENABLE | (bur_addr << 20);
    DEV_UDSP->CHN[channel].CFG0 = DEV_UDSP_CHNn_CFG0_SMR_ENABLE;

    // CCTL
    if (addr_HSB == 0x4 || addr_HSB == 0x5)
    {
        // write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_WB_ALL);
        // 将D-cache空间写入memory,但不会将D-cache空间内容无效化
        write_csr(NDS_MCCTLCOMMAND, 7);
    }
}

void UDSP_Cmd(uint32_t channelx, uint32_t state)
{
    if (state != DISABLE)
    {
        DEV_UDSP->EN = (1UL << (channelx)) | (1UL << (channelx + 16));
    }
    else
    {
        DEV_UDSP->EN = (1UL << (channelx + 16));
    }
}

uint32_t UDSP_GetCmdStatus(uint32_t channelx)
{
    return (DEV_UDSP->EN & (1UL << (channelx))) >> channelx;
}

/**
 * @brief        计算fft
 * @details      计算将buffer0中计算fft
 * @param        @arg channel: 使用的usdp通道， 参数范围 0-7
 *               @arg fft_struct: @UDSP_FFT_InputStruct
 * @return       @arg =0：无任何异常
 *                    >=:配置成功，但数据有溢出
 *                    <0: 配置失败
 * @note         注意udsp不能直接访问local memory和cache，但内部会处理
 */
int32_t udsp_rfft(int channel, UDSP_FFT_InputStruct *fft_struct)
{
    int32_t ret = 0;
    uint32_t input_addr_HSB, output_addr_HSB;
    uint32_t low_addr, upper_addr, current_addr;
    input_addr_HSB = (uint32_t)fft_struct->in_data_current;
    input_addr_HSB = input_addr_HSB >> 28;
    low_addr = (uint32_t)fft_struct->in_data_low;
    upper_addr = (uint32_t)fft_struct->in_data_upper;
    current_addr = (uint32_t)fft_struct->in_data_current;

    if (input_addr_HSB == 0)
    {
        low_addr = low_addr | 0x61000000;
        upper_addr = upper_addr | 0x61000000;
        current_addr = current_addr | 0x61000000;
    }

    DEV_UDSP->CHN[channel].SLA = low_addr;
    DEV_UDSP->CHN[channel].SUA = upper_addr;
    DEV_UDSP->CHN[channel].SCA = current_addr;
    output_addr_HSB = (uint32_t)fft_struct->out_data_current;
    output_addr_HSB = output_addr_HSB >> 28;
    low_addr = (uint32_t)fft_struct->out_data_low;
    upper_addr = (uint32_t)fft_struct->out_data_upper;
    current_addr = (uint32_t)fft_struct->out_data_current;

    if (output_addr_HSB == 0)
    {
        low_addr = low_addr | 0x61000000;
        upper_addr = upper_addr | 0x61000000;
        current_addr = current_addr | 0x61000000;
    }

    DEV_UDSP->CHN[channel].DLA = low_addr;
    DEV_UDSP->CHN[channel].DUA = upper_addr;
    DEV_UDSP->CHN[channel].DCA = current_addr;
    DEV_UDSP->CHN[channel].SMF = (fft_struct->input_size << 16)                                                                                                                             // 源偏移地址
                                 | DEV_UDSP_CHNn_SMF_SRC_DATA_TYPE_REALINT32 | DEV_UDSP_CHNn_SMF_SRC_DATA_FORMAT_LOW_24BIT | ((fft_struct->input_size - 1) << 12) | (fft_struct->nmemb - 1) // 总长度
        ;
    uint32_t spectrum_enable = fft_struct->spectrum_enable;
    spectrum_enable = spectrum_enable > 1 ? 1 : spectrum_enable;
    DEV_UDSP->CHN[channel].DMF = (fft_struct->output_size << 16)                                                                                // 目的地址偏移
                                 | DEV_UDSP_CHNn_DMF_DST_DATA_TYPE_REALINT32 | ((fft_struct->output_size - 1) << 12) | (fft_struct->nmemb + 1); // 因为复数，并只输出前一半加1

    if (spectrum_enable == DISABLE)
    {
        DEV_UDSP->CHN[channel].DMF |= DEV_UDSP_CHNn_DMF_DST_DATA_TYPE_COMPLEXORLONG64;
    }

    DEV_UDSP->CHN[channel].LMF0 = DEV_UDSP_CHNn_LMF0_SMA_WR_BUF0_SEL_ENABLE | DEV_UDSP_CHNn_LMF0_SMA_RD_BUF0_SEL_ENABLE;
    uint32_t fft_point_flag = 0;

    switch (fft_struct->nmemb)
    {
    case 32:
        fft_point_flag = 0;
        break;

    case 64:
        fft_point_flag = 1;
        break;

    case 128:
        fft_point_flag = 2;
        break;

    case 256:
        fft_point_flag = 3;
        break;

    case 512:
        fft_point_flag = 4;
        break;

    case 1024:
        fft_point_flag = 5;
        break;

    default:
        ret = -1;
        break;
    }

    uint32_t win_enable = fft_struct->win_enable;
    win_enable = win_enable > 1 ? 1 : win_enable;
    DEV_UDSP->CHN[channel].CFG0 = DEV_UDSP_CHNn_CFG0_SMR_ENABLE | (win_enable << 2) | DEV_UDSP_CHNn_CFG0_FFT_ENABLE | (spectrum_enable << 8) | DEV_UDSP_CHNn_CFG0_SMW_ENABLE | (fft_point_flag << 20);

    // CCTL
    if (input_addr_HSB == 0x4 || input_addr_HSB == 0x5)
    {
        // write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_WB_ALL);
        // 将D-cache空间写入memory,但不会将D-cache空间内容无效化
        write_csr(NDS_MCCTLCOMMAND, 7);
    }

    if (output_addr_HSB == 0x4 || output_addr_HSB == 0x5)
    {
        // write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_INVAL_ALL);
        // 将D-cache空间无效化
        write_csr(NDS_MCCTLCOMMAND, 23);
    }

    return ret;
}

/**
 * @brief        计算irfft
 * @details      就算将buffer0中计算fft
 * @param        @arg channel: 使用的usdp通道， 参数范围 0-7
 *               @arg fft_struct: @UDSP_FFT_InputStruct
 * @return       @arg =0：无任何异常
 *                    >=:配置成功，但数据有溢出
 *                    <0: 配置失败
 * @note         注意udsp不能直接访问local memory和cache，但内部会处理
 */
// 输入是32bit但实际ifft只能处理24bit的数据
int udsp_irfft(int channel, UDSP_IRFFT_InputStruct *irfft_struct)
{
    int32_t ret = 0;
    uint32_t input_size = irfft_struct->input_size;
    uint32_t ifft_number = irfft_struct->nmemb;
    int32_t *complex_temp = irfft_struct->complex_temp;

    if (input_size > 4)
    {
        return -1;
    }

    int8_t *complex_temp_i8 = (void *)0;
    int16_t *complex_temp_i16 = (void *)0;
    int32_t *complex_temp_i32 = (void *)0;

    if (input_size == 1)
    {
        complex_temp_i8 = (int8_t *)irfft_struct->in_data_current;
    }
    else if (input_size == 2)
    {
        complex_temp_i16 = (int16_t *)irfft_struct->in_data_current;
    }
    else if (input_size == 4)
    {
        complex_temp_i32 = (int32_t *)irfft_struct->in_data_current;
    }

    for (int i = 0; i < (ifft_number / 2 + 1) * 2; i++)
    {
        if (input_size == 1)
        {
            complex_temp[i] = complex_temp_i8[i];
        }
        else if (input_size == 2)
        {
            complex_temp[i] = complex_temp_i16[i];
        }
        else if (input_size == 4)
        {
            complex_temp[i] = complex_temp_i32[i];
        }
    }

    // 将输入共轭对称
    for (int i = 0; i < (ifft_number / 2 - 1); i++)
    {
        complex_temp[(ifft_number * 2 - 2) - 2 * i] = complex_temp[2 + 2 * i];
        complex_temp[(ifft_number * 2 - 1) - 2 * i] = -complex_temp[3 + 2 * i];
    }

    uint32_t input_addr_HSB, output_addr_HSB;
    uint32_t low_addr, upper_addr, current_addr;
    input_addr_HSB = (uint32_t)complex_temp;
    input_addr_HSB = input_addr_HSB >> 28;
    low_addr = (uint32_t)complex_temp;
    upper_addr = (uint32_t)complex_temp + ifft_number * 2 * sizeof(complex_temp[0]);
    current_addr = (uint32_t)complex_temp;

    if (input_addr_HSB == 0)
    {
        low_addr = low_addr | 0x61000000;
        upper_addr = upper_addr | 0x61000000;
        current_addr = current_addr | 0x61000000;
    }

    DEV_UDSP->CHN[channel].SLA = low_addr;
    DEV_UDSP->CHN[channel].SUA = upper_addr;
    DEV_UDSP->CHN[channel].SCA = current_addr;
    output_addr_HSB = (uint32_t)irfft_struct->out_data_current;
    output_addr_HSB = output_addr_HSB >> 28;
    low_addr = (uint32_t)irfft_struct->out_data_low;
    upper_addr = (uint32_t)irfft_struct->out_data_upper;
    current_addr = (uint32_t)irfft_struct->out_data_current;

    if (output_addr_HSB == 0)
    {
        low_addr = low_addr | 0x61000000;
        upper_addr = upper_addr | 0x61000000;
        current_addr = current_addr | 0x61000000;
    }

    DEV_UDSP->CHN[channel].DLA = low_addr;
    DEV_UDSP->CHN[channel].DUA = upper_addr;
    DEV_UDSP->CHN[channel].DCA = current_addr;
    DEV_UDSP->CHN[channel].SMF = (sizeof(complex_temp[0]) << 16)                                 // 源偏移地址 与输入无关
                                 | DEV_UDSP_CHNn_SMF_SRC_DATA_TYPE_COMPLEXORLONG64 | ((2) << 12) // fft ifft 不能发是32bit输入
                                 | (ifft_number * 2 - 1)                                         // 复数的长度需要乘2
        ;
    DEV_UDSP->CHN[channel].DMF = (irfft_struct->output_size << 16) // 目的地址偏移
                                 | DEV_UDSP_CHNn_DMF_DST_DATA_TYPE_REALINT32 | ((irfft_struct->output_size - 1) << 12) | (ifft_number - 1);
    DEV_UDSP->CHN[channel].LMF0 = DEV_UDSP_CHNn_LMF0_SMA_WR_BUF0_SEL_ENABLE | DEV_UDSP_CHNn_LMF0_SMA_RD_BUF0_SEL_ENABLE;
    //  DEV_UDSP->CHN[channel].LMF4 = 6<<12;//[33:08]
    uint32_t fft_point_flag = 0;

    switch (ifft_number)
    {
    case 32:
        fft_point_flag = 0;
        break;

    case 64:
        fft_point_flag = 1;
        break;

    case 128:
        fft_point_flag = 2;
        break;

    case 256:
        fft_point_flag = 3;
        break;

    case 512:
        fft_point_flag = 4;
        break;

    case 1024:
        fft_point_flag = 5;
        break;

    default:
        ret = -1;
        break;
    }

    DEV_UDSP->CHN[channel].LMF4 = (fft_point_flag + 3) << 12;
    DEV_UDSP->CHN[channel].CFG0 = DEV_UDSP_CHNn_CFG0_SMR_ENABLE | DEV_UDSP_CHNn_CFG0_IFFT_ENABLE | DEV_UDSP_CHNn_CFG0_SMW_ENABLE | (fft_point_flag << 20);

    // CCTL
    if (input_addr_HSB == 0x4 || input_addr_HSB == 0x5)
    {
        // write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_WB_ALL);
        // 将D-cache空间写入memory,但不会将D-cache空间内容无效化
        write_csr(NDS_MCCTLCOMMAND, 7);
    }

    if (output_addr_HSB == 0x4 || output_addr_HSB == 0x5)
    {
        // write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_INVAL_ALL);
        // 将D-cache空间无效化
        write_csr(NDS_MCCTLCOMMAND, 23);
    }

    return ret;
}

/*
    各点数RFFT, nmemb可为128,256,512,1024

    TODO: 如果每次调用的窗函数相同，则只需配第一次，但目前每次都配
*/
static void dsp_rfft(dspStartParam_s *startParam, int16_t nmemb)
{
    udsp_init();
    UDSP_FFT_InputStruct fft_struct;
    fft_struct.in_data_current = (void *)startParam->src;
    fft_struct.in_data_low = (void *)startParam->src;
    fft_struct.in_data_upper = (void *)(startParam->src + startParam->srcLen);
    fft_struct.out_data_current = (void *)startParam->dest;
    fft_struct.out_data_low = (void *)startParam->dest;
    fft_struct.out_data_upper = (void *)(startParam->dest + startParam->destLen);
    fft_struct.input_size = sizeof(int16_t);
    fft_struct.nmemb = nmemb;
    fft_struct.spectrum_enable = startParam->mode;
    fft_struct.output_size = startParam->mode ? sizeof(uint64_t) : sizeof(int32_t);

    if (nmemb == 1024 || startParam->win == 0)
    {
        fft_struct.win_enable = 0;
        udsp_rfft(ALGO_UDSP_CALC_CHANNEL, &fft_struct);
        UDSP_Cmd(ALGO_UDSP_CALC_CHANNEL, ENABLE);
    }
    else
    {
        fft_struct.win_enable = 1;
        udsp_load_buffer1(ALGO_UDSP_PARAM_CHANNEL, startParam->win, sizeof(int32_t), nmemb, 0);
        udsp_rfft(ALGO_UDSP_CALC_CHANNEL, &fft_struct);
        UDSP_Cmd(ALGO_UDSP_PARAM_CHANNEL, ENABLE);
        UDSP_Cmd(ALGO_UDSP_CALC_CHANNEL, ENABLE);
    }
}

static int32_t temp[2048] = {0}; // large enough for 1024-point IFFT

static void dsp_irfft(dspStartParam_s *startParam, int16_t nmemb)
{
    udsp_init();
    UDSP_IRFFT_InputStruct fft_struct;
    fft_struct.in_data_current = (void *)startParam->src;
    fft_struct.in_data_low = (void *)startParam->src;
    fft_struct.in_data_upper = (void *)(startParam->src + startParam->srcLen);
    fft_struct.out_data_current = (void *)startParam->dest;
    fft_struct.out_data_low = (void *)startParam->dest;
    fft_struct.out_data_upper = (void *)(startParam->dest + startParam->destLen);
    fft_struct.input_size = sizeof(int32_t); // 实部或虚部的size
    fft_struct.nmemb = nmemb;
    fft_struct.output_size = sizeof(int32_t);
    fft_struct.complex_temp = temp;
    udsp_irfft(ALGO_UDSP_CALC_CHANNEL, &fft_struct);
    UDSP_Cmd(ALGO_UDSP_CALC_CHANNEL, ENABLE);
}

#if 1
static void dspFeature(dspStartParam_s *startParam)
{
    DEV_RMU->RSTEN0 &= ~DEV_RMU_RSTEN0_UDSP;
    DEV_CMU->CLKEN0 |= DEV_CMU_CLKEN0_UDSP;
    DEV_RMU->RSTEN0 |= DEV_RMU_RSTEN0_UDSP;

    //! 1.打开buf1使能
    DEV_UDSP->CHN[ALGO_UDSP_PARAM_CHANNEL].SCA = startParam->win;
    DEV_UDSP->CHN[ALGO_UDSP_PARAM_CHANNEL].SLA = startParam->win;
    DEV_UDSP->CHN[ALGO_UDSP_PARAM_CHANNEL].SUA = startParam->win + 4096;
    DEV_UDSP->CHN[ALGO_UDSP_PARAM_CHANNEL].LMF0 = DEV_UDSP_CHNn_LMF0_SMA_WR_BUF1_SEL_ENABLE;
    DEV_UDSP->CHN[ALGO_UDSP_PARAM_CHANNEL].SMF = 0x433ff;
    DEV_UDSP->CHN[ALGO_UDSP_PARAM_CHANNEL].CFG0 = 1;

    //! 2.cfg
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].SCA = startParam->src;
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].SLA = startParam->src;
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].SUA = startParam->src + startParam->srcLen;
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].DCA = startParam->dest;
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].DLA = startParam->dest;
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].DUA = startParam->dest + startParam->destLen;
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].SMF = (2 << 16);                               //! 源数据是 16bit 且2 个数据拼成了 1 个 32bit
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].SMF |= DEV_UDSP_CHNn_SMF_SRC_DATA_WIDTH_16BIT; //! 数据宽度
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].SMF |= 0xFF;                                   //! 数据长度
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].DMF = (2 << 16);
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].DMF |= DEV_UDSP_CHNn_DMF_DST_DATA_WIDTH_16BIT;

    if (startParam->cfg == FBANK_CFG)
    {
        DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].DMF |= 25;
    }
    else
    {
        DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].DMF |= 11;
    }

    //! 3.打开buf0读写使能
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].LMF0 = DEV_UDSP_CHNn_LMF0_SMA_WR_BUF0_SEL_ENABLE;
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].LMF0 |= DEV_UDSP_CHNn_LMF0_SMA_RD_BUF0_SEL_ENABLE;
    if (startParam->cfg == MFCC_CFG)
    {
        DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].LMF0 |= (1 << 8);
    }

    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].LMF1 = (1 << 20);
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].LMF2 = 0;
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].LMF3 = (5 << 8) | 2;
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].LMF4 = (4 << 20);
    //! 配置cfg0
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].CFG0 = DEV_UDSP_CHNn_CFG0_FFT_POINT_0256POINT;
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].CFG0 |= DEV_UDSP_CHNn_CFG0_SMR_ENABLE | DEV_UDSP_CHNn_CFG0_PRE_ENABLE | DEV_UDSP_CHNn_CFG0_WIN_ENABLE | DEV_UDSP_CHNn_CFG0_FFT_ENABLE | DEV_UDSP_CHNn_CFG0_ABS2_ENABLE | DEV_UDSP_CHNn_CFG0_FBK_ENABLE | DEV_UDSP_CHNn_CFG0_LOG_ENABLE | DEV_UDSP_CHNn_CFG0_SMW_ENABLE;
    if (startParam->cfg == MFCC_CFG)
    {
        DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].CFG0 |= DEV_UDSP_CHNn_CFG0_MAC_ENABLE;
    }

    //! 配置cfg1
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].CFG1 = (11 << 16);
    DEV_UDSP->CHN[ALGO_UDSP_CALC_CHANNEL].CFG1 |= 25;
    //! 配置中断
    DEV_UDSP->IE = (1 << (ALGO_UDSP_CALC_CHANNEL));
    //! 启动dsp
    DEV_UDSP->EN = (1 << (ALGO_UDSP_CALC_CHANNEL + 16)) | (1 << (ALGO_UDSP_PARAM_CHANNEL + 16)) | (1 << (ALGO_UDSP_CALC_CHANNEL)) | (1 << (ALGO_UDSP_PARAM_CHANNEL));
}
#endif

/*!
 * \brief dsp初始化函数,外界可调,主要功能
 *        a. 变量初始化
 *        b. 为调度器下探指针提供接口
 */
void dspInit(dspListener_s *dspListener)
{
    gDspListener = dspListener;
}

uint8_t startDsp(dspStartParam_s *startParam)
{
    if (startParam->cfg == FFT_128_CFG)
    {
        dsp_rfft(startParam, 128);
    }
    else if (startParam->cfg == IFFT_128_CFG)
    {
        dsp_irfft(startParam, 128);
    }
    else if (startParam->cfg == FFT_256_CFG)
    {
        dsp_rfft(startParam, 256);
    }
    else if (startParam->cfg == IFFT_256_CFG)
    {
        dsp_irfft(startParam, 256);
    }
    else if (startParam->cfg == FFT_512_CFG)
    {
        dsp_rfft(startParam, 512);
    }
    else if (startParam->cfg == IFFT_512_CFG)
    {
        dsp_irfft(startParam, 512);
    }
    else if (startParam->cfg == FFT_1024_CFG)
    {
        dsp_rfft(startParam, 1024);
    }
    else if (startParam->cfg == IFFT_1024_CFG)
    {
        dsp_irfft(startParam, 1024);
    }
    else if ((startParam->cfg == FBANK_CFG) || (startParam->cfg == MFCC_CFG))
    {
        dspFeature(startParam);
    }

    return 1;
}

void udsp_irq_handler(void)
{
    // fft数据计算有溢出
    if (DEV_UDSP->PD & (DEV_UDSP_PD_FFT_BIT31_OF | DEV_UDSP_PD_FFT_BIT32_OF))
    {
        // DPrintf("fft overflow\n");
        DEV_UDSP->PD = (DEV_UDSP_PD_FFT_BIT31_OF | DEV_UDSP_PD_FFT_BIT32_OF);
    }
    //! 若此时是算法通道，则直接通知调度器
    else if (DEV_UDSP->PD & (1 << (ALGO_UDSP_CALC_CHANNEL)))
    {
        DEV_UDSP->PD = 3;

        // 通知调度器
        if ((gDspListener != NULL) && (gDspListener->dspListener != NULL))
        {
            gDspListener->dspListener();
        }
    }

    DEV_RMU->RSTEN0 &= ~DEV_RMU_RSTEN0_UDSP;
    DEV_CMU->CLKEN0 &= ~DEV_CMU_CLKEN0_UDSP;
}
