diff --git a/Software/PC_Application/Device/RegisterAccess/max2871.cpp b/Software/PC_Application/Device/RegisterAccess/max2871.cpp index b42b62d..e021adf 100644 --- a/Software/PC_Application/Device/RegisterAccess/max2871.cpp +++ b/Software/PC_Application/Device/RegisterAccess/max2871.cpp @@ -10,12 +10,11 @@ MAX2871::MAX2871() 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->INT, 31); regs[0]->assignUI(ui->N, 15, 16); regs[0]->assignUI(ui->frac, 3, 12); @@ -26,7 +25,7 @@ MAX2871::MAX2871() 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->MUX, 26, 3); regs[2]->assignUI(ui->DBR, 25); regs[2]->assignUI(ui->RDIV2, 24); regs[2]->assignUI(ui->R, 14, 10); @@ -50,9 +49,10 @@ MAX2871::MAX2871() 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->BS, 24, 2, 8); regs[4]->assignUI(ui->FB, 23); regs[4]->assignUI(ui->DIVA, 20, 3); + regs[4]->assignUI(ui->BS, 12, 8); regs[4]->assignUI(ui->SDVCO, 11); regs[4]->assignUI(ui->MTLD, 10); regs[4]->assignUI(ui->BDIV, 9, 1); @@ -61,17 +61,98 @@ MAX2871::MAX2871() 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->VAS_DLY, 29, 2); 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->MUX, 18, 1, 3); 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); + + ui->ref->setPrefixes(" kMG"); + ui->ref->setUnit("Hz"); + ui->freqRef->setPrefixes(" kMG"); + ui->freqRef->setUnit("Hz"); + ui->freqPFD->setPrefixes(" kMG"); + ui->freqPFD->setUnit("Hz"); + ui->freqVCO->setPrefixes(" kMG"); + ui->freqVCO->setUnit("Hz"); + ui->freqOutA->setPrefixes(" kMG"); + ui->freqOutA->setUnit("Hz"); + ui->freqOutB->setPrefixes(" kMG"); + ui->freqOutB->setUnit("Hz"); + + // user friendly frequency calculation connections + QObject::connect(ui->ref, &SIUnitEdit::valueChanged, ui->freqRef, &SIUnitEdit::setValue); + auto updatePFD = [=]() { + auto pfd = ui->ref->value(); + if(ui->DBR->isChecked()) { + pfd *= 2; + } + pfd /= ui->R->value(); + if(ui->RDIV2->isChecked()) { + pfd /= 2; + } + ui->freqPFD->setValue(pfd); + bool valid = pfd <= 125000000 || (pfd <= 140000000 && ui->INT->isChecked()); + // check value and set background + QPalette palette; + palette.setColor(QPalette::Base,valid ? Qt::white : Qt::red); + ui->freqPFD->setPalette(palette); + }; + QObject::connect(ui->ref, &SIUnitEdit::valueChanged, updatePFD); + QObject::connect(ui->INT, &QCheckBox::toggled, updatePFD); + QObject::connect(ui->DBR, &QCheckBox::toggled, updatePFD); + QObject::connect(ui->RDIV2, &QCheckBox::toggled, updatePFD); + QObject::connect(ui->R, qOverload(&QSpinBox::valueChanged), updatePFD); + auto updateVCO = [=]() { + auto pfd = ui->freqPFD->value(); + auto vco = pfd * ui->N->value(); + if(!ui->INT->isChecked()){ + vco += pfd * (double) ui->frac->value() / ui->M->value(); + } + if(!ui->FB->isChecked()) { + // using divided down vco output + // multiply by divider ratio (but only up to 16) + auto mult = 1UL << ui->DIVA->currentIndex(); + if(mult > 16) { + mult = 16; + } + vco *= mult; + } + ui->freqVCO->setValue(vco); + bool valid = vco >= 3000000000 && vco <= 6000000000; + // check value and set background + QPalette palette; + palette.setColor(QPalette::Base,valid ? Qt::white : Qt::red); + ui->freqVCO->setPalette(palette); + }; + QObject::connect(ui->freqPFD, &SIUnitEdit::valueChanged, updateVCO); + QObject::connect(ui->N, qOverload(&QSpinBox::valueChanged), updateVCO); + QObject::connect(ui->frac, qOverload(&QSpinBox::valueChanged), updateVCO); + QObject::connect(ui->FB, &QCheckBox::toggled, updateVCO); + QObject::connect(ui->INT, &QCheckBox::toggled, updateVCO); + QObject::connect(ui->M, qOverload(&QSpinBox::valueChanged), updateVCO); + auto updateOutA = [=]() { + auto out_a = ui->freqVCO->value() / (1 << ui->DIVA->currentIndex()); + ui->freqOutA->setValue(out_a); + }; + QObject::connect(ui->freqVCO, &SIUnitEdit::valueChanged, updateOutA); + QObject::connect(ui->DIVA, qOverload(&QComboBox::currentIndexChanged), updateOutA); + auto updateOutB = [=]() { + auto out_b = ui->freqVCO->value(); + if(ui->BDIV->currentIndex() == 0) { + out_b /= (1 << ui->DIVA->currentIndex()); + } + ui->freqOutB->setValue(out_b); + }; + QObject::connect(ui->freqVCO, &SIUnitEdit::valueChanged, updateOutB); + QObject::connect(ui->DIVA, qOverload(&QComboBox::currentIndexChanged), updateOutB); + QObject::connect(ui->BDIV, qOverload(&QComboBox::currentIndexChanged), updateOutB); + + ui->ref->setValue(100000000); } MAX2871::~MAX2871() @@ -79,3 +160,23 @@ MAX2871::~MAX2871() delete ui; } +void MAX2871::fromJSON(nlohmann::json j) +{ + registersFromJSON(j["registers"]); + ui->cbRef->setCurrentText(QString::fromStdString(j["reference"])); + if(ui->cbRef->currentText() == "Manual") { + ui->ref->setValue(j["reference_frequency"]); + } +} + +nlohmann::json MAX2871::toJSON() +{ + nlohmann::json j; + j["registers"] = registersToJSON(); + j["reference"] = ui->cbRef->currentText().toStdString(); + if(ui->cbRef->currentText() == "Manual") { + j["reference_frequency"] = ui->ref->value(); + } + return j; +} + diff --git a/Software/PC_Application/Device/RegisterAccess/max2871.h b/Software/PC_Application/Device/RegisterAccess/max2871.h index 8fa2780..09aa2f2 100644 --- a/Software/PC_Application/Device/RegisterAccess/max2871.h +++ b/Software/PC_Application/Device/RegisterAccess/max2871.h @@ -14,6 +14,9 @@ public: MAX2871(); ~MAX2871(); + void fromJSON(nlohmann::json j) override; + nlohmann::json toJSON() override; + private: Ui::MAX2871Widget *ui; }; diff --git a/Software/PC_Application/Device/RegisterAccess/max2871widget.ui b/Software/PC_Application/Device/RegisterAccess/max2871widget.ui index 16d362c..41ec1ca 100644 --- a/Software/PC_Application/Device/RegisterAccess/max2871widget.ui +++ b/Software/PC_Application/Device/RegisterAccess/max2871widget.ui @@ -6,8 +6,8 @@ 0 0 - 1432 - 586 + 1283 + 638 @@ -15,7 +15,7 @@ - + @@ -31,7 +31,631 @@ - + + + + + + + + + + + + Reference Input + + + + + + + Manual + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Calculated Frequencies + + + + + + Ref In: + + + + + + + true + + + true + + + + + + + PFD: + + + + + + + true + + + true + + + + + + + VCO: + + + + + + + true + + + true + + + + + + + Out A: + + + + + + + true + + + true + + + + + + + Out B: + + + + + + + true + + + true + + + + + + + + + + + + + + + + + + Reference + + + + + + Doubler + + + + + + + Div-by-2 + + + + + + + + + R-divider: + + + + + + + 1023 + + + + + + + + + R/N counter reset + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Divider Settings + + + + + + Integer-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 A + + + + + + + + + Out A Power: + + + + + + + + -4 dBm + + + + + -1 dBm + + + + + +2 dBm + + + + + +5 dBm + + + + + + + + + + + + + + + + + + + Shutdown + + + + + + Shutdown VCO + + + + + + + Shutdown VCO LDO + + + + + + + Shutdown Reference Input + + + + + + + Shutdown VCO Divider + + + + + + + Shutdown Mode + + + + + + + Shutdown PLL + + + + + + @@ -135,865 +759,401 @@ + + + + - + - Shutdown + VCO - + - + + + + + VCO Band: + + + + + + + 63 + + + + + + + - Shutdown VCO + VAS Shutdown - + - Shutdown VCO LDO + VAS temperature compensation - + + + + + VAS_DLY: + + + + + + + + 00 (when VAS_TEMP=0) + + + + + Unknown + + + + + Unknown + + + + + 11 (when VAS_TEMP=1) + + + + + + + + - Shutdown Reference Input + Fundamental Feedback + + + + + + + + + + ADC + + + + + + Start - + - Shutdown VCO Divider + Valid Code - - - Shutdown Mode - - - - - - - Shutdown PLL - - + + + + + Mode: + + + + + + + + Disabled + + + + + Temperature + + + + + Reserved + + + + + Reserved + + + + + Tune pin + + + + + Reserved + + + + + Reserved + + + + + Reserved + + + + + - - - - - - - - - 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 - - + + + Mixed + + + + + + Mute until lock + + + + + + + Mute Delay + + + + + + + Cycle Slip Mode + + + + + + + Integer mode when F=0 + + + + + + + Double buffer mode + + + + + - + - Linearity: + Clock Divider Mode: - + - Disabled + Mute until Lock Delay - 10% + Fast-lock enabled - 20% + Phase Adjustment mode - 30% + Reserved - + - Test: + Noise Mode: - + - Normal mode + Low-noise - Long Reset mode + Reserved - Force source + Low-spur 1 - Force sink + Low-spur 2 - + - Current: + MUX Pin: - - - 15 - + + + + 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 + + - + - Polarity: + Band Select: - - - - Negative - - - - - Positive - - + + + 1023 + + + + + + + Clock Divider: + - - - High Impedance + + + 4095 - - - - - - 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 - - - - - - - - - + + + @@ -1001,6 +1161,13 @@ + + + SIUnitEdit + QLineEdit +
CustomWidgets/siunitedit.h
+
+
diff --git a/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.cpp b/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.cpp index 76bc1f5..982e06b 100644 --- a/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.cpp +++ b/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.cpp @@ -4,7 +4,13 @@ #include "register.h" #include "max2871.h" +#include +#include #include +#include +#include + +using namespace std; RawRegisterDialog::RawRegisterDialog(Device *dev, QWidget *parent) : QDialog(parent), @@ -20,6 +26,60 @@ RawRegisterDialog::RawRegisterDialog(Device *dev, QWidget *parent) : // trigger extraction of device information, this will trigger the receivedDirectRegisterInfo slot which will further populate the dialog dev->SendCommandWithoutPayload(Protocol::PacketType::RequestDirectRegisterInfo); + + connect(ui->buttonBox->button(QDialogButtonBox::Save), &QPushButton::clicked, [=](){ + auto filename = QFileDialog::getSaveFileName(this, "Save register settigns", "", "Raw register file (*.regs)", nullptr, QFileDialog::DontUseNativeDialog); + if(filename.length() > 0) { + if(!filename.endsWith(".regs")) { + filename.append(".regs"); + } + nlohmann::json j; + for(auto dev : devices) { + nlohmann::json jdev; + jdev["partnumber"] = dev->getPartnumber().toStdString(); + jdev["settings"] = dev->toJSON(); + j[dev->getName().toStdString()] = jdev; + } + ofstream file; + file.open(filename.toStdString()); + file << setw(4) << j << endl; + file.close(); + } + }); + connect(ui->buttonBox->button(QDialogButtonBox::Open), &QPushButton::clicked, [=](){ + auto filename = QFileDialog::getOpenFileName(this, "Load register settigns", "", "Raw register file (*.regs)", nullptr, QFileDialog::DontUseNativeDialog); + if(filename.length() > 0) { + ifstream file; + file.open(filename.toStdString()); + if(!file.is_open()) { + throw runtime_error("Unable to open file"); + } + + nlohmann::json j; + file >> j; + + for(auto jdev : j.items()) { + auto name = QString::fromStdString(jdev.key()); + bool found = false; + for(auto dev : devices) { + if(dev->getName() == name) { + // potential match + auto part = QString::fromStdString(jdev.value()["partnumber"]); + if(part == dev->getPartnumber()) { + dev->fromJSON(jdev.value()["settings"]); + } else { + qWarning() << "Got registers for device" << name <<", but partnumber does not match"; + } + found = true; + break; + } + } + if(!found) { + qWarning() << "Got registers for device" << name <<", but got no device with that name"; + } + } + } + }); } RawRegisterDialog::~RawRegisterDialog() @@ -33,7 +93,7 @@ void RawRegisterDialog::receivedDirectRegisterInfo(Protocol::DirectRegisterInfo qWarning() << "Received invalid register device:" << info.num; return; } - auto regdev = RegisterDevice::create(dev, info.num, info.type); + auto regdev = RegisterDevice::create(dev, info.num, info.type, info.name); if(!regdev) { qWarning() << "Unable to create register device" << info.type <<", unknown type"; return; diff --git a/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.ui b/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.ui index b4d64f1..0e5cd43 100644 --- a/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.ui +++ b/Software/PC_Application/Device/RegisterAccess/rawregisterdialog.ui @@ -27,45 +27,12 @@ Qt::Horizontal - QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Open|QDialogButtonBox::Save + 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 index 13490b8..600844c 100644 --- a/Software/PC_Application/Device/RegisterAccess/register.cpp +++ b/Software/PC_Application/Device/RegisterAccess/register.cpp @@ -1,12 +1,14 @@ #include "register.h" #include #include +#include Register::Register(QString name, int address, int width) : QObject(nullptr), name(name), address(address), - width(width) + width(width), + updating(false) { value = 0; } @@ -28,27 +30,49 @@ void Register::assignUI(QCheckBox *cb, int bitpos, bool inverted) }); } -void Register::assignUI(QComboBox *cb, int pos, int width) +void Register::assignUI(QComboBox *cb, int pos, int width, int ui_bitoffset) { connect(this, &Register::valueChanged, [=]() { auto value = getValue(pos, width); - if(cb->count() > static_cast(value)) { - cb->setCurrentIndex(value); + auto mask = (1UL << width) - 1; + mask <<= ui_bitoffset; + value <<= ui_bitoffset; + auto old_gui = cb->currentIndex(); + old_gui &= ~mask; + old_gui |= value; + if(cb->count() > static_cast(old_gui)) { + updating = true; + cb->setCurrentIndex(old_gui); + updating = false; } }); connect(cb, qOverload(&QComboBox::currentIndexChanged), [=](int index){ - setValue(index, pos, width); + if(!updating) { + index >>= ui_bitoffset; + setValue(index, pos, width); + } }); } -void Register::assignUI(QSpinBox *sb, int pos, int width) +void Register::assignUI(QSpinBox *sb, int pos, int width, int ui_bitoffset) { connect(this, &Register::valueChanged, [=]() { auto value = getValue(pos, width); - sb->setValue(value); + auto mask = (1UL << width) - 1; + mask <<= ui_bitoffset; + value <<= ui_bitoffset; + auto old_gui = sb->value(); + old_gui &= ~mask; + old_gui |= value; + updating = true; + sb->setValue(old_gui); + updating = false; }); connect(sb, qOverload(&QSpinBox::valueChanged), [=](int index){ - setValue(index, pos, width); + if(!updating) { + index >>= ui_bitoffset; + setValue(index, pos, width); + } }); } @@ -74,10 +98,7 @@ unsigned long Register::getValue() unsigned long Register::getValue(int pos, int width) { - unsigned long mask = 0; - for(int i=0;i>= pos; @@ -91,10 +112,7 @@ void Register::setValue(unsigned long newval) void Register::setValue(unsigned long newval, int pos, int width) { - unsigned long mask = 0; - for(int i=0;idev = dev; regdev->number = number; regdev->partnumber = partnumber; + regdev->name = name; // read initial register content Protocol::PacketInfo p; @@ -45,6 +46,16 @@ RegisterDevice::RegisterDevice() widget = new QWidget; } +QString RegisterDevice::getName() const +{ + return name; +} + +QString RegisterDevice::getPartnumber() const +{ + return partnumber; +} + QWidget *RegisterDevice::getWidget() const { return widget; @@ -64,3 +75,25 @@ void RegisterDevice::addRegister(Register *reg) }); } +nlohmann::json RegisterDevice::registersToJSON() +{ + nlohmann::json j; + for(auto r : regs) { + j[r->getAddress()] = r->getValue(); + } + return j; +} + +void RegisterDevice::registersFromJSON(nlohmann::json j) +{ + for(auto val : j.items()) { + auto address = QString::fromStdString(val.key()).toInt(); + for(auto r : regs) { + if(r->getAddress() == address) { + r->setValue(val.value()); + break; + } + } + } +} + diff --git a/Software/PC_Application/Device/RegisterAccess/registerdevice.h b/Software/PC_Application/Device/RegisterAccess/registerdevice.h index 87aa795..a38e706 100644 --- a/Software/PC_Application/Device/RegisterAccess/registerdevice.h +++ b/Software/PC_Application/Device/RegisterAccess/registerdevice.h @@ -7,26 +7,30 @@ #include "savable.h" #include "Device/device.h" -class RegisterDevice //: public Savable +class RegisterDevice : public Savable { public: - static RegisterDevice *create(Device *dev, int number, QString partnumber); + static RegisterDevice *create(Device *dev, int number, QString partnumber, QString name); ~RegisterDevice(); void setRegister(int address, unsigned long value); -// void fromJSON(nlohmann::json j) override; -// nlohmann::json toJSON() override; QWidget *getWidget() const; + QString getPartnumber() const; + QString getName() const; protected: void addRegister(Register *reg); + nlohmann::json registersToJSON(); + void registersFromJSON(nlohmann::json j); + RegisterDevice(); Device *dev; int number; QString partnumber; + QString name; std::vector regs; QWidget *widget; };