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

View file

@ -218,6 +218,47 @@ void App_Start() {
Cal::setFrequencyCal(recv_packet.frequencyCorrection.ppm);
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
break;
case Protocol::PacketType::RequestDirectRegisterInfo:
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
LOG_INFO("Requested register devices, sending %d packets", RegisterDevice::getNumDevices());
for(uint8_t i=0;i<RegisterDevice::getNumDevices();i++) {
auto dev = RegisterDevice::getDevice(i);
Protocol::PacketInfo send;
send.type = Protocol::PacketType::DirectRegisterInfo;
send.directRegInfo = dev->getInfo();
Communication::Send(send);
}
break;
case Protocol::PacketType::DirectRegisterWrite:
if(recv_packet.directRegWrite.device >= RegisterDevice::getNumDevices()) {
// invalid device
Communication::SendWithoutPayload(Protocol::PacketType::Nack);
} else {
LOG_INFO(
"Register write: dev %u, address %u, data 0x%08x",
recv_packet.directRegWrite.device,
recv_packet.directRegWrite.address,
(uint32_t) recv_packet.directRegWrite.data);
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
auto dev = RegisterDevice::getDevice(recv_packet.directRegWrite.device);
dev->writeRegister(recv_packet.directRegWrite.address, recv_packet.directRegWrite.data);
}
break;
case Protocol::PacketType::DirectRegisterRead:
if(recv_packet.directRegWrite.device >= RegisterDevice::getNumDevices()) {
// invalid device
Communication::SendWithoutPayload(Protocol::PacketType::Nack);
} else {
Communication::SendWithoutPayload(Protocol::PacketType::Ack);
auto dev = RegisterDevice::getDevice(recv_packet.directRegWrite.device);
Protocol::PacketInfo send;
send.type = Protocol::PacketType::DirectRegisterWrite;
send.directRegWrite.device = recv_packet.directRegRead.device;
send.directRegWrite.address = recv_packet.directRegRead.address;
send.directRegWrite.data = dev->readRegister(recv_packet.directRegRead.address);
Communication::Send(send);
}
break;
default:
// this packet type is not supported
Communication::SendWithoutPayload(Protocol::PacketType::Nack);

View file

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

View file

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

View file

@ -0,0 +1,24 @@
#include <RegisterDevice.hpp>
#include <cstring>
uint8_t RegisterDevice::cnt = 0;
std::array<RegisterDevice*, RegisterDevice::maxDevices> RegisterDevice::devices;
Protocol::DirectRegisterInfo RegisterDevice::getInfo() {
Protocol::DirectRegisterInfo i;
i.num = num;
strncpy(i.name, name, sizeof(i.name));
i.name[sizeof(i.name) - 1] = '\0';
strncpy(i.type, type, sizeof(i.type));
i.type[sizeof(i.type) - 1] = '\0';
return i;
}
RegisterDevice* RegisterDevice::getDevice(uint8_t num) {
if(num < cnt) {
return devices[num];
} else {
return nullptr;
}
}

View file

@ -0,0 +1,41 @@
#pragma once
#include <cstdint>
#include <array>
#include "Protocol.hpp"
extern int global;
class RegisterDevice {
public:
constexpr RegisterDevice(const char *type, const char *name) :
type(type),
name(name),
num(0)
{
num = cnt;
if(cnt < maxDevices) {
devices[cnt] = this;
cnt++;
} else {
// not enough room in array. A debug message would be useful here
// but the constructor is called before any hardware initialization
// so we can do nothing here
}
}
virtual void writeRegister(uint32_t address, uint64_t data) = 0;
virtual uint64_t readRegister(uint32_t address) = 0;
Protocol::DirectRegisterInfo getInfo();
static uint8_t getNumDevices() { return cnt;};
static RegisterDevice *getDevice(uint8_t num);
private:
static constexpr uint8_t maxDevices = 10;
static std::array<RegisterDevice*,maxDevices> devices;
static uint8_t cnt;
const char *type;
const char *name;
uint8_t num;
};

View file

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

View file

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

View file

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

View file

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