using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HTRA_CSharp_Examples
{
    class DSP_LPF
    {
		public void Example()
		{
			#region 1 打开设备

			int Status = 0;              //函数的返回。
			IntPtr Device = IntPtr.Zero; //当前设备的内存地址。
			int DevNum = 0;              //指定设备号。

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

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

			//设备数据接口为USB时直接运行，为网口时将 #if true 改为 #if false
#if true
			BootProfile.PhysicalInterface = HtraApi.PhysicalInterface_TypeDef.USB;
#else
			//配置网络相关参数
			BootProfile.PhysicalInterface = HtraApi.PhysicalInterface_TypeDef.ETH;
			BootProfile.ETH_IPVersion = HtraApi.IPVersion_TypeDef.IPv4;
			BootProfile.ETH_RemotePort = 5000;
			BootProfile.ETH_ReadTimeOut = 5000;
			BootProfile.ETH_IPAddress = new byte[16];
			BootProfile.ETH_IPAddress[0] = 192;
			BootProfile.ETH_IPAddress[1] = 168;
			BootProfile.ETH_IPAddress[2] = 1;
			BootProfile.ETH_IPAddress[3] = 100;
#endif

			Status = HtraApi.Device_Open(ref Device, DevNum, ref BootProfile, ref BootInfo); //打开设备

			if (Status == 0)
			{
				System.Console.WriteLine("Device is opened successfully");
			}

			/*设备打开失败，返回错误提示，发生以下错误时，设备无法正常运行，建议按照提示操作后重新打开设备*/
			else
			{
				switch (Status)
				{
					case HtraApi.APIRETVAL_ERROR_BusOpenFailed:
						System.Console.WriteLine("Error - Check the device power supply, data cable connection and driver installation");
						return;

					case HtraApi.APIRETVAL_ERROR_RFACalFileIsMissing:
						System.Console.WriteLine("Error - RF calibration file is missing");
						return;

					case HtraApi.APIRETVAL_ERROR_IFACalFileIsMissing:
						System.Console.WriteLine("Error - IF calibration file is missing");
						return;

					case HtraApi.APIRETVAL_ERROR_DeviceConfigFileIsMissing:
						System.Console.WriteLine("Error - Configuration file missing");
						return;

					case HtraApi.APIRETVAL_ERROR_DeviceSpecFileIsMissing:
						System.Console.WriteLine("Error - Device specification file is missing");
						return;

					default:
						System.Console.WriteLine("Return other errors！ Status = " + Status);
						return;
				}
			}
			#endregion

			#region 2 配置参数
			HtraApi.IQStream_TypeDef IQStream = new HtraApi.IQStream_TypeDef();				  //当前配置下获取IQ数据相关的参数，包括IQ数据、ScaleToV、I_MaxValue等。
			HtraApi.IQS_Profile_TypeDef IQSIn = new HtraApi.IQS_Profile_TypeDef();			  //IQS模式输入配置，包括中心频率、抽取倍数、参考电平等。
			HtraApi.IQS_Profile_TypeDef IQSOut = new HtraApi.IQS_Profile_TypeDef();		      //IQS模式输出配置。
			HtraApi.IQS_StreamInfo_TypeDef StreamInfo = new HtraApi.IQS_StreamInfo_TypeDef(); //当前配置下的IQ数据流相关信息。

			HtraApi.IQS_ProfileDeInit(ref Device, ref IQSIn); //调用此函数初始化配置IQS模式的相关参数。

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

			Status = HtraApi.IQS_Configuration(ref Device, ref IQSIn, ref IQSOut, ref StreamInfo); //通过调用此函数下发IQS模式的相关配置。

			Int16[] AlternIQStream = new Int16[StreamInfo.StreamSamples * 2]; //创建数组存放IQ数据，数据存放格式为IQIQIQ...

			//打开DSP功能
			IntPtr DSP = IntPtr.Zero;  //开辟数字信号处理地址
			HtraApi.DSP_Open(ref DSP); //开启信号处理功能

			//低通滤波器配置
			HtraApi.Filter_TypeDef LPF_ProfileIn = new HtraApi.Filter_TypeDef();   //配置需要生成滤波器系数的参数，包括滤波器抽头数、截止频率、阻带衰减等。
			HtraApi.Filter_TypeDef LPF_ProfileOut = new HtraApi.Filter_TypeDef();  //输出生成滤波器系数的参数。
			HtraApi.IQStream_TypeDef IQStreamOut = new HtraApi.IQStream_TypeDef(); //低通滤波之后的IQ数据。

			HtraApi.DSP_LPF_DeInit(ref LPF_ProfileIn); //初始化配置LPF模式的相关参数。

			LPF_ProfileIn.As = 90;    //配置滤波器的阻带衰减。
			LPF_ProfileIn.fc = 0.25f; //配置滤波器截止频率。
			LPF_ProfileIn.mu = 0;     //配置分数采样偏移量。
			LPF_ProfileIn.n = 90;     //配置滤波器阶数。

			LPF_ProfileIn.Samples = (UInt32)StreamInfo.StreamSamples; //配置采样点数。

			HtraApi.DSP_LPF_Configuration(ref DSP, ref LPF_ProfileIn, ref LPF_ProfileOut); //配置LPF的相关参数。

			//FFT模式配置
			HtraApi.DSP_FFT_TypeDef IQToSpectrumIn = new HtraApi.DSP_FFT_TypeDef();   //配置需要下发的FFT模式参数，包括FFT点数、检波方式等。
			HtraApi.DSP_FFT_TypeDef IQToSpectrumOut = new HtraApi.DSP_FFT_TypeDef();  //反馈实际下发的FFT模式参数，包括FFT点数、检波方式等。
			UInt32 TracePoints = 0;													  //此参数用于存放经过FFT后的频谱点数。

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

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

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

			HtraApi.DSP_FFT_Configuration(ref DSP, ref IQToSpectrumIn, ref IQToSpectrumOut, ref TracePoints, ref RBWRatio); //下发FFT模式的相关配置。

			double[] Frequency = new double[TracePoints]; //创建数组存放频率数据。
			float[] Spectrum = new float[TracePoints];    //创建数组存放幅度数据。
			#endregion

			#region 3 数据采集
			while (true)
			{
				Status = HtraApi.IQS_BusTriggerStart(ref Device); //调用IQS_BusTriggerStart触发设备。若触发源为外部触发，则不需要调用此函数。

				for (UInt64 i = 0; i < StreamInfo.PacketCount; i++)
				{
					Status = HtraApi.IQS_GetIQStream_PM1(ref Device, ref IQStream); //获取IQ数据。
					if (Status == 0)
					{
						unsafe
						{
							System.Int16* IQ = (System.Int16*)IQStream.AlternIQStream; //用于取出IQ数据
							UInt32 points = StreamInfo.PacketSamples;                  //包中数据个数
							if (i == StreamInfo.PacketCount - 1 && StreamInfo.StreamSamples % StreamInfo.PacketSamples != 0) //最后一个包判断，是最后一个包，且最后一个不满
							{
								points = (UInt32)StreamInfo.StreamSamples % StreamInfo.PacketSamples; //最后一个包内数据个数计算
							}
							for (int j = 0; j < points; j++) //IQ数据写入数组
							{
								AlternIQStream[j + StreamInfo.PacketSamples * (int)i] = IQ[j];
							}
						}
					}

					else
					{
						/*获取数据失败时，返回错误提示，发生以下错误时，建议按照提示进行操作*/
						switch (Status)
						{
							case HtraApi.APIRETVAL_ERROR_BusError:  //IQS_GetIQStream返回-8时，建议重新配置参数，再进行获取
								System.Console.WriteLine("Error - Bus communication error");
								Status = HtraApi.IQS_Configuration(ref Device, ref IQSIn, ref IQSOut, ref StreamInfo);
								break;

							case HtraApi.APIRETVAL_ERROR_BusDataError: //IQS_GetIQStream返回-9时，建议重新配置参数，再进行获取
								System.Console.WriteLine("Error - The data content is incorrect");
								Status = HtraApi.IQS_Configuration(ref Device, ref IQSIn, ref IQSOut, ref StreamInfo);
								break;

							case HtraApi.APIRETVAL_WARNING_BusTimeOut: //IQS_GetIQStream返回-10时，建议检查触发源是否正常触发，再进行获取
								System.Console.WriteLine("Warning - Get data timed out, check if the trigger source is triggered normally");
								break;

							case HtraApi.APIRETVAL_WARNING_IFOverflow: //IQS_GetIQStream返回-12时，建议重新配置参数，再进行获取
								System.Console.WriteLine("WARNING - IF saturation is recommended to be reconfigured, reference level <= signal power");
								break;

							case HtraApi.APIRETVAL_WARNING_ReconfigurationIsRecommended: //IQS_GetIQStream返回-14时，建议重新配置参数，再进行获取
								System.Console.WriteLine("Warning - The current device temperature has changed significantly relative to the configured temperature, and it is recommended to reconfigure \n");
								break;

							case HtraApi.APIRETVAL_WARNING_ClockUnlocked_SYSCLK: //IQS_GetIQStream返回-15时，建议重新配置参数，再进行获取
								System.Console.WriteLine("Warning - There may be an anomaly in the hardware status of the device and reconfiguration is recommended\n");
								break;
							default:
								break;
						}
						System.Console.WriteLine("Status = " + Status);
					}

				}

				unsafe
				{
					fixed (Int16* ptr = AlternIQStream)
					{
						IQStream.AlternIQStream = (IntPtr)ptr;                                        //让AlternIQStream指针指向实际存在IQ数据的地址。
						HtraApi.DSP_LPF_Execute_Complex(ref DSP, ref IQStream, ref IQStreamOut);      //执行低通滤波。
						HtraApi.DSP_FFT_IQSToSpectrum(ref DSP, ref IQStreamOut, Frequency, Spectrum); //执行IQ转频谱函数。
					}
				}

				for (int i = 0; i < TracePoints; i++)
				{
					System.Console.WriteLine("Frequency:" + Frequency[i].ToString() + ",  " + "Spectrum:" + Spectrum[i].ToString());
				}
			}
			#endregion

			#region 4 关闭
			Status = HtraApi.IQS_BusTriggerStop(ref Device); //调用IQS_BusTriggerStop停止触发设备。若触发源为外部触发，则不需要调用此函数。
			HtraApi.DSP_Close(ref DSP);
			HtraApi.Device_Close(ref Device);
			#endregion
		}
	}
}
