#include <iostream>
#include <fstream>
#include <vector>
#include <chrono>
#include <string>
#include "htra_api.h"
#include <math.h>
#include <thread>
#include <queue>
#include <mutex> 
#include <condition_variable>
#include <windows.h>
#include "example.h"
using namespace std;

#define IS_USB 1 //默认使用的是USB型设备，若使用的是网口型设备则将IS_USB定义为0。

void IQS_Get(void* Device);   //获取IQ数据。
void IQS_FFT(void* DSP);      //执行FFT操作。
void IQS_Write(void* Device); //写入数据到文件。

string filePath = "./IQ_Data.iqs"; //定义输出文件路径。
ofstream outfile;                  //定义输出流对象。

queue<vector<int16_t>> IQS_instant_queue;				 //定义缓存队列。
std::mutex IQS_instant_Mtx;								 //Write线程等待Get写入的同步量。
std::mutex Write_Mtx;									 //互斥使用队列的同步量。
std::unique_lock<std::mutex> lck_Write(IQS_instant_Mtx); //用IQS_instant_Mtx加锁。
std::condition_variable Write_start;					 //Get开始获取的条件变量。
bool Write_flag = false;								 //设置写文件线程唤醒标志。

queue<vector<int8_t>> IQS_Get_queue;			   //数据队列。
std::mutex IQS_Get_Mtx;							   //FFT线程等待Get写入的同步量。
std::unique_lock<std::mutex> lck_FFT(IQS_Get_Mtx); //用IQS_Get_Mtx加锁。
std::condition_variable FFT_start;				   //Get开始获取的条件变量。
std::mutex FFT_Mtx;								   //互斥使用队列的同步量。


int IQS_Multithread_GetIQ_FFT_Write()
{
	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单路采样率等。
	IQS_TriggerInfo_TypeDef TriggerInfo; //触发信息。

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

	IQS_ProfileIn.CenterFreq_Hz = 1e9;       //配置中心频率。
	IQS_ProfileIn.RefLevel_dBm = 0;          //配置参考电平。
	IQS_ProfileIn.DataFormat = Complex16bit; //配置IQ数据格式。
	IQS_ProfileIn.TriggerMode = Adaptive;    //配置触发模式。
	IQS_ProfileIn.DecimateFactor = 2;        //配置抽取倍数。

	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的返回值进行相对应的错误处理。

	outfile.open(filePath, ios::app | ios::binary);	//打开文件。
	if (!outfile)
	{
		cout << "Failed to open the file" << endl;
		exit(1);
	}

	// DSP 
	uint32_t TracePoints = 0;
	DSP_FFT_TypeDef DSP_FFT_ProfileIn; //FFT输入配置，包括FFT分析点数、窗型、输出频谱截取等。
	DSP_FFT_TypeDef DSP_FFT_ProfileOut; //FFT输出配置。
	double RBWRatio = 0;

	void* DSP = NULL;

	Status = DSP_Open(&DSP); //启动DSP功能。

	Status = DSP_FFT_DeInit(&DSP_FFT_ProfileIn); //初始化FFT参数。

	DSP_FFT_ProfileIn.FFTSize = StreamInfo.PacketSamples;   //配置FFT分析点数。
	DSP_FFT_ProfileIn.SamplePts = StreamInfo.PacketSamples; //配置有效采样点数。

	Status = DSP_FFT_Configuration(&DSP, &DSP_FFT_ProfileIn, &DSP_FFT_ProfileOut, &TracePoints, &RBWRatio); //配置FFT参数。

    //启动多线程。
	std::thread GetIQS(IQS_Get, Device);  //获取IQ数据。
	std::thread FFT(IQS_FFT, DSP);        //从队列中获取 IQ 数据，并执行 FFT。
	std::thread Write(IQS_Write, Device); //写文件线程。

	GetIQS.join(); //等待获取IQ数据线程结束。                  
	FFT.join();    //等待FFT线程结束。
	Write.join();  //等待写文件线程结束。

	return 0;
}

