#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include "htra_api.h"
#include <fstream>
#include"msgpack.h"
#include <time.h>
#include <filesystem>
#include <thread>
#include <queue>
#include <mutex> 
#include <condition_variable>
#include <atomic> 
using namespace std;

#define IS_USB 1 // The default is using a USB device. If a network device is used, define IS_USB as 0.

// Function declarations
void IQS_Get(void* Device, IQS_StreamInfo_TypeDef StreamInfo);
void IQ_Write(const BootInfo_TypeDef* BootInfo, const DeviceInfo_TypeDef* DeviceInfo, const IQS_Profile_TypeDef* IQS_Profile, const IQS_StreamInfo_TypeDef* StreamInfo);

queue<vector<int8_t>> IQS_Get_queue;  // Data queue
std::mutex IQS_Get_Mtx;               // Mutex: protects the queue
std::condition_variable write_start;

// uint_16 Little-endian to big-endian conversion
uint16_t IQS_littleToBigEndian16(uint16_t value) {
	return (value >> 8) | (value << 8);
}
// uint_32 Little-endian to big-endian conversion
uint32_t IQS_littleToBigEndian32(uint32_t value) {
	uint32_t result = ((value >> 24) & 0xFF) | ((value >> 8) & 0xFF00) | ((value << 8) & 0xFF0000) | ((value << 24) & 0xFF000000);
	return result;
}
// uint_64 Little-endian to big-endian conversion
uint64_t IQS_littleToBigEndian64(uint64_t val)
{
	return (
		((val & 0x00000000000000FFULL) << 56) |  // 1st byte -> 8th byte
		((val & 0x000000000000FF00ULL) << 40) |  // 2nd byte -> 7th byte
		((val & 0x0000000000FF0000ULL) << 24) |  // 3rd byte -> 6th byte
		((val & 0x00000000FF000000ULL) << 8) |   // 4th byte -> 5th byte
		((val & 0x000000FF00000000ULL) >> 8) |   // 5th byte -> 4th byte
		((val & 0x0000FF0000000000ULL) >> 24) |  // 6th byte -> 3rd byte
		((val & 0x00FF000000000000ULL) >> 40) |  // 7th byte -> 2nd byte
		((val & 0xFF00000000000000ULL) >> 56)    // 8th byte -> 1st byte
		);
}
// float Little-endian to big-endian conversion
float IQS_littleToBigEndianFloat(float value) {
	union {
		float floatValue;
		uint32_t intValue;
	} u;

	u.floatValue = value;
	u.intValue = IQS_littleToBigEndian32(u.intValue);
	return u.floatValue;
}
// double Little-endian to big-endian conversion
double IQS_littleToBigEndianDouble(double value) {
	union {
		double doubleValue;
		uint8_t bytes[8];
	} u, result;

	u.doubleValue = value;

	// Swap byte order
	for (int i = 0; i < 8; i++) {
		result.bytes[i] = u.bytes[7 - i];
	}

	return result.doubleValue;
}


