#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include "htra_api.h" 
#include "example.h"
using namespace std;

#define IS_USB 1 // 默认假设是 USB，若接口为ETH，请为此行代码添加注释

int DSP_DDC()
{
	int Status = 0;      //函数的返回。
	void* Device = NULL; //当前设备的内存地址。
	int DevNum = 0;      //指定设备号。

	BootProfile_TypeDef BootProfile; //启动配置结构体，包括物理接口、供电方式等。
	BootInfo_TypeDef BootInfo;       //启动信息结构体，包括设备信息、USB速率等。

	BootProfile.DevicePowerSupply = USBPortAndPowerPort; //使用USB数据端口及独立电源端口双供电。

#if IS_USB==1
	//配置USB接口。
	BootProfile.PhysicalInterface = USB;
#else 
	//配置ETH接口。
	BootProfile.PhysicalInterface = ETH;
	BootProfile.ETH_IPVersion = IPv4;
	BootProfile.ETH_RemotePort = 5000;
	BootProfile.ETH_ReadTimeOut = 5000;
	BootProfile.ETH_IPAddress[0] = 192;
	BootProfile.ETH_IPAddress[1] = 168;
	BootProfile.ETH_IPAddress[2] = 1;
	BootProfile.ETH_IPAddress[3] = 100;
#endif

	Status = Device_Open(&Device, DevNum, &BootProfile, &BootInfo); //打开设备。

	Device_Open_ErrorHandling(Status, &Device, DevNum, &BootProfile, &BootInfo); //当Status不为0时，根据Status的返回值进行相对应的错误处理。

	IQS_Profile_TypeDef IQS_ProfileIn;  //IQS模式输入配置，包括中心频率、抽取倍数、参考电平等。
	IQS_Profile_TypeDef IQS_ProfileOut; //IQS模式输出配置。
	IQS_StreamInfo_TypeDef StreamInfo;  //当前配置下的IQ数据流相关信息。
	IQStream_TypeDef IQStream;          //当前配置下获取IQ数据相关的参数，包括IQ数据、ScaleToV、I_MaxValue等。

	Status = IQS_ProfileDeInit(&Device, &IQS_ProfileIn); //调用此函数初始化配置IQS模式的相关参数。

	//下发参数配置
	IQS_ProfileIn.CenterFreq_Hz = 1e9;       //配置中心频率。
	IQS_ProfileIn.RefLevel_dBm = 0;          //配置参考电平。
	IQS_ProfileIn.DecimateFactor = 1;	     //配置抽取倍数。
	IQS_ProfileIn.DataFormat = Complex16bit; //配置IQ数据格式。
	IQS_ProfileIn.TriggerMode = FixedPoints; //配置触发模式。FixedPoints模式是触发信号的上升沿开始采样。采到TriggerLength个点后结束采样。Adaptive模式是触发信号的上升沿开始采样，下降沿结束采样。
	IQS_ProfileIn.TriggerSource = Bus;       //配置触发源。
	IQS_ProfileIn.BusTimeout_ms = 5000;      //配置总线超时时间。
	IQS_ProfileIn.TriggerLength = 16242;     //配置采样点数。仅当TriggerMode设置为FixedPoints时生效。

	Status = IQS_Configuration(&Device, &IQS_ProfileIn, &IQS_ProfileOut, &StreamInfo); //通过调用此函数下发IQS模式的相关配置。

	IQS_Configuration_ErrorHandling(Status, &Device, DevNum, &BootProfile, &BootInfo, &IQS_ProfileIn, &IQS_ProfileOut, &StreamInfo); //当Status不为0时，根据Status的返回值进行相对应的错误处理

	vector<int16_t> AlternIQStream(StreamInfo.StreamSamples * 2); //存放IQ数据，数据存放格式为IQIQIQ...。

	/*启动DSP功能*/
	void* DSP = NULL;        //开辟数字信号处理地址
	Status = DSP_Open(&DSP); //开启信号处理功能

	/*配置DDC模式*/
	DSP_DDC_TypeDef DDC_ProfileIn;  //DDC输入参数配置，包括复混频的频率偏移值，复混频采样率，采样点数等。
	DSP_DDC_TypeDef DDC_ProfileOut; //DDC输出参数配置。
	IQStream_TypeDef IQStreamOut;   //DDC之后IQ相关数据。（配置、返回信息和暂存数据）

	Status = DSP_DDC_DeInit(&DDC_ProfileIn); //调用此函数初始化配置DDC模式的相关参数。


	DDC_ProfileIn.DDCOffsetFrequency = 10e6;                               //配置DDC的频率偏移。
	DDC_ProfileIn.DecimateFactor = 2;                                      //配置DDC的抽取倍数。
	DDC_ProfileIn.SamplePoints = StreamInfo.StreamSamples;                 //配置采样点数。
	DDC_ProfileIn.SampleRate = StreamInfo.IQSampleRate;                    //配置采样率。
	Status = DSP_DDC_Configuration(&DSP, &DDC_ProfileIn, &DDC_ProfileOut); //通过调用此函数下发DDC模式的相关配置。

	//FFT模式配置
	DSP_FFT_TypeDef IQToSpectrumIn;  //FFT模式输入参数配置，包括FFT点数、检波方式等。
	DSP_FFT_TypeDef IQToSpectrumOut; //FFT模式输出参数配置。
	uint32_t TracePoints = 0;        //存放FFT后的频谱点数。

	DSP_FFT_DeInit(&IQToSpectrumIn); //调用此函数初始化配置FFT模式的相关参数。

	IQToSpectrumIn.Calibration = 0;                         //配置是否开启校准，0则不开校准，其他值开启。
	IQToSpectrumIn.DetectionRatio = 1;                      //配置检波率。
	IQToSpectrumIn.TraceDetector = TraceDetector_PosPeak;   //配置检波方式。
	IQToSpectrumIn.FFTSize = DDC_ProfileOut.SamplePoints;   //配置FFT点数。
	IQToSpectrumIn.Intercept = 1;                           //配置截取率。
	IQToSpectrumIn.SamplePts = DDC_ProfileOut.SamplePoints; //配置采样点数。
	IQToSpectrumIn.WindowType = FlatTop;                    //配置窗型。

	double RBWRatio = 0; //返回RBW比值，RBW = RBWRatio * StreamInfo.IQSampleRate。

	DSP_FFT_Configuration(&DSP, &IQToSpectrumIn, &IQToSpectrumOut, &TracePoints, &RBWRatio); //通过调用此函数下发FFT模式的相关配置。

	vector<double> Frequency(TracePoints); //存放频率数组。
	vector<float> Spectrum(TracePoints);   //存放功率数组。

	//循环获取并FFT。
	while (1)
	{
		Status = IQS_BusTriggerStart(&Device); //调用IQS_BusTriggerStart触发设备。若触发源为外部触发，则不需要调用此函数。

		uint32_t IQPoints = 0;
		for (int i = 0; i < StreamInfo.PacketCount; i++)
		{
			Status = IQS_GetIQStream_PM1(&Device, &IQStream); //获取IQ数据。

			if (Status == APIRETVAL_NoError)
			{
				if (i != StreamInfo.PacketCount - 1) //当前包不为最后一包时。
				{
					memcpy(AlternIQStream.data() + IQPoints, IQStream.AlternIQStream, sizeof(int16_t) * 2 * StreamInfo.PacketSamples);
					IQPoints += StreamInfo.PacketSamples * 2;
				}

				else //当前包为最后一包时。
				{
					if (StreamInfo.StreamSamples % StreamInfo.PacketSamples != 0) //最后一包IQ数据不满一整包时。
					{
						memcpy(AlternIQStream.data() + IQPoints, IQStream.AlternIQStream, sizeof(int16_t) * 2 * (StreamInfo.StreamSamples % StreamInfo.PacketSamples));
					}

					else //最后一包IQ数据为一整包时。
					{
						memcpy(AlternIQStream.data() + IQPoints, IQStream.AlternIQStream, sizeof(int16_t) * 2 * StreamInfo.PacketSamples);
					}
				}

			}
			else //当Status不为0时，根据Status的返回值进行相对应的错误处理。
			{
				IQS_ErrorHandlingExceptOpenAndConfiguration(Status, &Device, DevNum, &BootProfile, &BootInfo, &IQS_ProfileIn, &IQS_ProfileOut, &StreamInfo);
			}

		}
		IQStream.AlternIQStream = AlternIQStream.data(); //让AlternIQStream指针指向实际存在IQ数据的地址。

		Status = DSP_DDC_Execute(&DSP, &IQStream, &IQStreamOut);                               //执行DDC。
		Status = DSP_FFT_IQSToSpectrum(&DSP, &IQStreamOut, Frequency.data(), Spectrum.data()); //执行IQ转频谱函数。

	}
		Status = IQS_BusTriggerStop(&Device); //调用IQS_BusTriggerStop停止触发设备。若触发源为外部触发，则不需要调用此函数。

		DSP_Close(&DSP); //关闭DSP功能
		Status = Device_Close(&Device); //关闭设备
		return 0;
}
