#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include "htra_api.h" 
#include "portaudio.h"
#include "example.h"

using namespace std;

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

int DSP_AMDemod()
{
	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模式输入配置，包括中心频率、抽取倍数、参考电平等。
	IQS_Profile_TypeDef IQS_ProfileOut; //IQS模式输出配置。
	IQS_StreamInfo_TypeDef StreamInfo;  //当前配置下的IQ数据流相关信息。

	Status = IQS_ProfileDeInit(&Device, &IQS_ProfileIn); //调用此函数初始化配置IQS模式的相关参数。

	IQS_ProfileIn.CenterFreq_Hz = 97.6e6;    //配置中心频率。     
	IQS_ProfileIn.RefLevel_dBm = -35;        //配置参考电平。
	IQS_ProfileIn.DataFormat = Complex16bit; //配置IQ数据格式。
	IQS_ProfileIn.TriggerMode = Adaptive;    //配置触发模式。FixedPoints模式是触发信号的上升沿开始采样。采到TriggerLength个点后结束采样。Adaptive模式是触发信号的上升沿开始采样，下降沿结束采样。
	IQS_ProfileIn.TriggerSource = Bus;       //配置触发源为内部总线触发，若设备接外部触发源，则配置External。
	IQS_ProfileIn.DecimateFactor = 512;      //配置抽取倍数。
	IQS_ProfileIn.BusTimeout_ms = 50000;     //配置Bus超时时间。

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

	IQStream_TypeDef IQStream;                        //存放IQ数据包（IQ数据和相关配置信息）。
	void* ADM = nullptr;
	ADM_Open(&ADM);


	/*播放音频配置*/
	PaStreamParameters outputParameters; //此结构体用于存放音频配置相关参数，包括播放音频设备号、通道数、数据格式等。
	PaStream* stream;                    //此参数为PortAudio存储音频输入输出相关的内存地址。
	PaError err;                         //此参数为PortAudio的函数错误码返回值。

	err = Pa_Initialize();                             //调用此函数初始化PortAudio函数。
	vector<float> audio(StreamInfo.PacketSamples);     //开辟内存用于存放解调后的音频数据。
	vector<float> LPF_audio(StreamInfo.PacketSamples); //开辟内存用于存放解调并且低通滤波的音频数据。

	outputParameters.device = Pa_GetDefaultOutputDevice();									                //配置默认播放音频的设备号。
	outputParameters.channelCount = 1;									                                    //配置通道数。
	outputParameters.sampleFormat = paFloat32;									                            //配置音频数据类型，用一个32位有符号浮点型存储每个音频数据块，音频数据范围最高为1.0，最低为-1.0。
	outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; //配置所需的延时时间。
	outputParameters.hostApiSpecificStreamInfo = NULL;                                                      //指向主机 API 特定数据结构的可选指针包含设备设置 和/或 流处理的附加信息,正确操作从不需要hostApiSpecificStreamInfo，如果不使用它应该设置为 NULL。

	err = Pa_OpenStream(&stream, NULL, &outputParameters, StreamInfo.IQSampleRate, StreamInfo.PacketSamples, paClipOff, NULL, NULL); //打开音频数据流。
	err = Pa_StartStream(stream);																									 //开始音频处理。

	/*启动DSP功能*/
	void* DSP = NULL;        //开辟数字信号处理地址。
	Status = DSP_Open(&DSP); //开启信号处理功能。

	/*配置低通滤波器，对音频数据进行低通滤波*/
	Filter_TypeDef LPF_ProfileIn;
	Filter_TypeDef LPF_ProfileOut;

	DSP_LPF_DeInit(&LPF_ProfileIn); //初始化配置LPF模式的相关参数。

	LPF_ProfileIn.As = 90;   //配置滤波器的阻带衰减。
	LPF_ProfileIn.fc = 0.25; //配置滤波器截止频率。
	LPF_ProfileIn.mu = 0;    //配置分数采样偏移量。
	LPF_ProfileIn.n = 90;    //配置滤波器阶数。

	DSP_LPF_Configuration(&DSP, &LPF_ProfileIn, &LPF_ProfileOut); //配置LPF的相关参数。

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

	//循环获取并播放AM广播
	while (1)
	{
		Status = IQS_GetIQStream_PM1(&Device, &IQStream); //获取IQ数据。
		if (Status == APIRETVAL_NoError)
		{
			ADM_AMDemod(&ADM, IQStream.AlternIQStream, IQStream.IQS_Profile.DataFormat, StreamInfo.PacketSamples, IQStream.IQS_StreamInfo.IQSampleRate, audio.data());
			
			for (int i = 0; i < StreamInfo.PacketSamples; i++) //用于将解调后的音频数据缩小到-1~1的范围中，所除的数可以更改。
			{
				audio[i] /= 32;
			}

			DSP_LPF_Execute_Real(&DSP, audio.data(), LPF_audio.data());               //对音频数据进行低通滤波。
			err = Pa_WriteStream(stream, LPF_audio.data(), StreamInfo.PacketSamples); //播放音频数据。
		}
		else //当Status不为0时，根据Status的返回值进行相对应的错误处理。
		{
			IQS_ErrorHandlingExceptOpenAndConfiguration(Status, &Device, DevNum, &BootProfile, &BootInfo, &IQS_ProfileIn, &IQS_ProfileOut, &StreamInfo);
		}
		
	}

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

	//关闭各个功能模块。
	err = Pa_StopStream(stream);  //停止音频处理。
	err = Pa_CloseStream(stream); //关闭音频数据流。
	Pa_Terminate();               //释放 PortAudio 分配的所有资源。

	DSP_Close(&DSP);                //释放数字信号处理分配的所有资源。
	ADM_Close(&ADM);          //释放调制解分配的所有资源。
	Status = Device_Close(&Device); //关闭设备。
	return 0;
}