// Compress IQS_Profile_TypeDef and IQS_StreamInfo_TypeDef using msgpack
msgpack_sbuffer pack(const IQS_Profile_TypeDef* IQS_Profile, const IQS_StreamInfo_TypeDef* StreamInfo) 
{
	msgpack_sbuffer sbuf;  // msgpack_sbuffer is a structure from the MessagePack library, used to dynamically store the serialized result.

	msgpack_sbuffer_init(&sbuf); // Initialize the msgpack_sbuffer buffer to store serialized data.

	msgpack_packer pck; // msgpack_packer is a packing tool provided by MessagePack, used to convert C++ data structures into MessagePack formatted byte streams.

	msgpack_packer_init(&pck, &sbuf, msgpack_sbuffer_write); // Initialize the msgpack_packer object and link it to the sbuf, ensuring serialized data is written to sbuf.

	// Pack IQS_Profile_TypeDef and IQS_StreamInfo_TypeDef structures
	msgpack_pack_double(&pck, IQS_Profile->CenterFreq_Hz);   
	msgpack_pack_double(&pck, IQS_Profile->RefLevel_dBm);
	msgpack_pack_uint32(&pck, IQS_Profile->DecimateFactor);
	msgpack_pack_int(&pck, IQS_Profile->RxPort);
	msgpack_pack_uint32(&pck, IQS_Profile->BusTimeout_ms);
	msgpack_pack_int(&pck, IQS_Profile->TriggerSource);
	msgpack_pack_int(&pck, IQS_Profile->TriggerEdge);
	msgpack_pack_int(&pck, IQS_Profile->TriggerMode);
	msgpack_pack_uint64(&pck, IQS_Profile->TriggerLength);
	msgpack_pack_int(&pck, IQS_Profile->TriggerOutMode);
	msgpack_pack_int(&pck, IQS_Profile->TriggerOutPulsePolarity);
	msgpack_pack_double(&pck, IQS_Profile->TriggerLevel_dBm);
	msgpack_pack_double(&pck, IQS_Profile->TriggerLevel_SafeTime);
	msgpack_pack_double(&pck, IQS_Profile->TriggerDelay);
	msgpack_pack_double(&pck, IQS_Profile->PreTriggerTime);
	msgpack_pack_int(&pck, IQS_Profile->TriggerTimerSync);
	msgpack_pack_double(&pck, IQS_Profile->TriggerTimer_Period);
	msgpack_pack_uint8(&pck, IQS_Profile->EnableReTrigger);
	msgpack_pack_double(&pck, IQS_Profile->ReTrigger_Period);
	msgpack_pack_uint16(&pck, IQS_Profile->ReTrigger_Count);
	msgpack_pack_int(&pck, IQS_Profile->DataFormat);
	msgpack_pack_int(&pck, IQS_Profile->GainStrategy);
	msgpack_pack_int(&pck, IQS_Profile->Preamplifier);
	msgpack_pack_uint8(&pck, IQS_Profile->AnalogIFBWGrade);
	msgpack_pack_uint8(&pck, IQS_Profile->IFGainGrade);
	msgpack_pack_uint8(&pck, IQS_Profile->EnableDebugMode);
	msgpack_pack_int(&pck, IQS_Profile->ReferenceClockSource);
	msgpack_pack_double(&pck, IQS_Profile->ReferenceClockFrequency);
	msgpack_pack_uint8(&pck, IQS_Profile->EnableReferenceClockOut);
	msgpack_pack_int(&pck, IQS_Profile->SystemClockSource);
	msgpack_pack_double(&pck, IQS_Profile->ExternalSystemClockFrequency);
	msgpack_pack_double(&pck, IQS_Profile->NativeIQSampleRate_SPS);
	msgpack_pack_uint8(&pck, IQS_Profile->EnableIFAGC);
	msgpack_pack_int8(&pck, IQS_Profile->Atten);
	msgpack_pack_int(&pck, IQS_Profile->DCCancelerMode);
	msgpack_pack_int(&pck, IQS_Profile->QDCMode);
	msgpack_pack_float(&pck, IQS_Profile->QDCIGain);
	msgpack_pack_float(&pck, IQS_Profile->QDCQGain);
	msgpack_pack_float(&pck, IQS_Profile->QDCPhaseComp);
	msgpack_pack_int8(&pck, IQS_Profile->DCCIOffset);
	msgpack_pack_int8(&pck, IQS_Profile->DCCQOffset);
	msgpack_pack_int(&pck, IQS_Profile->LOOptimization);
	msgpack_pack_double(&pck, StreamInfo->Bandwidth);
	msgpack_pack_double(&pck, StreamInfo->IQSampleRate);
	msgpack_pack_uint64(&pck, StreamInfo->PacketCount);
	msgpack_pack_uint64(&pck, StreamInfo->StreamSamples);
	msgpack_pack_uint64(&pck, StreamInfo->StreamDataSize);
	msgpack_pack_uint32(&pck, StreamInfo->PacketSamples);
	msgpack_pack_uint32(&pck, StreamInfo->PacketDataSize);
	msgpack_pack_uint32(&pck, StreamInfo->GainParameter);

	return sbuf;
}

