Experimental direct register access

This commit is contained in:
Jan Käberich 2021-05-26 20:38:27 +02:00
parent 95a715233e
commit 9f33d47da0
26 changed files with 1761 additions and 8 deletions

View 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;
}

View 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

File diff suppressed because it is too large Load diff

View file

@ -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);
}
}

View file

@ -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

View file

@ -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>

View 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());
}
});
}

View 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

View file

@ -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);
});
}

View file

@ -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

View file

@ -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;
}

View file

@ -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();

View file

@ -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 \

View file

@ -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) {

View file

@ -48,6 +48,7 @@ private slots:
void DisconnectDevice();
int UpdateDeviceList();
void StartManualControl();
void RawRegisterAccess();
void UpdateReference();
void StartFirmwareUpdateDialog();
void DeviceNeedsUpdate(int reported, int expected);

View file

@ -6,9 +6,7 @@
#include "Calibration/calkit.h"
#include "touchstone.h"
#include <signal.h>
#include <complex>
static QApplication *app;

View file

@ -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"/>