#include <stdio.h>
#include <vector>
#include "htra_api.h"
#include <iostream>
#include <fstream>
#include <string>
#include <msgpack.h>
#include <filesystem>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;

/* Byte order reversal (Endian conversion) */
// 64-bit unsigned integer byte order reversal
uint64_t swap_64(uint64_t x){
	return((x & 0x00000000000000FFULL) << 56) |
		((x & 0x000000000000FF00ULL) << 40) |
		((x & 0x0000000000FF0000ULL) << 24) |
		((x & 0x00000000FF000000ULL) << 8) |
		((x & 0x000000FF00000000ULL) >> 8) |
		((x & 0x0000FF0000000000ULL) >> 24) |
		((x & 0x00FF000000000000ULL) >> 40) |
		((x & 0xFF00000000000000ULL) >> 56);
}

// 32-bit unsigned integer byte order reversal
uint32_t swap_32(uint32_t val)
{

	return ((0xff000000 & val << 24) \
		| (0x00ff0000 & val << 8) \
		| (0x0000ff00 & val >> 8) \
		| (0x000000ff & val >> 24));
}

// 16-bit unsigned integer byte order reversal
uint16_t swap_16(uint16_t val)
{
	return ((val & 0x00ff) << 8) | ((val & 0xff00) >> 8);
}

// Float data byte order reversal
float convertEndianFloat(float value) {
	union {
		float f;
		uint32_t i;
	} u;
	u.f = value;
	u.i = swap_32(u.i);
	return u.f;
}

// Double data byte order reversal
double convertEndianDouble(double value) {
	union {
		double d;
		uint64_t l;
	} u;
	u.d = value;
	u.l = swap_64(u.l);
	return u.d;
}