vector<uint8_t> Serialize_DeviceInfo(const DeviceInfo_TypeDef* DeviceInfo, uint16_t len)
{
	vector<uint8_t> buf;
	buf.reserve(2 + len);

	auto append = [&](const void* data, size_t len)
	{
		const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
		buf.insert(buf.end(), p, p + len);
	};

	uint16_t Size = IQS_littleToBigEndian16(len);
	append(&Size, 2);


	uint64_t DeviceUID = IQS_littleToBigEndian64(DeviceInfo->DeviceUID);
	append(&DeviceUID, 8);

	uint16_t Model = IQS_littleToBigEndian16(DeviceInfo->Model);
	append(&Model, 2);

	uint16_t HardwareVersion = IQS_littleToBigEndian16(DeviceInfo->HardwareVersion);
	append(&HardwareVersion, 2);

	uint32_t MFWVersion = IQS_littleToBigEndian32(DeviceInfo->MFWVersion);
	append(&MFWVersion, 4);

	uint32_t FFWVersion = IQS_littleToBigEndian32(DeviceInfo->FFWVersion);
	append(&FFWVersion, 4);

	return buf;
}

vector<uint8_t> Serialize_TriggerInfo(const IQS_TriggerInfo_TypeDef* IQS_TriggerInfo, uint16_t len)
{
	vector<uint8_t> buf;
	buf.resize(2 + len);

	uint16_t Size = IQS_littleToBigEndian16(len);
	uint8_t* p = reinterpret_cast<uint8_t*>(Size);
	memcpy(buf.data(), &p, 2);


	uint64_t SysTimerCountOfFirstDataPoint = IQS_littleToBigEndian64(IQS_TriggerInfo->SysTimerCountOfFirstDataPoint);
	p = reinterpret_cast<uint8_t*>(SysTimerCountOfFirstDataPoint);
	memcpy(buf.data() + 2, &p, 8);

	uint16_t InPacketTriggeredDataSize = IQS_littleToBigEndian16(IQS_TriggerInfo->InPacketTriggeredDataSize);
	p = reinterpret_cast<uint8_t*>(InPacketTriggeredDataSize);
	memcpy(buf.data() + 10, &p, 2);

	uint16_t InPacketTriggerEdges = IQS_littleToBigEndian16(IQS_TriggerInfo->InPacketTriggerEdges);
	p = reinterpret_cast<uint8_t*>(InPacketTriggerEdges);
	memcpy(buf.data() + 12, &p, 2);

	memcpy(buf.data() + 14, IQS_TriggerInfo->StartDataIndexOfTriggerEdges, 25 * sizeof(uint32_t));
	memcpy(buf.data() + 14 + 100, IQS_TriggerInfo->SysTimerCountOfEdges, 25 * sizeof(uint64_t));
	memcpy(buf.data() + 14 + 100 + 200, IQS_TriggerInfo->EdgeType, 25 * sizeof(int8_t));

	return buf;
}

vector<uint8_t> Serialize_DeviceState(const DeviceState_TypeDef* DeviceState, uint16_t len)
{
	vector<uint8_t> buf;
	buf.reserve(2 + len);


	auto append = [&](const void* data, size_t len)
	{
		const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
		buf.insert(buf.end(), p, p + len);
	};

	uint16_t Size = IQS_littleToBigEndian16(len);
	append(&Size, 2);


	int16_t Temperature = IQS_littleToBigEndian16(DeviceState->Temperature);
	append(&Temperature, 2);

	uint16_t RFState = IQS_littleToBigEndian16(DeviceState->RFState);
	append(&RFState, 2);

	uint16_t BBState = IQS_littleToBigEndian16(DeviceState->BBState);
	append(&BBState, 2);

	double AbsoluteTimeStamp = IQS_littleToBigEndianDouble(DeviceState->AbsoluteTimeStamp);
	append(&AbsoluteTimeStamp, 8);

	float Latitude = IQS_littleToBigEndianFloat(DeviceState->Latitude);
	append(&Latitude, 4);

	float Longitude = IQS_littleToBigEndianFloat(DeviceState->Longitude);
	append(&Longitude, 4);

	uint16_t GainPattern = IQS_littleToBigEndian16(DeviceState->GainPattern);
	append(&GainPattern, 2);

	int64_t RFCFreq = IQS_littleToBigEndian64(DeviceState->RFCFreq);
	append(&RFCFreq, 8);

	uint32_t ConvertPattern = IQS_littleToBigEndian32(DeviceState->ConvertPattern);
	append(&ConvertPattern, 4);

	uint32_t NCOFTW = IQS_littleToBigEndian32(DeviceState->NCOFTW);
	append(&NCOFTW, 4);

	uint32_t SampleRate = IQS_littleToBigEndian32(DeviceState->SampleRate);
	append(&SampleRate, 4);

	uint16_t CPU_BCFlag = IQS_littleToBigEndian16(DeviceState->CPU_BCFlag);
	append(&CPU_BCFlag, 2);

	uint16_t IFOverflow = IQS_littleToBigEndian16(DeviceState->IFOverflow);
	append(&IFOverflow, 2);

	uint16_t DecimateFactor = IQS_littleToBigEndian16(DeviceState->DecimateFactor);
	append(&DecimateFactor, 2);

	uint16_t OptionState = IQS_littleToBigEndian16(DeviceState->OptionState);
	append(&OptionState, 2);

	return buf;
}

