mirror of
https://github.com/jankae/LibreVNA.git
synced 2026-01-06 16:49:59 +01:00
Split register fields + save/load register values
This commit is contained in:
parent
9f33d47da0
commit
b99f443673
|
|
@ -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<int>(&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<int>(&QSpinBox::valueChanged), updateVCO);
|
||||
QObject::connect(ui->frac, qOverload<int>(&QSpinBox::valueChanged), updateVCO);
|
||||
QObject::connect(ui->FB, &QCheckBox::toggled, updateVCO);
|
||||
QObject::connect(ui->INT, &QCheckBox::toggled, updateVCO);
|
||||
QObject::connect(ui->M, qOverload<int>(&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<int>(&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<int>(&QComboBox::currentIndexChanged), updateOutB);
|
||||
QObject::connect(ui->BDIV, qOverload<int>(&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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ public:
|
|||
MAX2871();
|
||||
~MAX2871();
|
||||
|
||||
void fromJSON(nlohmann::json j) override;
|
||||
nlohmann::json toJSON() override;
|
||||
|
||||
private:
|
||||
Ui::MAX2871Widget *ui;
|
||||
};
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -4,7 +4,13 @@
|
|||
#include "register.h"
|
||||
#include "max2871.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QFileDialog>
|
||||
#include <QDebug>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -27,45 +27,12 @@
|
|||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Open|QDialogButtonBox::Save</set>
|
||||
<set>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>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
#include "register.h"
|
||||
#include <exception>
|
||||
#include <QHeaderView>
|
||||
#include <QDebug>
|
||||
|
||||
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<int>(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<int>(old_gui)) {
|
||||
updating = true;
|
||||
cb->setCurrentIndex(old_gui);
|
||||
updating = false;
|
||||
}
|
||||
});
|
||||
connect(cb, qOverload<int>(&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<int>(&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<width;i++) {
|
||||
mask |= (1UL << i);
|
||||
}
|
||||
unsigned long mask = (1UL << width) - 1;
|
||||
mask <<= pos;
|
||||
auto masked = value & mask;
|
||||
masked >>= 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;i<width;i++) {
|
||||
mask |= (1UL << i);
|
||||
}
|
||||
unsigned long mask = (1UL << width) - 1;
|
||||
newval &= mask;
|
||||
newval <<= pos;
|
||||
mask <<= pos;
|
||||
|
|
|
|||
|
|
@ -14,8 +14,12 @@ 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);
|
||||
// pos: bitpos at which the field in the register starts which is associated with the UI element
|
||||
// width: amount of bits in the field
|
||||
// ui_bitoffset: set to LSB of the ui element in this register field (only required for elements that
|
||||
// are not represented as one field in a register, e.g. when splitting bits across multiple registers)
|
||||
void assignUI(QComboBox *cb, int pos, int width, int ui_bitoffset = 0);
|
||||
void assignUI(QSpinBox *sb, int pos, int width, int ui_bitoffset = 0);
|
||||
|
||||
QString hexString();
|
||||
bool setFromString(QString hex);
|
||||
|
|
@ -37,6 +41,7 @@ private:
|
|||
int address;
|
||||
int width;
|
||||
unsigned long value;
|
||||
bool updating; // for preventing endless recursion when updating register/its UI connections
|
||||
};
|
||||
|
||||
#endif // REGISTER_H
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "max2871.h"
|
||||
#include "Device/device.h"
|
||||
|
||||
RegisterDevice *RegisterDevice::create(Device *dev, int number, QString partnumber)
|
||||
RegisterDevice *RegisterDevice::create(Device *dev, int number, QString partnumber, QString name)
|
||||
{
|
||||
RegisterDevice *regdev = nullptr;
|
||||
if(partnumber == "MAX2871") {
|
||||
|
|
@ -13,6 +13,7 @@ RegisterDevice *RegisterDevice::create(Device *dev, int number, QString partnumb
|
|||
regdev->dev = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Register*> regs;
|
||||
QWidget *widget;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue