mirror of
https://github.com/jankae/LibreVNA.git
synced 2026-04-05 14:35:23 +00:00
WIP: device synchronization
This commit is contained in:
parent
047f6ce981
commit
58918f81c1
90 changed files with 8970 additions and 310 deletions
|
|
@ -75,3 +75,13 @@ QString CompoundDevice::getDesription()
|
|||
{
|
||||
return name + ", "+QString::number(deviceSerials.size())+" devices, "+QString::number(portMapping.size())+" ports in total";
|
||||
}
|
||||
|
||||
int CompoundDevice::PortMapping::findActiveStage(std::vector<CompoundDevice::PortMapping> map, int device, int port)
|
||||
{
|
||||
for(unsigned int i=0;i<map.size();i++) {
|
||||
if(map[i].device == device && map[i].port == port) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return map.size();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ public:
|
|||
public:
|
||||
unsigned int device;
|
||||
unsigned int port;
|
||||
static int findActiveStage(std::vector<PortMapping> map, int device, int port);
|
||||
};
|
||||
|
||||
enum class Synchronization {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ USBInBuffer::USBInBuffer(libusb_device_handle *handle, unsigned char endpoint, i
|
|||
{
|
||||
buffer = new unsigned char[buffer_size];
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
libusb_fill_bulk_transfer(transfer, handle, endpoint, buffer, buffer_size, CallbackTrampoline, this, 100);
|
||||
libusb_fill_bulk_transfer(transfer, handle, endpoint, buffer, buffer_size, CallbackTrampoline, this, 0);
|
||||
libusb_submit_transfer(transfer);
|
||||
}
|
||||
|
||||
|
|
@ -66,9 +66,11 @@ int USBInBuffer::getReceived() const
|
|||
|
||||
void USBInBuffer::Callback(libusb_transfer *transfer)
|
||||
{
|
||||
// qDebug() << libusb_error_name(transfer->status);
|
||||
switch(transfer->status) {
|
||||
case LIBUSB_TRANSFER_COMPLETED:
|
||||
received_size += transfer->actual_length;
|
||||
// qDebug() << transfer->actual_length <<"total:" << received_size;
|
||||
inCallback = true;
|
||||
emit DataReceived();
|
||||
inCallback = false;
|
||||
|
|
@ -249,6 +251,7 @@ bool Device::SendPacket(const Protocol::PacketInfo& packet, std::function<void(T
|
|||
t.packet = packet;
|
||||
t.timeout = timeout;
|
||||
t.callback = cb;
|
||||
lock_guard<mutex> lock(transmissionMutex);
|
||||
transmissionQueue.enqueue(t);
|
||||
// qDebug() << "Enqueued packet, queue at " << transmissionQueue.size();
|
||||
if(!transmissionActive) {
|
||||
|
|
@ -321,6 +324,16 @@ std::set<QString> Device::GetDevices()
|
|||
return serials;
|
||||
}
|
||||
|
||||
void Device::SetTrigger(bool set)
|
||||
{
|
||||
qDebug() << "Trigger" << set << "to" << this;
|
||||
if(set) {
|
||||
SendCommandWithoutPayload(Protocol::PacketType::SetTrigger);
|
||||
} else {
|
||||
SendCommandWithoutPayload(Protocol::PacketType::ClearTrigger);
|
||||
}
|
||||
}
|
||||
|
||||
void Device::USBHandleThread()
|
||||
{
|
||||
qDebug() << "Receive thread started";
|
||||
|
|
@ -460,7 +473,9 @@ void Device::ReceivedData()
|
|||
uint16_t handled_len;
|
||||
// qDebug() << "Received data";
|
||||
do {
|
||||
// qDebug() << "Decoding" << dataBuffer->getReceived() << "Bytes";
|
||||
handled_len = Protocol::DecodeBuffer(dataBuffer->getBuffer(), dataBuffer->getReceived(), &packet);
|
||||
// qDebug() << "Handled" << handled_len << "Bytes, type:" << (int) packet.type;
|
||||
dataBuffer->removeBytes(handled_len);
|
||||
switch(packet.type) {
|
||||
case Protocol::PacketType::VNADatapoint:
|
||||
|
|
@ -502,6 +517,14 @@ void Device::ReceivedData()
|
|||
case Protocol::PacketType::FrequencyCorrection:
|
||||
emit FrequencyCorrectionReceived(packet.frequencyCorrection.ppm);
|
||||
break;
|
||||
case Protocol::PacketType::SetTrigger:
|
||||
qDebug() << "Trigger" << true << "from" << this;
|
||||
emit TriggerReceived(true);
|
||||
break;
|
||||
case Protocol::PacketType::ClearTrigger:
|
||||
qDebug() << "Trigger" << false << "from" << this;
|
||||
emit TriggerReceived(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -557,8 +580,9 @@ bool Device::startNextTransmission()
|
|||
|
||||
void Device::transmissionFinished(TransmissionResult result)
|
||||
{
|
||||
lock_guard<mutex> lock(transmissionMutex);
|
||||
// remove transmitted packet
|
||||
// qDebug() << "Transmission finsished (" << result << "), queue at " << transmissionQueue.size();
|
||||
// qDebug() << "Transmission finsished (" << result << "), queue at " << transmissionQueue.size() << " Outstanding ACKs:"<<outstandingAckCount;
|
||||
if(transmissionQueue.empty()) {
|
||||
qWarning() << "transmissionFinished with empty transmission queue, stray Ack?";
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <set>
|
||||
#include <QQueue>
|
||||
#include <QTimer>
|
||||
#include <mutex>
|
||||
|
||||
Q_DECLARE_METATYPE(Protocol::Datapoint)
|
||||
Q_DECLARE_METATYPE(Protocol::ManualStatusV1)
|
||||
|
|
@ -87,8 +88,11 @@ signals:
|
|||
void ConnectionLost();
|
||||
void AckReceived();
|
||||
void NackReceived();
|
||||
void TriggerReceived(bool set);
|
||||
void LogLineReceived(QString line);
|
||||
void NeedsFirmwareUpdate(int usedProtocol, int requiredProtocol);
|
||||
public slots:
|
||||
void SetTrigger(bool set);
|
||||
private slots:
|
||||
void ReceivedData();
|
||||
void ReceivedLog();
|
||||
|
|
@ -120,6 +124,7 @@ private:
|
|||
std::function<void(TransmissionResult)> callback;
|
||||
};
|
||||
|
||||
std::mutex transmissionMutex;
|
||||
QQueue<Transmission> transmissionQueue;
|
||||
bool startNextTransmission();
|
||||
QTimer transmissionTimer;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "virtualdevice.h"
|
||||
|
||||
#include "preferences.h"
|
||||
#include "CustomWidgets/informationbox.h"
|
||||
#include "../VNA_embedded/Application/Communication/Protocol.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
|
@ -99,130 +100,74 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
static constexpr VirtualDevice::Info defaultInfo = {
|
||||
.ProtocolVersion = Protocol::Version,
|
||||
.FW_major = 0,
|
||||
.FW_minor = 0,
|
||||
.FW_patch = 0,
|
||||
.hardware_version = 1,
|
||||
.HW_Revision = '0',
|
||||
.ports = 2,
|
||||
.supportsVNAmode = true,
|
||||
.supportsSAmode = true,
|
||||
.supportsSGmode = true,
|
||||
.supportsExtRef = true,
|
||||
.Limits = {
|
||||
.minFreq = 0,
|
||||
.maxFreq = 6000000000,
|
||||
.maxFreqHarmonic = 18000000000,
|
||||
.minIFBW = 10,
|
||||
.maxIFBW = 1000000,
|
||||
.maxPoints = 10000,
|
||||
.mindBm = -100,
|
||||
.maxdBm = 100,
|
||||
.minRBW = 1,
|
||||
.maxRBW = 1000000,
|
||||
}
|
||||
};
|
||||
|
||||
static const VirtualDevice::Status defaultStatus = {
|
||||
.statusString = "",
|
||||
.overload = false,
|
||||
.unlocked = false,
|
||||
.unlevel = false,
|
||||
.extRef = false,
|
||||
};
|
||||
|
||||
VirtualDevice::VirtualDevice(QString serial)
|
||||
: QObject(),
|
||||
info{},
|
||||
status{}
|
||||
{
|
||||
cdev = nullptr;
|
||||
isCompound = false;
|
||||
cdev = nullptr;
|
||||
zerospan = false;
|
||||
auto dev = new Device(serial);
|
||||
devices.push_back(dev);
|
||||
|
||||
// Check if this is a compound device
|
||||
auto pref = Preferences::getInstance();
|
||||
for(auto cd : pref.compoundDevices) {
|
||||
if(cd->name == serial) {
|
||||
// connect request to this compound device
|
||||
cdev = cd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isCompoundDevice()) {
|
||||
// just acting as a wrapper for device, pass on signals
|
||||
auto dev = new Device(serial);
|
||||
devices.push_back(dev);
|
||||
connect(dev, &Device::ConnectionLost, this, &VirtualDevice::ConnectionLost);
|
||||
connect(dev, &Device::DeviceInfoUpdated, [&](){
|
||||
auto i = devices[0]->Info();
|
||||
info.ProtocolVersion = i.ProtocolVersion;
|
||||
info.FW_major = i.FW_major;
|
||||
info.FW_minor = i.FW_minor;
|
||||
info.FW_patch = i.FW_patch;
|
||||
info.hardware_version = i.hardware_version;
|
||||
info.HW_Revision = i.HW_Revision;
|
||||
info.ports = 2;
|
||||
info.supportsVNAmode = true;
|
||||
info.supportsSAmode = true;
|
||||
info.supportsSGmode = true;
|
||||
info.supportsExtRef = true;
|
||||
info.Limits.minFreq = i.limits_minFreq;
|
||||
info.Limits.maxFreq = i.limits_maxFreq;
|
||||
info.Limits.maxFreqHarmonic = i.limits_maxFreqHarmonic;
|
||||
info.Limits.minIFBW = i.limits_minIFBW;
|
||||
info.Limits.maxIFBW = i.limits_maxIFBW;
|
||||
info.Limits.maxPoints = i.limits_maxPoints;
|
||||
info.Limits.mindBm = (double) i.limits_cdbm_min / 100;
|
||||
info.Limits.maxdBm = (double) i.limits_cdbm_max / 100;
|
||||
info.Limits.minRBW = i.limits_minRBW;
|
||||
info.Limits.maxRBW = i.limits_minRBW;
|
||||
connect(dev, &Device::DeviceInfoUpdated, [=](){
|
||||
info = Info(devices[0]);
|
||||
emit InfoUpdated();
|
||||
});
|
||||
connect(dev, &Device::LogLineReceived, this, &VirtualDevice::LogLineReceived);
|
||||
connect(dev, &Device::DeviceStatusUpdated, [&](){
|
||||
status.statusString = devices[0]->getLastDeviceInfoString();
|
||||
status.overload = devices[0]->StatusV1().ADC_overload;
|
||||
status.unlevel = devices[0]->StatusV1().unlevel;
|
||||
status.unlocked = !devices[0]->StatusV1().LO1_locked || !devices[0]->StatusV1().source_locked;
|
||||
status.extRef = devices[0]->StatusV1().extRefInUse;
|
||||
connect(dev, &Device::DeviceStatusUpdated, [=](){
|
||||
status = Status(devices[0]);
|
||||
emit StatusUpdated(status);
|
||||
});
|
||||
connect(dev, &Device::NeedsFirmwareUpdate, this, &VirtualDevice::NeedsFirmwareUpdate);
|
||||
|
||||
connect(dev, &Device::SpectrumResultReceived, [&](Protocol::SpectrumAnalyzerResult res){
|
||||
SAMeasurement m;
|
||||
m.pointNum = res.pointNum;
|
||||
if(zerospan) {
|
||||
m.us = res.us;
|
||||
} else {
|
||||
m.frequency = res.frequency;
|
||||
}
|
||||
m.measurements["PORT1"] = res.port1;
|
||||
m.measurements["PORT2"] = res.port2;
|
||||
emit SAmeasurementReceived(m);
|
||||
});
|
||||
connect(dev, &Device::DatapointReceived, [&](Protocol::VNADatapoint<32> *res){
|
||||
VNAMeasurement m;
|
||||
m.pointNum = res->pointNum;
|
||||
m.Z0 = 50.0;
|
||||
if(zerospan) {
|
||||
m.us = res->us;
|
||||
} else {
|
||||
m.frequency = res->frequency;
|
||||
m.dBm = (double) res->cdBm / 100;
|
||||
}
|
||||
for(auto map : portStageMapping) {
|
||||
// map.first is the port (starts at zero)
|
||||
// map.second is the stage at which this port had the stimulus (starts at zero)
|
||||
complex<double> ref = res->getValue(map.second, map.first, true);
|
||||
for(int i=0;i<2;i++) {
|
||||
complex<double> input = res->getValue(map.second, i, false);
|
||||
if(!std::isnan(ref.real()) && !std::isnan(input.real())) {
|
||||
// got both required measurements
|
||||
QString name = "S"+QString::number(i+1)+QString::number(map.first+1);
|
||||
m.measurements[name] = input / ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete res;
|
||||
emit VNAmeasurementReceived(m);
|
||||
});
|
||||
connect(dev, &Device::SpectrumResultReceived, this, &VirtualDevice::singleSpectrumResultReceived);
|
||||
connect(dev, &Device::DatapointReceived, this, &VirtualDevice::singleDatapointReceived);
|
||||
} else {
|
||||
// TODO
|
||||
// Connect to the actual devices
|
||||
for(auto devSerial : cdev->deviceSerials) {
|
||||
auto dev = new Device(devSerial);
|
||||
devices.push_back(dev);
|
||||
// Create device connections
|
||||
connect(dev, &Device::ConnectionLost, this, &VirtualDevice::ConnectionLost);
|
||||
connect(dev, &Device::NeedsFirmwareUpdate, this, &VirtualDevice::NeedsFirmwareUpdate);
|
||||
connect(dev, &Device::LogLineReceived, [=](QString line){
|
||||
emit LogLineReceived(line.prepend(dev->serial()+": "));
|
||||
});
|
||||
connect(dev, &Device::DeviceInfoUpdated, [=](){
|
||||
compoundInfoUpdated(dev);
|
||||
});
|
||||
connect(dev, &Device::DeviceStatusUpdated, [=](){
|
||||
compoundStatusUpdated(dev);
|
||||
});
|
||||
connect(dev, &Device::DatapointReceived, [=](Protocol::VNADatapoint<32> *data){
|
||||
compoundDatapointReceivecd(data, dev);
|
||||
});
|
||||
connect(dev, &Device::SpectrumResultReceived, [=](Protocol::SpectrumAnalyzerResult res) {
|
||||
compoundSpectrumResultReceived(res, dev);
|
||||
});
|
||||
}
|
||||
if(cdev->sync == CompoundDevice::Synchronization::USB) {
|
||||
// create trigger connections for USB synchronization
|
||||
for(int i=0;i<devices.size() - 1;i++) {
|
||||
connect(devices[i], &Device::TriggerReceived, devices[i+1], &Device::SetTrigger, Qt::QueuedConnection);
|
||||
}
|
||||
connect(devices.back(), &Device::TriggerReceived, devices.front(), &Device::SetTrigger, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
}
|
||||
connected = this;
|
||||
}
|
||||
|
|
@ -244,12 +189,12 @@ void VirtualDevice::RegisterTypes()
|
|||
|
||||
bool VirtualDevice::isCompoundDevice() const
|
||||
{
|
||||
return isCompound;
|
||||
return cdev != nullptr;
|
||||
}
|
||||
|
||||
Device *VirtualDevice::getDevice()
|
||||
{
|
||||
if(isCompound || devices.size() < 1) {
|
||||
if(isCompoundDevice() || devices.size() < 1) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return devices[0];
|
||||
|
|
@ -271,12 +216,12 @@ const VirtualDevice::Info &VirtualDevice::getInfo() const
|
|||
return info;
|
||||
}
|
||||
|
||||
const VirtualDevice::Info &VirtualDevice::getInfo(VirtualDevice *vdev)
|
||||
VirtualDevice::Info VirtualDevice::getInfo(VirtualDevice *vdev)
|
||||
{
|
||||
if(vdev) {
|
||||
return vdev->info;
|
||||
} else {
|
||||
return defaultInfo;
|
||||
return Info();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -285,12 +230,12 @@ const VirtualDevice::Status &VirtualDevice::getStatus() const
|
|||
return status;
|
||||
}
|
||||
|
||||
const VirtualDevice::Status &VirtualDevice::getStatus(VirtualDevice *vdev)
|
||||
VirtualDevice::Status VirtualDevice::getStatus(VirtualDevice *vdev)
|
||||
{
|
||||
if(vdev) {
|
||||
return vdev->status;
|
||||
} else {
|
||||
return defaultStatus;
|
||||
return Status();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -316,26 +261,27 @@ bool VirtualDevice::setVNA(const VirtualDevice::VNASettings &s, std::function<vo
|
|||
|
||||
// create port->stage mapping
|
||||
portStageMapping.clear();
|
||||
for(int i=0;i<s.excitedPorts.size();i++) {
|
||||
for(unsigned int i=0;i<s.excitedPorts.size();i++) {
|
||||
portStageMapping[s.excitedPorts[i]] = i;
|
||||
}
|
||||
|
||||
zerospan = (s.freqStart == s.freqStop) && (s.dBmStart == s.dBmStop);
|
||||
auto pref = Preferences::getInstance();
|
||||
Protocol::SweepSettings sd;
|
||||
sd.f_start = s.freqStart;
|
||||
sd.f_stop = s.freqStop;
|
||||
sd.points = s.points;
|
||||
sd.if_bandwidth = s.IFBW;
|
||||
sd.cdbm_excitation_start = s.dBmStart * 100;
|
||||
sd.cdbm_excitation_stop = s.dBmStop * 100;
|
||||
sd.stages = s.excitedPorts.size() - 1;
|
||||
sd.suppressPeaks = pref.Acquisition.suppressPeaks ? 1 : 0;
|
||||
sd.fixedPowerSetting = pref.Acquisition.adjustPowerLevel || s.dBmStart != s.dBmStop ? 0 : 1;
|
||||
sd.logSweep = s.logSweep ? 1 : 0;
|
||||
|
||||
zerospan = (s.freqStart == s.freqStop) && (s.dBmStart == s.dBmStop);
|
||||
if(!isCompoundDevice()) {
|
||||
Protocol::SweepSettings sd;
|
||||
sd.f_start = s.freqStart;
|
||||
sd.f_stop = s.freqStop;
|
||||
sd.points = s.points;
|
||||
sd.if_bandwidth = s.IFBW;
|
||||
sd.cdbm_excitation_start = s.dBmStart * 100;
|
||||
sd.cdbm_excitation_stop = s.dBmStop * 100;
|
||||
sd.stages = s.excitedPorts.size() - 1;
|
||||
sd.port1Stage = find(s.excitedPorts.begin(), s.excitedPorts.end(), 0) - s.excitedPorts.begin();
|
||||
sd.port2Stage = find(s.excitedPorts.begin(), s.excitedPorts.end(), 1) - s.excitedPorts.begin();
|
||||
sd.suppressPeaks = pref.Acquisition.suppressPeaks ? 1 : 0;
|
||||
sd.fixedPowerSetting = pref.Acquisition.adjustPowerLevel || s.dBmStart != s.dBmStop ? 0 : 1;
|
||||
sd.logSweep = s.logSweep ? 1 : 0;
|
||||
sd.syncMode = 0;
|
||||
return devices[0]->Configure(sd, [=](Device::TransmissionResult r){
|
||||
if(cb) {
|
||||
|
|
@ -343,8 +289,31 @@ bool VirtualDevice::setVNA(const VirtualDevice::VNASettings &s, std::function<vo
|
|||
}
|
||||
});
|
||||
} else {
|
||||
// TODO
|
||||
return false;
|
||||
// set the synchronization mode
|
||||
switch(cdev->sync) {
|
||||
case CompoundDevice::Synchronization::USB: sd.syncMode = 1; break;
|
||||
case CompoundDevice::Synchronization::ExtRef: sd.syncMode = 2; break;
|
||||
case CompoundDevice::Synchronization::Trigger: sd.syncMode = 3; break;
|
||||
}
|
||||
// create vector of currently used stimulus ports
|
||||
vector<CompoundDevice::PortMapping> activeMapping;
|
||||
for(auto p : s.excitedPorts) {
|
||||
activeMapping.push_back(cdev->portMapping[p]);
|
||||
}
|
||||
// Configure the devices
|
||||
results.clear();
|
||||
bool success = true;
|
||||
for(unsigned int i=0;i<devices.size();i++) {
|
||||
sd.port1Stage = CompoundDevice::PortMapping::findActiveStage(activeMapping, i, 0);
|
||||
sd.port2Stage = CompoundDevice::PortMapping::findActiveStage(activeMapping, i, 1);
|
||||
success &= devices[i]->Configure(sd, [=](Device::TransmissionResult r){
|
||||
if(cb) {
|
||||
results[devices[i]] = r;
|
||||
checkIfAllTransmissionsComplete(cb);
|
||||
}
|
||||
});
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -353,8 +322,7 @@ QString VirtualDevice::serial()
|
|||
if(!isCompoundDevice()) {
|
||||
return devices[0]->serial();
|
||||
} else {
|
||||
// TODO
|
||||
return "";
|
||||
return cdev->name;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -420,18 +388,30 @@ bool VirtualDevice::setSG(const SGSettings &s)
|
|||
return false;
|
||||
}
|
||||
auto pref = Preferences::getInstance();
|
||||
Protocol::PacketInfo packet;
|
||||
packet.type = Protocol::PacketType::Generator;
|
||||
Protocol::GeneratorSettings &sd = packet.generator;
|
||||
sd.frequency = s.freq;
|
||||
sd.cdbm_level = s.dBm * 100;
|
||||
sd.applyAmplitudeCorrection = 1;
|
||||
|
||||
if(!isCompoundDevice()) {
|
||||
Protocol::PacketInfo packet;
|
||||
packet.type = Protocol::PacketType::Generator;
|
||||
Protocol::GeneratorSettings &sd = packet.generator;
|
||||
sd.frequency = s.freq;
|
||||
sd.cdbm_level = s.dBm * 100;
|
||||
sd.activePort = s.port;
|
||||
sd.applyAmplitudeCorrection = 1;
|
||||
return devices[0]->SendPacket(packet);
|
||||
} else {
|
||||
// TODO
|
||||
return false;
|
||||
// configure all devices
|
||||
bool success = true;
|
||||
for(unsigned int i=0;i<devices.size();i++) {
|
||||
sd.activePort = 0;
|
||||
if(s.port > 0) {
|
||||
if(cdev->portMapping[s.port-1].device == i) {
|
||||
// this device has the active port
|
||||
sd.activePort = cdev->portMapping[s.port-1].port+1;
|
||||
}
|
||||
}
|
||||
success &= devices[i]->SendPacket(packet);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -443,17 +423,7 @@ bool VirtualDevice::setIdle(std::function<void (bool)> cb)
|
|||
success &= dev->SetIdle([=](Device::TransmissionResult r){
|
||||
if(cb) {
|
||||
results[dev] = r;
|
||||
if(results.size() == devices.size()) {
|
||||
// got all responses
|
||||
bool success = true;
|
||||
for(auto res : results) {
|
||||
if(res.second != Device::TransmissionResult::Ack) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cb(success);
|
||||
}
|
||||
checkIfAllTransmissionsComplete(cb);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -523,10 +493,25 @@ bool VirtualDevice::setExtRef(QString option_in, QString option_out)
|
|||
return success;
|
||||
}
|
||||
|
||||
std::set<QString> VirtualDevice::GetDevices()
|
||||
std::set<QString> VirtualDevice::GetAvailableVirtualDevices()
|
||||
{
|
||||
auto pref = Preferences::getInstance();
|
||||
auto ret = Device::GetDevices();
|
||||
// TODO check if compound devices are configured and add them if all sub-devices are available
|
||||
// Add compound devices as well
|
||||
for(auto vdev : pref.compoundDevices) {
|
||||
// check if all serial number required for this compound device are available
|
||||
bool serialMissing = false;
|
||||
for(auto s : vdev->deviceSerials) {
|
||||
if(ret.count(s) == 0) {
|
||||
serialMissing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!serialMissing) {
|
||||
// this compound device is available
|
||||
ret.insert(vdev->name);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -535,6 +520,164 @@ VirtualDevice *VirtualDevice::getConnected()
|
|||
return connected;
|
||||
}
|
||||
|
||||
void VirtualDevice::singleDatapointReceived(Protocol::VNADatapoint<32> *res)
|
||||
{
|
||||
VNAMeasurement m;
|
||||
m.pointNum = res->pointNum;
|
||||
m.Z0 = 50.0;
|
||||
if(zerospan) {
|
||||
m.us = res->us;
|
||||
} else {
|
||||
m.frequency = res->frequency;
|
||||
m.dBm = (double) res->cdBm / 100;
|
||||
}
|
||||
for(auto map : portStageMapping) {
|
||||
// map.first is the port (starts at zero)
|
||||
// map.second is the stage at which this port had the stimulus (starts at zero)
|
||||
complex<double> ref = res->getValue(map.second, map.first, true);
|
||||
for(int i=0;i<2;i++) {
|
||||
complex<double> input = res->getValue(map.second, i, false);
|
||||
if(!std::isnan(ref.real()) && !std::isnan(input.real())) {
|
||||
// got both required measurements
|
||||
QString name = "S"+QString::number(i+1)+QString::number(map.first+1);
|
||||
m.measurements[name] = input / ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete res;
|
||||
emit VNAmeasurementReceived(m);
|
||||
}
|
||||
|
||||
void VirtualDevice::compoundDatapointReceivecd(Protocol::VNADatapoint<32> *data, Device *dev)
|
||||
{
|
||||
if(!compoundVNABuffer.count(data->pointNum)) {
|
||||
compoundVNABuffer[data->pointNum] = std::map<Device*, Protocol::VNADatapoint<32>*>();
|
||||
}
|
||||
auto &buf = compoundVNABuffer[data->pointNum];
|
||||
buf[dev] = data;
|
||||
if(buf.size() == devices.size()) {
|
||||
// Got datapoints from all devices, can create merged VNA result
|
||||
VNAMeasurement m;
|
||||
m.pointNum = data->pointNum;
|
||||
m.Z0 = 50.0;
|
||||
if(zerospan) {
|
||||
m.us = data->us;
|
||||
} else {
|
||||
m.frequency = data->frequency;
|
||||
m.dBm = (double) data->cdBm / 100;
|
||||
}
|
||||
// assemble data
|
||||
for(auto map : portStageMapping) {
|
||||
// map.first is the port (starts at zero)
|
||||
// map.second is the stage at which this port had the stimulus (starts at zero)
|
||||
|
||||
// figure out which device had the stimulus for the port...
|
||||
auto stimulusDev = devices[cdev->portMapping[map.first].device];
|
||||
// ...and which device port was used for the stimulus...
|
||||
auto stimulusDevPort = cdev->portMapping[map.first].port;
|
||||
// ...grab the reference receiver data
|
||||
complex<double> ref = buf[stimulusDev]->getValue(map.second, stimulusDevPort, true);
|
||||
|
||||
// for all ports of the compound device...
|
||||
for(unsigned int i=0;i<cdev->portMapping.size();i++) {
|
||||
// ...figure out which physical device and port was used for this input...
|
||||
auto inputDevice = devices[cdev->portMapping[i].device];
|
||||
// ...and grab the data
|
||||
auto inputPort = cdev->portMapping[i].port;
|
||||
complex<double> input = buf[inputDevice]->getValue(map.second, inputPort, false);
|
||||
if(!std::isnan(ref.real()) && !std::isnan(input.real())) {
|
||||
// got both required measurements
|
||||
QString name = "S"+QString::number(i+1)+QString::number(map.first+1);
|
||||
m.measurements[name] = input / ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit VNAmeasurementReceived(m);
|
||||
|
||||
// Clear this and all incomplete older datapoint buffers
|
||||
for(auto p : compoundVNABuffer) {
|
||||
for(auto d : p.second) {
|
||||
delete d.second;
|
||||
}
|
||||
}
|
||||
compoundVNABuffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualDevice::singleSpectrumResultReceived(Protocol::SpectrumAnalyzerResult res)
|
||||
{
|
||||
SAMeasurement m;
|
||||
m.pointNum = res.pointNum;
|
||||
if(zerospan) {
|
||||
m.us = res.us;
|
||||
} else {
|
||||
m.frequency = res.frequency;
|
||||
}
|
||||
m.measurements["PORT1"] = res.port1;
|
||||
m.measurements["PORT2"] = res.port2;
|
||||
emit SAmeasurementReceived(m);
|
||||
}
|
||||
|
||||
void VirtualDevice::compoundSpectrumResultReceived(Protocol::SpectrumAnalyzerResult res, Device *dev)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void VirtualDevice::compoundInfoUpdated(Device *dev)
|
||||
{
|
||||
compoundInfoBuffer[dev] = dev->Info();
|
||||
if(compoundInfoBuffer.size() == devices.size()) {
|
||||
// got information of all devices
|
||||
info = Info(devices[0]);
|
||||
for(int i=1;i<devices.size();i++) {
|
||||
try {
|
||||
info.subset(Info(devices[i]));
|
||||
} catch (exception &e) {
|
||||
InformationBox::ShowError("Failed to get device information", e.what());
|
||||
emit ConnectionLost();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(cdev->sync == CompoundDevice::Synchronization::ExtRef) {
|
||||
// can't use the external reference if it is used for synchronization
|
||||
info.supportsExtRef = false;
|
||||
}
|
||||
info.ports = cdev->portMapping.size();
|
||||
emit InfoUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualDevice::compoundStatusUpdated(Device *dev)
|
||||
{
|
||||
compoundStatusBuffer[dev] = dev->StatusV1();
|
||||
if(compoundStatusBuffer.size() == devices.size()) {
|
||||
// got status of all devices
|
||||
status = Status(devices[0]);
|
||||
for(int i=1;i<devices.size();i++) {
|
||||
status.merge(Status(devices[i]));
|
||||
}
|
||||
emit StatusUpdated(status);
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualDevice::checkIfAllTransmissionsComplete(std::function<void (bool)> cb)
|
||||
{
|
||||
if(results.size() == devices.size()) {
|
||||
// got all responses
|
||||
bool success = true;
|
||||
for(auto res : results) {
|
||||
if(res.second != Device::TransmissionResult::Ack) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(cb) {
|
||||
cb(success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Sparam VirtualDevice::VNAMeasurement::toSparam(int port1, int port2)
|
||||
{
|
||||
Sparam S;
|
||||
|
|
@ -579,3 +722,109 @@ VirtualDevice::VNAMeasurement VirtualDevice::VNAMeasurement::interpolateTo(const
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
VirtualDevice::Info::Info()
|
||||
{
|
||||
ProtocolVersion = Protocol::Version;
|
||||
FW_major = 0;
|
||||
FW_minor = 0;
|
||||
FW_patch = 0;
|
||||
hardware_version = 1;
|
||||
HW_Revision = '0';
|
||||
ports = 2;
|
||||
supportsVNAmode = true;
|
||||
supportsSAmode = true;
|
||||
supportsSGmode = true;
|
||||
supportsExtRef = true;
|
||||
Limits = {
|
||||
.minFreq = 0,
|
||||
.maxFreq = 6000000000,
|
||||
.maxFreqHarmonic = 18000000000,
|
||||
.minIFBW = 10,
|
||||
.maxIFBW = 1000000,
|
||||
.maxPoints = 10000,
|
||||
.mindBm = -100,
|
||||
.maxdBm = 100,
|
||||
.minRBW = 1,
|
||||
.maxRBW = 1000000,
|
||||
};
|
||||
}
|
||||
|
||||
VirtualDevice::Info::Info(Device *dev)
|
||||
{
|
||||
auto info = dev->Info();
|
||||
ProtocolVersion = info.ProtocolVersion;
|
||||
FW_major = info.FW_major;
|
||||
FW_minor = info.FW_minor;
|
||||
FW_patch = info.FW_patch;
|
||||
hardware_version = info.hardware_version;
|
||||
HW_Revision = info.HW_Revision;
|
||||
ports = 2;
|
||||
supportsVNAmode = true;
|
||||
supportsSAmode = true;
|
||||
supportsSGmode = true;
|
||||
supportsExtRef = true;
|
||||
Limits.minFreq = info.limits_minFreq;
|
||||
Limits.maxFreq = info.limits_maxFreq;
|
||||
Limits.maxFreqHarmonic = info.limits_maxFreqHarmonic;
|
||||
Limits.minIFBW = info.limits_minIFBW;
|
||||
Limits.maxIFBW = info.limits_maxIFBW;
|
||||
Limits.maxPoints = info.limits_maxPoints;
|
||||
Limits.mindBm = (double) info.limits_cdbm_min / 100;
|
||||
Limits.maxdBm = (double) info.limits_cdbm_max / 100;
|
||||
Limits.minRBW = info.limits_minRBW;
|
||||
Limits.maxRBW = info.limits_minRBW;
|
||||
}
|
||||
|
||||
void VirtualDevice::Info::subset(const VirtualDevice::Info &merge)
|
||||
{
|
||||
if((merge.ProtocolVersion != ProtocolVersion)
|
||||
|| (merge.FW_major != FW_major)
|
||||
|| (merge.FW_minor != FW_minor)
|
||||
|| (merge.FW_patch != FW_patch)) {
|
||||
throw runtime_error("Incompatible device, unable to create compound device. All devices must run the same firmware version.");
|
||||
}
|
||||
ports += merge.ports;
|
||||
supportsVNAmode &= merge.supportsVNAmode;
|
||||
supportsSGmode &= merge.supportsSGmode;
|
||||
supportsSAmode &= merge.supportsSAmode;
|
||||
supportsExtRef &= merge.supportsExtRef;
|
||||
Limits.minFreq = max(Limits.minFreq, merge.Limits.minFreq);
|
||||
Limits.maxFreq = min(Limits.maxFreq, merge.Limits.maxFreq);
|
||||
Limits.maxFreqHarmonic = min(Limits.maxFreqHarmonic, merge.Limits.maxFreqHarmonic);
|
||||
Limits.minIFBW = max(Limits.minIFBW, merge.Limits.minIFBW);
|
||||
Limits.maxIFBW = min(Limits.maxIFBW, merge.Limits.maxIFBW);
|
||||
Limits.maxPoints = min(Limits.maxPoints, merge.Limits.maxPoints);
|
||||
Limits.mindBm = max(Limits.mindBm, merge.Limits.mindBm);
|
||||
Limits.maxdBm = min(Limits.maxdBm, merge.Limits.maxdBm);
|
||||
Limits.minRBW = max(Limits.minRBW, merge.Limits.minRBW);
|
||||
Limits.maxRBW = min(Limits.maxRBW, merge.Limits.maxRBW);
|
||||
}
|
||||
|
||||
VirtualDevice::Status::Status()
|
||||
{
|
||||
statusString = "";
|
||||
overload = false;
|
||||
unlocked = false;
|
||||
unlevel = false;
|
||||
extRef = false;
|
||||
}
|
||||
|
||||
VirtualDevice::Status::Status(Device *dev)
|
||||
{
|
||||
auto status = dev->StatusV1();
|
||||
statusString = dev->getLastDeviceInfoString();
|
||||
overload = status.ADC_overload;
|
||||
unlevel = status.unlevel;
|
||||
unlocked = !status.LO1_locked || !status.source_locked;
|
||||
extRef = status.extRefInUse;
|
||||
}
|
||||
|
||||
void VirtualDevice::Status::merge(const VirtualDevice::Status &merge)
|
||||
{
|
||||
statusString += " / "+merge.statusString;
|
||||
overload |= merge.overload;
|
||||
unlevel |= merge.unlevel;
|
||||
unlocked |= merge.unlocked;
|
||||
extRef &= merge.extRef;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ public:
|
|||
|
||||
class Info {
|
||||
public:
|
||||
Info();
|
||||
Info(Device *dev);
|
||||
|
||||
void subset(const Info &merge);
|
||||
|
||||
uint16_t ProtocolVersion;
|
||||
uint8_t FW_major;
|
||||
uint8_t FW_minor;
|
||||
|
|
@ -42,6 +47,11 @@ public:
|
|||
|
||||
class Status {
|
||||
public:
|
||||
Status();
|
||||
Status(Device *dev);
|
||||
|
||||
void merge(const Status &merge);
|
||||
|
||||
QString statusString;
|
||||
bool overload;
|
||||
bool unlocked;
|
||||
|
|
@ -56,9 +66,9 @@ public:
|
|||
CompoundDevice *getCompoundDevice();
|
||||
std::vector<Device*> getDevices();
|
||||
const Info& getInfo() const;
|
||||
static const VirtualDevice::Info &getInfo(VirtualDevice *vdev);
|
||||
static VirtualDevice::Info getInfo(VirtualDevice *vdev);
|
||||
const Status &getStatus() const;
|
||||
static const VirtualDevice::Status &getStatus(VirtualDevice *vdev);
|
||||
static VirtualDevice::Status getStatus(VirtualDevice *vdev);
|
||||
|
||||
class VNASettings {
|
||||
public:
|
||||
|
|
@ -148,7 +158,7 @@ public:
|
|||
public:
|
||||
double freq;
|
||||
double dBm;
|
||||
int port;
|
||||
int port; // starts at one, set to zero to disable all ports
|
||||
};
|
||||
|
||||
QStringList availableSGPorts();
|
||||
|
|
@ -161,7 +171,7 @@ public:
|
|||
|
||||
bool setExtRef(QString option_in, QString option_out);
|
||||
|
||||
static std::set<QString> GetDevices();
|
||||
static std::set<QString> GetAvailableVirtualDevices();
|
||||
static VirtualDevice* getConnected();
|
||||
|
||||
signals:
|
||||
|
|
@ -172,10 +182,19 @@ signals:
|
|||
void StatusUpdated(Status status);
|
||||
void LogLineReceived(QString line);
|
||||
void NeedsFirmwareUpdate(int usedProtocol, int requiredProtocol);
|
||||
|
||||
private slots:
|
||||
void singleDatapointReceived(Protocol::VNADatapoint<32> *res);
|
||||
void compoundDatapointReceivecd(Protocol::VNADatapoint<32> *data, Device *dev);
|
||||
void singleSpectrumResultReceived(Protocol::SpectrumAnalyzerResult res);
|
||||
void compoundSpectrumResultReceived(Protocol::SpectrumAnalyzerResult res, Device *dev);
|
||||
void compoundInfoUpdated(Device *dev);
|
||||
void compoundStatusUpdated(Device *dev);
|
||||
private:
|
||||
void checkIfAllTransmissionsComplete(std::function<void(bool)> cb = nullptr);
|
||||
|
||||
Info info;
|
||||
Status status;
|
||||
bool isCompound;
|
||||
std::vector<Device*> devices;
|
||||
bool zerospan;
|
||||
|
||||
|
|
@ -183,7 +202,10 @@ private:
|
|||
|
||||
CompoundDevice *cdev;
|
||||
|
||||
std::map<int, std::vector<Protocol::VNADatapoint<32>*>> compoundDataBuffer;
|
||||
std::map<int, std::map<Device*, Protocol::VNADatapoint<32>*>> compoundVNABuffer;
|
||||
std::map<int, std::map<Device*, Protocol::SpectrumAnalyzerResult>> compoundSABuffer;
|
||||
std::map<Device*, Protocol::DeviceInfo> compoundInfoBuffer;
|
||||
std::map<Device*, Protocol::DeviceStatusV1> compoundStatusBuffer;
|
||||
|
||||
std::map<int, int> portStageMapping; // maps from excitedPort (count starts at zero) to stage (count starts at zero)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public:
|
|||
virtual nlohmann::json toJSON() override;
|
||||
virtual void fromJSON(nlohmann::json j) override;
|
||||
|
||||
void setAveragingMode(Averaging::Mode mode) override {Q_UNUSED(mode)};
|
||||
void setAveragingMode(Averaging::Mode mode) override {Q_UNUSED(mode)}
|
||||
|
||||
private slots:
|
||||
void updateDevice();
|
||||
|
|
|
|||
|
|
@ -94,18 +94,10 @@ SignalgeneratorWidget::SignalgeneratorWidget(VirtualDevice *dev, QWidget *parent
|
|||
connect(ui->levelSlider, &QSlider::valueChanged, [=](int value) {
|
||||
setLevel((double) value / 100.0);
|
||||
});
|
||||
connect(ui->EnablePort1, &QCheckBox::toggled, [=](){
|
||||
if(ui->EnablePort1->isChecked() && ui->EnablePort2->isChecked()) {
|
||||
ui->EnablePort2->setCheckState(Qt::CheckState::Unchecked);
|
||||
}
|
||||
emit SettingsChanged();
|
||||
});
|
||||
connect(ui->EnablePort2, &QCheckBox::toggled, [=](){
|
||||
if(ui->EnablePort1->isChecked() && ui->EnablePort2->isChecked()) {
|
||||
ui->EnablePort1->setCheckState(Qt::CheckState::Unchecked);
|
||||
}
|
||||
emit SettingsChanged();
|
||||
});
|
||||
connect(ui->EnablePort1, &QCheckBox::toggled, this, &SignalgeneratorWidget::SettingsChanged);
|
||||
connect(ui->EnablePort2, &QCheckBox::toggled, this, &SignalgeneratorWidget::SettingsChanged);
|
||||
connect(ui->EnablePort3, &QCheckBox::toggled, this, &SignalgeneratorWidget::SettingsChanged);
|
||||
connect(ui->EnablePort4, &QCheckBox::toggled, this, &SignalgeneratorWidget::SettingsChanged);
|
||||
connect(ui->EnabledSweep, &QCheckBox::toggled, [=](bool enabled){
|
||||
ui->current->setEnabled(enabled);
|
||||
if(enabled) {
|
||||
|
|
@ -152,6 +144,10 @@ VirtualDevice::SGSettings SignalgeneratorWidget::getDeviceStatus()
|
|||
s.port = 1;
|
||||
} else if(ui->EnablePort2->isChecked()) {
|
||||
s.port = 2;
|
||||
} else if(ui->EnablePort3->isChecked()) {
|
||||
s.port = 3;
|
||||
} else if(ui->EnablePort4->isChecked()) {
|
||||
s.port = 4;
|
||||
} else {
|
||||
s.port = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,6 +142,9 @@
|
|||
<property name="text">
|
||||
<string>Port 1</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
|
@ -149,6 +152,29 @@
|
|||
<property name="text">
|
||||
<string>Port 2</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="EnablePort3">
|
||||
<property name="text">
|
||||
<string>Port 3</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="EnablePort4">
|
||||
<property name="text">
|
||||
<string>Port 4</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
@ -277,4 +303,7 @@
|
|||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<buttongroups>
|
||||
<buttongroup name="buttonGroup"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ void AppWindow::SetupSCPI()
|
|||
}));
|
||||
scpi_dev->add(new SCPICommand("LIST", nullptr, [=](QStringList) -> QString {
|
||||
QString ret;
|
||||
for(auto d : Device::GetDevices()) {
|
||||
for(auto d : VirtualDevice::GetAvailableVirtualDevices()) {
|
||||
ret += d + ",";
|
||||
}
|
||||
// remove last comma
|
||||
|
|
@ -854,7 +854,7 @@ int AppWindow::UpdateDeviceList()
|
|||
{
|
||||
deviceActionGroup->setExclusive(true);
|
||||
ui->menuConnect_to->clear();
|
||||
auto devices = Device::GetDevices();
|
||||
auto devices = VirtualDevice::GetAvailableVirtualDevices();
|
||||
if(vdevice) {
|
||||
devices.insert(vdevice->serial());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "Generator.hpp"
|
||||
#include "SpectrumAnalyzer.hpp"
|
||||
#include "HW_HAL.hpp"
|
||||
#include "Trigger.hpp"
|
||||
|
||||
#define LOG_LEVEL LOG_LEVEL_INFO
|
||||
#define LOG_MODULE "App"
|
||||
|
|
@ -37,7 +38,10 @@ static bool sweepActive;
|
|||
|
||||
extern ADC_HandleTypeDef hadc1;
|
||||
|
||||
#define FLAG_USB_PACKET 0x01
|
||||
#define FLAG_USB_PACKET 0x01
|
||||
#define FLAG_TRIGGER_OUT_ISR 0x02
|
||||
|
||||
static bool lastReportedTrigger;
|
||||
|
||||
static void USBPacketReceived(const Protocol::PacketInfo &p) {
|
||||
recv_packet = p;
|
||||
|
|
@ -46,6 +50,12 @@ static void USBPacketReceived(const Protocol::PacketInfo &p) {
|
|||
portYIELD_FROM_ISR(woken);
|
||||
}
|
||||
|
||||
static void TriggerOutISR() {
|
||||
BaseType_t woken = false;
|
||||
xTaskNotifyFromISR(handle, FLAG_TRIGGER_OUT_ISR, eSetBits, &woken);
|
||||
portYIELD_FROM_ISR(woken);
|
||||
}
|
||||
|
||||
inline void App_Init() {
|
||||
STM::Init();
|
||||
Delay::Init();
|
||||
|
|
@ -60,6 +70,7 @@ inline void App_Init() {
|
|||
Log_SetRedirect(usb_log);
|
||||
LOG_INFO("Start");
|
||||
Exti::Init();
|
||||
Trigger::Init(TriggerOutISR);
|
||||
#ifdef HAS_FLASH
|
||||
if(!HWHAL::flash.isPresent()) {
|
||||
LOG_CRIT("Failed to detect onboard FLASH");
|
||||
|
|
@ -247,16 +258,60 @@ inline void App_Process() {
|
|||
HW::setAcquisitionFrequencies(recv_packet.acquisitionFrequencySettings);
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
break;
|
||||
case Protocol::PacketType::SetTrigger:
|
||||
if(Trigger::GetMode() == Trigger::Mode::USB_GUI) {
|
||||
Trigger::SetInput(true);
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
} else {
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Nack);
|
||||
}
|
||||
break;
|
||||
case Protocol::PacketType::ClearTrigger:
|
||||
if(Trigger::GetMode() == Trigger::Mode::USB_GUI) {
|
||||
Trigger::SetInput(false);
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
} else {
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Nack);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// this packet type is not supported
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Nack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(notification & FLAG_TRIGGER_OUT_ISR) {
|
||||
// trigger output (from FPGA) changed level
|
||||
bool set = Trigger::GetOutput();
|
||||
switch(Trigger::GetMode()) {
|
||||
case Trigger::Mode::Off:
|
||||
// nothing to do
|
||||
break;
|
||||
case Trigger::Mode::USB_GUI:
|
||||
lastReportedTrigger = set;
|
||||
Communication::SendWithoutPayload(set ? Protocol::PacketType::SetTrigger : Protocol::PacketType::ClearTrigger);
|
||||
break;
|
||||
case Trigger::Mode::ExtRef:
|
||||
if(set) {
|
||||
HWHAL::Si5351.Enable(HWHAL::SiChannel::ReferenceOut);
|
||||
} else {
|
||||
HWHAL::Si5351.Disable(HWHAL::SiChannel::ReferenceOut);
|
||||
}
|
||||
break;
|
||||
case Trigger::Mode::Trigger:
|
||||
// not supported by the hardware, nothing to do
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(HW::TimedOut()) {
|
||||
vTaskDelay(1000);
|
||||
LOG_WARN("Timed out, FPGA status: 0x%04x", FPGA::GetStatus());
|
||||
vTaskDelay(1000);
|
||||
LOG_WARN("Trigger out: %d (last reported: %d), in: %d", (uint8_t) Trigger::GetOutput(), (uint8_t) lastReportedTrigger, (uint8_t) Trigger::GetInput());
|
||||
HW::SetMode(HW::Mode::Idle);
|
||||
// insert the last received packet (restarts the timed out operation)
|
||||
Communication::BlockNextAck();
|
||||
USBPacketReceived(last_measure_packet);
|
||||
}
|
||||
HW::updateDeviceStatus();
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
static uint8_t inputBuffer[1024];
|
||||
uint16_t inputCnt = 0;
|
||||
static uint8_t outputBuffer[1024];
|
||||
|
||||
static Communication::Callback callback = nullptr;
|
||||
static uint8_t blockAcks = 0;
|
||||
|
||||
void Communication::SetCallback(Callback cb) {
|
||||
callback = cb;
|
||||
|
|
@ -66,7 +66,15 @@ void communication_usb_input(const uint8_t *buf, uint16_t len) {
|
|||
}
|
||||
|
||||
bool Communication::SendWithoutPayload(Protocol::PacketType type) {
|
||||
if(type == Protocol::PacketType::Ack && blockAcks) {
|
||||
blockAcks--;
|
||||
return true;
|
||||
}
|
||||
Protocol::PacketInfo p;
|
||||
p.type = type;
|
||||
return Send(p);
|
||||
}
|
||||
|
||||
void Communication::BlockNextAck() {
|
||||
blockAcks++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ using Callback = void(*)(const Protocol::PacketInfo&);
|
|||
void SetCallback(Callback cb);
|
||||
void Input(const uint8_t *buf, uint16_t len);
|
||||
bool Send(const Protocol::PacketInfo &packet);
|
||||
void BlockNextAck();
|
||||
bool SendWithoutPayload(Protocol::PacketType type);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,6 +117,8 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_
|
|||
case PacketType::RequestFrequencyCorrection:
|
||||
case PacketType::RequestAcquisitionFrequencySettings:
|
||||
case PacketType::RequestDeviceStatus:
|
||||
case PacketType::SetTrigger:
|
||||
case PacketType::ClearTrigger:
|
||||
// no payload
|
||||
break;
|
||||
case PacketType::VNADatapoint: payload_size = packet.VNAdatapoint->requiredBufferSize(); break;
|
||||
|
|
|
|||
|
|
@ -331,6 +331,8 @@ enum class PacketType : uint8_t {
|
|||
DeviceStatusV1 = 25,
|
||||
RequestDeviceStatus = 26,
|
||||
VNADatapoint = 27,
|
||||
SetTrigger = 28,
|
||||
ClearTrigger = 29,
|
||||
};
|
||||
|
||||
using PacketInfo = struct _packetinfo {
|
||||
|
|
|
|||
|
|
@ -325,7 +325,6 @@ bool Si5351C::WriteRegisterRange(Reg start, const uint8_t *data, uint8_t len) {
|
|||
bool Si5351C::ExtCLKAvailable() {
|
||||
uint8_t value;
|
||||
ReadRegister(Reg::DeviceStatus, &value);
|
||||
LOG_DEBUG("Device status: 0x%02x", value);
|
||||
if (value & 0x10) {
|
||||
return false;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "Util.hpp"
|
||||
#include "Trigger.hpp"
|
||||
#include <array>
|
||||
|
||||
#define LOG_LEVEL LOG_LEVEL_DEBUG
|
||||
|
|
@ -229,6 +230,7 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
|
|||
FPGA::Enable(FPGA::Periphery::Amplifier, s.trackingGenerator);
|
||||
FPGA::Enable(FPGA::Periphery::Port1Mixer);
|
||||
FPGA::Enable(FPGA::Periphery::Port2Mixer);
|
||||
Trigger::SetMode((Trigger::Mode) s.syncMode);
|
||||
|
||||
if(s.SignalID) {
|
||||
// use different ADC prescalers depending on RBW: For small RBWs, images with the shifted ADC samplerate can be closer to the IF
|
||||
|
|
@ -431,7 +433,9 @@ void SA::Work() {
|
|||
// more measurements required for signal ID
|
||||
signalIDstep++;
|
||||
}
|
||||
HW::Ref::update();
|
||||
if(Trigger::GetMode() != Trigger::Mode::ExtRef) {
|
||||
HW::Ref::update();
|
||||
}
|
||||
StartNextSample();
|
||||
}
|
||||
|
||||
|
|
|
|||
73
Software/VNA_embedded/Application/Trigger.cpp
Normal file
73
Software/VNA_embedded/Application/Trigger.cpp
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#include "Trigger.hpp"
|
||||
|
||||
#include "Drivers/Exti.hpp"
|
||||
#include "main.h"
|
||||
#include "HW_HAL.hpp"
|
||||
#include "Communication/Protocol.hpp"
|
||||
#include "Hardware.hpp"
|
||||
|
||||
static Trigger::Mode mode;
|
||||
static Trigger::CallbackISR callback = nullptr;
|
||||
|
||||
void Trigger::Init(CallbackISR cb) {
|
||||
mode = Mode::Off;
|
||||
callback = cb;
|
||||
Exti::SetCallback(FPGA_TRIGGER_OUT_GPIO_Port, FPGA_TRIGGER_OUT_Pin, Exti::EdgeType::Both, Exti::Pull::Down, [](void*){
|
||||
STM::DispatchToInterrupt(callback);
|
||||
}, nullptr);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void vApplicationIdleHook() {
|
||||
if(mode == Trigger::Mode::ExtRef) {
|
||||
STM::DispatchToInterrupt([](){
|
||||
Trigger::SetInput(HW::Ref::available());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Trigger::SetMode(Mode m) {
|
||||
if(mode == m) {
|
||||
// already in the correct mdoe
|
||||
return;
|
||||
}
|
||||
if(mode == Mode::ExtRef) {
|
||||
// reset reference to default settings
|
||||
HWHAL::Si5351.Disable(HWHAL::SiChannel::ReferenceOut);
|
||||
}
|
||||
mode = m;
|
||||
if(mode == Mode::ExtRef) {
|
||||
// Disable the external reference
|
||||
Protocol::ReferenceSettings s;
|
||||
s.AutomaticSwitch = 0;
|
||||
s.ExtRefOuputFreq = 0;
|
||||
s.UseExternalRef = 0;
|
||||
HW::Ref::set(s);
|
||||
HW::Ref::update();
|
||||
|
||||
HWHAL::Si5351.SetCLK(HWHAL::SiChannel::ReferenceOut, 10000000, Si5351C::PLL::A);
|
||||
if(GetOutput()) {
|
||||
HWHAL::Si5351.Enable(HWHAL::SiChannel::ReferenceOut);
|
||||
} else {
|
||||
HWHAL::Si5351.Disable(HWHAL::SiChannel::ReferenceOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
Trigger::Mode Trigger::GetMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
void Trigger::SetInput(bool high) {
|
||||
if(high) {
|
||||
FPGA_TRIGGER_IN_GPIO_Port->BSRR = FPGA_TRIGGER_IN_Pin;
|
||||
} else {
|
||||
FPGA_TRIGGER_IN_GPIO_Port->BSRR = FPGA_TRIGGER_IN_Pin << 16;
|
||||
}
|
||||
}
|
||||
bool Trigger::GetOutput() {
|
||||
return FPGA_TRIGGER_OUT_GPIO_Port->IDR & FPGA_TRIGGER_OUT_Pin;
|
||||
}
|
||||
bool Trigger::GetInput() {
|
||||
return FPGA_TRIGGER_IN_GPIO_Port->IDR & FPGA_TRIGGER_IN_Pin;
|
||||
}
|
||||
25
Software/VNA_embedded/Application/Trigger.hpp
Normal file
25
Software/VNA_embedded/Application/Trigger.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Trigger {
|
||||
|
||||
enum class Mode : uint8_t {
|
||||
Off = 0,
|
||||
USB_GUI = 1,
|
||||
ExtRef = 2,
|
||||
Trigger = 3,
|
||||
};
|
||||
|
||||
using CallbackISR = void(*)(void);
|
||||
|
||||
void Init(CallbackISR cb);
|
||||
|
||||
void SetMode(Mode m);
|
||||
Mode GetMode();
|
||||
|
||||
void SetInput(bool high);
|
||||
bool GetOutput();
|
||||
bool GetInput();
|
||||
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include "task.h"
|
||||
#include "Util.hpp"
|
||||
#include "usb.h"
|
||||
#include "Trigger.hpp"
|
||||
#include <cmath>
|
||||
|
||||
#define LOG_LEVEL LOG_LEVEL_INFO
|
||||
|
|
@ -279,6 +280,7 @@ bool VNA::Setup(Protocol::SweepSettings s) {
|
|||
FPGA::Enable(FPGA::Periphery::LO1Chip);
|
||||
FPGA::Enable(FPGA::Periphery::LO1RF);
|
||||
FPGA::SetupSweep(s.stages, s.port1Stage, s.port2Stage, s.syncMode != 0);
|
||||
Trigger::SetMode((Trigger::Mode) s.syncMode);
|
||||
FPGA::Enable(FPGA::Periphery::PortSwitch);
|
||||
pointCnt = 0;
|
||||
stageCnt = 0;
|
||||
|
|
@ -350,7 +352,9 @@ bool VNA::MeasurementDone(const FPGA::SamplingResult &result) {
|
|||
|
||||
void VNA::Work() {
|
||||
// end of sweep
|
||||
HW::Ref::update();
|
||||
if(Trigger::GetMode() != Trigger::Mode::ExtRef) {
|
||||
HW::Ref::update();
|
||||
}
|
||||
// Compile info packet
|
||||
Protocol::PacketInfo packet;
|
||||
packet.type = Protocol::PacketType::DeviceStatusV1;
|
||||
|
|
@ -365,86 +369,87 @@ void VNA::SweepHalted() {
|
|||
if(!active) {
|
||||
return;
|
||||
}
|
||||
LOG_DEBUG("Halted before point %d", pointCnt);
|
||||
// Check if IF table has entry at this point
|
||||
if (IFTableIndexCnt < IFTableNumEntries && IFTable[IFTableIndexCnt].pointCnt == pointCnt) {
|
||||
Si5351.WriteRawCLKConfig(SiChannel::Port1LO2, IFTable[IFTableIndexCnt].clkconfig);
|
||||
Si5351.WriteRawCLKConfig(SiChannel::Port2LO2, IFTable[IFTableIndexCnt].clkconfig);
|
||||
Si5351.WriteRawCLKConfig(SiChannel::RefLO2, IFTable[IFTableIndexCnt].clkconfig);
|
||||
Si5351.ResetPLL(Si5351C::PLL::B);
|
||||
IFTableIndexCnt++;
|
||||
// PLL reset causes the 2.LO to turn off briefly and then ramp on back, needs delay before next point
|
||||
Delay::us(1300);
|
||||
}
|
||||
uint64_t frequency = getPointFrequency(pointCnt);
|
||||
int16_t power = settings.cdbm_excitation_start
|
||||
+ (settings.cdbm_excitation_stop - settings.cdbm_excitation_start)
|
||||
* pointCnt / (settings.points - 1);
|
||||
bool adcShiftRequired = false;
|
||||
if (frequency < HW::BandSwitchFrequency) {
|
||||
auto driveStrength = fixedPowerLowband;
|
||||
if(!settings.fixedPowerSetting) {
|
||||
auto amplitude = HW::GetAmplitudeSettings(power, frequency, true, false);
|
||||
// attenuator value has already been set in sweep setup
|
||||
driveStrength = amplitude.lowBandPower;
|
||||
}
|
||||
|
||||
// need the Si5351 as Source
|
||||
bool freqSuccess = Si5351.SetCLK(SiChannel::LowbandSource, frequency, Si5351C::PLL::B, driveStrength);
|
||||
static bool lowbandDisabled = false;
|
||||
if (pointCnt == 0) {
|
||||
// First point in sweep, switch to correct source
|
||||
FPGA::Disable(FPGA::Periphery::SourceRF);
|
||||
lowbandDisabled = true;
|
||||
}
|
||||
if(lowbandDisabled && freqSuccess) {
|
||||
// frequency is valid, can enable lowband source now
|
||||
Si5351.Enable(SiChannel::LowbandSource);
|
||||
// Resuming the halted sweep requires I2C bus operations to the Si5355. When trigger synchronization is enabled
|
||||
// in the external reference mode, this might collide with the trigger input check. Instead both these actions
|
||||
// are handled through the STM::DispatchToInterrupt functionality, ensuring that they do not interrupt each other
|
||||
STM::DispatchToInterrupt([](){
|
||||
LOG_DEBUG("Halted before point %d", pointCnt);
|
||||
// Check if IF table has entry at this point
|
||||
if (IFTableIndexCnt < IFTableNumEntries && IFTable[IFTableIndexCnt].pointCnt == pointCnt) {
|
||||
Si5351.WriteRawCLKConfig(SiChannel::Port1LO2, IFTable[IFTableIndexCnt].clkconfig);
|
||||
Si5351.WriteRawCLKConfig(SiChannel::Port2LO2, IFTable[IFTableIndexCnt].clkconfig);
|
||||
Si5351.WriteRawCLKConfig(SiChannel::RefLO2, IFTable[IFTableIndexCnt].clkconfig);
|
||||
Si5351.ResetPLL(Si5351C::PLL::B);
|
||||
IFTableIndexCnt++;
|
||||
// PLL reset causes the 2.LO to turn off briefly and then ramp on back, needs delay before next point
|
||||
Delay::us(1300);
|
||||
lowbandDisabled = false;
|
||||
}
|
||||
|
||||
// At low frequencies the 1.LO feedthrough mixes with the 2.LO in the second mixer.
|
||||
// Depending on the stimulus frequency, the resulting mixing product might alias to the 2.IF
|
||||
// in the ADC which causes a spike. Check for this and shift the ADC sampling frequency if necessary
|
||||
|
||||
uint32_t LO_mixing = (HW::getIF1() + frequency) - (HW::getIF1() - HW::getIF2());
|
||||
if(abs(Util::Alias(LO_mixing, HW::getADCRate()) - HW::getIF2()) <= actualBandwidth * 2) {
|
||||
// the image is in or near the IF bandwidth and would cause a peak
|
||||
// Use a slightly different ADC sample rate if possible
|
||||
if(HW::getIF2() == HW::DefaultIF2) {
|
||||
adcShiftRequired = true;
|
||||
uint64_t frequency = getPointFrequency(pointCnt);
|
||||
int16_t power = settings.cdbm_excitation_start
|
||||
+ (settings.cdbm_excitation_stop - settings.cdbm_excitation_start)
|
||||
* pointCnt / (settings.points - 1);
|
||||
bool adcShiftRequired = false;
|
||||
if (frequency < HW::BandSwitchFrequency) {
|
||||
auto driveStrength = fixedPowerLowband;
|
||||
if(!settings.fixedPowerSetting) {
|
||||
auto amplitude = HW::GetAmplitudeSettings(power, frequency, true, false);
|
||||
// attenuator value has already been set in sweep setup
|
||||
driveStrength = amplitude.lowBandPower;
|
||||
}
|
||||
|
||||
// need the Si5351 as Source
|
||||
bool freqSuccess = Si5351.SetCLK(SiChannel::LowbandSource, frequency, Si5351C::PLL::B, driveStrength);
|
||||
static bool lowbandDisabled = false;
|
||||
if (pointCnt == 0) {
|
||||
// First point in sweep, switch to correct source
|
||||
FPGA::Disable(FPGA::Periphery::SourceRF);
|
||||
lowbandDisabled = true;
|
||||
}
|
||||
if(lowbandDisabled && freqSuccess) {
|
||||
// frequency is valid, can enable lowband source now
|
||||
Si5351.Enable(SiChannel::LowbandSource);
|
||||
Delay::us(1300);
|
||||
lowbandDisabled = false;
|
||||
}
|
||||
|
||||
// At low frequencies the 1.LO feedthrough mixes with the 2.LO in the second mixer.
|
||||
// Depending on the stimulus frequency, the resulting mixing product might alias to the 2.IF
|
||||
// in the ADC which causes a spike. Check for this and shift the ADC sampling frequency if necessary
|
||||
|
||||
uint32_t LO_mixing = (HW::getIF1() + frequency) - (HW::getIF1() - HW::getIF2());
|
||||
if(abs(Util::Alias(LO_mixing, HW::getADCRate()) - HW::getIF2()) <= actualBandwidth * 2) {
|
||||
// the image is in or near the IF bandwidth and would cause a peak
|
||||
// Use a slightly different ADC sample rate if possible
|
||||
if(HW::getIF2() == HW::DefaultIF2) {
|
||||
adcShiftRequired = true;
|
||||
}
|
||||
}
|
||||
} else if(!FPGA::IsEnabled(FPGA::Periphery::SourceRF)){
|
||||
// first sweep point in highband is also halted, disable lowband source
|
||||
Si5351.Disable(SiChannel::LowbandSource);
|
||||
FPGA::Enable(FPGA::Periphery::SourceRF);
|
||||
}
|
||||
} else if(!FPGA::IsEnabled(FPGA::Periphery::SourceRF)){
|
||||
// first sweep point in highband is also halted, disable lowband source
|
||||
Si5351.Disable(SiChannel::LowbandSource);
|
||||
FPGA::Enable(FPGA::Periphery::SourceRF);
|
||||
}
|
||||
|
||||
if (pointCnt == 0) {
|
||||
HAL_Delay(2);
|
||||
}
|
||||
if (pointCnt == 0) {
|
||||
HAL_Delay(2);
|
||||
}
|
||||
|
||||
if(adcShiftRequired) {
|
||||
FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, alternativePrescaler);
|
||||
FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, alternativePhaseInc);
|
||||
adcShifted = true;
|
||||
} else if(adcShifted) {
|
||||
// reset to default value
|
||||
FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, HW::getADCPrescaler());
|
||||
FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, HW::getDFTPhaseInc());
|
||||
adcShifted = false;
|
||||
}
|
||||
if(adcShiftRequired) {
|
||||
FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, alternativePrescaler);
|
||||
FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, alternativePhaseInc);
|
||||
adcShifted = true;
|
||||
} else if(adcShifted) {
|
||||
// reset to default value
|
||||
FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, HW::getADCPrescaler());
|
||||
FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, HW::getDFTPhaseInc());
|
||||
adcShifted = false;
|
||||
}
|
||||
|
||||
if(usb_available_buffer() >= reservedUSBbuffer) {
|
||||
// enough space available, can resume immediately
|
||||
FPGA::ResumeHaltedSweep();
|
||||
} else {
|
||||
// USB buffer could potentially overflow before next halted point, wait until more space is available.
|
||||
// This function is called from a low level interrupt, need to dispatch to lower priority to allow USB
|
||||
// handling to continue
|
||||
STM::DispatchToInterrupt([](){
|
||||
if(usb_available_buffer() >= reservedUSBbuffer) {
|
||||
// enough space available, can resume immediately
|
||||
FPGA::ResumeHaltedSweep();
|
||||
} else {
|
||||
// USB buffer could potentially overflow before next halted point, wait until more space is available.
|
||||
uint32_t start = HAL_GetTick();
|
||||
while(usb_available_buffer() < reservedUSBbuffer) {
|
||||
if(HAL_GetTick() - start > 100) {
|
||||
|
|
@ -457,8 +462,8 @@ void VNA::SweepHalted() {
|
|||
}
|
||||
}
|
||||
FPGA::ResumeHaltedSweep();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void VNA::Stop() {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
#define configUSE_PREEMPTION 1
|
||||
#define configSUPPORT_STATIC_ALLOCATION 1
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 0
|
||||
#define configUSE_IDLE_HOOK 0
|
||||
#define configUSE_IDLE_HOOK 1
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configCPU_CLOCK_HZ ( SystemCoreClock )
|
||||
#define configTICK_RATE_HZ ((TickType_t)1000)
|
||||
|
|
|
|||
|
|
@ -89,6 +89,10 @@ void Error_Handler(void);
|
|||
#define FPGA_PROGRAM_B_GPIO_Port GPIOB
|
||||
#define EN_6V_Pin GPIO_PIN_12
|
||||
#define EN_6V_GPIO_Port GPIOB
|
||||
#define FPGA_TRIGGER_OUT_Pin GPIO_PIN_11
|
||||
#define FPGA_TRIGGER_OUT_GPIO_Port GPIOC
|
||||
#define FPGA_TRIGGER_IN_Pin GPIO_PIN_3
|
||||
#define FPGA_TRIGGER_IN_GPIO_Port GPIOB
|
||||
#define FPGA_RESET_Pin GPIO_PIN_5
|
||||
#define FPGA_RESET_GPIO_Port GPIOB
|
||||
#define FPGA_DONE_Pin GPIO_PIN_9
|
||||
|
|
|
|||
|
|
@ -55,6 +55,24 @@
|
|||
/* GetIdleTaskMemory prototype (linked to static allocation support) */
|
||||
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );
|
||||
|
||||
/* Hook prototypes */
|
||||
void vApplicationIdleHook(void);
|
||||
|
||||
/* USER CODE BEGIN 2 */
|
||||
__weak void vApplicationIdleHook( void )
|
||||
{
|
||||
/* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
|
||||
to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle
|
||||
task. It is essential that code added to this hook function never attempts
|
||||
to block in any way (for example, call xQueueReceive() with a block time
|
||||
specified, or call vTaskDelay()). If the application makes use of the
|
||||
vTaskDelete() API function (as this demo application does) then it is also
|
||||
important that vApplicationIdleHook() is permitted to return to its calling
|
||||
function, because it is the responsibility of the idle task to clean up
|
||||
memory allocated by the kernel to any task that has since been deleted. */
|
||||
}
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
|
||||
static StaticTask_t xIdleTaskTCBBuffer;
|
||||
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];
|
||||
|
|
|
|||
|
|
@ -724,7 +724,7 @@ static void MX_GPIO_Init(void)
|
|||
HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(GPIOB, FPGA_PROGRAM_B_Pin|EN_6V_Pin|FPGA_RESET_Pin, GPIO_PIN_RESET);
|
||||
HAL_GPIO_WritePin(GPIOB, FPGA_PROGRAM_B_Pin|EN_6V_Pin|FPGA_TRIGGER_IN_Pin|FPGA_RESET_Pin, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pin : FPGA_INIT_B_Pin */
|
||||
GPIO_InitStruct.Pin = FPGA_INIT_B_Pin;
|
||||
|
|
@ -752,13 +752,19 @@ static void MX_GPIO_Init(void)
|
|||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(FPGA_INTR_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pins : FPGA_PROGRAM_B_Pin EN_6V_Pin FPGA_RESET_Pin */
|
||||
GPIO_InitStruct.Pin = FPGA_PROGRAM_B_Pin|EN_6V_Pin|FPGA_RESET_Pin;
|
||||
/*Configure GPIO pins : FPGA_PROGRAM_B_Pin EN_6V_Pin FPGA_TRIGGER_IN_Pin FPGA_RESET_Pin */
|
||||
GPIO_InitStruct.Pin = FPGA_PROGRAM_B_Pin|EN_6V_Pin|FPGA_TRIGGER_IN_Pin|FPGA_RESET_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : FPGA_TRIGGER_OUT_Pin */
|
||||
GPIO_InitStruct.Pin = FPGA_TRIGGER_OUT_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
|
||||
HAL_GPIO_Init(FPGA_TRIGGER_OUT_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : FPGA_DONE_Pin */
|
||||
GPIO_InitStruct.Pin = FPGA_DONE_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
|
|
|
|||
|
|
@ -86,14 +86,16 @@ FREERTOS.INCLUDE_vTaskDelete=0
|
|||
FREERTOS.INCLUDE_vTaskPrioritySet=0
|
||||
FREERTOS.INCLUDE_vTaskSuspend=1
|
||||
FREERTOS.INCLUDE_xTaskResumeFromISR=0
|
||||
FREERTOS.IPParameters=Tasks01,INCLUDE_vTaskDelete,INCLUDE_vTaskPrioritySet,INCLUDE_uxTaskPriorityGet,INCLUDE_xTaskResumeFromISR,INCLUDE_vTaskSuspend,MEMORY_ALLOCATION,configTOTAL_HEAP_SIZE,configENABLE_BACKWARD_COMPATIBILITY,configUSE_MUTEXES,FootprintOK,configUSE_NEWLIB_REENTRANT
|
||||
FREERTOS.IPParameters=Tasks01,INCLUDE_vTaskDelete,INCLUDE_vTaskPrioritySet,INCLUDE_uxTaskPriorityGet,INCLUDE_xTaskResumeFromISR,INCLUDE_vTaskSuspend,MEMORY_ALLOCATION,configTOTAL_HEAP_SIZE,configENABLE_BACKWARD_COMPATIBILITY,configUSE_MUTEXES,FootprintOK,configUSE_NEWLIB_REENTRANT,configUSE_IDLE_HOOK
|
||||
FREERTOS.MEMORY_ALLOCATION=1
|
||||
FREERTOS.Tasks01=defaultTask,0,1024,StartDefaultTask,Default,NULL,Static,defaultTaskBuffer,defaultTaskControlBlock
|
||||
FREERTOS.configENABLE_BACKWARD_COMPATIBILITY=1
|
||||
FREERTOS.configTOTAL_HEAP_SIZE=2048
|
||||
FREERTOS.configUSE_IDLE_HOOK=1
|
||||
FREERTOS.configUSE_MUTEXES=1
|
||||
FREERTOS.configUSE_NEWLIB_REENTRANT=1
|
||||
File.Version=6
|
||||
GPIO.groupedBy=Group By Peripherals
|
||||
I2C2.I2C_Speed_Mode=I2C_Fast
|
||||
I2C2.IPParameters=Timing,I2C_Speed_Mode
|
||||
I2C2.Timing=0x00F07BFF
|
||||
|
|
@ -134,24 +136,26 @@ Mcu.Pin21=PA13
|
|||
Mcu.Pin22=PA14
|
||||
Mcu.Pin23=PA15
|
||||
Mcu.Pin24=PC10
|
||||
Mcu.Pin25=PB4
|
||||
Mcu.Pin26=PB5
|
||||
Mcu.Pin27=PB6
|
||||
Mcu.Pin28=PB9
|
||||
Mcu.Pin29=VP_ADC1_TempSens_Input
|
||||
Mcu.Pin25=PC11
|
||||
Mcu.Pin26=PB3
|
||||
Mcu.Pin27=PB4
|
||||
Mcu.Pin28=PB5
|
||||
Mcu.Pin29=PB6
|
||||
Mcu.Pin3=PA3
|
||||
Mcu.Pin30=VP_FREERTOS_VS_CMSIS_V1
|
||||
Mcu.Pin31=VP_SYS_VS_tim17
|
||||
Mcu.Pin32=VP_SYS_VS_DBSignals
|
||||
Mcu.Pin33=VP_TIM1_VS_ClockSourceINT
|
||||
Mcu.Pin34=VP_TIM2_VS_ClockSourceINT
|
||||
Mcu.Pin30=PB9
|
||||
Mcu.Pin31=VP_ADC1_TempSens_Input
|
||||
Mcu.Pin32=VP_FREERTOS_VS_CMSIS_V1
|
||||
Mcu.Pin33=VP_SYS_VS_tim17
|
||||
Mcu.Pin34=VP_SYS_VS_DBSignals
|
||||
Mcu.Pin35=VP_TIM1_VS_ClockSourceINT
|
||||
Mcu.Pin36=VP_TIM2_VS_ClockSourceINT
|
||||
Mcu.Pin4=PA4
|
||||
Mcu.Pin5=PA5
|
||||
Mcu.Pin6=PA6
|
||||
Mcu.Pin7=PA7
|
||||
Mcu.Pin8=PC4
|
||||
Mcu.Pin9=PB0
|
||||
Mcu.PinsNb=35
|
||||
Mcu.PinsNb=37
|
||||
Mcu.ThirdPartyNb=0
|
||||
Mcu.UserConstants=
|
||||
Mcu.UserName=STM32G431CBUx
|
||||
|
|
@ -270,6 +274,10 @@ PB2.GPIOParameters=GPIO_Label
|
|||
PB2.GPIO_Label=FPGA_PROGRAM_B
|
||||
PB2.Locked=true
|
||||
PB2.Signal=GPIO_Output
|
||||
PB3.GPIOParameters=GPIO_Label
|
||||
PB3.GPIO_Label=FPGA_TRIGGER_IN
|
||||
PB3.Locked=true
|
||||
PB3.Signal=GPIO_Output
|
||||
PB4.Locked=true
|
||||
PB4.Mode=Sink_AllSignals
|
||||
PB4.Signal=UCPD1_CC2
|
||||
|
|
@ -287,6 +295,11 @@ PB9.Signal=GPIO_Input
|
|||
PC10.Locked=true
|
||||
PC10.Mode=Asynchronous
|
||||
PC10.Signal=USART3_TX
|
||||
PC11.GPIOParameters=GPIO_PuPd,GPIO_Label
|
||||
PC11.GPIO_Label=FPGA_TRIGGER_OUT
|
||||
PC11.GPIO_PuPd=GPIO_PULLDOWN
|
||||
PC11.Locked=true
|
||||
PC11.Signal=GPIO_Input
|
||||
PC4.GPIOParameters=GPIO_Pu
|
||||
PC4.GPIO_Pu=GPIO_PULLUP
|
||||
PC4.Locked=true
|
||||
|
|
@ -311,7 +324,7 @@ ProjectManager.FreePins=false
|
|||
ProjectManager.HalAssertFull=false
|
||||
ProjectManager.HeapSize=0x200
|
||||
ProjectManager.KeepUserCode=true
|
||||
ProjectManager.LastFirmware=true
|
||||
ProjectManager.LastFirmware=false
|
||||
ProjectManager.LibraryCopy=1
|
||||
ProjectManager.MainLocation=Src
|
||||
ProjectManager.NoMain=false
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue