from htra_api import *
from math import *
import numpy as np

###打开设备###
Status = 0          #函数的返回。
Device = c_void_p() #当前设备的内存地址。
DevNum = c_int(0)   #指定设备号。

BootProfile = BootProfile_TypeDef() #启动配置结构体，包括物理接口、供电方式等。
BootInfo = BootInfo_TypeDef()       #启动信息结构体，包括设备信息、USB速率等。

BootProfile.DevicePowerSupply = DevicePowerSupply_TypeDef.USBPortAndPowerPort #使用USB数据端口及独立电源端口双供电
BootProfile.PhysicalInterface = PhysicalInterface_TypeDef.USB                 #使用USB接口进行数据传输。

#使用网口设备配置ETH接口
#BootProfile.PhysicalInterface = PhysicalInterface_TypeDef.ETH #使用网口进行数据传输
#BootProfile.ETH_IPVersion = IPVersion_TypeDef.IPv4
#BootProfile.ETH_RemotePort = 5000
#BootProfile.ETH_ReadTimeOut = 10000
#BootProfile.ETH_IPAddress[0] = 192
#BootProfile.ETH_IPAddress[1] = 168
#BootProfile.ETH_IPAddress[2] = 1
#BootProfile.ETH_IPAddress[3] = 100

Status = dll.Device_Open(pointer(Device),DevNum,pointer(BootProfile),pointer(BootInfo)) #打开设备。
if(Status == 0):
    print("Device is opened successfully")
else:
    print("Return other errors Status = {:d}".format(Status))

###配置下发###
DET_ProfileIn = DET_Profile_TypeDef()  #DET输入配置，包括中心频率、抽取倍数、参考电平等等。
DET_ProfileOut = DET_Profile_TypeDef() #DET输出配置。
StreamInfo = DET_StreamInfo_TypeDef()  #当前配置下的DET数据相关信息，包括DET数据点数、字节数等。

dll.DET_ProfileDeInit(pointer(Device),pointer(DET_ProfileIn)) #调用此函数初始化配置DET模式的相关参数。

DET_ProfileIn.CenterFreq_Hz = 1e9                           #配置中心频率。
DET_ProfileIn.RefLevel_dBm = 0                              #配置参考电平。
DET_ProfileIn.DecimateFactor = 2                            #配置抽取倍数。
DET_ProfileIn.TriggerSource = DET_TriggerSource_TypeDef.Bus #配置触发源为内部总线触发。
DET_ProfileIn.TriggerMode = TriggerMode_TypeDef.FixedPoints
DET_ProfileIn.TriggerLength = 16242                         #配置单次触发采集的点数。仅当TriggerMode设置为FixedPoints时生效。

Status = dll.DET_Configuration(pointer(Device),pointer(DET_ProfileIn),pointer(DET_ProfileOut),pointer(StreamInfo)) #下发DET模式的相关配置。

if(Status == 0):
    print("configuration delievery succeeded")
else:
    print("DET_Configuration call is incorrect Status = {:d}".format(Status))

###获取数据###
NormalizedPowerPacket = (c_float * StreamInfo.PacketSamples)() #创建功率数组（转换单位前数据）。
NormalizedPowerStream = (c_float * DET_ProfileOut.TriggerLength)() #创建功率数组（转换单位后数据）。
ScaleToV = c_float()                                           #此参数为绝对幅度（V单位）的比例因子。
TriggerInfo = DET_TriggerInfo_TypeDef()                        #此结构体用于存放DET模式下的触发信息。
MeasAuxInfo = MeasAuxInfo_TypeDef()                            #此结构体用于存放测量数据的辅助信息。

# 尝试导入绘图模块pyplot，绘制DET模式时间功率图
try:
    from plot_module import start_plot
    max = DET_ProfileOut.TriggerLength*8*DET_ProfileOut.DecimateFactor
    x_array = np.arange(0, max, 8*DET_ProfileOut.DecimateFactor)
    update_plot = start_plot(Sup_title="Power Detection", Subplot1_X=x_array, Subplot1_Y=NormalizedPowerStream, xlabel1="time(ns)", ylabel1="PvT(dBm)",title1=None)

except ImportError:
    print("matplotlib.pyplot not available. Plotting disabled.")
    update_plot = None
    start_plot = None


try:
    while True:
        Status = dll.DET_BusTriggerStart(pointer(Device))  # 调用DET_BusTriggerStart触发设备。若触发源为外部触发，则不需要调用此函数。

        for i in range(0, StreamInfo.PacketCount):
            Status = dll.DET_GetPowerStream(pointer(Device), NormalizedPowerPacket, pointer(ScaleToV),
                                            pointer(TriggerInfo), pointer(MeasAuxInfo))

            # 计算当前包的数据大小（最后一包可能不满一个包）
            if i == StreamInfo.PacketCount - 1 and StreamInfo.StreamSamples % StreamInfo.PacketSamples != 0:
                num_remaining_samples = StreamInfo.StreamSamples % StreamInfo.PacketSamples
                NormalizedPowerStream[i * StreamInfo.PacketSamples:i * StreamInfo.PacketSamples + num_remaining_samples] = NormalizedPowerPacket[:num_remaining_samples]
            else:
                # 完整复制数据
                NormalizedPowerStream[i * StreamInfo.PacketSamples:(i + 1) * StreamInfo.PacketSamples] = NormalizedPowerPacket[:]

        # 计算转换后的功率值
        for i in range(0, StreamInfo.StreamSamples):
            if i < len(NormalizedPowerStream):
                NormalizedPowerStream[i] = 10 * log10(20 * pow(NormalizedPowerStream[i] * ScaleToV.value, 2))

        if update_plot and not update_plot():
            break

except KeyboardInterrupt:
    print("Stopped by user with Ctrl+C")
finally:
    Status = dll.DET_BusTriggerStop(pointer(Device))  # 调用DET_BusTriggerStop停止触发设备。
    dll.Device_Close(pointer(Device))  # 关闭设备
    print("Device closed.")
