#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <map>
#include "htra_api.h"
#include "example.h"
#include <ctime>
#include <thread>
#include <iomanip> 
#define EXAMPLE_MACRO_NAME
using namespace std;

/*README
有关EIO拓展板的连接和使用请参考《SA NX系列频谱分析仪用户指南》中的GNSS模块的使用相关章节
*/

// 将UTC时间转换为北京时间
void UtcToBeijingTime(int16_t& hour_var, int16_t& minute_var, int16_t& second_var,
	int16_t& year_var, int16_t& month_var, int16_t& day_var) {
	// 创建tm结构体来辅助转换
	struct tm utc_tm = {};
	// 设置tm结构体的各字段值，注意年份和月份的取值范围要求
	utc_tm.tm_year = year_var - 1900;  // tm结构体中年份需减去1900
	utc_tm.tm_mon = month_var - 1;      // 月份从0开始计数
	utc_tm.tm_mday = day_var;
	utc_tm.tm_hour = hour_var;
	utc_tm.tm_min = minute_var;
	utc_tm.tm_sec = second_var;
	// 先将tm结构体转换为time_t类型
	time_t utc_time = mktime(&utc_tm);
	// 加上8小时（北京时间比UTC时间快8小时）
	utc_time += 8 * 60 * 60;
	// 使用localtime_s替代localtime
	struct tm beijing_tm;
	errno_t err = localtime_s(&beijing_tm, &utc_time);
	if (err == 0) {
		// 更新原始变量为北京时间的值，同时处理可能的日期变化
		hour_var = beijing_tm.tm_hour;
		minute_var = beijing_tm.tm_min;
		second_var = beijing_tm.tm_sec;
		// 更新年份、月份和日期，注意tm结构体中年份需加1900，月份从0开始计数需转换回常规计数方式
		year_var = beijing_tm.tm_year + 1900;
		month_var = beijing_tm.tm_mon + 1;
		day_var = beijing_tm.tm_mday;
		// 检查是否因日期变化产生跨月或跨年情况
		if (day_var < 1) {
			// 如果日期小于1，说明跨月了，先将月份减1
			month_var--;
			if (month_var < 1) {
				// 如果月份小于1，说明跨年了，将年份减1，月份设置为12
				year_var--;
				month_var = 12;
			}
			// 根据月份重新计算该月的最大天数
			int max_days = 31;
			if (month_var == 4 || month_var == 6 || month_var == 9 || month_var == 11) {
				max_days = 30;
			}
			else if (month_var == 2) {
				if ((year_var % 4 == 0 && year_var % 100 != 0) || year_var % 400 == 0) {
					max_days = 29;
				}
				else {
					max_days = 28;
				}
			}
			day_var = max_days + day_var;
		}
	}
	else {
		// 处理错误情况
		std::cerr << "Error converting UTC to Beijing Time! Error code: " << err << std::endl;
	}
}

