#include <iostream>
#include <vector>
#include <string>
#include "htra_api.h"
#include "example.h"
using namespace std;

#define IS_USB 1 // Default to using USB-type device; set IS_USB to 0 if using Ethernet-type device.

int IQS_GetIQ_EZStandard()
{
	int Status = 0;      // Function return value.
	void* Device = NULL; // Pointer to current device.
	int DevNum = 0;      // Specified device number.

	BootProfile_TypeDef BootProfile; // Boot configuration struct, including physical interface, power supply method, etc.
	BootInfo_TypeDef BootInfo;       // Boot information struct, including device info, USB rate, etc.

	BootProfile.DevicePowerSupply = USBPortAndPowerPort; // Use both USB data port and independent power port.

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

	Device_Open_ErrorHandling(Status, &Device, DevNum, &BootProfile, &BootInfo); // If Status is not 0, handle errors accordingly.

	IQS_EZProfile_TypeDef IQS_EZProfileIn;  // IQS input configuration, including start frequency, stop frequency, RBW, reference level, etc.
	IQS_EZProfile_TypeDef IQS_EZProfileOut; // IQS output configuration.
	IQS_StreamInfo_TypeDef EZStreamInfo;    // IQ data info under current config, including bandwidth, IQ sampling rate, etc.

	Status = IQS_EZProfileDeInit(&Device, &IQS_EZProfileIn); // Initialize configuration for EZ mode in IQS.

	IQS_EZProfileIn.CenterFreq_Hz = 1e9;       // Set center frequency.
	IQS_EZProfileIn.RefLevel_dBm = 0;          // Set reference level.
	IQS_EZProfileIn.DecimateFactor = 2;		   // Set decimation factor.
	IQS_EZProfileIn.DataFormat = Complex16bit; // Set IQ data format.
	IQS_EZProfileIn.TriggerSource = Bus;       // Set trigger source to internal bus trigger.
	IQS_EZProfileIn.TriggerMode = FixedPoints; // Set trigger mode.
	IQS_EZProfileIn.TriggerLength = 16384;     // Set number of points collected per trigger.

	Status = IQS_EZConfiguration(&Device, &IQS_EZProfileIn, &IQS_EZProfileOut, &EZStreamInfo); // Apply IQS configuration in EZ mode.

	if (Status == 0)
	{
		printf("EZConfiguration delievery succeeded.\n");
	}
	else
	{
		printf("Error in IQS_EZConfiguration call. Status = %d\n", Status);
		Device_Close(&Device);
		return 0;
	}

	IQStream_TypeDef IQStream; // Stores IQ data packet including IQ samples, configuration info, etc.
	bool tag = false;		   // When IQS_EZProfileIn.TriggerMode = Adaptive, trigger once before acquiring data.

	vector<int16_t> I_Data(EZStreamInfo.StreamSamples); // Create I channel data array.
	vector<int16_t> Q_Data(EZStreamInfo.StreamSamples); // Create Q channel data array.

	if (IQS_EZProfileIn.TriggerMode == Adaptive)
	{
		I_Data.resize(EZStreamInfo.PacketSamples); // Resize I_Data to store data in Adaptive mode.
		Q_Data.resize(EZStreamInfo.PacketSamples); // Resize Q_Data to store data in Adaptive mode.
	}

	while (1)
	{
		if (IQS_EZProfileOut.TriggerMode == Adaptive && tag != true) // If TriggerMode = Adaptive, only trigger once.
		{
			Status = IQS_BusTriggerStart(&Device);                   // Trigger device. Not needed if trigger source is external.
			tag = true;
		}
		if (IQS_EZProfileOut.TriggerMode == FixedPoints)             // If TriggerMode = FixedPoints, trigger every loop.
		{
			Status = IQS_BusTriggerStart(&Device);                   // Not needed if trigger source is external.
		}

		/* Get IQ data */
		for (int j = 0; j < EZStreamInfo.PacketCount; j++)	         // Only valid when TriggerMode is FixedPoints.
		{
			Status = IQS_GetIQStream_PM1(&Device, &IQStream);        // Get IQ data packet, trigger info, I-channel max, and max index.

			if (Status == APIRETVAL_NoError)
			{
				// UserCode here
				// Note: When using IQ mode, it is recommended to call IQS_GetIQStream in a separate thread dedicated to data fetching, and not combine with processing logic in the same thread.

				//int16_t* IQ = (int16_t*)IQStream.AlternIQStream;
				//uint32_t Points = EZStreamInfo.PacketSamples;

				//if (j == EZStreamInfo.PacketCount - 1 && EZStreamInfo.StreamSamples % EZStreamInfo.PacketSamples != 0 && IQS_EZProfileOut.TriggerMode == FixedPoints) // The last packet may be incomplete (e.g., 16242 points), so only process the remaining points.
				//{
				//	Points = EZStreamInfo.StreamSamples % EZStreamInfo.PacketSamples;
				//}

				//for (uint32_t i = 0; i < Points; i++)
				//{
				//	I_Data[i + EZStreamInfo.PacketSamples * j] = IQ[i * 2];
				//	Q_Data[i + EZStreamInfo.PacketSamples * j] = IQ[i * 2 + 1];
				//}
			}

			/* If data acquisition fails, return error message. For the following error codes, take recommended actions. */
			else
			{
				switch (Status)
				{
				case APIRETVAL_WARNING_IFOverflow: 
					printf("Warning - IF saturation detected. Reconfiguration recommended. Reference level <= signal power\n");  // If IQS_GetIQStream_PM1 returns -12, reconfiguration is recommended.
					break;
				case APIRETVAL_WARNING_ReconfigurationIsRecommended:
					printf("Warning - Significant temperature change detected on the device. Reconfiguration of temperature is recommended\n"); // If IQS_GetIQStream_PM1 returns -14, reconfigure parameters before continuing.
					break;
				default:
					printf("Other error returned. Status = %d\n", Status);
					Device_Close(&Device);
					break;
				}
			}
		}
	}

	Status = IQS_BusTriggerStop(&Device); // Stop triggering device.

	Device_Close(&Device); // Close device.

	return 0;

}
