mirror of
https://github.com/jankae/LibreVNA.git
synced 2026-03-09 14:53:49 +01:00
Experimental direct register access
This commit is contained in:
parent
95a715233e
commit
9f33d47da0
81
Software/PC_Application/Device/RegisterAccess/max2871.cpp
Normal file
81
Software/PC_Application/Device/RegisterAccess/max2871.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#include "max2871.h"
|
||||
#include "ui_max2871widget.h"
|
||||
#include "register.h"
|
||||
|
||||
MAX2871::MAX2871()
|
||||
{
|
||||
addRegister(new Register("Register 0", 0, 32));
|
||||
addRegister(new Register("Register 1", 1, 32));
|
||||
addRegister(new Register("Register 2", 2, 32));
|
||||
addRegister(new Register("Register 3", 3, 32));
|
||||
addRegister(new Register("Register 4", 4, 32));
|
||||
addRegister(new Register("Register 5", 5, 32));
|
||||
addRegister(new Register("Register 6", 6, 32));
|
||||
|
||||
ui = new Ui::MAX2871Widget;
|
||||
ui->setupUi(widget);
|
||||
|
||||
regs[0]->assignUI(ui->FracNEnable, 31, true);
|
||||
regs[0]->assignUI(ui->N, 15, 16);
|
||||
regs[0]->assignUI(ui->frac, 3, 12);
|
||||
|
||||
regs[1]->assignUI(ui->CPL, 29, 2);
|
||||
regs[1]->assignUI(ui->CPT, 27, 2);
|
||||
regs[1]->assignUI(ui->P, 15, 12);
|
||||
regs[1]->assignUI(ui->M, 3, 12);
|
||||
|
||||
regs[2]->assignUI(ui->LDS, 31, 1);
|
||||
regs[2]->assignUI(ui->SDN, 29, 2);
|
||||
// regs[2]->assignUI(ui->MUX, 26, 3); // TODO MSB in reg 5
|
||||
regs[2]->assignUI(ui->DBR, 25);
|
||||
regs[2]->assignUI(ui->RDIV2, 24);
|
||||
regs[2]->assignUI(ui->R, 14, 10);
|
||||
regs[2]->assignUI(ui->REG4DB, 13);
|
||||
regs[2]->assignUI(ui->CP, 9, 4);
|
||||
regs[2]->assignUI(ui->LDF, 8, 1);
|
||||
regs[2]->assignUI(ui->LDP, 7, 1);
|
||||
regs[2]->assignUI(ui->PDP, 6, 1);
|
||||
regs[2]->assignUI(ui->SHDN, 5);
|
||||
regs[2]->assignUI(ui->TRI, 4);
|
||||
regs[2]->assignUI(ui->RST, 3);
|
||||
|
||||
regs[3]->assignUI(ui->VCO, 26, 6);
|
||||
regs[3]->assignUI(ui->VAS_SHDN, 25);
|
||||
regs[3]->assignUI(ui->VAS_TEMP, 24);
|
||||
regs[3]->assignUI(ui->CSM, 18);
|
||||
regs[3]->assignUI(ui->MUTEDEL, 17);
|
||||
regs[3]->assignUI(ui->CDM, 15, 2);
|
||||
regs[3]->assignUI(ui->CDIV, 3, 12);
|
||||
|
||||
regs[4]->assignUI(ui->SDLDO, 28);
|
||||
regs[4]->assignUI(ui->SDDIV, 27);
|
||||
regs[4]->assignUI(ui->SDREF, 26);
|
||||
// regs[4]->assignUI(ui->BS, , ); // TODO value split in register
|
||||
regs[4]->assignUI(ui->FB, 23);
|
||||
regs[4]->assignUI(ui->DIVA, 20, 3);
|
||||
regs[4]->assignUI(ui->SDVCO, 11);
|
||||
regs[4]->assignUI(ui->MTLD, 10);
|
||||
regs[4]->assignUI(ui->BDIV, 9, 1);
|
||||
regs[4]->assignUI(ui->RFB_EN, 8);
|
||||
regs[4]->assignUI(ui->BPWR, 6, 2);
|
||||
regs[4]->assignUI(ui->RFA_EN, 5);
|
||||
regs[4]->assignUI(ui->APWR, 3, 2);
|
||||
|
||||
// regs[5]->assignUI(ui->VAS_DLY, , ); // TODO connect with VAS_SHDN
|
||||
regs[5]->assignUI(ui->SDPLL, 25);
|
||||
regs[5]->assignUI(ui->F01, 24);
|
||||
regs[5]->assignUI(ui->LD, 22, 2);
|
||||
// regs[5]->assignUI(ui->MUX, , ); // TODO LSB in reg 2
|
||||
regs[5]->assignUI(ui->ADCS, 6);
|
||||
regs[5]->assignUI(ui->ADCM, 3, 3);
|
||||
|
||||
regs[6]->assignUI(ui->ADC, 16, 7);
|
||||
|
||||
Register::fillTableWidget(ui->table, regs);
|
||||
}
|
||||
|
||||
MAX2871::~MAX2871()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
21
Software/PC_Application/Device/RegisterAccess/max2871.h
Normal file
21
Software/PC_Application/Device/RegisterAccess/max2871.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef MAX2871_H
|
||||
#define MAX2871_H
|
||||
|
||||
#include "registerdevice.h"
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class MAX2871Widget;
|
||||
}
|
||||
|
||||
class MAX2871 : public RegisterDevice
|
||||
{
|
||||
public:
|
||||
MAX2871();
|
||||
~MAX2871();
|
||||
|
||||
private:
|
||||
Ui::MAX2871Widget *ui;
|
||||
};
|
||||
|
||||
#endif // MAX2871_H
|
||||
1006
Software/PC_Application/Device/RegisterAccess/max2871widget.ui
Normal file
1006
Software/PC_Application/Device/RegisterAccess/max2871widget.ui
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,50 @@
|
|||
#include "rawregisterdialog.h"
|
||||
#include "ui_rawregisterdialog.h"
|
||||
|
||||
#include "register.h"
|
||||
#include "max2871.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
RawRegisterDialog::RawRegisterDialog(Device *dev, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::RawRegisterDialog),
|
||||
dev(dev)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
devices.resize(dev->Info().num_directRegisterDevices);
|
||||
|
||||
connect(dev, &Device::ReceivedDirectRegisterInfo, this, &RawRegisterDialog::receivedDirectRegisterInfo);
|
||||
connect(dev, &Device::ReceivedDirectRegister, this, &RawRegisterDialog::receivedDirectRegister);
|
||||
|
||||
// trigger extraction of device information, this will trigger the receivedDirectRegisterInfo slot which will further populate the dialog
|
||||
dev->SendCommandWithoutPayload(Protocol::PacketType::RequestDirectRegisterInfo);
|
||||
}
|
||||
|
||||
RawRegisterDialog::~RawRegisterDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void RawRegisterDialog::receivedDirectRegisterInfo(Protocol::DirectRegisterInfo info)
|
||||
{
|
||||
if(info.num >= devices.size()) {
|
||||
qWarning() << "Received invalid register device:" << info.num;
|
||||
return;
|
||||
}
|
||||
auto regdev = RegisterDevice::create(dev, info.num, info.type);
|
||||
if(!regdev) {
|
||||
qWarning() << "Unable to create register device" << info.type <<", unknown type";
|
||||
return;
|
||||
}
|
||||
devices[info.num] = regdev;
|
||||
ui->tabs->addTab(regdev->getWidget(), QString(info.type)+": "+QString(info.name));
|
||||
}
|
||||
|
||||
void RawRegisterDialog::receivedDirectRegister(Protocol::DirectRegisterWrite reg)
|
||||
{
|
||||
if(reg.device < devices.size() && devices[reg.device]) {
|
||||
devices[reg.device]->setRegister(reg.address, reg.data);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef REGISTERTESTDIALOG_H
|
||||
#define REGISTERTESTDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "Device/device.h"
|
||||
#include "registerdevice.h"
|
||||
|
||||
namespace Ui {
|
||||
class RawRegisterDialog;
|
||||
}
|
||||
|
||||
class RawRegisterDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RawRegisterDialog(Device *dev, QWidget *parent = nullptr);
|
||||
~RawRegisterDialog();
|
||||
|
||||
private slots:
|
||||
void receivedDirectRegisterInfo(Protocol::DirectRegisterInfo info);
|
||||
void receivedDirectRegister(Protocol::DirectRegisterWrite reg);
|
||||
private:
|
||||
Ui::RawRegisterDialog *ui;
|
||||
Device *dev;
|
||||
std::vector<RegisterDevice*> devices;
|
||||
};
|
||||
|
||||
#endif // REGISTERTESTDIALOG_H
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RawRegisterDialog</class>
|
||||
<widget class="QDialog" name="RawRegisterDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>973</width>
|
||||
<height>640</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Device Registers</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabs">
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Open|QDialogButtonBox::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>RawRegisterDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>RawRegisterDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
151
Software/PC_Application/Device/RegisterAccess/register.cpp
Normal file
151
Software/PC_Application/Device/RegisterAccess/register.cpp
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
#include "register.h"
|
||||
#include <exception>
|
||||
#include <QHeaderView>
|
||||
|
||||
Register::Register(QString name, int address, int width)
|
||||
: QObject(nullptr),
|
||||
name(name),
|
||||
address(address),
|
||||
width(width)
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
|
||||
void Register::assignUI(QCheckBox *cb, int bitpos, bool inverted)
|
||||
{
|
||||
connect(this, &Register::valueChanged, [=](unsigned int newval) {
|
||||
bool bit = newval & (1UL << bitpos);
|
||||
if(inverted) {
|
||||
bit = !bit;
|
||||
}
|
||||
cb->setChecked(bit);
|
||||
});
|
||||
connect(cb, &QCheckBox::toggled, [=](bool checked){
|
||||
if(inverted) {
|
||||
checked = !checked;
|
||||
}
|
||||
setValue(checked, bitpos, 1);
|
||||
});
|
||||
}
|
||||
|
||||
void Register::assignUI(QComboBox *cb, int pos, int width)
|
||||
{
|
||||
connect(this, &Register::valueChanged, [=]() {
|
||||
auto value = getValue(pos, width);
|
||||
if(cb->count() > static_cast<int>(value)) {
|
||||
cb->setCurrentIndex(value);
|
||||
}
|
||||
});
|
||||
connect(cb, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index){
|
||||
setValue(index, pos, width);
|
||||
});
|
||||
}
|
||||
|
||||
void Register::assignUI(QSpinBox *sb, int pos, int width)
|
||||
{
|
||||
connect(this, &Register::valueChanged, [=]() {
|
||||
auto value = getValue(pos, width);
|
||||
sb->setValue(value);
|
||||
});
|
||||
connect(sb, qOverload<int>(&QSpinBox::valueChanged), [=](int index){
|
||||
setValue(index, pos, width);
|
||||
});
|
||||
}
|
||||
|
||||
QString Register::hexString()
|
||||
{
|
||||
return "0x" + QString("%1").arg(value, (width-1)/4 + 1, 16, QChar('0'));
|
||||
}
|
||||
|
||||
bool Register::setFromString(QString s)
|
||||
{
|
||||
bool okay;
|
||||
auto num = s.toULong(&okay, 0);
|
||||
if(okay) {
|
||||
setValue(num);
|
||||
}
|
||||
return okay;
|
||||
}
|
||||
|
||||
unsigned long Register::getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned long Register::getValue(int pos, int width)
|
||||
{
|
||||
unsigned long mask = 0;
|
||||
for(int i=0;i<width;i++) {
|
||||
mask |= (1UL << i);
|
||||
}
|
||||
mask <<= pos;
|
||||
auto masked = value & mask;
|
||||
masked >>= pos;
|
||||
return masked;
|
||||
}
|
||||
|
||||
void Register::setValue(unsigned long newval)
|
||||
{
|
||||
setValue(newval, 0, width);
|
||||
}
|
||||
|
||||
void Register::setValue(unsigned long newval, int pos, int width)
|
||||
{
|
||||
unsigned long mask = 0;
|
||||
for(int i=0;i<width;i++) {
|
||||
mask |= (1UL << i);
|
||||
}
|
||||
newval &= mask;
|
||||
newval <<= pos;
|
||||
mask <<= pos;
|
||||
auto oldval = value;
|
||||
value &= ~mask;
|
||||
value |= newval;
|
||||
if(newval != oldval) {
|
||||
emit valueChanged(value);
|
||||
}
|
||||
}
|
||||
|
||||
int Register::getAddress() const
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
QString Register::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
void Register::fillTableWidget(QTableWidget *l, std::vector<Register *> regs)
|
||||
{
|
||||
l->clear();
|
||||
l->setRowCount(regs.size());
|
||||
l->setColumnCount(3);
|
||||
l->setHorizontalHeaderLabels({"Name", "Address", "Value"});
|
||||
l->verticalHeader()->setVisible(false);
|
||||
l->horizontalHeader()->setStretchLastSection(true);
|
||||
// l->setSortingEnabled(true);
|
||||
for(unsigned int i=0;i<regs.size();i++) {
|
||||
l->setItem(i, 0, new QTableWidgetItem(regs[i]->getName()));
|
||||
l->item(i, 0)->setFlags(l->item(i, 0)->flags() &= ~Qt::ItemIsEditable);
|
||||
auto address = "0x" + QString::number(regs[i]->address, 16);
|
||||
l->setItem(i, 1, new QTableWidgetItem(address));
|
||||
l->item(i, 1)->setFlags(l->item(i, 1)->flags() &= ~Qt::ItemIsEditable);
|
||||
auto valueItem = new QTableWidgetItem;
|
||||
valueItem->setFlags(valueItem->flags() | Qt::ItemIsEditable);
|
||||
valueItem->setData(Qt::DisplayRole, regs[i]->hexString());
|
||||
l->setItem(i, 2, valueItem);
|
||||
connect(regs[i], &Register::valueChanged, [=]() {
|
||||
l->item(i, 2)->setData(Qt::DisplayRole, regs[i]->hexString());
|
||||
});
|
||||
}
|
||||
connect(l, &QTableWidget::cellChanged, [=](int row, int column){
|
||||
if(column == 2) {
|
||||
auto reg = regs[row];
|
||||
QString input = l->item(row, column)->data(Qt::DisplayRole).toString();
|
||||
reg->setFromString(input);
|
||||
l->item(row, column)->setData(Qt::DisplayRole, reg->hexString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
42
Software/PC_Application/Device/RegisterAccess/register.h
Normal file
42
Software/PC_Application/Device/RegisterAccess/register.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef REGISTER_H
|
||||
#define REGISTER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QSpinBox>
|
||||
#include <QTableWidget>
|
||||
|
||||
class Register : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Register(QString name, int address, int width);
|
||||
|
||||
void assignUI(QCheckBox *cb, int bitpos, bool inverted = false);
|
||||
void assignUI(QComboBox *cb, int pos, int width);
|
||||
void assignUI(QSpinBox *sb, int pos, int width);
|
||||
|
||||
QString hexString();
|
||||
bool setFromString(QString hex);
|
||||
unsigned long getValue();
|
||||
unsigned long getValue(int pos, int width);
|
||||
QString getName() const;
|
||||
|
||||
static void fillTableWidget(QTableWidget *w, std::vector<Register*> regs);
|
||||
|
||||
int getAddress() const;
|
||||
|
||||
public slots:
|
||||
void setValue(unsigned long newval);
|
||||
void setValue(unsigned long newval, int pos, int width);
|
||||
signals:
|
||||
void valueChanged(unsigned long newval);
|
||||
private:
|
||||
QString name;
|
||||
int address;
|
||||
int width;
|
||||
unsigned long value;
|
||||
};
|
||||
|
||||
#endif // REGISTER_H
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
#include "registerdevice.h"
|
||||
|
||||
#include "max2871.h"
|
||||
#include "Device/device.h"
|
||||
|
||||
RegisterDevice *RegisterDevice::create(Device *dev, int number, QString partnumber)
|
||||
{
|
||||
RegisterDevice *regdev = nullptr;
|
||||
if(partnumber == "MAX2871") {
|
||||
regdev = new MAX2871();
|
||||
}
|
||||
if(regdev) {
|
||||
regdev->dev = dev;
|
||||
regdev->number = number;
|
||||
regdev->partnumber = partnumber;
|
||||
|
||||
// read initial register content
|
||||
Protocol::PacketInfo p;
|
||||
p.type = Protocol::PacketType::DirectRegisterRead;
|
||||
p.directRegRead.device = number;
|
||||
for(unsigned int i=0;i<regdev->regs.size();i++) {
|
||||
p.directRegRead.address = regdev->regs[i]->getAddress();
|
||||
dev->SendPacket(p);
|
||||
}
|
||||
}
|
||||
return regdev;
|
||||
}
|
||||
|
||||
RegisterDevice::~RegisterDevice()
|
||||
{
|
||||
delete widget;
|
||||
}
|
||||
|
||||
void RegisterDevice::setRegister(int address, unsigned long value)
|
||||
{
|
||||
for(auto reg : regs) {
|
||||
if(reg->getAddress() == address) {
|
||||
reg->setValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RegisterDevice::RegisterDevice()
|
||||
{
|
||||
widget = new QWidget;
|
||||
}
|
||||
|
||||
QWidget *RegisterDevice::getWidget() const
|
||||
{
|
||||
return widget;
|
||||
}
|
||||
|
||||
void RegisterDevice::addRegister(Register *reg)
|
||||
{
|
||||
regs.push_back(reg);
|
||||
QObject::connect(reg, &Register::valueChanged, [=]() {
|
||||
// transfer register content to device
|
||||
Protocol::PacketInfo p;
|
||||
p.type = Protocol::PacketType::DirectRegisterWrite;
|
||||
p.directRegWrite.device = number;
|
||||
p.directRegWrite.address = reg->getAddress();
|
||||
p.directRegWrite.data = reg->getValue();
|
||||
dev->SendPacket(p);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef REGISTERDEVICE_H
|
||||
#define REGISTERDEVICE_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "register.h"
|
||||
#include "savable.h"
|
||||
#include "Device/device.h"
|
||||
|
||||
class RegisterDevice //: public Savable
|
||||
{
|
||||
public:
|
||||
static RegisterDevice *create(Device *dev, int number, QString partnumber);
|
||||
~RegisterDevice();
|
||||
|
||||
void setRegister(int address, unsigned long value);
|
||||
// void fromJSON(nlohmann::json j) override;
|
||||
// nlohmann::json toJSON() override;
|
||||
|
||||
QWidget *getWidget() const;
|
||||
|
||||
protected:
|
||||
void addRegister(Register *reg);
|
||||
|
||||
RegisterDevice();
|
||||
Device *dev;
|
||||
|
||||
int number;
|
||||
QString partnumber;
|
||||
std::vector<Register*> regs;
|
||||
QWidget *widget;
|
||||
};
|
||||
|
||||
#endif // REGISTERDEVICE_H
|
||||
|
|
@ -139,6 +139,7 @@ static constexpr Protocol::DeviceInfo defaultInfo = {
|
|||
.limits_maxRBW = 1000000,
|
||||
.limits_maxAmplitudePoints = 255,
|
||||
.limits_maxFreqHarmonic = 18000000000,
|
||||
.num_directRegisterDevices = 0,
|
||||
};
|
||||
|
||||
Protocol::DeviceInfo Device::lastInfo = defaultInfo;
|
||||
|
|
@ -462,6 +463,12 @@ void Device::ReceivedData()
|
|||
case Protocol::PacketType::FrequencyCorrection:
|
||||
emit FrequencyCorrectionReceived(packet.frequencyCorrection.ppm);
|
||||
break;
|
||||
case Protocol::PacketType::DirectRegisterInfo:
|
||||
emit ReceivedDirectRegisterInfo(packet.directRegInfo);
|
||||
break;
|
||||
case Protocol::PacketType::DirectRegisterWrite:
|
||||
emit ReceivedDirectRegister(packet.directRegWrite);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ Q_DECLARE_METATYPE(Protocol::Datapoint);
|
|||
Q_DECLARE_METATYPE(Protocol::ManualStatus);
|
||||
Q_DECLARE_METATYPE(Protocol::SpectrumAnalyzerResult);
|
||||
Q_DECLARE_METATYPE(Protocol::AmplitudeCorrectionPoint);
|
||||
Q_DECLARE_METATYPE(Protocol::DirectRegisterInfo);
|
||||
Q_DECLARE_METATYPE(Protocol::DirectRegisterWrite);
|
||||
|
||||
|
||||
class USBInBuffer : public QObject {
|
||||
Q_OBJECT;
|
||||
|
|
@ -82,6 +85,8 @@ signals:
|
|||
void NackReceived();
|
||||
void LogLineReceived(QString line);
|
||||
void NeedsFirmwareUpdate(int usedProtocol, int requiredProtocol);
|
||||
void ReceivedDirectRegisterInfo(Protocol::DirectRegisterInfo);
|
||||
void ReceivedDirectRegister(Protocol::DirectRegisterWrite);
|
||||
private slots:
|
||||
void ReceivedData();
|
||||
void ReceivedLog();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ HEADERS += \
|
|||
CustomWidgets/tilewidget.h \
|
||||
CustomWidgets/toggleswitch.h \
|
||||
CustomWidgets/touchstoneimport.h \
|
||||
Device/RegisterAccess/max2871.h \
|
||||
Device/RegisterAccess/rawregisterdialog.h \
|
||||
Device/RegisterAccess/register.h \
|
||||
Device/RegisterAccess/registerdevice.h \
|
||||
Device/device.h \
|
||||
Device/devicelog.h \
|
||||
Device/firmwareupdatedialog.h \
|
||||
|
|
@ -141,6 +145,10 @@ SOURCES += \
|
|||
CustomWidgets/tilewidget.cpp \
|
||||
CustomWidgets/toggleswitch.cpp \
|
||||
CustomWidgets/touchstoneimport.cpp \
|
||||
Device/RegisterAccess/max2871.cpp \
|
||||
Device/RegisterAccess/rawregisterdialog.cpp \
|
||||
Device/RegisterAccess/register.cpp \
|
||||
Device/RegisterAccess/registerdevice.cpp \
|
||||
Device/device.cpp \
|
||||
Device/devicelog.cpp \
|
||||
Device/firmwareupdatedialog.cpp \
|
||||
|
|
@ -251,6 +259,8 @@ FORMS += \
|
|||
CustomWidgets/jsonpickerdialog.ui \
|
||||
CustomWidgets/tilewidget.ui \
|
||||
CustomWidgets/touchstoneimport.ui \
|
||||
Device/RegisterAccess/max2871widget.ui \
|
||||
Device/RegisterAccess/rawregisterdialog.ui \
|
||||
Device/devicelog.ui \
|
||||
Device/firmwareupdatedialog.ui \
|
||||
Device/manualcontroldialog.ui \
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "Calibration/calibrationtracedialog.h"
|
||||
#include "ui_main.h"
|
||||
#include "Device/firmwareupdatedialog.h"
|
||||
#include "Device/RegisterAccess/rawregisterdialog.h"
|
||||
#include "preferences.h"
|
||||
#include "Generator/signalgenwidget.h"
|
||||
#include <QDesktopWidget>
|
||||
|
|
@ -183,6 +184,7 @@ AppWindow::AppWindow(QWidget *parent)
|
|||
});
|
||||
|
||||
connect(ui->actionManual_Control, &QAction::triggered, this, &AppWindow::StartManualControl);
|
||||
connect(ui->actionRaw_Register_Access, &QAction::triggered, this, &AppWindow::RawRegisterAccess);
|
||||
connect(ui->actionFirmware_Update, &QAction::triggered, this, &AppWindow::StartFirmwareUpdateDialog);
|
||||
connect(ui->actionSource_Calibration, &QAction::triggered, this, &AppWindow::SourceCalibrationDialog);
|
||||
connect(ui->actionReceiver_Calibration, &QAction::triggered, this, &AppWindow::ReceiverCalibrationDialog);
|
||||
|
|
@ -228,6 +230,8 @@ AppWindow::AppWindow(QWidget *parent)
|
|||
qRegisterMetaType<Protocol::ManualStatus>("Manual");
|
||||
qRegisterMetaType<Protocol::SpectrumAnalyzerResult>("SpectrumAnalyzerResult");
|
||||
qRegisterMetaType<Protocol::AmplitudeCorrectionPoint>("AmplitudeCorrection");
|
||||
qRegisterMetaType<Protocol::DirectRegisterInfo>("DirectRegisterInfo");
|
||||
qRegisterMetaType<Protocol::DirectRegisterWrite>("DirectRegisterWrite");
|
||||
|
||||
// List available devices
|
||||
if(UpdateDeviceList() && Preferences::getInstance().Startup.ConnectToFirstDevice) {
|
||||
|
|
@ -286,6 +290,7 @@ bool AppWindow::ConnectToDevice(QString serial)
|
|||
lADCOverload.setVisible(device->Info().ADC_overload);
|
||||
lUnlevel.setVisible(device->Info().unlevel);
|
||||
lUnlock.setVisible(!device->Info().LO1_locked || !device->Info().source_locked);
|
||||
ui->actionRaw_Register_Access->setEnabled(device->Info().num_directRegisterDevices > 0);
|
||||
});
|
||||
connect(device, &Device::NeedsFirmwareUpdate, this, &AppWindow::DeviceNeedsUpdate);
|
||||
ui->actionDisconnect->setEnabled(true);
|
||||
|
|
@ -321,6 +326,7 @@ void AppWindow::DisconnectDevice()
|
|||
device = nullptr;
|
||||
ui->actionDisconnect->setEnabled(false);
|
||||
ui->actionManual_Control->setEnabled(false);
|
||||
ui->actionRaw_Register_Access->setEnabled(false);
|
||||
ui->actionFirmware_Update->setEnabled(false);
|
||||
ui->actionSource_Calibration->setEnabled(false);
|
||||
ui->actionReceiver_Calibration->setEnabled(false);
|
||||
|
|
@ -594,6 +600,12 @@ void AppWindow::StartManualControl()
|
|||
control->show();
|
||||
}
|
||||
|
||||
void AppWindow::RawRegisterAccess()
|
||||
{
|
||||
auto control = new RawRegisterDialog(device, this);
|
||||
control->show();
|
||||
}
|
||||
|
||||
void AppWindow::UpdateReference()
|
||||
{
|
||||
if(!device) {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ private slots:
|
|||
void DisconnectDevice();
|
||||
int UpdateDeviceList();
|
||||
void StartManualControl();
|
||||
void RawRegisterAccess();
|
||||
void UpdateReference();
|
||||
void StartFirmwareUpdateDialog();
|
||||
void DeviceNeedsUpdate(int reported, int expected);
|
||||
|
|
|
|||
|
|
@ -6,9 +6,7 @@
|
|||
|
||||
#include "Calibration/calkit.h"
|
||||
#include "touchstone.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <complex>
|
||||
|
||||
static QApplication *app;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
<addaction name="actionDisconnect"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionManual_Control"/>
|
||||
<addaction name="actionRaw_Register_Access"/>
|
||||
<addaction name="actionFirmware_Update"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionSource_Calibration"/>
|
||||
|
|
@ -209,6 +210,14 @@
|
|||
<string>Frequency Calibration</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRaw_Register_Access">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Raw Register Access</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="icons.qrc"/>
|
||||
|
|
|
|||
|
|
@ -218,6 +218,47 @@ void App_Start() {
|
|||
Cal::setFrequencyCal(recv_packet.frequencyCorrection.ppm);
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
break;
|
||||
case Protocol::PacketType::RequestDirectRegisterInfo:
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
LOG_INFO("Requested register devices, sending %d packets", RegisterDevice::getNumDevices());
|
||||
for(uint8_t i=0;i<RegisterDevice::getNumDevices();i++) {
|
||||
auto dev = RegisterDevice::getDevice(i);
|
||||
Protocol::PacketInfo send;
|
||||
send.type = Protocol::PacketType::DirectRegisterInfo;
|
||||
send.directRegInfo = dev->getInfo();
|
||||
Communication::Send(send);
|
||||
}
|
||||
break;
|
||||
case Protocol::PacketType::DirectRegisterWrite:
|
||||
if(recv_packet.directRegWrite.device >= RegisterDevice::getNumDevices()) {
|
||||
// invalid device
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Nack);
|
||||
} else {
|
||||
LOG_INFO(
|
||||
"Register write: dev %u, address %u, data 0x%08x",
|
||||
recv_packet.directRegWrite.device,
|
||||
recv_packet.directRegWrite.address,
|
||||
(uint32_t) recv_packet.directRegWrite.data);
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
auto dev = RegisterDevice::getDevice(recv_packet.directRegWrite.device);
|
||||
dev->writeRegister(recv_packet.directRegWrite.address, recv_packet.directRegWrite.data);
|
||||
}
|
||||
break;
|
||||
case Protocol::PacketType::DirectRegisterRead:
|
||||
if(recv_packet.directRegWrite.device >= RegisterDevice::getNumDevices()) {
|
||||
// invalid device
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Nack);
|
||||
} else {
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
|
||||
auto dev = RegisterDevice::getDevice(recv_packet.directRegWrite.device);
|
||||
Protocol::PacketInfo send;
|
||||
send.type = Protocol::PacketType::DirectRegisterWrite;
|
||||
send.directRegWrite.device = recv_packet.directRegRead.device;
|
||||
send.directRegWrite.address = recv_packet.directRegRead.address;
|
||||
send.directRegWrite.data = dev->readRegister(recv_packet.directRegRead.address);
|
||||
Communication::Send(send);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// this packet type is not supported
|
||||
Communication::SendWithoutPayload(Protocol::PacketType::Nack);
|
||||
|
|
|
|||
|
|
@ -100,6 +100,9 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_
|
|||
case PacketType::SourceCalPoint:
|
||||
case PacketType::ReceiverCalPoint: payload_size = sizeof(packet.amplitudePoint); break;
|
||||
case PacketType::FrequencyCorrection: payload_size = sizeof(packet.frequencyCorrection); break;
|
||||
case PacketType::DirectRegisterInfo: payload_size = sizeof(packet.directRegInfo); break;
|
||||
case PacketType::DirectRegisterWrite: payload_size = sizeof(packet.directRegWrite); break;
|
||||
case PacketType::DirectRegisterRead: payload_size = sizeof(packet.directRegRead); break;
|
||||
case PacketType::Ack:
|
||||
case PacketType::PerformFirmwareUpdate:
|
||||
case PacketType::ClearFlash:
|
||||
|
|
@ -109,6 +112,7 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_
|
|||
case PacketType::RequestReceiverCal:
|
||||
case PacketType::SetIdle:
|
||||
case PacketType::RequestFrequencyCorrection:
|
||||
case PacketType::RequestDirectRegisterInfo:
|
||||
// no payload
|
||||
break;
|
||||
case PacketType::None:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
namespace Protocol {
|
||||
|
||||
static constexpr uint16_t Version = 5;
|
||||
static constexpr uint16_t Version = 6;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
|
|
@ -68,6 +68,7 @@ using DeviceInfo = struct _deviceInfo {
|
|||
uint32_t limits_maxRBW;
|
||||
uint8_t limits_maxAmplitudePoints;
|
||||
uint64_t limits_maxFreqHarmonic;
|
||||
uint8_t num_directRegisterDevices; // number of peripheral chips whos registers are exposed via the USB API (for debugging)
|
||||
};
|
||||
|
||||
using ManualStatus = struct _manualstatus {
|
||||
|
|
@ -156,6 +157,25 @@ using FrequencyCorrection = struct _frequencycorrection {
|
|||
float ppm;
|
||||
};
|
||||
|
||||
using DirectRegisterInfo = struct _directregisterinfo {
|
||||
uint8_t num;
|
||||
char type[20]; // Chip partnumber
|
||||
char name[20]; // Arbitrary name
|
||||
};
|
||||
|
||||
using DirectRegisterWrite = struct _directregisterwrite {
|
||||
uint8_t device;
|
||||
uint32_t address;
|
||||
uint64_t data;
|
||||
};
|
||||
|
||||
using DirectRegisterRead = struct _directregisterread {
|
||||
// Device will respond with DirectRegisterWrite
|
||||
uint8_t device;
|
||||
// uint8_t read_all:1; // if set to one, address is ignored and all registers returned (each in own packet)
|
||||
uint32_t address;
|
||||
};
|
||||
|
||||
enum class PacketType : uint8_t {
|
||||
None = 0,
|
||||
Datapoint = 1,
|
||||
|
|
@ -180,6 +200,10 @@ enum class PacketType : uint8_t {
|
|||
SetIdle = 20,
|
||||
RequestFrequencyCorrection = 21,
|
||||
FrequencyCorrection = 22,
|
||||
RequestDirectRegisterInfo = 23,
|
||||
DirectRegisterInfo = 24,
|
||||
DirectRegisterWrite = 25,
|
||||
DirectRegisterRead = 26,
|
||||
};
|
||||
|
||||
using PacketInfo = struct _packetinfo {
|
||||
|
|
@ -197,6 +221,9 @@ using PacketInfo = struct _packetinfo {
|
|||
SpectrumAnalyzerResult spectrumResult;
|
||||
AmplitudeCorrectionPoint amplitudePoint;
|
||||
FrequencyCorrection frequencyCorrection;
|
||||
DirectRegisterInfo directRegInfo;
|
||||
DirectRegisterWrite directRegWrite;
|
||||
DirectRegisterRead directRegRead;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
24
Software/VNA_embedded/Application/Drivers/RegisterDevice.cpp
Normal file
24
Software/VNA_embedded/Application/Drivers/RegisterDevice.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include <RegisterDevice.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
uint8_t RegisterDevice::cnt = 0;
|
||||
std::array<RegisterDevice*, RegisterDevice::maxDevices> RegisterDevice::devices;
|
||||
|
||||
Protocol::DirectRegisterInfo RegisterDevice::getInfo() {
|
||||
Protocol::DirectRegisterInfo i;
|
||||
i.num = num;
|
||||
strncpy(i.name, name, sizeof(i.name));
|
||||
i.name[sizeof(i.name) - 1] = '\0';
|
||||
strncpy(i.type, type, sizeof(i.type));
|
||||
i.type[sizeof(i.type) - 1] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
RegisterDevice* RegisterDevice::getDevice(uint8_t num) {
|
||||
if(num < cnt) {
|
||||
return devices[num];
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
41
Software/VNA_embedded/Application/Drivers/RegisterDevice.hpp
Normal file
41
Software/VNA_embedded/Application/Drivers/RegisterDevice.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include "Protocol.hpp"
|
||||
|
||||
extern int global;
|
||||
|
||||
class RegisterDevice {
|
||||
public:
|
||||
constexpr RegisterDevice(const char *type, const char *name) :
|
||||
type(type),
|
||||
name(name),
|
||||
num(0)
|
||||
{
|
||||
num = cnt;
|
||||
if(cnt < maxDevices) {
|
||||
devices[cnt] = this;
|
||||
cnt++;
|
||||
} else {
|
||||
// not enough room in array. A debug message would be useful here
|
||||
// but the constructor is called before any hardware initialization
|
||||
// so we can do nothing here
|
||||
}
|
||||
}
|
||||
virtual void writeRegister(uint32_t address, uint64_t data) = 0;
|
||||
virtual uint64_t readRegister(uint32_t address) = 0;
|
||||
|
||||
Protocol::DirectRegisterInfo getInfo();
|
||||
|
||||
static uint8_t getNumDevices() { return cnt;};
|
||||
static RegisterDevice *getDevice(uint8_t num);
|
||||
|
||||
private:
|
||||
static constexpr uint8_t maxDevices = 10;
|
||||
static std::array<RegisterDevice*,maxDevices> devices;
|
||||
static uint8_t cnt;
|
||||
const char *type;
|
||||
const char *name;
|
||||
uint8_t num;
|
||||
};
|
||||
|
|
@ -417,3 +417,18 @@ uint8_t MAX2871::GetTemp() {
|
|||
// convert to celsius and return
|
||||
return 95 - 1.14f * ADC_raw;
|
||||
}
|
||||
|
||||
void MAX2871::writeRegister(uint32_t address, uint64_t data) {
|
||||
if(address <= 5) {
|
||||
regs[address] = (uint32_t) data;
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t MAX2871::readRegister(uint32_t address) {
|
||||
if(address <= 5) {
|
||||
return regs[address];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "stm.hpp"
|
||||
#include "RegisterDevice.hpp"
|
||||
|
||||
class MAX2871 {
|
||||
class MAX2871 : public RegisterDevice {
|
||||
public:
|
||||
constexpr MAX2871(SPI_HandleTypeDef *hspi, GPIO_TypeDef *LE = nullptr,
|
||||
constexpr MAX2871(const char *name, SPI_HandleTypeDef *hspi, GPIO_TypeDef *LE = nullptr,
|
||||
uint16_t LEpin = 0, GPIO_TypeDef *RF_EN = nullptr,
|
||||
uint16_t RF_ENpin = 0, GPIO_TypeDef *LD = nullptr, uint16_t LDpin = 0,
|
||||
GPIO_TypeDef *CE = nullptr, uint16_t CEpin = 0,
|
||||
GPIO_TypeDef *MUX = nullptr, uint16_t MUXpin = 0) :
|
||||
regs(), f_PFD(0),
|
||||
RegisterDevice("MAX2871", name),
|
||||
regs(), f_PFD(0),
|
||||
hspi(hspi),
|
||||
CE(CE), CEpin(CEpin),
|
||||
LE(LE), LEpin(LEpin),
|
||||
|
|
@ -60,6 +62,9 @@ public:
|
|||
uint64_t GetActualFrequency() {
|
||||
return outputFrequency;
|
||||
}
|
||||
|
||||
void writeRegister(uint32_t address, uint64_t data) override;
|
||||
uint64_t readRegister(uint32_t address) override;
|
||||
private:
|
||||
static constexpr uint64_t MaxFreq = 6100000000; // 6GHz according to datasheet, but slight overclocking is possible
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "HW_HAL.hpp"
|
||||
|
||||
Si5351C HWHAL::Si5351 = Si5351C(&hi2c2, 26000000);
|
||||
MAX2871 HWHAL::Source = MAX2871(&hspi1, FPGA_CS_GPIO_Port, FPGA_CS_Pin, nullptr, 0, nullptr, 0, nullptr, 0, GPIOA, GPIO_PIN_6);
|
||||
MAX2871 HWHAL::LO1 = MAX2871(&hspi1, FPGA_CS_GPIO_Port, FPGA_CS_Pin, nullptr, 0, nullptr, 0, nullptr, 0, GPIOA, GPIO_PIN_6);
|
||||
MAX2871 HWHAL::Source = MAX2871("Source", &hspi1, FPGA_CS_GPIO_Port, FPGA_CS_Pin, nullptr, 0, nullptr, 0, nullptr, 0, GPIOA, GPIO_PIN_6);
|
||||
MAX2871 HWHAL::LO1 = MAX2871("1.LO", &hspi1, FPGA_CS_GPIO_Port, FPGA_CS_Pin, nullptr, 0, nullptr, 0, nullptr, 0, GPIOA, GPIO_PIN_6);
|
||||
extern SPI_HandleTypeDef hspi1;
|
||||
Flash HWHAL::flash = Flash(&hspi1, FLASH_CS_GPIO_Port, FLASH_CS_Pin);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ static constexpr int16_t LowBandMaxPower = -190;
|
|||
static constexpr int16_t HighBandMinPower = -1060;
|
||||
static constexpr int16_t HighBandMaxPower = -160;
|
||||
|
||||
static constexpr uint8_t registerDevices = 2;
|
||||
|
||||
static constexpr Protocol::DeviceInfo Info = {
|
||||
.ProtocolVersion = Protocol::Version,
|
||||
.FW_major = FW_MAJOR,
|
||||
|
|
@ -75,6 +77,7 @@ static constexpr Protocol::DeviceInfo Info = {
|
|||
.limits_maxRBW = (uint32_t) (ADCSamplerate * 2.23f / MinSamples),
|
||||
.limits_maxAmplitudePoints = Cal::maxPoints,
|
||||
.limits_maxFreqHarmonic = 18000000000,
|
||||
.num_directRegisterDevices = registerDevices,
|
||||
};
|
||||
|
||||
enum class Mode {
|
||||
|
|
|
|||
Loading…
Reference in a new issue