// 将浮点数形式的经度或纬度转换为度分秒格式的字符串
string ConvertTODMSFormat(float coordinate) {
	int degrees = static_cast<int>(coordinate);
	float minutesFloat = (coordinate - degrees) * 60;
	int minutes = static_cast<int>(minutesFloat);
	float seconds = (minutesFloat - minutes) * 60;

	std::stringstream ss;
	ss << std::abs(degrees) << "°" << minutes << "'" << std::fixed << std::setprecision(2) << seconds << "''";

	return ss.str();
}

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

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

	/*设置GNSS外部天线*/
	GNSSAntennaState_TypeDef GNSSAntennaState; //启动GNSS天线信息
	GNSSAntennaState = GNSS_AntennaExternal;   //配置外部天线

	//设置GNSS天线状态
	Status = Device_SetGNSSAntennaState(&Device, GNSSAntennaState); //下发GNSS天线相关配置

	GNSSInfo_TypeDef GNSSInfo = { 0 }; //当前天线配置下的GNSS信息

	//每隔1s输出一次当前GNSS的锁定状态，直至设备成功锁定GNSS模块
	while (!GNSSInfo.GNSS_LockState)
	{
		Status = Device_GetGNSSInfo_Realtime(&Device, &GNSSInfo);				//实时获取GNSS设备状态
		cout << "GNSS_LockState: " << (int16_t)GNSSInfo.GNSS_LockState << endl; //输出GNSS天线锁定状态 GNSS_LockState=1 为锁定
		this_thread::sleep_for(chrono::milliseconds(1000));					    //延时1s
	}

	DOCXOWorkMode_TypeDef DOCXOWorkMode; //配置DOCXO天线状态
	DOCXOWorkMode = DOCXO_LockMode;

	/*设置和获取DOCXO的状态*/
	uint16_t HardwareVersion = BootInfo.DeviceInfo.HardwareVersion;
	uint16_t OCXO_Enable = (HardwareVersion >> 10) & 0x3;

	if (OCXO_Enable)
	{
		Status = Device_SetDOCXOWorkMode(&Device, DOCXOWorkMode); //设置GNSS中DOCXO工作状态

		auto start_time = std::chrono::high_resolution_clock::now(); // 获取当前时间

		Status = Device_GetGNSSInfo_Realtime(&Device, &GNSSInfo); //获取GNSS设备状态

		// 检查锁定状态
		if (GNSSInfo.DOCXO_LockState)
		{
			cout << endl;
			// 打印当前GNSS_LockState状态
			cout << "GNSS_LockState: " << (int16_t)GNSSInfo.GNSS_LockState << endl;
			// 打印当前DOCXO_LockState状态
			cout << "DOCXO_LockState: " << (int16_t)GNSSInfo.DOCXO_LockState << endl;
		}
		else
		{
			while (1)
			{
				Status = Device_GetGNSSInfo_Realtime(&Device, &GNSSInfo); //获取GNSS设备状态

				// 检查锁定状态
				if (GNSSInfo.DOCXO_LockState == 1 && GNSSInfo.GNSS_LockState == 1)
				{
					cout << endl;
					// 打印当前GNSS_LockState状态
					cout << "GNSS_LockState: " << (int16_t)GNSSInfo.GNSS_LockState << endl;
					// 打印当前DOCXO_LockState状态
					cout << "DOCXO_LockState: " << (int16_t)GNSSInfo.DOCXO_LockState << endl;
					break;
				}
				if (GNSSInfo.GNSS_LockState == 0)
				{
					DOCXOWorkMode = DOCXO_LockMode;
					Status = Device_SetDOCXOWorkMode(&Device, DOCXOWorkMode); //设置GNSS中DOCXO工作状态
				}
				// 打印当前GNSS_LockState状态
				cout << "GNSS_LockState: " << (int16_t)GNSSInfo.GNSS_LockState << endl;

				// 打印当前DOCXO_LockState状态
				cout << "DOCXO_LockState: " << (int16_t)GNSSInfo.DOCXO_LockState << endl;

				// 检查超时：是否超过180秒
				auto current_time = std::chrono::high_resolution_clock::now();
				auto duration = std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1, 1>>>(current_time - start_time);
				// 如果超时超过600秒，退出循环
				if (duration.count() > 600)
				{
					cout << "The DOCXO is not locked, please check whether the cable connection is normal." << endl;
					break;
					return 0;
				}
				this_thread::sleep_for(chrono::milliseconds(1000)); //延时1s
			}
			cout << "DOCXO is locked!" << endl;
		}
	}

		
	SWP_Profile_TypeDef SWP_ProfileIn;  //SWP输入配置，包括起始频率、终止频率、RBW、参考电平等。
	SWP_Profile_TypeDef SWP_ProfileOut; //SWP输出配置。
	SWP_TraceInfo_TypeDef TraceInfo;    //当前配置下的迹线信息，包括迹线点数、跳频点数等。

	SWP_ProfileDeInit(&Device, &SWP_ProfileIn); //调用此函数初始化配置SWP模式的相关参数。

	SWP_ProfileIn.StartFreq_Hz = 9e3;                                           //配置起始频率
	SWP_ProfileIn.StopFreq_Hz = 6.35e9;                                         //配置终止频率
	SWP_ProfileIn.RBW_Hz = 300e3;                                               //配置RBW
	SWP_ProfileIn.ReferenceClockSource = ReferenceClockSource_Internal_Premium; //配置GNSS模块的10MHz参考时钟（仅高品质GNSS模块可用）
	SWP_ProfileIn.ReferenceClockFrequency = 10e6;                               //配置参考时钟频率

	Status = SWP_Configuration(&Device, &SWP_ProfileIn, &SWP_ProfileOut, &TraceInfo); //通过调用此函数下发SWP模式的相关配置

	SWP_Configuration_ErrorHandling(Status, &Device, DevNum, &BootProfile, &BootInfo, &SWP_ProfileIn, &SWP_ProfileOut, &TraceInfo); //当Status不为0时，根据Status的返回值进行相对应的错误处理。

	vector<double> Frequency(TraceInfo.FullsweepTracePoints);    //创建频率数组。
	vector<float> PowerSpec_dBm(TraceInfo.FullsweepTracePoints); //创建功率数组。
	int HopIndex = 0;                                            //当前跳频点索引。
	int FrameIndex = 0;                                          //当前帧索引。
	MeasAuxInfo_TypeDef MeasAuxInfo;                             //测量数据的辅助信息，包括：功率最大值索引、功率最大值、设备温度、经纬度、绝对时间戳等。

	for (int i = 0; i < TraceInfo.TotalHops; i++) //TraceInfo.TotalHops代表当前配置下的帧数，因此循环TraceInfo.TotalHops次调用SWP_GetPartialSweep即可得到完整迹线。
	{
		Status = SWP_GetPartialSweep(&Device, Frequency.data() + i * TraceInfo.PartialsweepTracePoints, PowerSpec_dBm.data() + i * TraceInfo.PartialsweepTracePoints, &HopIndex, &FrameIndex, &MeasAuxInfo); //获取频谱数据。

		if (Status == APIRETVAL_NoError)
		{
			// UserCode here
			double time_stamp;
			time_stamp = MeasAuxInfo.AbsoluteTimeStamp;                                                                       //获取当前的绝对时间戳单位：S
			int16_t hour_var, minute_var, second_var, year_var, month_var, day_var;
			Status = Device_AnysisGNSSTime(time_stamp, &hour_var, &minute_var, &second_var, &year_var, &month_var, &day_var); //转成UTC时间（解析时间为UTC时间）
			UtcToBeijingTime(hour_var, minute_var, second_var, year_var, month_var, day_var);								  //UTC时间转北京时间

			cout << year_var << "/" << month_var << "/" << day_var << " " << hour_var << ":" << minute_var << ":" << second_var << endl; //输出北京时间
		}

		else //当Status不为0时，根据Status的返回值进行相对应的错误处理。
		{
			SWP_ErrorHandlingExceptOpenAndConfiguration(Status, &Device, DevNum, &BootProfile, &BootInfo, &SWP_ProfileIn, &SWP_ProfileOut, &TraceInfo);
		}
	}

	Device_Close(&Device); //关闭设备	
	return 0;
}