//获取IQ数据的线程。
void IQS_Get(void* Device)
{
	cout << "Getting data" << endl;
	int Status = 0;
	vector<int16_t> IQ(16242 * 2);	//创建存放IQ数据的数组。

	uint32_t FFT_count = 500;

	IQStream_TypeDef IQStream;	                      //存放IQ数据包数据，包括IQ数据、配置信息等。
	uint32_t IQStreamSize = sizeof(IQStream_TypeDef); //IQ数据包字节数。
	vector<int8_t> IQ_FFT(1);						  //存放IQStream的临时变量。

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

	while (1)
	{
		for (int i = 0; i < FFT_count; i++)	//每获取FFT_count包IQ点，就做一次FFT，2抽取下每包都做FFT来不及。
		{
			Status = IQS_GetIQStream_PM1(&Device, &IQStream);

			if (Status != APIRETVAL_NoError)
			{
				cout << "IQS_GetIQStream Status = " << Status << endl;
			}

			if (Status == APIRETVAL_NoError)
			{
				IQ_FFT.resize(IQStream.IQS_StreamInfo.PacketDataSize + IQStreamSize);	                                //调整 IQ_FFT的大小以容纳IQStream和其中的 IQ 数据。
				memcpy(IQ_FFT.data(), &IQStream, IQStreamSize);			                                                //将IQStream深度拷贝到IQ_FFT。
				memcpy(IQ_FFT.data() + IQStreamSize, IQStream.AlternIQStream, IQStream.IQS_StreamInfo.PacketDataSize);	//将IQ数据深拷贝到IQ_FFT的后续位置。
				memcpy(IQ.data(), IQStream.AlternIQStream, IQStream.IQS_StreamInfo.PacketDataSize);	                    //将IQ数据深度拷贝给IQ。
				Write_Mtx.lock();
				IQS_instant_queue.push(IQ);								                                                //将获取到的IQ数据放入队列
				Write_Mtx.unlock();
				Write_flag = true;
				Write_start.notify_all();							                                                	//通知写文件线程停止等待
			}
		}
		FFT_Mtx.lock();
		IQS_Get_queue.push(IQ_FFT);
		FFT_Mtx.unlock();
		FFT_start.notify_all();
	}
}

//IQ数据做FFT的线程
void IQS_FFT(void* DSP)
{
	cout << "Getting to do FFT" << endl;
	IQStream_TypeDef IQStream;                                          //存放IQ数据包数据，包括IQ数据、配置信息等。
	uint32_t IQStreamSize = sizeof(IQStream_TypeDef);                   //IQ数据包字节数
	vector<int8_t> IQ_FFT(IQStreamSize + 16242 * 2 * sizeof(int16_t));  //存储 IQ 数据包及其中的IQ数据
	vector<double> Frequency(1);                                       //创建频率数组
	vector<float> PowerSpec_dBm(1);                                    //创建功率数组

	while (1)
	{
		if (IQS_Get_queue.empty())    //队列非空
		{
			FFT_start.wait(lck_FFT);
			continue;
		}

		//从队列取出一个元素
		FFT_Mtx.lock();
		IQ_FFT = IQS_Get_queue.front();
		IQS_Get_queue.pop();
		FFT_Mtx.unlock();
		
		//将取出的元素赋给IQStream
		memcpy(&IQStream, IQ_FFT.data(), IQStreamSize);
		IQStream.AlternIQStream = IQ_FFT.data() + IQStreamSize;

		//设置Frequency和PowerSpec_dBm为预定大小
		if (Frequency.size() < IQStream.IQS_StreamInfo.PacketSamples)
		{
			Frequency.resize(IQStream.IQS_StreamInfo.PacketSamples);
			PowerSpec_dBm.resize(IQStream.IQS_StreamInfo.PacketSamples);
		}

		//将数据进行FFT转为频谱
		DSP_FFT_IQSToSpectrum(&DSP, &IQStream, Frequency.data(), PowerSpec_dBm.data());
	}
}

//IQ数据写入文件的线程
void IQS_Write(void* Device)
{
	//存放每次从队列取出的元素，每包数据64968字节，16bit精度=2字节，存在I和Q两路数据，所以每路为16242个点
	vector<int16_t> IQ_Write(16242 * 2);

	cout << "Writing data" << endl;

	while (1)
	{
		while (!Write_flag)
		{
			Write_start.wait(lck_Write);
		}

		if (!IQS_instant_queue.empty())										//队列非空
		{
			Write_Mtx.lock();
			IQ_Write = IQS_instant_queue.front();							//从队列中取出队头数据
			IQS_instant_queue.pop();
			Write_Mtx.unlock();

			outfile.write((const char*)(IQ_Write.data()), IQ_Write.size());	//将取出的数据写入文件
		}
		else
		{
			Sleep(0.001);
		}
	}
}
