diff --git a/Software/PC_Application/Device/RegisterAccess/max2871.cpp b/Software/PC_Application/Device/RegisterAccess/max2871.cpp new file mode 100644 index 0000000..b42b62d --- /dev/null +++ b/Software/PC_Application/Device/RegisterAccess/max2871.cpp @@ -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; +} + diff --git a/Software/PC_Application/Device/RegisterAccess/max2871.h b/Software/PC_Application/Device/RegisterAccess/max2871.h new file mode 100644 index 0000000..8fa2780 --- /dev/null +++ b/Software/PC_Application/Device/RegisterAccess/max2871.h @@ -0,0 +1,21 @@ +#ifndef MAX2871_H +#define MAX2871_H + +#include "registerdevice.h" +#include + +namespace Ui { +class MAX2871Widget; +} + +class MAX2871 : public RegisterDevice +{ +public: + MAX2871(); + ~MAX2871(); + +private: + Ui::MAX2871Widget *ui; +}; + +#endif // MAX2871_H diff --git a/Software/PC_Application/Device/RegisterAccess/max2871widget.ui b/Software/PC_Application/Device/RegisterAccess/max2871widget.ui new file mode 100644 index 0000000..16d362c --- /dev/null +++ b/Software/PC_Application/Device/RegisterAccess/max2871widget.ui @@ -0,0 +1,1006 @@ + + + MAX2871Widget + + + + 0 + 0 + 1432 + 586 + + + + Form + + + + + + + + + + Registers + + + + + + + + + + + + + + Lock Detect + + + + + + Speed: + + + + + + + + fPFD <= 32MHz + + + + + fPFD > 32MHz + + + + + + + + + Frac-N + + + + + Int-N + + + + + + + + Function: + + + + + + + + 10ns + + + + + 6ns + + + + + + + + Precision: + + + + + + + + Low + + + + + Digital lock detect + + + + + Analog lock detect + + + + + High + + + + + + + + LD Pin: + + + + + + + + + + Shutdown + + + + + + Shutdown VCO + + + + + + + Shutdown VCO LDO + + + + + + + Shutdown Reference Input + + + + + + + Shutdown VCO Divider + + + + + + + Shutdown Mode + + + + + + + Shutdown PLL + + + + + + + + + + + + + + + + + + Reference + + + + + + Doubler + + + + + + + Div-by-2 + + + + + + + + + R-divider: + + + + + + + 1023 + + + + + + + + + R/N counter reset + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Divider Settings + + + + + + Fractional-N mode + + + + + + + + + N: + + + + + + + 16 + + + 65535 + + + + + + + FRAC: + + + + + + + 4095 + + + + + + + M: + + + + + + + 4095 + + + + + + + 4095 + + + + + + + Phase: + + + + + + + + + + + + Charge Pump + + + + + + Linearity: + + + + + + + + Disabled + + + + + 10% + + + + + 20% + + + + + 30% + + + + + + + + Test: + + + + + + + + Normal mode + + + + + Long Reset mode + + + + + Force source + + + + + Force sink + + + + + + + + Current: + + + + + + + 15 + + + + + + + Polarity: + + + + + + + + Negative + + + + + Positive + + + + + + + + High Impedance + + + + + + + + + + Output + + + + + + + + Divider: + + + + + + + + 1 + + + + + 2 + + + + + 4 + + + + + 8 + + + + + 16 + + + + + 32 + + + + + 64 + + + + + 128 + + + + + + + + Out B Path: + + + + + + + + Divided output + + + + + Fundamental frequency + + + + + + + + + + Enable Out B + + + + + + + + + Out B Power: + + + + + + + + -4 dBm + + + + + -1 dBm + + + + + +2 dBm + + + + + +5 dBm + + + + + + + + + + Enable Out B + + + + + + + + + Out A Power: + + + + + + + + -4 dBm + + + + + -1 dBm + + + + + +2 dBm + + + + + +5 dBm + + + + + + + + + + + + + + + + + + + VCO + + + + + + + + VCO Band: + + + + + + + 63 + + + + + + + + + VAS Shutdown + + + + + + + VAS temperature compensation + + + + + + + Fundamental Feedback + + + + + + + + + + ADC + + + + + + Start + + + + + + + Valid Code + + + + + + + + + Mode: + + + + + + + + Disabled + + + + + Temperature + + + + + Reserved + + + + + Reserved + + + + + Tune pin + + + + + Reserved + + + + + Reserved + + + + + Reserved + + + + + + + + Code: + + + + + + + 128 + + + + + + + + + + + + + + Mixed + + + + + + Mute until lock + + + + + + + Mute Delay + + + + + + + Cycle Slip Mode + + + + + + + Integer mode when F=0 + + + + + + + Double buffer mode + + + + + + + + + Clock Divider Mode: + + + + + + + + Mute until Lock Delay + + + + + Fast-lock enabled + + + + + Phase Adjustment mode + + + + + Reserved + + + + + + + + Noise Mode: + + + + + + + + Low-noise + + + + + Reserved + + + + + Low-spur 1 + + + + + Low-spur 2 + + + + + + + + MUX Pin: + + + + + + + + Three-state output + + + + + DVDD + + + + + DGND + + + + + R-divider output + + + + + N-divider/2 output + + + + + Analog lock detect + + + + + Digital lock detect + + + + + Sync input + + + + + Reserved + + + + + Reserved + + + + + Reserved + + + + + Reserved + + + + + Read SPI registers 6 + + + + + Reserved + + + + + Reserved + + + + + Reserved + + + + + + + + Band Select: + + + + + + + 1023 + + + + + + + Clock Divider: + + + + + + + 4095 + + + + + + + + + + + + + + + + + + + diff --git a/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.cpp b/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.cpp new file mode 100644 index 0000000..76bc1f5 --- /dev/null +++ b/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.cpp @@ -0,0 +1,50 @@ +#include "rawregisterdialog.h" +#include "ui_rawregisterdialog.h" + +#include "register.h" +#include "max2871.h" + +#include + +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); + } +} diff --git a/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.h b/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.h new file mode 100644 index 0000000..dc8ad7a --- /dev/null +++ b/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.h @@ -0,0 +1,29 @@ +#ifndef REGISTERTESTDIALOG_H +#define REGISTERTESTDIALOG_H + +#include +#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 devices; +}; + +#endif // REGISTERTESTDIALOG_H diff --git a/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.ui b/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.ui new file mode 100644 index 0000000..b4d64f1 --- /dev/null +++ b/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.ui @@ -0,0 +1,71 @@ + + + RawRegisterDialog + + + + 0 + 0 + 973 + 640 + + + + Device Registers + + + + + + -1 + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Open|QDialogButtonBox::Save + + + + + + + + + buttonBox + rejected() + RawRegisterDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + buttonBox + accepted() + RawRegisterDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + diff --git a/Software/PC_Application/Device/RegisterAccess/register.cpp b/Software/PC_Application/Device/RegisterAccess/register.cpp new file mode 100644 index 0000000..13490b8 --- /dev/null +++ b/Software/PC_Application/Device/RegisterAccess/register.cpp @@ -0,0 +1,151 @@ +#include "register.h" +#include +#include + +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(value)) { + cb->setCurrentIndex(value); + } + }); + connect(cb, qOverload(&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(&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>= 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 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;isetItem(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()); + } + }); +} + diff --git a/Software/PC_Application/Device/RegisterAccess/register.h b/Software/PC_Application/Device/RegisterAccess/register.h new file mode 100644 index 0000000..f63597e --- /dev/null +++ b/Software/PC_Application/Device/RegisterAccess/register.h @@ -0,0 +1,42 @@ +#ifndef REGISTER_H +#define REGISTER_H + +#include +#include +#include +#include +#include + +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 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 diff --git a/Software/PC_Application/Device/RegisterAccess/registerdevice.cpp b/Software/PC_Application/Device/RegisterAccess/registerdevice.cpp new file mode 100644 index 0000000..5c3d621 --- /dev/null +++ b/Software/PC_Application/Device/RegisterAccess/registerdevice.cpp @@ -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;iregs.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); + }); +} + diff --git a/Software/PC_Application/Device/RegisterAccess/registerdevice.h b/Software/PC_Application/Device/RegisterAccess/registerdevice.h new file mode 100644 index 0000000..87aa795 --- /dev/null +++ b/Software/PC_Application/Device/RegisterAccess/registerdevice.h @@ -0,0 +1,34 @@ +#ifndef REGISTERDEVICE_H +#define REGISTERDEVICE_H + +#include + +#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 regs; + QWidget *widget; +}; + +#endif // REGISTERDEVICE_H diff --git a/Software/PC_Application/Device/device.cpp b/Software/PC_Application/Device/device.cpp index f33e8e4..f3b7294 100644 --- a/Software/PC_Application/Device/device.cpp +++ b/Software/PC_Application/Device/device.cpp @@ -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; } diff --git a/Software/PC_Application/Device/device.h b/Software/PC_Application/Device/device.h index 2800dba..6ebabbf 100644 --- a/Software/PC_Application/Device/device.h +++ b/Software/PC_Application/Device/device.h @@ -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(); diff --git a/Software/PC_Application/LibreVNA-GUI.pro b/Software/PC_Application/LibreVNA-GUI.pro index cc13701..b8d0c77 100644 --- a/Software/PC_Application/LibreVNA-GUI.pro +++ b/Software/PC_Application/LibreVNA-GUI.pro @@ -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 \ diff --git a/Software/PC_Application/appwindow.cpp b/Software/PC_Application/appwindow.cpp index 5d96151..4e80c3b 100644 --- a/Software/PC_Application/appwindow.cpp +++ b/Software/PC_Application/appwindow.cpp @@ -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 @@ -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("Manual"); qRegisterMetaType("SpectrumAnalyzerResult"); qRegisterMetaType("AmplitudeCorrection"); + qRegisterMetaType("DirectRegisterInfo"); + qRegisterMetaType("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) { diff --git a/Software/PC_Application/appwindow.h b/Software/PC_Application/appwindow.h index 0fcdc48..bcb4cd1 100644 --- a/Software/PC_Application/appwindow.h +++ b/Software/PC_Application/appwindow.h @@ -48,6 +48,7 @@ private slots: void DisconnectDevice(); int UpdateDeviceList(); void StartManualControl(); + void RawRegisterAccess(); void UpdateReference(); void StartFirmwareUpdateDialog(); void DeviceNeedsUpdate(int reported, int expected); diff --git a/Software/PC_Application/main.cpp b/Software/PC_Application/main.cpp index 680c030..e74066f 100644 --- a/Software/PC_Application/main.cpp +++ b/Software/PC_Application/main.cpp @@ -6,9 +6,7 @@ #include "Calibration/calkit.h" #include "touchstone.h" - #include - #include static QApplication *app; diff --git a/Software/PC_Application/main.ui b/Software/PC_Application/main.ui index 5402d31..c7badf0 100644 --- a/Software/PC_Application/main.ui +++ b/Software/PC_Application/main.ui @@ -50,6 +50,7 @@ + @@ -209,6 +210,14 @@ Frequency Calibration + + + false + + + Raw Register Access + + diff --git a/Software/VNA_embedded/Application/App.cpp b/Software/VNA_embedded/Application/App.cpp index ad73e7f..072b21c 100644 --- a/Software/VNA_embedded/Application/App.cpp +++ b/Software/VNA_embedded/Application/App.cpp @@ -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;igetInfo(); + 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); diff --git a/Software/VNA_embedded/Application/Communication/Protocol.cpp b/Software/VNA_embedded/Application/Communication/Protocol.cpp index fb07b85..7373e59 100644 --- a/Software/VNA_embedded/Application/Communication/Protocol.cpp +++ b/Software/VNA_embedded/Application/Communication/Protocol.cpp @@ -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: diff --git a/Software/VNA_embedded/Application/Communication/Protocol.hpp b/Software/VNA_embedded/Application/Communication/Protocol.hpp index 02a9a3d..e630984 100644 --- a/Software/VNA_embedded/Application/Communication/Protocol.hpp +++ b/Software/VNA_embedded/Application/Communication/Protocol.hpp @@ -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; }; }; diff --git a/Software/VNA_embedded/Application/Drivers/RegisterDevice.cpp b/Software/VNA_embedded/Application/Drivers/RegisterDevice.cpp new file mode 100644 index 0000000..394d0eb --- /dev/null +++ b/Software/VNA_embedded/Application/Drivers/RegisterDevice.cpp @@ -0,0 +1,24 @@ +#include + +#include + +uint8_t RegisterDevice::cnt = 0; +std::array 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; + } +} diff --git a/Software/VNA_embedded/Application/Drivers/RegisterDevice.hpp b/Software/VNA_embedded/Application/Drivers/RegisterDevice.hpp new file mode 100644 index 0000000..58f13a9 --- /dev/null +++ b/Software/VNA_embedded/Application/Drivers/RegisterDevice.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#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 devices; + static uint8_t cnt; + const char *type; + const char *name; + uint8_t num; +}; diff --git a/Software/VNA_embedded/Application/Drivers/max2871.cpp b/Software/VNA_embedded/Application/Drivers/max2871.cpp index 9781898..10a561f 100644 --- a/Software/VNA_embedded/Application/Drivers/max2871.cpp +++ b/Software/VNA_embedded/Application/Drivers/max2871.cpp @@ -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; + } +} diff --git a/Software/VNA_embedded/Application/Drivers/max2871.hpp b/Software/VNA_embedded/Application/Drivers/max2871.hpp index 4648887..29ec5ee 100644 --- a/Software/VNA_embedded/Application/Drivers/max2871.hpp +++ b/Software/VNA_embedded/Application/Drivers/max2871.hpp @@ -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 diff --git a/Software/VNA_embedded/Application/HW_HAL.cpp b/Software/VNA_embedded/Application/HW_HAL.cpp index 8db068b..a48066e 100644 --- a/Software/VNA_embedded/Application/HW_HAL.cpp +++ b/Software/VNA_embedded/Application/HW_HAL.cpp @@ -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); diff --git a/Software/VNA_embedded/Application/Hardware.hpp b/Software/VNA_embedded/Application/Hardware.hpp index 5c75117..5b14d21 100644 --- a/Software/VNA_embedded/Application/Hardware.hpp +++ b/Software/VNA_embedded/Application/Hardware.hpp @@ -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 {