// Read IQS mode configuration information and device-related information
int GetIQSWavFileInfo(const char* FilePath,IQS_Profile_TypeDef *IQS_Profile, IQS_StreamInfo_TypeDef * IQS_StreamInfo, DeviceInfo_TypeDef *DeviceInfo,uint32_t *IQSize)
{
	int Status = 0;
	
	// Open the recorded file
	fstream File;
	string FilePath_s = FilePath;
	File.open(FilePath_s, ios::in | ios::binary);

	if (!File.is_open())
	{
		Status = -1009;
		return Status;
	}

	uint16_t StructSize = 0;
	uint32_t IQ_Size = 0;
	char InfoSize_2[2];
	char InfoSize_4[4];
	char InfoSize_8[8];

	/* Get IQS_Profile and IQS_StreamInfo */

	// Read IQS_Profile and IQS_StreamInfo structure byte length (total size of the two structures)  
	File.seekp(108, ios::beg);
	File.read(InfoSize_2, sizeof(InfoSize_2));
	memcpy(&StructSize, InfoSize_2, sizeof(InfoSize_2));
	StructSize = swap_16(StructSize); // Convert the read byte length from big-endian to little-endian (host byte order)

	char* IQSProAndStream = new char[StructSize]; // Read data for IQS_Profile and IQS_StreamInfo
	File.read(IQSProAndStream, StructSize);  

	// Use msgpack to unpack the read data and parse the parameters in the file according to the file format specification. (The data in IQS_Profile and IQS_StreamInfo is recorded in little-endian byte order)
	msgpack_unpacked unpacked;
	msgpack_unpacked_init(&unpacked);
	size_t off = 0;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off); // Parse center frequency (in Hz), unpack the 64-bit float (double) value and assign it to IQS_Profile's CenterFreq_Hz
	IQS_Profile->CenterFreq_Hz = unpacked.data.via.f64;
	  
	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off); // Parse reference level (in dBm), unpack the 64-bit float and assign it to IQS_Profile's RefLevel_dBm
	IQS_Profile->RefLevel_dBm = unpacked.data.via.f64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off); // Parse decimation factor, convert the unpacked 64-bit unsigned integer to a 32-bit unsigned integer, and assign it to IQS_Profile's DecimateFactor
	IQS_Profile->DecimateFactor = static_cast<uint32_t>(unpacked.data.via.u64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off); // Parse the rest as per the format specification in the file
	IQS_Profile->RxPort = static_cast<RxPort_TypeDef>(unpacked.data.via.i64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->BusTimeout_ms = static_cast<uint32_t>(unpacked.data.via.u64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->TriggerSource = static_cast<IQS_TriggerSource_TypeDef>(unpacked.data.via.i64); 

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->TriggerEdge = static_cast<TriggerEdge_TypeDef>(unpacked.data.via.i64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->TriggerMode = static_cast<TriggerMode_TypeDef>(unpacked.data.via.i64); 

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->TriggerLength = unpacked.data.via.u64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->TriggerOutMode = static_cast<TriggerOutMode_TypeDef>(unpacked.data.via.i64); 

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->TriggerOutPulsePolarity = static_cast<TriggerOutPulsePolarity_TypeDef>(unpacked.data.via.i64); 

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->TriggerLevel_dBm = unpacked.data.via.f64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->TriggerLevel_SafeTime = unpacked.data.via.f64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->TriggerDelay = (TriggerOutMode_TypeDef)unpacked.data.via.f64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->PreTriggerTime = (TriggerOutPulsePolarity_TypeDef)unpacked.data.via.f64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->TriggerTimerSync = static_cast<TriggerTimerSync_TypeDef>(unpacked.data.via.i64);
		
	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->TriggerTimer_Period = unpacked.data.via.f64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->EnableReTrigger = static_cast<uint8_t>(unpacked.data.via.u64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->ReTrigger_Period = unpacked.data.via.f64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->ReTrigger_Count = static_cast<uint16_t>(unpacked.data.via.u64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->DataFormat = static_cast<DataFormat_TypeDef>(unpacked.data.via.i64); 

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->GainStrategy = static_cast<GainStrategy_TypeDef>(unpacked.data.via.i64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->Preamplifier = static_cast<PreamplifierState_TypeDef>(unpacked.data.via.i64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->AnalogIFBWGrade = static_cast<uint8_t>(unpacked.data.via.u64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->IFGainGrade = static_cast<uint8_t>(unpacked.data.via.u64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->EnableDebugMode = static_cast<uint8_t>(unpacked.data.via.u64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->ReferenceClockSource = static_cast<ReferenceClockSource_TypeDef>(unpacked.data.via.i64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->ReferenceClockFrequency = unpacked.data.via.f64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->EnableReferenceClockOut = static_cast<uint8_t>(unpacked.data.via.u64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->SystemClockSource = static_cast<SystemClockSource_TypeDef>(unpacked.data.via.i64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->ExternalSystemClockFrequency = unpacked.data.via.f64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->NativeIQSampleRate_SPS = unpacked.data.via.f64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->EnableIFAGC = static_cast<uint8_t>(unpacked.data.via.u64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->Atten = static_cast<int8_t>(unpacked.data.via.i64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->DCCancelerMode = static_cast<DCCancelerMode_TypeDef>(unpacked.data.via.i64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->QDCMode = static_cast<QDCMode_TypeDef>(unpacked.data.via.i64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->QDCIGain = static_cast<float>(unpacked.data.via.f64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->QDCQGain = static_cast<float>(unpacked.data.via.f64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->QDCPhaseComp = static_cast<float>(unpacked.data.via.f64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->DCCIOffset = static_cast<int8_t>(unpacked.data.via.i64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->DCCQOffset = static_cast<int8_t>(unpacked.data.via.i64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_Profile->LOOptimization = static_cast<LOOptimization_TypeDef>(unpacked.data.via.i64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_StreamInfo->Bandwidth = unpacked.data.via.f64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_StreamInfo->IQSampleRate = unpacked.data.via.f64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_StreamInfo->PacketCount = unpacked.data.via.u64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_StreamInfo->StreamSamples = unpacked.data.via.u64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_StreamInfo->StreamDataSize = unpacked.data.via.u64;

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_StreamInfo->PacketSamples = static_cast<uint32_t>(unpacked.data.via.u64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_StreamInfo->PacketDataSize = static_cast<uint32_t>(unpacked.data.via.u64);

	msgpack_unpack_next(&unpacked, IQSProAndStream, (size_t)StructSize, &off);
	IQS_StreamInfo->GainParameter = static_cast<uint32_t>(unpacked.data.via.u64);

	// Get DeviceInfo
	File.read(InfoSize_2, sizeof(InfoSize_2)); // DeviceInfo structure size

	File.read(InfoSize_8, sizeof(InfoSize_8));              // Read device UID
	memcpy(&DeviceInfo->DeviceUID, InfoSize_8, sizeof(InfoSize_8));
	DeviceInfo->DeviceUID = swap_64(DeviceInfo->DeviceUID); // Big-endian to little-endian

	File.read(InfoSize_2, sizeof(InfoSize_2));      // Read device type
	memcpy(&DeviceInfo->Model, InfoSize_2, sizeof(InfoSize_2)); 
	DeviceInfo->Model = swap_16(DeviceInfo->Model); // Big-endian to little-endian

	File.read(InfoSize_2, sizeof(InfoSize_2));                          // Read device hardware version
	memcpy(&DeviceInfo->HardwareVersion, InfoSize_2, sizeof(InfoSize_2));  
	DeviceInfo->HardwareVersion = swap_16(DeviceInfo->HardwareVersion); // Big-endian to little-endian
		
	File.read(InfoSize_4, sizeof(InfoSize_4));                // Read device MCU firmware version
	memcpy(&DeviceInfo->MFWVersion, InfoSize_4, sizeof(InfoSize_4));
	DeviceInfo->MFWVersion = swap_32(DeviceInfo->MFWVersion); // Big-endian to little-endian

	File.read(InfoSize_4, sizeof(InfoSize_4));                // Read device FPGA firmware version
	memcpy(&DeviceInfo->FFWVersion, InfoSize_4, sizeof(InfoSize_4));
	DeviceInfo->FFWVersion = swap_32(DeviceInfo->FFWVersion); // Big-endian to little-endian

	// Get total IQ data size
	File.seekp(25 * 1024 * 1024 + 404, ios::beg); // Move file pointer to the data format block size position
	File.read(InfoSize_4, sizeof(InfoSize_4));    // Read format block size
	memcpy(&IQ_Size, InfoSize_4, sizeof(InfoSize_4));

	*IQSize = IQ_Size / 64968; // Get total number of data packets (each packet has 64968 bytes)

	File.close();
	return Status;
}

// Read the interleaved IQ data stream in IQS mode, the scale factor (ScaleToV) for converting integers to absolute amplitude (in Volts), and trigger-related information
int GetIQSWavFileData(IQS_Profile_TypeDef* IQS_Profile, const char* FilePath, const uint32_t PacketNum, IQStream_TypeDef *IQStream, int16_t IQData[])
{
    int Status = 0;
    fstream File;
    string FilePath_s = FilePath;                 // Convert file path to string type
    File.open(FilePath_s, ios::in | ios::binary); // Open .wav file for binary reading.

    if (!File.is_open())
    {
        Status = -1009;
        return Status;
    }

    // Define buffer for reading file data
    char InfoSize_1[1];
    char InfoSize_2[2];
    char InfoSize_4[4];
    char InfoSize_8[8];

    /* Get IQS_TriggerInfo */
    // Jump to the position of the IQS_TriggerInfo structure based on PacketNum and structure size to locate the current structure
    File.seekp(408 + PacketNum * (405), ios::beg); // (Each packet is 405 bytes)
    File.read(InfoSize_2, sizeof(InfoSize_2));     // IQS_TriggerInfo Struct Size

    File.read(InfoSize_8, sizeof(InfoSize_8));
    memcpy(&IQStream->IQS_TriggerInfo.SysTimerCountOfFirstDataPoint, InfoSize_8, sizeof(InfoSize_8)); // Read the system timestamp of the first data point in the current packet
    IQStream->IQS_TriggerInfo.SysTimerCountOfFirstDataPoint = convertEndianDouble(IQStream->IQS_TriggerInfo.SysTimerCountOfFirstDataPoint); // Big-endian to little-endian (stored in big-endian in .wav file, needs endian conversion for little-endian display on host)

    File.read(InfoSize_2, sizeof(InfoSize_2));
    memcpy(&IQStream->IQS_TriggerInfo.InPacketTriggeredDataSize, InfoSize_2, sizeof(InfoSize_2)); // Read the size of valid trigger data in the current packet
    IQStream->IQS_TriggerInfo.InPacketTriggeredDataSize = swap_16(IQStream->IQS_TriggerInfo.InPacketTriggeredDataSize); // Big-endian to little-endian

    File.read(InfoSize_2, sizeof(InfoSize_2));
    memcpy(&IQStream->IQS_TriggerInfo.InPacketTriggerEdges, InfoSize_2, sizeof(InfoSize_2)); // Read the number of trigger edges in the current packet
    IQStream->IQS_TriggerInfo.InPacketTriggerEdges = swap_16(IQStream->IQS_TriggerInfo.InPacketTriggerEdges); // Big-endian to little-endian

    // The following parsing is the same, refer to "Recording File Format Description" for specific endianness and data types
    for (int i = 0; i < 25; i++)
    {
        File.read(InfoSize_4, sizeof(InfoSize_4));
        memcpy(&IQStream->IQS_TriggerInfo.StartDataIndexOfTriggerEdges[i], InfoSize_4, sizeof(InfoSize_4));
    }
    for (int i = 0; i < 25; i++)
    {
        File.read(InfoSize_8, sizeof(InfoSize_8));
        memcpy(&IQStream->IQS_TriggerInfo.SysTimerCountOfEdges[i], InfoSize_8, sizeof(InfoSize_8));
    }
    for (int i = 0; i < 25; i++)
    {
        File.read(InfoSize_1, sizeof(InfoSize_1));
        memcpy(&IQStream->IQS_TriggerInfo.EdgeType[i], InfoSize_1, sizeof(InfoSize_1));
    }

	
    /* Get DeviceState */
    File.read(InfoSize_2, sizeof(InfoSize_2)); // DeviceState struct size

    File.read(InfoSize_2, sizeof(InfoSize_2));
    memcpy(&IQStream->DeviceState.Temperature, InfoSize_2, sizeof(InfoSize_2)); // Read temperature information
    IQStream->DeviceState.Temperature = swap_16(IQStream->DeviceState.Temperature); // Big-endian to little-endian

    File.read(InfoSize_2, sizeof(InfoSize_2));
    memcpy(&IQStream->DeviceState.RFState, InfoSize_2, sizeof(InfoSize_2)); // Read RF state
    IQStream->DeviceState.RFState = swap_16(IQStream->DeviceState.RFState); // Big-endian to little-endian

    File.read(InfoSize_2, sizeof(InfoSize_2));
    memcpy(&IQStream->DeviceState.BBState, InfoSize_2, sizeof(InfoSize_2)); // Read baseband state
    IQStream->DeviceState.BBState = swap_16(IQStream->DeviceState.BBState); // Big-endian to little-endian

    File.read(InfoSize_8, sizeof(InfoSize_8)); // Parsing follows the same logic
	memcpy(&IQStream->DeviceState.AbsoluteTimeStamp, InfoSize_8, sizeof(InfoSize_8));
	IQStream->DeviceState.AbsoluteTimeStamp = convertEndianDouble(IQStream->DeviceState.AbsoluteTimeStamp);

	File.read(InfoSize_4, sizeof(InfoSize_4));
	memcpy(&IQStream->DeviceState.Latitude, InfoSize_4, sizeof(InfoSize_4));
	IQStream->DeviceState.Latitude = convertEndianFloat(IQStream->DeviceState.Latitude);

	File.read(InfoSize_4, sizeof(InfoSize_4));
	memcpy(&IQStream->DeviceState.Longitude, InfoSize_4, sizeof(InfoSize_4));
	IQStream->DeviceState.Longitude = convertEndianFloat(IQStream->DeviceState.Longitude);

	File.read(InfoSize_2, sizeof(InfoSize_2));
	memcpy(&IQStream->DeviceState.GainPattern, InfoSize_2, sizeof(InfoSize_2));
	IQStream->DeviceState.GainPattern = swap_16(IQStream->DeviceState.GainPattern);

	File.read(InfoSize_8, sizeof(InfoSize_8));
	memcpy(&IQStream->DeviceState.RFCFreq, InfoSize_8, sizeof(InfoSize_8));
	IQStream->DeviceState.RFCFreq = swap_64(IQStream->DeviceState.RFCFreq);

	File.read(InfoSize_4, sizeof(InfoSize_4));
	memcpy(&IQStream->DeviceState.ConvertPattern, InfoSize_4, sizeof(InfoSize_4));
	IQStream->DeviceState.ConvertPattern = swap_32(IQStream->DeviceState.ConvertPattern);

	File.read(InfoSize_4, sizeof(InfoSize_4));
	memcpy(&IQStream->DeviceState.NCOFTW, InfoSize_4, sizeof(InfoSize_4));
	IQStream->DeviceState.NCOFTW = swap_32(IQStream->DeviceState.NCOFTW);

	File.read(InfoSize_4, sizeof(InfoSize_4));
	memcpy(&IQStream->DeviceState.SampleRate, InfoSize_4, sizeof(InfoSize_4));
	IQStream->DeviceState.SampleRate = swap_32(IQStream->DeviceState.SampleRate);

	File.read(InfoSize_2, sizeof(InfoSize_2));
	memcpy(&IQStream->DeviceState.CPU_BCFlag, InfoSize_2, sizeof(InfoSize_2));
	IQStream->DeviceState.CPU_BCFlag = swap_16(IQStream->DeviceState.CPU_BCFlag);

	File.read(InfoSize_2, sizeof(InfoSize_2));
	memcpy(&IQStream->DeviceState.IFOverflow, InfoSize_2, sizeof(InfoSize_2));
	IQStream->DeviceState.IFOverflow = swap_16(IQStream->DeviceState.IFOverflow);

	File.read(InfoSize_2, sizeof(InfoSize_2));
	memcpy(&IQStream->DeviceState.DecimateFactor, InfoSize_2, sizeof(InfoSize_2));
	IQStream->DeviceState.DecimateFactor = swap_16(IQStream->DeviceState.DecimateFactor);

	File.read(InfoSize_2, sizeof(InfoSize_2));
	memcpy(&IQStream->DeviceState.OptionState, InfoSize_2, sizeof(InfoSize_2));
	IQStream->DeviceState.OptionState = swap_16(IQStream->DeviceState.OptionState);

	/* Get IQS_ScaleToV, MaxPower_dBm, MaxIndex */
	File.read(InfoSize_4, sizeof(InfoSize_4));
	memcpy(&IQStream->IQS_ScaleToV, InfoSize_4, sizeof(InfoSize_4));
	IQStream->IQS_ScaleToV = convertEndianFloat(IQStream->IQS_ScaleToV);

	File.read(InfoSize_4, sizeof(InfoSize_4));
	memcpy(&IQStream->MaxPower_dBm, InfoSize_4, sizeof(InfoSize_4));
	IQStream->MaxPower_dBm = convertEndianFloat(IQStream->MaxPower_dBm);

	File.read(InfoSize_4, sizeof(InfoSize_4));
	memcpy(&IQStream->MaxIndex, InfoSize_4, sizeof(InfoSize_4));
	IQStream->MaxIndex = swap_32(IQStream->MaxIndex);

	/* Get total IQ data length */
	File.seekp(25 * 1024 * 1024 + 404, ios::beg); // Move file pointer to the data format block length
	File.read(InfoSize_4, sizeof(InfoSize_4));    // Read total IQ data length

	int format = 0;

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

	/* Get IQ data */
	File.seekp(25 * 1024 * 1024 + 408 + PacketNum * 64968, ios::beg); // Move file pointer to the start of the specified packet

	for (uint32_t i = 0; i < (64968 / format); i++)
	{
		File.read(InfoSize_2, sizeof(InfoSize_2));
		memcpy(&IQData[i], InfoSize_2, sizeof(InfoSize_2));
	}

	File.close();
	return Status;
}

// Get related information from the wav file
int IQSMode_PlayBack()
{
    int Status = 0;
    char path[] = "./data/0029_20241231_170621.part1.iq.wav"; // Modify the recording file name as needed, e.g., 0022_20241225_164858.part1.iq.wav

    IQStream_TypeDef IQStream;
    DeviceInfo_TypeDef DeviceInfo;
    IQS_Profile_TypeDef IQS_Profile;
    IQS_StreamInfo_TypeDef StreamInfo;
    uint32_t PacketCount = 0;

    string FilePath_last = "./data/";  // File save path is ./data/

    // Check if the directory exists, create it if it doesn't
    if (!(filesystem::exists(FilePath_last))) {
        // Try to create the directory and its parent directories
        filesystem::create_directories(FilePath_last);
        cout << "Data folder path: Htra_RecordingandPlayBack\\data" << endl;
        if (filesystem::create_directories(FilePath_last)) {
            cout << "Failed to create directory \"" << FilePath_last << "\"." << endl;
            return 0;
        }
    }

    Status = GetIQSWavFileInfo(path, &IQS_Profile, &StreamInfo, &DeviceInfo, &PacketCount); // Get IQS structure information and DeviceInfo

    IQStream.IQS_Profile = IQS_Profile;
    IQStream.IQS_StreamInfo = StreamInfo;
    IQStream.DeviceInfo = DeviceInfo;

    vector<int16_t> IQ_Data(StreamInfo.PacketSamples * 2 );         // Create IQ data array (one packet).
    vector<int16_t> I_Data(StreamInfo.PacketSamples * PacketCount); // Create I data array.
    vector<int16_t> Q_Data(StreamInfo.PacketSamples * PacketCount); // Create Q data array.
                
    char FileName[255]; // Define file name character array
    
    sprintf_s(FileName, "./data/IQSMode_Data.txt"); // Format file name as "IQSMode_Data.txt"

    // Create an fstream object to handle file storage of parsed IQ data
    fstream File1;
    // Open the file in write mode
    File1.open(FileName, ios::out);

    for (uint32_t PacketNum = 0; PacketNum < PacketCount; PacketNum++)                            
    {                                                                                                        
        Status = GetIQSWavFileData(&IQS_Profile, path, PacketNum, &IQStream, IQ_Data.data()); // Get data

        uint32_t Points = StreamInfo.PacketSamples;

        if (PacketNum == PacketCount - 1 && StreamInfo.StreamSamples % StreamInfo.PacketSamples != 0)  // The last packet may not be a full packet (16242 points); so only loop through the points that are not a full packet
        {
            Points = StreamInfo.StreamSamples % (uint64_t)StreamInfo.PacketSamples;
        }

        for (uint32_t i = 0; i < Points; i++)
        {
            Q_Data[i + StreamInfo.PacketSamples * PacketNum] = IQ_Data[i * 2];
            I_Data[i + StreamInfo.PacketSamples * PacketNum] = IQ_Data[i * 2 + 1];
            File1 << IQ_Data[i * 2 + 1] << "\t" << IQ_Data[i * 2]  << "\n";
        }
    }

    File1.close(); // Close the file stream, save and release resources

    return 0;
}