// Write the PacketCount package returned based on the set TriggerLength
int Write_ONE_IQData_Info(const BootInfo_TypeDef* BootInfo, const DeviceInfo_TypeDef* DeviceInfo, const IQS_Profile_TypeDef* IQS_Profile, const IQS_StreamInfo_TypeDef* StreamInfo, const IQStream_TypeDef* IQStream)
{
    static vector<uint32_t> document_couont(1, 0);
    static vector<uint32_t> bagcount(1, 0);
    bagcount[0]++;

    IQStream_TypeDef IQStream_temp_temp = *IQStream;

    int Status = 0;
    uint32_t format = 0;      // Data format
    uint32_t FILE_length = 0; // File length

    // Determine data format
    switch (IQS_Profile->DataFormat)
    {
    case  Complex32bit:
        format = 4;
        break;
    case Complex16bit:
        format = 2;
        break;
    case Complex8bit:
        format = 1;
        break;
    default:
        break;
    }

    static char time1[39] = { 0 }; // Used to store file name
    char FilePath_1[100];          // Open a binary file named after the file name for writing
    string s = "./data/";          // Assuming the file save path is ./data/

    // Check if the directory exists, if not, create it
    if (!(filesystem::exists(s))) {
    // Try creating the directory and its parent directories
        filesystem::create_directories(s);
        if (filesystem::create_directories(s)) {
            cout << "Failed to create directory \"" << s << "\"." << endl;
            return 0;
        }
    }

    uint16_t InfoSize_2 = 0;      // Used to temporarily store two bytes of data
    uint32_t InfoSize_4 = 0;      // Used to temporarily store four bytes of data
    uint64_t InfoSize_8 = 0;      // Used to temporarily store eight bytes of data

	uint32_t data_lenth = StreamInfo->PacketDataSize;

    if (bagcount[0] % 61500 == 1) // When the packet count reaches 61500, the file header and data will be approximately 4GB, so a new package is needed
    {
        document_couont[0]++;

        // Get the current time
        time_t timep;
        struct tm* p;
        time(&timep);
        p = gmtime(&timep);
        char hex[4] = { 0 };

        // Take the last four digits of the UID
        hex[0] = DeviceInfo->DeviceUID % 16;
        hex[1] = (DeviceInfo->DeviceUID / 16) % 16;
        hex[2] = (DeviceInfo->DeviceUID / 16 / 16) % 16;
        hex[3] = (DeviceInfo->DeviceUID / 16 / 16 / 16) % 16;

        sprintf(time1, "%X%X%X%X_%d%02d%02d_%02d%02d%02d.part%d.iq.wav", hex[3], hex[2], hex[1], hex[0], 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, 8 + p->tm_hour, p->tm_min, p->tm_sec, document_couont[0]); // Format the file name, using the last four digits of the UID followed by year, month, day, hour, minute, second, and part number

        s += time1; // Add the generated file name to the path
        strcpy_s(FilePath_1, s.c_str());
        fstream File(FilePath_1, ios::out | ios::binary);

        // Write data according to the "File Format Specification"
        memcpy(&InfoSize_4, "RIFF", 4);
        File.write((char*)&InfoSize_4, 4); // Document identifier

        File.seekp(8, ios::beg);
        memcpy(&InfoSize_4, "WAVE", 4); // File format type
        File.write((char*)&InfoSize_4, 4);

        memcpy(&InfoSize_4, "fmt ", 4); // Format chunk identifier. If it is less than four characters, the right side is filled with spaces
        File.write((char*)&InfoSize_4, 4);
        int digit = 16;
        File.write((char*)&digit, 4); // Format length
        uint16_t digit_1 = 1;
        File.write((char*)&digit_1, 2); // Encoding format code, common WAV files use PCM pulse code modulation format, this value is usually 1
        uint16_t digit_2 = 2;
        File.write((char*)&digit_2, 2); // Number of channels 2

        File.write((char*)&StreamInfo->IQSampleRate, 4);                    // Sampling frequency returned by the device
        uint32_t trans_rate = StreamInfo->IQSampleRate * digit_2 * format;  // Data transfer rate: number of channels x sample rate x number of bits per sample / 8
        File.write((char*)&trans_rate, 4);
        uint16_t data_align = digit_2 * format;
        File.write((char*)&data_align, 2);                                  // Data block alignment unit: number of channels x bits / 8
        uint16_t data_with = format * 8;
        File.write((char*)&data_with, 2);                                   // Sample width: number of binary digits used to store each sample

        // Write prof chunk 
        memcpy(&InfoSize_4, "prof", 4); // prof chunk identifier
        File.write((char*)&InfoSize_4, 4);
        uint32_t digit_3 = 356;          // prof chunk length
        File.write((char*)&digit_3, 4);

        File.write((char*)&document_couont[0], 2); // File number
        uint8_t digit_4 = 0x8c;
        uint8_t digit_5 = 0x22;
        uint8_t digit_6 = 0x52;
        uint8_t digit_7 = 0x9b;
        uint8_t digit_8 = 0x00;
        uint8_t digit_9 = 0x02;
        File.write((char*)&digit_4, 1); // 'H'
        File.write((char*)&digit_5, 1); //'D'
        File.write((char*)&digit_6, 1); //'l'
        File.write((char*)&digit_7, 1); //'J'
        File.write((char*)&digit_8, 1); // Protocol version
        File.write((char*)&digit_9, 1);


        uint32_t digit_10 = IQS_littleToBigEndian32(BootInfo->APIVersion);
        File.write((char*)&digit_10, 4);   // API version information
        char c = 'X';                      // Placeholder for file reserve
        for (int i = 0; i < 108 - 56; i++) // Configuration information and byte length
        {
            File.write(&c, 1);
        }


		File.seekp(66, ios::beg);
		double ampOffset = 0.0;
		File.write((char*)&ampOffset, 8);
		File.seekp(108, ios::beg);

        // Compress and write IQS_Profile_TypeDef and IQS_StreamInfo_TypeDef structures
        auto msgBuffer = pack(IQS_Profile, StreamInfo); // Compress IQS_Profile_TypeDef and IQS_StreamInfo_TypeDef using msgpack
        uint16_t Profile_Stream = IQS_littleToBigEndian16(msgBuffer.size);
        File.write((char*)&Profile_Stream, 2);           // Write the length of the structure

        for (int i = 0; i < msgBuffer.size; i++)        // Write the compressed structure data to the file
        {
            File.write(&msgBuffer.data[i], 1);
        }

        // Write DeviceInfo_TypeDef structure
		vector<uint8_t> Vector_DeviceInfo = Serialize_DeviceInfo(DeviceInfo, sizeof(DeviceInfo_TypeDef));
		File.write(reinterpret_cast<char*>(Vector_DeviceInfo.data()), Vector_DeviceInfo.size());


        int end_IQS = File.tellp();                 // Current write pointer position
        for (int j = 0; j < 400 - end_IQS; j++)    // Write 'X' to the file until the "trig" identifier position
        {
            File.write(&c, 1);
        }

		// Write "trig"
		memcpy(&InfoSize_4, "trig", 4); // "trig" chunk identifier
		File.write((char*)&InfoSize_4, 4);

		InfoSize_4 = 26214392; // "trig" chunk length is fixed to 25*1024*1024+400-408
		File.write((char*)&InfoSize_4, 4);

		// Write IQS_Triggerinfo structure
		vector<uint8_t> Vector_TriggerInfo = Serialize_TriggerInfo(&IQStream_temp_temp.IQS_TriggerInfo, 337);
		File.write(reinterpret_cast<char*>(Vector_TriggerInfo.data()), Vector_TriggerInfo.size());


		// Write DeviceState structure
		vector<uint8_t> Vector_DeviceState = Serialize_DeviceState(&IQStream_temp_temp.DeviceState, 52);
		File.write(reinterpret_cast<char*>(Vector_DeviceState.data()), Vector_DeviceState.size());

		IQStream_temp_temp.IQS_ScaleToV = IQS_littleToBigEndianFloat(IQStream_temp_temp.IQS_ScaleToV);
		File.write((char*)&IQStream_temp_temp.IQS_ScaleToV, 4);

		IQStream_temp_temp.MaxPower_dBm = IQS_littleToBigEndianFloat(IQStream_temp_temp.MaxPower_dBm);
		File.write((char*)&IQStream_temp_temp.MaxPower_dBm, 4);

		IQStream_temp_temp.MaxIndex = IQS_littleToBigEndian32(IQStream_temp_temp.MaxIndex);
		File.write((char*)&IQStream_temp_temp.MaxIndex, 4);

		int end_stream = File.tellp(); // Current write pointer position
		for (int i = 0; i < 25 * 1024 * 1024 + 400 - end_stream; i++) // Move file pointer to the "data" identifier
		{
			File.write(&c, 1);
		}

		memcpy(&InfoSize_4, "data", 4); // Write "data" identifier
		File.write((char*)&InfoSize_4, 4); // Document identifier
		File.write((char*)&data_lenth, 4); // Write data length

		// Write data to file according to the format
		vector<char> buf(IQStream_temp_temp.IQS_StreamInfo.PacketDataSize);
		memcpy(buf.data(), IQStream_temp_temp.AlternIQStream, IQStream_temp_temp.IQS_StreamInfo.PacketDataSize);
		File.write(buf.data(), buf.size());

		FILE_length = 25 * 1024 * 1024 + 408 + data_lenth - 8;
		File.seekp(4, ios::beg);
		File.write((char*)&FILE_length, 4); // Write format block length (excluding 'RIFF' and format block itself)
		File.close();
	}

	// When the data is not the first packet of each file, do not write structures that do not change with the packet number
	else
	{

		s += time1;
		fstream File;
		strcpy_s(FilePath_1, s.c_str());

		File.open(FilePath_1, ios::in | ios::binary | ios::out); // Open file in read-write mode to prevent overwriting, appending cannot move pointer

		File.seekp(408 + ((bagcount[0] % 61500) - 1) * 405, ios::beg); // The position where the structure of the second packet data should be written

		// Write IQS_Triggerinfo structure
		vector<uint8_t> Vector_TriggerInfo = Serialize_TriggerInfo(&IQStream_temp_temp.IQS_TriggerInfo, 337);
		File.write(reinterpret_cast<char*>(Vector_TriggerInfo.data()), Vector_TriggerInfo.size());
		
		// Write the DevicesTate structure		
		vector<uint8_t> Vector_DeviceState = Serialize_DeviceState(&IQStream_temp_temp.DeviceState, 52);
		File.write(reinterpret_cast<char*>(Vector_DeviceState.data()), Vector_DeviceState.size());

		IQStream_temp_temp.IQS_ScaleToV = IQS_littleToBigEndianFloat(IQStream_temp_temp.IQS_ScaleToV);
		File.write((char*)&IQStream_temp_temp.IQS_ScaleToV, 4);

		IQStream_temp_temp.MaxPower_dBm = IQS_littleToBigEndianFloat(IQStream_temp_temp.MaxPower_dBm);
		File.write((char*)&IQStream_temp_temp.MaxPower_dBm, 4);

		IQStream_temp_temp.MaxIndex = IQS_littleToBigEndian32(IQStream_temp_temp.MaxIndex);
		File.write((char*)&IQStream_temp_temp.MaxIndex, 4);

		InfoSize_4 = (bagcount[0] % 61500) * data_lenth;
		File.seekp(25 * 1024 * 1024 + 404, ios::beg); // Update data block length
		File.write((char*)&InfoSize_4, 4);

		File.seekp(25 * 1024 * 1024 + 408 + ((bagcount[0] % 61500) - 1) * data_lenth, ios::beg);

		vector<char> buf(IQStream_temp_temp.IQS_StreamInfo.PacketDataSize);
		memcpy(buf.data(), IQStream_temp_temp.AlternIQStream, IQStream_temp_temp.IQS_StreamInfo.PacketDataSize);
		File.write(buf.data(), buf.size());

		FILE_length = 25 * 1024 * 1024 + 408 + (bagcount[0] % 61500) * data_lenth - 8; // Update file size
		File.seekp(4, ios::beg);
		File.write((char*)&FILE_length, 4);

		File.close();
	}

	if ((bagcount[0] % 61500) == StreamInfo->PacketCount) // When the recorded packet count equals the number of packets for this Trigglength, stop recording
	{
		bagcount[0] = 0;								  // Reset packet count
		document_couont[0] = 0;						  // Reset document count
	}

	return 0;
}

