More fixes to memories and .pro file

rigcreator
Phil Taylor 2023-05-03 19:08:20 +01:00
rodzic e6f20ee45f
commit a7c04e98e9
8 zmienionych plików z 335 dodań i 216 usunięć

Wyświetl plik

@ -45,104 +45,14 @@ memories::memories(rigCapabilities rigCaps, QWidget *parent) :
ui->vfoMode->hide();
ui->memoryMode->hide();
// Hide all columns except recall
for (int i=1;i<ui->table->columnCount();i++)
{
ui->table->hideColumn(i);
}
foreach (auto parse, rigCaps.memParser) {
switch (parse.spec)
{
case 'a':
ui->groupLabel->show();
ui->group->show();
ui->vfoMode->show();
ui->memoryMode->show();
break;
case 'b':
ui->table->showColumn(columnNum);
break;
case 'c':
ui->table->showColumn(columnMemory);
break;
case 'd':
ui->table->showColumn(columnFrequency);
break;
case 'e':
ui->table->showColumn(columnMode);
break;
case 'f':
ui->table->showColumn(columnFilter);
break;
case 'g':
ui->table->showColumn(columnData);
break;
case 'h':
ui->table->showColumn(columnDuplex);
ui->table->showColumn(columnToneMode);
break;
case 'i':
ui->table->showColumn(columnData);
ui->table->showColumn(columnToneMode);
break;
case 'j':
ui->table->showColumn(columnDSQL);
break;
case 'k':
ui->table->showColumn(columnTone);
break;
case 'l':
ui->table->showColumn(columnTSQL);
break;
case 'm':
ui->table->showColumn(columnDTCSPolarity);
break;
case 'n':
ui->table->showColumn(columnDTCS);
break;
case 'o':
ui->table->showColumn(columnDVSquelch);
break;
case 'p':
ui->table->showColumn(columnOffset);
break;
case 'q':
ui->table->showColumn(columnUR);
break;
case 'r':
ui->table->showColumn(columnR1);
break;
case 's':
ui->table->showColumn(columnR2);
break;
case 't':
ui->table->showColumn(columnName);
break;
case 'u':
break;
case 'v':
break;
case 'w':
break;
case 'x':
break;
case 'y':
break;
case 'z':
break;
default:
break;
}
}
ui->group->blockSignals(true);
for (int i=1;i<=rigCaps.memGroups;i++) {
ui->group->addItem(QString("Group %0").arg(i,2,10,QChar('0')));
}
if (rigCaps.commands.contains(funcSatelliteMode)){
ui->group->addItem("Satellite");
}
ui->group->setCurrentIndex(-1);
ui->group->blockSignals(false);
@ -320,7 +230,9 @@ void memories::rowDeleted(quint32 mem)
void memories::on_table_cellChanged(int row, int col)
{
Q_UNUSED(col)
// If the import is updating a hidden column, ignore it.
if (ui->table->isColumnHidden(col))
return;
if (row != currentRow || currentMemory == Q_NULLPTR)
{
@ -430,7 +342,7 @@ void memories::on_table_cellChanged(int row, int col)
bool write=true;
for (int f=1; f<ui->table->columnCount();f++)
{
if (!ui->table->isColumnHidden(f) && (ui->table->item(row,f) == NULL))
if (!ui->table->isColumnHidden(f) && ui->table->item(row,f) == NULL)
write=false;
}
if (write) {
@ -446,6 +358,106 @@ void memories::on_group_currentIndexChanged(int index)
ui->table->blockSignals(true);
ui->table->setRowCount(0);
ui->table->blockSignals(false);
// Hide all columns except recall
for (int i=1;i<ui->table->columnCount();i++)
{
ui->table->hideColumn(i);
}
QVector<memParserFormat> parser;
if (ui->group->currentText() == "Satellite") {
parser = rigCaps.memParser;
} else {
parser = rigCaps.satParser;
}
foreach (auto parse, parser) {
switch (parse.spec)
{
case 'a':
ui->groupLabel->show();
ui->group->show();
ui->vfoMode->show();
ui->memoryMode->show();
break;
case 'b':
ui->table->showColumn(columnNum);
break;
case 'c':
ui->table->showColumn(columnMemory);
break;
case 'd':
ui->table->showColumn(columnFrequency);
break;
case 'e':
ui->table->showColumn(columnMode);
break;
case 'f':
ui->table->showColumn(columnFilter);
break;
case 'g':
ui->table->showColumn(columnData);
break;
case 'h':
ui->table->showColumn(columnDuplex);
ui->table->showColumn(columnToneMode);
break;
case 'i':
ui->table->showColumn(columnData);
ui->table->showColumn(columnToneMode);
break;
case 'j':
ui->table->showColumn(columnDSQL);
break;
case 'k':
ui->table->showColumn(columnTone);
break;
case 'l':
ui->table->showColumn(columnTSQL);
break;
case 'm':
ui->table->showColumn(columnDTCSPolarity);
break;
case 'n':
ui->table->showColumn(columnDTCS);
break;
case 'o':
ui->table->showColumn(columnDVSquelch);
break;
case 'p':
ui->table->showColumn(columnOffset);
break;
case 'q':
ui->table->showColumn(columnUR);
break;
case 'r':
ui->table->showColumn(columnR1);
break;
case 's':
ui->table->showColumn(columnR2);
break;
case 't':
ui->table->showColumn(columnName);
break;
case 'u':
break;
case 'v':
break;
case 'w':
break;
case 'x':
break;
case 'y':
break;
case 'z':
break;
default:
break;
}
}
for (quint16 m=1;m<=rigCaps.memories;m++)
{
if (rigCaps.memGroups>1)
@ -609,3 +621,147 @@ QStandardItemModel* memories::createModel(QStandardItemModel* model, QStringList
return model;
}
void memories::on_csvImport_clicked()
{
QString file = QFileDialog::getOpenFileName(this,"Select import filename","","CSV Files (*.csv)");
if (!file.isEmpty())
{
ui->table->sortByColumn(0,Qt::AscendingOrder); // Force natural order
QFile data(file);
if (!data.open(QIODevice::ReadOnly)) {
qInfo() << "Couldn't open file for .csv export" << data.errorString();
return;
}
QTextStream input(&data);
QStringList row;
int rows=0;
while (readCSVRow(input, &row)) {
qInfo() << row;
if (!rows++)
continue; // Skip the first row
int count=-1;
for(int i=0;i<ui->table->rowCount();i++) {
if (ui->table->item(i, 1)->text().toInt() == row[0].toInt()) {
count=i;
break;
}
}
if (count == -1)
{
// We need to add a new row
count = ui->table->rowCount();
ui->table->insertRow(count);
QPushButton* recall = new QPushButton("Recall");
ui->table->setCellWidget(count,columnRecall,recall);
connect(recall, &QPushButton::clicked, this,
[=]() { qInfo() << "Recalling" << row[0].toInt(); emit recallMemory(quint32((ui->group->currentIndex()+1) << 16) | (row[0].toInt()));});
}
// count is now the row we need to work on.
for (int i=0; i<row.size();i++)
{
if (i < ui->table->columnCount()-1) {
ui->table->model()->setData(ui->table->model()->index(count,i+1),QString(row[i]));
}
}
}
}
}
void memories::on_csvExport_clicked()
{
QString file = QFileDialog::getSaveFileName(this,"Select export filename","","CSV Files (*.csv)");
if (!file.isEmpty())
{
ui->table->sortByColumn(0,Qt::AscendingOrder); // Force natural order
QFile data(file);
if (data.open(QFile::WriteOnly | QIODevice::Truncate)) {
QTextStream output(&data);
for(int i=2;i<ui->table->columnCount();i++) {
output << "\"" << ui->table->horizontalHeaderItem(i)->text() << "\"";
if (i < ui->table->columnCount()-1)
output << ",";
else
output << "\n";
}
for(int i=0;i<ui->table->rowCount();i++) {
for(int j=1;j<ui->table->columnCount();j++) {
output << "\"" << ((ui->table->item(i,j) == NULL) ? " " : ui->table->item(i,j)->text().trimmed()) << "\"";
if (j < ui->table->columnCount()-1)
output << ",";
else
output << "\n";
}
}
}
data.close();
}
}
// Public Domain CSV parser from user iamantony
// https://www.appsloveworld.com/cplus/100/37/parsing-through-a-csv-file-in-qt
bool memories::readCSVRow(QTextStream &in, QStringList *row) {
static const int delta[][5] = {
// , " \n ? eof
{ 1, 2, -1, 0, -1 }, // 0: parsing (store char)
{ 1, 2, -1, 0, -1 }, // 1: parsing (store column)
{ 3, 4, 3, 3, -2 }, // 2: quote entered (no-op)
{ 3, 4, 3, 3, -2 }, // 3: parsing inside quotes (store char)
{ 1, 3, -1, 0, -1 }, // 4: quote exited (no-op)
// -1: end of row, store column, success
// -2: eof inside quotes
};
row->clear();
if (in.atEnd())
return false;
int state = 0, t;
char ch;
QString cell;
while (state >= 0) {
if (in.atEnd())
t = 4;
else {
in >> ch;
if (ch == ',') t = 0;
else if (ch == '\"') t = 1;
else if (ch == '\n') t = 2;
else t = 3;
}
state = delta[state][t];
switch (state) {
case 0:
case 3:
cell += ch;
break;
case -1:
case 1:
row->append(cell);
cell = "";
break;
}
}
if (state == -2) {
qInfo() << "End-of-file found while inside quotes.";
return false;
}
return true;
}

Wyświetl plik

@ -7,6 +7,7 @@
#include <QStandardItemModel>
#include <QHeaderView>
#include <QPushButton>
#include <QFileDialog>
#include "tablewidget.h"
#include "wfviewtypes.h"
@ -39,6 +40,11 @@ private slots:
void on_group_currentIndexChanged(int index);
void on_vfoMode_clicked();
void on_memoryMode_clicked();
void on_csvImport_clicked();
void on_csvExport_clicked();
bool readCSVRow (QTextStream &in, QStringList *row);
void receiveMemory(memoryType mem);
void rowAdded(int row);
void rowDeleted(quint32 mem);

Wyświetl plik

@ -44,6 +44,33 @@
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="csvImport">
<property name="text">
<string>.csv Import</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="csvExport">
<property name="text">
<string>.csv Export</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="memoryMode">
<property name="text">

Wyświetl plik

@ -1845,6 +1845,8 @@ void rigCommander::parseCommand()
return;
}
QVector<memParserFormat> memParser;
switch (func)
{
case funcFreqGet:
@ -1870,8 +1872,13 @@ void rigCommander::parseCommand()
this->parseMode();
}
break;
case funcSatelliteMemory:
memParser=rigCaps.satParser;
case funcMemoryContents:
{
if (memParser.isEmpty()) {
memParser=rigCaps.memParser;
}
// Parse the memory entry into a memoryType:
memoryType mem;
@ -1882,7 +1889,7 @@ void rigCommander::parseCommand()
// 16 is fixed 0x0;
// 19 is fixed 0x0;
*/
foreach (auto parse, rigCaps.memParser) {
foreach (auto parse, memParser) {
QByteArray data = payloadIn.mid(offset+parse.pos,parse.len);
switch (parse.spec)
{
@ -1964,44 +1971,6 @@ void rigCommander::parseCommand()
}
}
/*
if (rigCaps.memGroups > 1)
{
mem.group = bcdHexToUChar(payloadIn[2]);
mem.channel = bcdHexToUInt(payloadIn[3],payloadIn[4]);
mem.memory = payloadIn[5] & 0xf;
mem.frequency = parseFrequency(payloadIn,9);
mem.mode=(mode_kind)bcdHexToUChar(payloadIn[11]);
mem.filter=payloadIn[12];
mem.datamode=payloadIn[13];
mem.duplex=duplexMode(payloadIn[14] >> 4 & 0x0f);
mem.tonemode=payloadIn[14] & 0x0f;
mem.dsql = (payloadIn[15] >> 4 & 0x0f);
// 16 is fixed 0x0;
mem.tone = bcdHexToUInt(payloadIn[17],payloadIn[18]);
// 19 is fixed 0x0;
mem.tsql = bcdHexToUInt(payloadIn[20],payloadIn[21]);
mem.dtcsp = payloadIn[22];
mem.dtcs = bcdHexToUInt(payloadIn[23],payloadIn[24]);
mem.dvsql = bcdHexToUChar(payloadIn[25]);
mem.duplexOffset = parseFrequencyRptOffset(payloadIn.mid(25,4)); // Ignore first byte
memcpy(mem.UR,payloadIn.mid(29,8),sizeof(mem.UR));
memcpy(mem.R1,payloadIn.mid(37,8),sizeof(mem.R1));
memcpy(mem.R2,payloadIn.mid(45,8),sizeof(mem.R2));
memcpy(mem.name,payloadIn.mid(53,16),sizeof(mem.name));
} else {
mem.channel = bcdHexToUInt(payloadIn[2],payloadIn[3]);
mem.memory = payloadIn[4];
mem.frequency = parseFrequency(payloadIn,8);
mem.mode=(mode_kind)bcdHexToUChar(payloadIn[10]);
mem.filter=payloadIn[11];
mem.datamode=payloadIn[12]>>4 & 0x0f;
mem.tonemode=payloadIn[12] & 0x0f;
mem.tone = bcdHexToUInt(payloadIn[14],payloadIn[15]);
mem.tsql = bcdHexToUInt(payloadIn[17],payloadIn[18]);
memcpy(mem.name,payloadIn.mid(19,10),sizeof(mem.name));
}
*/
emit haveMemory(mem);
}
case funcMemoryClear:
@ -4439,6 +4408,7 @@ void rigCommander::determineRigCaps()
rigCaps.memGroups = settings->value("MemGroups",0).toUInt();
rigCaps.memories = settings->value("Memories",0).toUInt();
rigCaps.memFormat = settings->value("MemFormat","").toString();
rigCaps.satFormat = settings->value("SatFormat","").toString();
// Temporary QList to hold the function string lookup // I would still like to find a better way of doing this!
QHash<QString, funcs> funcsLookup;
@ -4600,7 +4570,7 @@ void rigCommander::determineRigCaps()
delete settings;
// Setup memory format.
// Setup memory formats.
static QRegularExpression memFmtEx("%(?<flags>[-+#0])?(?<pos>\\d+|\\*)?(?:\\.(?<width>\\d+|\\*))?(?<spec>[abcdefghijklmnopqrstuvwxyz])");
QRegularExpressionMatchIterator i = memFmtEx.globalMatch(rigCaps.memFormat);
@ -4608,9 +4578,15 @@ void rigCommander::determineRigCaps()
QRegularExpressionMatch qmatch = i.next();
if (qmatch.hasCaptured("spec") && qmatch.hasCaptured("pos") && qmatch.hasCaptured("width")) {
rigCaps.memParser.append(memParserFormat(qmatch.captured("spec").at(0).toLatin1(),qmatch.captured("pos").toInt(),qmatch.captured("width").toInt()));
qInfo() << QString("Captured: %0 pos: %1 len: %2").arg(rigCaps.memParser.at(rigCaps.memParser.size()-1).spec).
arg(rigCaps.memParser.at(rigCaps.memParser.size()-1).pos).
arg(rigCaps.memParser.at(rigCaps.memParser.size()-1).len);
}
}
QRegularExpressionMatchIterator i2 = memFmtEx.globalMatch(rigCaps.satFormat);
while (i2.hasNext()) {
QRegularExpressionMatch qmatch = i2.next();
if (qmatch.hasCaptured("spec") && qmatch.hasCaptured("pos") && qmatch.hasCaptured("width")) {
rigCaps.satParser.append(memParserFormat(qmatch.captured("spec").at(0).toLatin1(),qmatch.captured("pos").toInt(),qmatch.captured("width").toInt()));
}
}

Wyświetl plik

@ -110,6 +110,7 @@ void rigCreator::loadRigFile(QString file)
ui->memGroups->setText(settings->value("MemGroups","0").toString());
ui->memories->setText(settings->value("Memories","0").toString());
ui->memoryFormat->setText(settings->value("MemFormat","").toString());
ui->satelliteFormat->setText(settings->value("SatFormat","").toString());
ui->commands->setRowCount(0);
int numCommands = settings->beginReadArray("Commands");
@ -345,6 +346,7 @@ void rigCreator::saveRigFile(QString file)
settings->setValue("MemGroups",ui->memGroups->text().toInt());
settings->setValue("Memories",ui->memories->text().toInt());
settings->setValue("MemFormat",ui->memoryFormat->text());
settings->setValue("SatFormat",ui->satelliteFormat->text());
//settings->remove("Commands");

Wyświetl plik

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>978</width>
<height>593</height>
<height>624</height>
</rect>
</property>
<property name="sizePolicy">
@ -1079,25 +1079,43 @@
</layout>
</widget>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget_2">
<widget class="QWidget" name="verticalLayoutWidget_2">
<property name="geometry">
<rect>
<x>10</x>
<y>550</y>
<width>951</width>
<height>31</height>
<height>61</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Memory Format</string>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Main Memory Format</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="memoryFormat"/>
</item>
</layout>
</item>
<item>
<widget class="QLineEdit" name="memoryFormat"/>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Satellite Memory Format</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="satelliteFormat"/>
</item>
</layout>
</item>
</layout>
</widget>

Wyświetl plik

@ -221,6 +221,8 @@ struct rigCapabilities {
quint16 memories;
QString memFormat;
QVector<memParserFormat> memParser;
QString satFormat;
QVector<memParserFormat> satParser;
};

Wyświetl plik

@ -333,71 +333,3 @@ FORMS += wfmain.ui \
controllersetup.ui \
aboutbox.ui
HEADERS += wfmain.h \
colorprefs.h \
commhandler.h \
cwsender.h \
cwsidetone.h \
loggingwindow.h \
prefs.h \
printhex.h \
rigcommander.h \
freqmemory.h \
rigcreator.h \
rigidentities.h \
sidebandchooser.h \
tablewidget.h \
udpbase.h \
udphandler.h \
udpcivdata.h \
udpaudio.h \
logcategories.h \
pahandler.h \
rthandler.h \
audiohandler.h \
audioconverter.h \
calibrationwindow.h \
satellitesetup.h \
udpserver.h \
packettypes.h \
meter.h \
qledlabel.h \
pttyhandler.h \
resampler/speex_resampler.h \
resampler/arch.h \
resampler/resample_sse.h \
repeatersetup.h \
repeaterattributes.h \
rigctld.h \
rigstate.h \
ulaw.h \
usbcontroller.h \
controllersetup.h \
transceiveradjustments.h \
audiotaper.h \
selectradio.h \
tcpserver.h \
cluster.h \
database.h \
aboutbox.h \
wfviewtypes.h \
audiodevices.h
FORMS += wfmain.ui \
calibrationwindow.ui \
cwsender.ui \
loggingwindow.ui \
rigcreator.ui \
satellitesetup.ui \
selectradio.ui \
repeatersetup.ui \
transceiveradjustments.ui \
controllersetup.ui \
aboutbox.ui