/*
    提供调用uDSP进行FFT计算的示例函数。
    uDSP支持128-1024点（必须为2的N次方）的FFT及IFFT，仅支持定点数。浮点数必须先转成int16类型。为降低数值误差，量化后的输入应尽量占满int16的范围
    可以选择输出实部虚部或能量谱，但不能同时输出。

    因uDSP为异步计算，结束后必须调用回调函数。回调函数无参数。
*/
#include "platform.h"
#include "hal_headfile.h"
#include "system.h"
#include "udsp_demo.h"
#include "debug.h"
#include "dspHandler.h"


static int32_t my_window[FFT_N] = {0};      // 窗函数，类型为Q8.23，即0x800000代表1，对于512点及以下的正向FFT有效，IFFT及1024点FFT无效。
static int32_t fft_output[FFT_N + 2] = {0}; // FFT输出，为了能在回调函数中读取，定义为全局数组
void (*user_udsp_callback)(void) = NULL;




void callback_rfft(void)
{
	if(user_udsp_callback != NULL)
	{
		user_udsp_callback();
	}
}

void callback_spectrum(void)
{
    debug("first 10 energy values (lower 32 bits, higher 32 bits): \n");
    for (int i = 0; i < 10; i++)
    {
        debug("%d\n", fft_output[2 * i], fft_output[2 * i + 1]);
    }
}

dspListener_s dsp_listener = {callback_rfft};
// dspListener_s dsp_listener = {callback_spectrum};

/*
    256点RFFT示例
    输入数据：int16，实数。如果不足256点，需要补0。
    输出数据：int32, 实部虚部交替排列，即[x0.real, x0.imag, x1.real, x1.imag, ..., x128.real, x128.imag]
    长度为 129 * 2 * 4 字节, x0.imag和x128.imag一定为0

    如果要返回能量值（实部虚部平方和），将param.mode设置为1

*/
void user_rfft(int16_t *src, int32_t *dest)
{
    dspStartParam_s param;
#if FFT_N == 256
    param.cfg = FFT_256_CFG;
#elif FFT_N == 512
    param.cfg = FFT_512_CFG;
#elif FFT_N == 1024
    param.cfg = FFT_1024_CFG;
#endif
    param.src = (uint32_t)src;     // 输入数据地址
    param.dest = (uint32_t)dest;   // 输出数据地址。如果输入数据后续不再使用，可以将输入输出设为同一地址。但是要按照输出长度预留内存。
    param.srcLen = FFT_N * 2;      // 输出长度，单位字节
    param.destLen = FFT_N * 4 + 8; // 输出长度，单位字节
    param.ctl = 0;                 // 不要改动
    param.mode = 0;                // 0: 输出频域信号，1：输出能量。能量为64位，由两个int32拼接而成
    param.win = my_window;         // 窗函数地址，对于512点及以下的正向FFT有效，IFFT及1024点FFT无效。如不使用，设置为0

    debug("start rfft\n");
    startDsp(&param);
}


void rfft_udsp_init(void* callback)
{
    // 全设为1，相当于不加窗。可根据需要改为其他窗函数
    for (int i = 0; i < FFT_N; i++)
    {
    	my_window[i] = 0x800000;
    }
    user_udsp_callback = callback;
	dspInit(&dsp_listener); //设置回调函数
}
/*
    结果可和numpy.fft.rfft对比
    
*/



//void rfft_demo(void)
//{
//    dspInit(&dsp_listener); //设置回调函数
//
//    int16_t x[FFT_N];
//    for (int i = 0; i < FFT_N; i++)
//        x[i] = i * 10;
//    rfft(x, fft_output);
//}
//
///**
//    * udsp计算完FFT后的回掉函数
//    *
//    * @param: none
//    * @return: none.
//    */
//   rfft_udsp_init(user_callback_rfft);
//   rfft((int16_t*)audio_buffer[0],(int32_t*)fft_256_output);
//   void user_callback_rfft(void)
//   {
//   	uint64_t Power;
//   	uint32_t Power_Spectrum[FFT_N];
//   	for (int i = 0;i < FFT_N/2; i++)
//   	{
//   		Power = fft_256_output[2 * i]*fft_256_output[2 * i] + fft_256_output[2 * i + 1]*fft_256_output[2 * i + 1];
//   		Power_Spectrum[i] = Power;
//   		debug("[%d]:%d\r\n",i,Power_Spectrum[i]);//不能打印太多，不然dac输出会断流，导致声音不正常
//   	}
//   }