int IQSMode_Recording()
{
	int Status = 0;      // Return value of the function.
	void* Device = NULL; // Memory address of the current device.
	int DevNum = 0;      // Specify the device number.

	BootProfile_TypeDef BootProfile; // Boot configuration structure, including physical interface, power supply, etc.
	BootInfo_TypeDef BootInfo;       // Boot information structure, including device information, USB speed, etc.

	BootProfile.DevicePowerSupply = USBPortAndPowerPort; // Use USB data port and independent power supply port for dual power supply.

#if IS_USB==1
	// Configure USB interface
	BootProfile.PhysicalInterface = USB;
#else 
	// Configure ETH interface
	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); // Open the device.

	if (Status == APIRETVAL_NoError)
	{
		printf("The device is turned on successfully\n");
	}

	// If device opening fails, return error message. The following errors indicate the device cannot function properly.It is recommended to follow the prompts to resolve the issue and then reopen the device.
	else
	{
		switch (Status)
		{

		case -1:cout << "Error - Check the power supply of the device, the connection of the data cable, and check if the driver is installed correctly" << endl; break;
		case -3:cout << "Error - RF calibration file is missing, please copy the RF calibration file to the CalFile folder" << endl; break;
		case -4:cout << "Error - IF calibration file is missing, please copy the IF calibration file to the CalFile folder" << endl; break;
		case -5:cout << "Error - Config file is missing, please copy the config file into the CalFile folder" << endl; break;
		case -6:cout << "Error - Device spec file is missing, please copy the device spec file to the CalFile folder" << endl; break;
		default:cout << "Returns other errors Status = " << Status << endl; break;
		}

		//return Status;
	}


	DeviceInfo_TypeDef DeviceInfo;                         // Structure to store device information, including device UID, model, firmware version, etc.

	Status = Device_QueryDeviceInfo(&Device, &DeviceInfo); // Retrieve device information, including UID, model, firmware version, etc.

	IQS_Profile_TypeDef IQS_ProfileIn;  // IQS input configuration, including center frequency, decimation factor, reference level, etc.
	IQS_Profile_TypeDef IQS_ProfileOut; // IQS output configuration.                   
	IQS_StreamInfo_TypeDef StreamInfo;  // IQ data information under the current configuration, including bandwidth, IQ single-channel sampling rate, etc.

	IQS_ProfileDeInit(&Device, &IQS_ProfileIn); // Initialize IQS mode related parameters.

	IQS_ProfileIn.CenterFreq_Hz = 1.2e9;          // Set center frequency.
	IQS_ProfileIn.RefLevel_dBm = 0;             // Set reference level.
	IQS_ProfileIn.DecimateFactor = 4;		    // Set decimation factor.
	IQS_ProfileIn.DataFormat = Complex16bit;    // Set IQ data format.
	IQS_ProfileIn.TriggerMode = FixedPoints;    // Set trigger mode.
	IQS_ProfileIn.TriggerSource = Bus;          // Set trigger source to internal bus trigger. If an external trigger source is used, configure External.
	IQS_ProfileIn.TriggerLength = 16240 * 20;	// Set TriggerLength, i.e., the length of data collected per trigger (one packet is fixed at 64968 bytes, and when the IQ format is 16bit, one packet is 64968/2 bytes/IQ2 points, which equals 16242 points. This means 2000 packets are sampled).

	Status = IQS_Configuration(&Device, &IQS_ProfileIn, &IQS_ProfileOut, &StreamInfo); // Apply IQS mode configuration.
	if (Status == 0)
	{
		printf("Configuration applied successfully\n");
	}

	std::cout << "Main Thread ID: " << std::this_thread::get_id() << std::endl;

	// Create threads
	std::thread Get(IQS_Get, (void*)Device, StreamInfo);
	std::thread Write(IQ_Write, &BootInfo, &DeviceInfo, &IQS_ProfileOut, &StreamInfo);

	// Wait for threads to finish
	Get.join();
	Write.join();

	Status = IQS_BusTriggerStop(&Device); // Stop triggering the device. If the trigger source is external, this function is not needed.

	Device_Close(&Device); // Close the device.
	std::cout << "end" << std::endl;

	return 0;
}

