#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
#include "htra_api.h" 
#include "example.h"
using namespace std;
#define IS_USB 1 //默认使用的是USB型设备，若使用的是网口型设备则将IS_USB定义为0。

int DSP_IQSToSpectrum()
{
	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输入配置，包括起始频率、终止频率、RBW、参考电平等。
	IQS_Profile_TypeDef IQS_ProfileOut; //IQS输出配置。
	IQS_StreamInfo_TypeDef StreamInfo;  //当前配置下IQ数据信息，包括带宽,IQ单路采样率等。
	IQStream_TypeDef IQStream;          //存放IQ数据包，包括：IQ数据、配置信息。

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

	IQS_ProfileIn.CenterFreq_Hz = 1e9;       //配置中心频率。        
	IQS_ProfileIn.RefLevel_dBm = 0;          //配置参考电平。
	IQS_ProfileIn.DataFormat = Complex16bit; //配置IQ数据格式。
	IQS_ProfileIn.TriggerMode = FixedPoints; //配置触发模式。
	IQS_ProfileIn.TriggerSource = Bus;       //配置触发源为内部总线触发。
	IQS_ProfileIn.DecimateFactor = 2;        //配置抽取倍数。
	IQS_ProfileIn.BusTimeout_ms = 5000;      //配置总线超时时间。
	IQS_ProfileIn.TriggerLength = 16242;     //配置采样点数。

	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...。

	void* DSP = NULL;                                                  
	DSP_Open(&DSP); //打开DSP功能。

	DSP_FFT_TypeDef IQToSpectrumIn;  //配置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 = StreamInfo.StreamSamples;    //配置FFT点数。
	IQToSpectrumIn.Intercept = 1;                         //配置截取率。
	IQToSpectrumIn.SamplePts = StreamInfo.StreamSamples;  //配置采样点数。
	IQToSpectrumIn.WindowType = FlatTop;                  //配置窗型。

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

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

	/*获取IQ数据，并将其转频谱*/
	vector<double> Frequency(TracePoints); //创建数组存放频率数据。
	vector<float> Spectrum(TracePoints);   //创建数组存放幅度数据。

	while (1)
	{
		Status = IQS_BusTriggerStart(&Device); //调用IQS_BusTriggerStart触发设备。若触发源为外部触发，则不需要调用此函数。
		if (Status==APIRETVAL_NoError)
		{
			uint32_t IQPoints = 0; //记录实际的IQ点数。
			for (int i = 0; i < StreamInfo.PacketCount; i++)
			{
				Status = IQS_GetIQStream_PM1(&Device, &IQStream); //获取IQ数据。

				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数据的地址。
		DSP_FFT_IQSToSpectrum(&DSP, &IQStream, Frequency.data(), Spectrum.data()); //执行IQ转频谱函数。
	}

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

	DSP_Close(&DSP);

	Status = Device_Close(&Device);

	return 0;
}