void IQS_Get(void* Device, const IQS_StreamInfo_TypeDef StreamInfo)
{
	std::cout << "Thread ID: " << std::this_thread::get_id() << " is running." << std::endl;
	int Status = 0;
	IQStream_TypeDef IQStream;                        // Structure to store IQ data packet, including IQ data, configuration information, etc.
	uint32_t IQStreamSize = sizeof(IQStream_TypeDef); // Get the byte size of IQStream
	vector<int8_t> IQ_item(1);						  // Temporarily store a deep copy of IQStream

	for (int i = 0; i < StreamInfo.PacketCount; i++) // Get each packet of data
	{
		Status = IQS_BusTriggerStart(&Device); // Trigger the device. If the trigger source is external, this function is not needed.
		if (Status == APIRETVAL_NoError)
		{
			Status = IQS_GetIQStream_PM1(&Device, &IQStream);                      // Get IQ data packet, trigger information, maximum value of I-path data, and maximum value index
			std::cout << Status << std::endl;
			IQ_item.resize(IQStream.IQS_StreamInfo.PacketDataSize + IQStreamSize); // Resize IQ_item to the size of IQStream
			memcpy(IQ_item.data(), &IQStream, IQStreamSize);					   // Deep copy IQStream to IQ_item
			memcpy(IQ_item.data() + IQStreamSize, IQStream.AlternIQStream, IQStream.IQS_StreamInfo.PacketDataSize);	// Deep copy IQ data from IQStream to IQ_item
			std::unique_lock<std::mutex> lock(IQS_Get_Mtx);
			IQS_Get_queue.push(IQ_item); // Push the acquired and copied IQStream structure into the queue
			write_start.notify_one();	 // Notify write thread to stop waiting
		}
	}
	std::cout << "get end" << std::endl;
}


void IQ_Write(const BootInfo_TypeDef* BootInfo, const DeviceInfo_TypeDef* DeviceInfo, const IQS_Profile_TypeDef* IQS_Profile, const IQS_StreamInfo_TypeDef* StreamInfo)
{
	std::cout << "Thread ID: " << std::this_thread::get_id() << " is running." << std::endl;
	IQStream_TypeDef IQStream;                                              // Structure to store IQ data packet, including IQ data, configuration information, etc.
	uint32_t IQStreamSize = sizeof(IQStream_TypeDef);                       // Get the byte size of IQStream
	vector<int8_t> IQ_item(IQStreamSize + 16242 * 2 * sizeof(int16_t) * 2);	// Temporary variable to store each IQStream structure retrieved from the queue

	for (int i = 0; i < StreamInfo->PacketCount; i++)
	{
		{
			std::unique_lock<std::mutex> lock(IQS_Get_Mtx);
			write_start.wait(lock, [] { return !IQS_Get_queue.empty(); });

			IQ_item = IQS_Get_queue.front(); // Assign the first element of the queue to IQ_item
			IQS_Get_queue.pop();			 // Discard the first element of the queue
		}
		memcpy(&IQStream, IQ_item.data(), IQStreamSize);	                             // Deep copy IQ_item to IQStream
		IQStream.AlternIQStream = IQ_item.data() + IQStreamSize;	                     // Assign the IQ data address from IQ_item to IQStream

		Write_ONE_IQData_Info(BootInfo, DeviceInfo, IQS_Profile, StreamInfo, &IQStream); // Write the structure to the file
	}
	std::cout << "write end" << std::endl;
}