From 8b7377f0960ff1b2936e4eccebd831312e673b56 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Tue, 14 Feb 2023 18:47:32 +0000 Subject: [PATCH 01/27] Add some feature in the hope of supporting sidetone --- cwsender.cpp | 61 ++++++++-- cwsender.h | 7 ++ cwsender.ui | 257 +++++++++++++++++++++++------------------ repeatersetup.cpp | 2 +- rigcommander.cpp | 70 ++++++++++- rigcommander.h | 3 + wfmain.cpp | 22 +++- wfmain.h | 2 + wfview.vcxproj | 20 ++-- wfview.vcxproj.filters | 12 ++ wfview.vcxproj.user | 8 +- wfviewtypes.h | 2 +- 12 files changed, 329 insertions(+), 137 deletions(-) diff --git a/cwsender.cpp b/cwsender.cpp index 3c66e83..eb08fcf 100644 --- a/cwsender.cpp +++ b/cwsender.cpp @@ -15,6 +15,7 @@ cwSender::cwSender(QWidget *parent) : ui->textToSendEdit->setFocus(); ui->statusbar->setToolTipDuration(3000); this->setToolTipDuration(3000); + connect(ui->textToSendEdit->lineEdit(), &QLineEdit::textEdited, this, &cwSender::textChanged); } cwSender::~cwSender() @@ -26,13 +27,14 @@ cwSender::~cwSender() void cwSender::showEvent(QShowEvent *event) { emit getCWSettings(); + QMainWindow::showEvent(event); (void)event; } void cwSender::handleKeySpeed(unsigned char wpm) { //qDebug(logCW()) << "Told that current WPM is" << wpm; - if((wpm >= 6) && (wpm <=48)) + if ((wpm >= 6) && (wpm <= 48)) { //qDebug(logCW()) << "Setting WPM UI control to" << wpm; ui->wpmSpin->blockSignals(true); @@ -41,6 +43,16 @@ void cwSender::handleKeySpeed(unsigned char wpm) } } +void cwSender::handleDashRatio(unsigned char ratio) +{ + if ((ratio >= 28) && (ratio <= 45)) + { + ui->dashSpin->blockSignals(true); + ui->dashSpin->setValue(double(ratio/10)); + ui->dashSpin->blockSignals(false); + } +} + void cwSender::handlePitch(unsigned char pitch) { quint16 cwPitch = round((((600.0 / 255.0) * pitch) + 300) / 5.0) * 5.0; ui->pitchSpin->blockSignals(true); @@ -68,6 +80,22 @@ void cwSender::handleCurrentModeUpdate(mode_kind mode) } } +void cwSender::textChanged(QString text) +{ + if (ui->sendImmediateChk->isChecked()) + { + if (text.back() == ' ') + { + int toSend = text.mid(0, 30).size(); + if (toSend > 0) { + emit sendCW(text.mid(0, 30)); + ui->transcriptText->appendPlainText(text.mid(0, 30)); + ui->textToSendEdit->clearEditText(); + } + } + } +} + void cwSender::on_sendBtn_clicked() { if( (ui->textToSendEdit->currentText().length() > 0) && @@ -114,12 +142,16 @@ void cwSender::on_wpmSpin_valueChanged(int wpm) emit setKeySpeed((unsigned char)wpm); } +void cwSender::on_dashSpin_valueChanged(double ratio) +{ + emit setDashRatio((unsigned char)double(ratio * 10)); +} + void cwSender::on_pitchSpin_valueChanged(int arg1) { // quint16 cwPitch = round((((600.0 / 255.0) * pitch) + 300) / 5.0) * 5.0; unsigned char pitch = 0; pitch = ceil((arg1 - 300) * (255.0 / 600.0)); - qDebug() << "Setting pitch" << pitch; emit setPitch(pitch); } @@ -189,7 +221,7 @@ void cwSender::runMacroButton(int buttonNumber) if(macroText[buttonNumber].isEmpty()) return; QString outText; - if(macroText[buttonNumber].contains("\%1")) + if(macroText[buttonNumber].contains("%1")) { outText = macroText[buttonNumber].arg(sequenceNumber, 3, 10, QChar('0')); sequenceNumber++; @@ -199,9 +231,20 @@ void cwSender::runMacroButton(int buttonNumber) } else { outText = macroText[buttonNumber]; } - emit sendCW(outText); + + if (ui->cutNumbersChk->isChecked()) + { + outText.replace("0", "T"); + outText.replace("9", "N"); + } + + for (int i = 0; i < outText.size(); i = i + 30) { + emit sendCW(outText.mid(i,30)); + } + ui->transcriptText->appendPlainText(outText); ui->textToSendEdit->setFocus(); + if( (currentMode==modeCW) || (currentMode==modeCW_R) ) { @@ -215,8 +258,8 @@ void cwSender::editMacroButton(int buttonNumber, QPushButton* btn) { bool ok; QString promptFirst = QString("Please enter the text for macro %1,\n" - "up to 30 characters.\n").arg(buttonNumber); - QString promptSecond = QString("You may use \"\%1\" to insert a sequence number."); + "up to 60 characters.\n").arg(buttonNumber); + QString promptSecond = QString("You may use \"%1\" to insert a sequence number."); QString prompt = promptFirst+promptSecond; QString newMacroText = QInputDialog::getText(this, "Macro Edit", @@ -225,12 +268,12 @@ void cwSender::editMacroButton(int buttonNumber, QPushButton* btn) if(!ok) return; - if(newMacroText.length() > 30) + if (newMacroText.length() > 60) { QMessageBox msgBox; msgBox.setText(QString("The text entered was too long \n" - "(max length is 30 characters).\n" - "Your input was %1 characters.").arg(newMacroText.length())); + "(max length is 60 characters).\n" + "Your input was %1 characters.").arg(newMacroText.length())); msgBox.exec(); this->raise(); return; diff --git a/cwsender.h b/cwsender.h index e07ccf7..b767135 100644 --- a/cwsender.h +++ b/cwsender.h @@ -29,12 +29,14 @@ signals: void sendCW(QString cwMessage); void stopCW(); void setKeySpeed(unsigned char wpm); + void setDashRatio(unsigned char ratio); void setPitch(unsigned char pitch); void setBreakInMode(unsigned char b); void getCWSettings(); public slots: void handleKeySpeed(unsigned char wpm); + void handleDashRatio(unsigned char ratio); void handlePitch(unsigned char pitch); void handleBreakInMode(unsigned char b); void handleCurrentModeUpdate(mode_kind mode); @@ -47,10 +49,14 @@ private slots: //void on_textToSendEdit_returnPressed(); + void textChanged(QString text); + void on_breakinCombo_activated(int index); void on_wpmSpin_valueChanged(int arg1); + void on_dashSpin_valueChanged(double arg1); + void on_pitchSpin_valueChanged(int arg1); void on_macro1btn_clicked(); @@ -79,6 +85,7 @@ private: Ui::cwSender *ui; QString macroText[11]; int sequenceNumber = 1; + int lastSentPos = 0; mode_kind currentMode; void processMacroButton(int buttonNumber, QPushButton *btn); void runMacroButton(int buttonNumber); diff --git a/cwsender.ui b/cwsender.ui index 3a9e358..20b8cc2 100644 --- a/cwsender.ui +++ b/cwsender.ui @@ -6,7 +6,7 @@ 0 0 - 886 + 822 451 @@ -177,115 +177,6 @@ - - - - QLayout::SetMinimumSize - - - - - - 0 - 0 - - - - <html><head/><body><p>Set the desired break-in mode:</p><p>1. None: You must manually key and unkey the radio.</p><p>2. Semi: Transmit is automatic and switches to receive at the end of the text.</p><p>3. Full: Same as semi, but with breaks between characters when possible.</p></body></html> - - - - Off - - - - - Semi - - - - - Full - - - - - - - - WPM: - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - Set the Words Per Minute - - - 6 - - - 48 - - - 20 - - - - - - - Break In - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - 300 - - - 900 - - - 5 - - - 600 - - - - - - - PITCH (Hz): - - - Qt::AlignCenter - - - - - @@ -370,6 +261,152 @@ + + + + QLayout::SetMinimumSize + + + + + + 0 + 0 + + + + <html><head/><body><p>Set the desired break-in mode:</p><p>1. None: You must manually key and unkey the radio.</p><p>2. Semi: Transmit is automatic and switches to receive at the end of the text.</p><p>3. Full: Same as semi, but with breaks between characters when possible.</p></body></html> + + + + Off + + + + + Semi + + + + + Full + + + + + + + + PITCH (Hz): + + + Qt::AlignCenter + + + + + + + WPM: + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + 300 + + + 900 + + + 5 + + + 600 + + + + + + + Break In + + + Qt::AlignCenter + + + + + + + 2.800000000000000 + + + 4.500000000000000 + + + 0.100000000000000 + + + 3.000000000000000 + + + + + + + Dash Ratio + + + + + + + + 0 + 0 + + + + Set the Words Per Minute + + + 6 + + + 48 + + + 20 + + + + + + + Cut Num + + + + + + + Send Immed + + + + + diff --git a/repeatersetup.cpp b/repeatersetup.cpp index 6af089f..f19d804 100644 --- a/repeatersetup.cpp +++ b/repeatersetup.cpp @@ -445,7 +445,7 @@ void repeaterSetup::showEvent(QShowEvent *event) emit getSplitModeEnabled(); if(rig.hasRepeaterModes) emit getRptDuplexOffset(); - + QMainWindow::showEvent(event); (void)event; } diff --git a/rigcommander.cpp b/rigcommander.cpp index b54acfe..3737ea4 100644 --- a/rigcommander.cpp +++ b/rigcommander.cpp @@ -1014,6 +1014,72 @@ void rigCommander::setCwPitch(unsigned char pitch) prepDataAndSend(payload); } +void rigCommander::getDashRatio() +{ + QByteArray payload; + switch (rigCaps.model) + { + case model705: + payload.setRawData("\x1A\x05\x02\x52", 4); + break; + case model9700: + payload.setRawData("\x1A\x05\x02\x24", 4); + break; + case model7100: + payload.setRawData("\x1A\x05\x01\x35", 4); + break; + case model7300: + payload.setRawData("\x1A\x05\x01\x61", 4); + break; + case model7610: + payload.setRawData("\x1A\x05\x02\x28", 4); + break; + case model7700: + payload.setRawData("\x1A\x05\x01\x34", 4); + break; + case model7850: + payload.setRawData("\x1A\x05\x02\x51", 4); + break; + default: + break; + } + prepDataAndSend(payload); +} + +void rigCommander::setDashRatio(unsigned char ratio) +{ + QByteArray payload; + switch (rigCaps.model) + { + case model705: + payload.setRawData("\x1A\x05\x02\x52", 4); + break; + case model9700: + payload.setRawData("\x1A\x05\x02\x24", 4); + break; + case model7100: + payload.setRawData("\x1A\x05\x01\x35", 4); + break; + case model7300: + payload.setRawData("\x1A\x05\x01\x61", 4); + break; + case model7610: + payload.setRawData("\x1A\x05\x02\x28", 4); + break; + case model7700: + payload.setRawData("\x1A\x05\x01\x34", 4); + break; + case model7850: + payload.setRawData("\x1A\x05\x02\x51", 4); + break; + default: + break; + } + + payload.append(bcdEncodeInt(ratio).at(1)); // Discard first byte + prepDataAndSend(payload); +} + void rigCommander::getPskTone() { QByteArray payload; @@ -1796,7 +1862,7 @@ void rigCommander::parseLevels() case '\x0C': state.set(KEYSPD, level, false); //qInfo(logRig()) << "Have received key speed in RC, raw level: " << level << ", WPM: " << (level/6.071)+6 << ", rounded: " << round((level/6.071)+6); - emit haveKeySpeed(round((level/6.071)+6)); + emit haveKeySpeed(round((level / 6.071) + 6)); break; case '\x0D': // Notch filder setting - ignore for now @@ -3198,6 +3264,8 @@ void rigCommander::parseDetailedRegisters1A05() case 90: emit haveLANGain(level); break; + case 228: + emit haveDashRatio(inputRaw); default: break; } diff --git a/rigcommander.h b/rigcommander.h index 740fda3..bc40264 100644 --- a/rigcommander.h +++ b/rigcommander.h @@ -129,6 +129,8 @@ public slots: void getPassband(); void getCwPitch(); void setCwPitch(unsigned char pitch); + void getDashRatio(); + void setDashRatio(unsigned char ratio); void getPskTone(); void setPskTone(unsigned char tone); void getRttyMark(); @@ -363,6 +365,7 @@ signals: // CW: void haveKeySpeed(unsigned char wpm); void haveCWBreakMode(unsigned char bmode); + void haveDashRatio(unsigned char ratio); // Rig State diff --git a/wfmain.cpp b/wfmain.cpp index 41aed09..cf58a30 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -355,10 +355,13 @@ void wfmain::rigConnections() connect(this, SIGNAL(setKeySpeed(unsigned char)), rig, SLOT(setKeySpeed(unsigned char))); connect(this, SIGNAL(getKeySpeed()), rig, SLOT(getKeySpeed())); connect(this, SIGNAL(setCwPitch(unsigned char)), rig, SLOT(setCwPitch(unsigned char))); + connect(this, SIGNAL(setDashRatio(unsigned char)), rig, SLOT(setDashRatio(unsigned char))); connect(this, SIGNAL(setCWBreakMode(unsigned char)), rig, SLOT(setBreakIn(unsigned char))); connect(this, SIGNAL(getCWBreakMode()), rig, SLOT(getBreakIn())); connect(this->rig, &rigCommander::haveKeySpeed, [=](const unsigned char& wpm) { cw->handleKeySpeed(wpm); }); + connect(this->rig, &rigCommander::haveDashRatio, + [=](const unsigned char& ratio) { cw->handleDashRatio(ratio); }); connect(this->rig, &rigCommander::haveCwPitch, [=](const unsigned char& speed) { cw->handlePitch(speed); }); connect(this->rig, &rigCommander::haveCWBreakMode, @@ -469,6 +472,7 @@ void wfmain::rigConnections() connect(this, SIGNAL(getPassband()), rig, SLOT(getPassband())); connect(this, SIGNAL(setPassband(quint16)), rig, SLOT(setPassband(quint16))); connect(this, SIGNAL(getCwPitch()), rig, SLOT(getCwPitch())); + connect(this, SIGNAL(getDashRatio()), rig, SLOT(getDashRatio())); connect(this, SIGNAL(getPskTone()), rig, SLOT(getPskTone())); connect(this, SIGNAL(getRttyMark()), rig, SLOT(getRttyMark())); connect(this, SIGNAL(getTone()), rig, SLOT(getTone())); @@ -1156,12 +1160,15 @@ void wfmain::setupMainUI() [=](const unsigned char &bmode) { issueCmd(cmdSetBreakMode, bmode);}); connect(this->cw, &cwSender::setKeySpeed, [=](const unsigned char& wpm) { issueCmd(cmdSetKeySpeed, wpm); }); + connect(this->cw, &cwSender::setDashRatio, + [=](const unsigned char& ratio) { issueCmd(cmdSetDashRatio, ratio); }); connect(this->cw, &cwSender::setPitch, [=](const unsigned char& pitch) { issueCmd(cmdSetCwPitch, pitch); }); connect(this->cw, &cwSender::getCWSettings, - [=]() { issueDelayedCommand(cmdGetKeySpeed); - issueDelayedCommand(cmdGetBreakMode);}); - + [=]() { issueDelayedCommand(cmdGetKeySpeed); + issueDelayedCommand(cmdGetBreakMode); + issueDelayedCommand(cmdGetCwPitch); + issueDelayedCommand(cmdGetDashRatio); }); } void wfmain::prepareSettingsWindow() @@ -3887,6 +3894,12 @@ void wfmain::doCmd(commandtype cmddata) emit setCwPitch(pitch); break; } + case cmdSetDashRatio: + { + unsigned char ratio = (*std::static_pointer_cast(data)); + emit setDashRatio(ratio); + break; + } case cmdSetATU: { bool atuOn = (*std::static_pointer_cast(data)); @@ -4012,6 +4025,9 @@ void wfmain::doCmd(cmds cmd) case cmdGetCwPitch: emit getCwPitch(); break; + case cmdGetDashRatio: + emit getDashRatio(); + break; case cmdGetPskTone: emit getPskTone(); break; diff --git a/wfmain.h b/wfmain.h index d305b55..e32a95c 100644 --- a/wfmain.h +++ b/wfmain.h @@ -141,6 +141,7 @@ signals: void getMeters(meterKind meter); void getPassband(); void getCwPitch(); + void getDashRatio(); void getPskTone(); void getRttyMark(); @@ -190,6 +191,7 @@ signals: void getKeySpeed(); void setKeySpeed(unsigned char wpm); void setCwPitch(unsigned char pitch); + void setDashRatio(unsigned char ratio); void setCWBreakMode(unsigned char breakMode); void getCWBreakMode(); diff --git a/wfview.vcxproj b/wfview.vcxproj index 658b730..df5a42e 100644 --- a/wfview.vcxproj +++ b/wfview.vcxproj @@ -111,7 +111,7 @@ $(SolutionDir)wfview-release\ - msvc2019_64_v62 + msvc2016_64_v632 core;gui;network;widgets;multimedia;printsupport;serialport;xml @@ -119,7 +119,7 @@ core;gui;network;widgets;multimedia;printsupport;serialport;xml - msvc2019_64_v62 + msvc2016_64_v632 core;gui;network;widgets;multimedia;printsupport;serialport;xml @@ -131,7 +131,7 @@ - .;..\rtaudio;..\portaudio\include;..\qcustomplot;..\opus\include;..\eigen;..\r8brain-free-src;resampler;release;/include;%(AdditionalIncludeDirectories) + .;.\hidapi\hidapi;..\rtaudio;..\portaudio\include;..\qcustomplot;..\opus\include;..\eigen;..\r8brain-free-src;resampler;release;/include;%(AdditionalIncludeDirectories) -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -permissive- -Zc:__cplusplus -Zc:externConstexpr -utf-8 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) release\ false @@ -152,8 +152,8 @@ true - ..\portaudio\msvc\X64\Release\portaudio_x64.lib;..\qcustomplot\x64\qcustomplot2.lib;..\opus\win32\VS2015\x64\Release\opus.lib;$(QTDIR)\lib\Qt6Multimedia.lib;$(QTDIR)\lib\Qt6PrintSupport.lib;$(QTDIR)\lib\Qt6Widgets.lib;$(QTDIR)\lib\Qt6Gui.lib;$(QTDIR)\lib\Qt6SerialPort.lib;$(QTDIR)\lib\Qt6Network.lib;$(QTDIR)\lib\Qt6Core.lib;$(QTDIR)\lib\Qt6EntryPoint.lib;shell32.lib;%(AdditionalDependencies) - ..\opus\win32\VS2015\x64\Release;..\qcustomplot\x64;..\portaudio\msvc\X64\Release;%(AdditionalLibraryDirectories) + ..\hidapi\windows\x64\Release\hidapi.lib;..\portaudio\msvc\X64\Release\portaudio_x64.lib;..\qcustomplot\x64\qcustomplot2.lib;..\opus\win32\VS2015\x64\Release\opus.lib;$(QTDIR)\lib\Qt6Multimedia.lib;$(QTDIR)\lib\Qt6PrintSupport.lib;$(QTDIR)\lib\Qt6Widgets.lib;$(QTDIR)\lib\Qt6Gui.lib;$(QTDIR)\lib\Qt6SerialPort.lib;$(QTDIR)\lib\Qt6Network.lib;$(QTDIR)\lib\Qt6Core.lib;$(QTDIR)\lib\Qt6EntryPoint.lib;shell32.lib;%(AdditionalDependencies) + ..\hidapi\windows\x64\Release;..\opus\win32\VS2015\x64\Release;..\qcustomplot\x64;..\portaudio\msvc\X64\Release;%(AdditionalLibraryDirectories) "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) true true @@ -275,7 +275,7 @@ cmd /c copy /y ..\portaudio\msvc\Win32\Release\portaudio_x86.dll wfview-release\ - .;..\rtaudio;..\portaudio\include;..\qcustomplot;..\opus\include;..\eigen;..\r8brain-free-src;resampler;debug;/include;%(AdditionalIncludeDirectories) + .;.\hidapi\hidapi;..\rtaudio;..\portaudio\include;..\qcustomplot;..\opus\include;..\eigen;..\r8brain-free-src;resampler;debug;/include;%(AdditionalIncludeDirectories) -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -permissive- -Zc:__cplusplus -Zc:externConstexpr -utf-8 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) debug\ false @@ -295,8 +295,8 @@ cmd /c copy /y ..\portaudio\msvc\Win32\Release\portaudio_x86.dll wfview-release\ stdc17 - ..\portaudio\msvc\X64\Debug\portaudio_x64.lib;..\qcustomplot\x64\qcustomplotd2.lib;..\opus\win32\VS2015\x64\Debug\opus.lib;$(QTDIR)\lib\Qt6Multimediad.lib;$(QTDIR)\lib\Qt6PrintSupportd.lib;$(QTDIR)\lib\Qt6Widgetsd.lib;$(QTDIR)\lib\Qt6Guid.lib;$(QTDIR)\lib\Qt6SerialPortd.lib;$(QTDIR)\lib\Qt6Networkd.lib;$(QTDIR)\lib\Qt6Cored.lib;$(QTDIR)\lib\Qt6EntryPointd.lib;shell32.lib;%(AdditionalDependencies) - ..\opus\win32\VS2015\x64\Debug;..\qcustomplot\x64;..\portaudio\msvc\X64\Debug;%(AdditionalLibraryDirectories) + ..\hidapi\windows\x64\Debug\hidapi.lib;..\portaudio\msvc\X64\Debug\portaudio_x64.lib;..\qcustomplot\x64\qcustomplotd2.lib;..\opus\win32\VS2015\x64\Debug\opus.lib;$(QTDIR)\lib\Qt6Multimediad.lib;$(QTDIR)\lib\Qt6PrintSupportd.lib;$(QTDIR)\lib\Qt6Widgetsd.lib;$(QTDIR)\lib\Qt6Guid.lib;$(QTDIR)\lib\Qt6SerialPortd.lib;$(QTDIR)\lib\Qt6Networkd.lib;$(QTDIR)\lib\Qt6Cored.lib;$(QTDIR)\lib\Qt6EntryPointd.lib;shell32.lib;%(AdditionalDependencies) + ..\hidapi\windows\x64\Debug;..\opus\win32\VS2015\x64\Debug;..\qcustomplot\x64;..\portaudio\msvc\X64\Debug;%(AdditionalLibraryDirectories) "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) true true @@ -415,6 +415,7 @@ cmd /c copy /y ..\portaudio\msvc\Win32\Debug\portaudio_x86.dll wfview-debug + @@ -443,6 +444,7 @@ cmd /c copy /y ..\portaudio\msvc\Win32\Debug\portaudio_x86.dll wfview-debug + @@ -450,6 +452,7 @@ cmd /c copy /y ..\portaudio\msvc\Win32\Debug\portaudio_x86.dll wfview-debug + @@ -538,6 +541,7 @@ cmd /c copy /y ..\portaudio\msvc\Win32\Debug\portaudio_x86.dll wfview-debug + diff --git a/wfview.vcxproj.filters b/wfview.vcxproj.filters index 04a65b6..2f52d05 100644 --- a/wfview.vcxproj.filters +++ b/wfview.vcxproj.filters @@ -149,6 +149,9 @@ Source Files + + Source Files + @@ -262,6 +265,9 @@ Header Files + + Header Files + @@ -299,6 +305,9 @@ Form Files + + Form Files + @@ -441,5 +450,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/wfview.vcxproj.user b/wfview.vcxproj.user index 55b6057..7c2d6bc 100644 --- a/wfview.vcxproj.user +++ b/wfview.vcxproj.user @@ -45,10 +45,10 @@ 2022-08-21T18:58:23.4329764Z - 2023-01-29T11:49:00.1257696Z + 2023-02-14T17:48:26.0594274Z - 2023-01-29T11:48:59.4191765Z + 2023-02-14T17:48:25.7629768Z 2022-08-22T10:47:49.1255783Z @@ -60,9 +60,9 @@ 2022-08-20T19:06:43.4553894Z - 2023-01-29T11:49:01.5629425Z + 2023-02-14T17:48:27.5731249Z - 2023-01-29T11:49:00.7644018Z + 2023-02-14T17:48:27.1219605Z \ No newline at end of file diff --git a/wfviewtypes.h b/wfviewtypes.h index b86e131..a331a5f 100644 --- a/wfviewtypes.h +++ b/wfviewtypes.h @@ -166,7 +166,7 @@ enum cmds { cmdSetRptAccessMode, cmdSetRptDuplexOffset, cmdGetRptDuplexOffset, cmdSelVFO, cmdVFOSwap, cmdVFOEqualAB, cmdVFOEqualMS, cmdSetQuickSplit, cmdGetPreamp, cmdGetAttenuator, cmdGetAntenna, - cmdGetBandStackReg, cmdGetKeySpeed, cmdSetKeySpeed, cmdGetBreakMode, cmdSetBreakMode, cmdSendCW, cmdStopCW, + cmdGetBandStackReg, cmdGetKeySpeed, cmdSetKeySpeed, cmdGetBreakMode, cmdSetBreakMode, cmdSendCW, cmdStopCW, cmdGetDashRatio, cmdSetDashRatio, cmdSetTime, cmdSetDate, cmdSetUTCOffset, // Below Only used for USB Controller at the moment. cmdSetBandUp, cmdSetBandDown, cmdSetModeUp, cmdSetModeDown, cmdSetStepUp, cmdSetStepDown, cmdSetSpanUp, cmdSetSpanDown, cmdIFFilterUp, cmdIFFilterDown From fd6d132fd3616f6681b1924f9b46dcdd69b1aaba Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Tue, 14 Feb 2023 20:27:32 +0000 Subject: [PATCH 02/27] Various fixes --- cwsender.cpp | 83 ++++++++++++++++++++++++++++++------------- cwsender.h | 5 +++ cwsender.ui | 11 +++++- prefs.h | 1 + wfmain.cpp | 6 +++- wfserver.vcxproj.user | 8 ++--- wfview.vcxproj.user | 8 ++--- 7 files changed, 88 insertions(+), 34 deletions(-) diff --git a/cwsender.cpp b/cwsender.cpp index eb08fcf..87d91f2 100644 --- a/cwsender.cpp +++ b/cwsender.cpp @@ -26,17 +26,15 @@ cwSender::~cwSender() void cwSender::showEvent(QShowEvent *event) { + (void)event; emit getCWSettings(); QMainWindow::showEvent(event); - (void)event; } void cwSender::handleKeySpeed(unsigned char wpm) { - //qDebug(logCW()) << "Told that current WPM is" << wpm; if ((wpm >= 6) && (wpm <= 48)) { - //qDebug(logCW()) << "Setting WPM UI control to" << wpm; ui->wpmSpin->blockSignals(true); ui->wpmSpin->setValue(wpm); ui->wpmSpin->blockSignals(false); @@ -45,19 +43,23 @@ void cwSender::handleKeySpeed(unsigned char wpm) void cwSender::handleDashRatio(unsigned char ratio) { - if ((ratio >= 28) && (ratio <= 45)) + double calc = double(ratio/10); + if ((calc >= 2.8) && (ratio <= 4.5)) { ui->dashSpin->blockSignals(true); - ui->dashSpin->setValue(double(ratio/10)); + ui->dashSpin->setValue(calc); ui->dashSpin->blockSignals(false); } } void cwSender::handlePitch(unsigned char pitch) { quint16 cwPitch = round((((600.0 / 255.0) * pitch) + 300) / 5.0) * 5.0; - ui->pitchSpin->blockSignals(true); - ui->pitchSpin->setValue(cwPitch); - ui->pitchSpin->blockSignals(false); + if (cwPitch >= 300 && cwPitch <= 900) + { + ui->pitchSpin->blockSignals(true); + ui->pitchSpin->setValue(cwPitch); + ui->pitchSpin->blockSignals(false); + } } void cwSender::handleBreakInMode(unsigned char b) @@ -82,16 +84,16 @@ void cwSender::handleCurrentModeUpdate(mode_kind mode) void cwSender::textChanged(QString text) { - if (ui->sendImmediateChk->isChecked()) + if (ui->sendImmediateChk->isChecked() && text.size() && text.back() == ' ') { - if (text.back() == ' ') - { - int toSend = text.mid(0, 30).size(); - if (toSend > 0) { - emit sendCW(text.mid(0, 30)); - ui->transcriptText->appendPlainText(text.mid(0, 30)); - ui->textToSendEdit->clearEditText(); - } + int toSend = text.mid(0, 30).size(); + if (toSend > 0) { + emit sendCW(text.mid(0, 30)); + ui->textToSendEdit->clearEditText(); + + ui->transcriptText->moveCursor(QTextCursor::End); + ui->transcriptText->insertPlainText(text.mid(0, 30).toUpper()); + ui->transcriptText->moveCursor(QTextCursor::End); } } } @@ -102,12 +104,22 @@ void cwSender::on_sendBtn_clicked() (ui->textToSendEdit->currentText().length() <= 30) ) { emit sendCW(ui->textToSendEdit->currentText()); - ui->transcriptText->appendPlainText(ui->textToSendEdit->currentText()); - ui->textToSendEdit->addItem(ui->textToSendEdit->currentText()); - if (ui->textToSendEdit->count() > 5) { - ui->textToSendEdit->removeItem(0); + + ui->transcriptText->moveCursor(QTextCursor::End); + ui->transcriptText->insertPlainText(ui->textToSendEdit->currentText().toUpper()+"\n"); + ui->transcriptText->moveCursor(QTextCursor::End); + if (!ui->sendImmediateChk->isChecked()) + { + ui->textToSendEdit->addItem(ui->textToSendEdit->currentText()); + if (ui->textToSendEdit->count() > 5) { + ui->textToSendEdit->removeItem(0); + } + ui->textToSendEdit->setCurrentIndex(-1); + } else { + ui->textToSendEdit->clearEditText(); + ui->textToSendEdit->clear(); } - ui->textToSendEdit->setCurrentIndex(-1); + ui->textToSendEdit->setFocus(); ui->statusbar->showMessage("Sending CW", 3000); } @@ -242,7 +254,10 @@ void cwSender::runMacroButton(int buttonNumber) emit sendCW(outText.mid(i,30)); } - ui->transcriptText->appendPlainText(outText); + ui->transcriptText->moveCursor(QTextCursor::End); + ui->transcriptText->insertPlainText(outText.toUpper()+"\n"); + ui->transcriptText->moveCursor(QTextCursor::End); + ui->textToSendEdit->setFocus(); @@ -264,7 +279,7 @@ void cwSender::editMacroButton(int buttonNumber, QPushButton* btn) QString newMacroText = QInputDialog::getText(this, "Macro Edit", prompt, - QLineEdit::Normal, macroText[buttonNumber], &ok); + QLineEdit::Normal, macroText[buttonNumber], &ok).toUpper(); if(!ok) return; @@ -307,6 +322,26 @@ void cwSender::on_sequenceSpin_valueChanged(int newSeq) ui->textToSendEdit->setFocus(); } +bool cwSender::getCutNumbers() +{ + return ui->cutNumbersChk->isChecked(); +} + +bool cwSender::getSendImmediate() +{ + return ui->sendImmediateChk->isChecked(); +} + +void cwSender::setCutNumbers(bool val) +{ + ui->cutNumbersChk->setChecked(val); +} + +void cwSender::setSendImmediate(bool val) +{ + ui->sendImmediateChk->setChecked(val); +} + QStringList cwSender::getMacroText() { // This is for preference saving: diff --git a/cwsender.h b/cwsender.h index b767135..56165e0 100644 --- a/cwsender.h +++ b/cwsender.h @@ -25,6 +25,11 @@ public: ~cwSender(); QStringList getMacroText(); void setMacroText(QStringList macros); + void setCutNumbers(bool val); + void setSendImmediate(bool val); + bool getCutNumbers(); + bool getSendImmediate(); + signals: void sendCW(QString cwMessage); void stopCW(); diff --git a/cwsender.ui b/cwsender.ui index 20b8cc2..8d72739 100644 --- a/cwsender.ui +++ b/cwsender.ui @@ -6,7 +6,7 @@ 0 0 - 822 + 835 451 @@ -246,6 +246,9 @@ Type here to send text as CW + + Qt::ImhUppercaseOnly + true @@ -348,6 +351,9 @@ + + 1 + 2.800000000000000 @@ -357,6 +363,9 @@ 0.100000000000000 + + QAbstractSpinBox::DefaultStepType + 3.000000000000000 diff --git a/prefs.h b/prefs.h index b66f44c..4118cdd 100644 --- a/prefs.h +++ b/prefs.h @@ -70,6 +70,7 @@ struct preferences { QString clusterTcpPassword; int clusterTimeout; bool clusterSkimmerSpotsEnable; + }; #endif // PREFS_H diff --git a/wfmain.cpp b/wfmain.cpp index e3b9469..e060f64 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -2437,6 +2437,8 @@ void wfmain::loadSettings() // CW Memory Load: settings->beginGroup("Keyer"); + cw->setCutNumbers(settings->value("CutNumbers", false).toBool()); + cw->setSendImmediate(settings->value("SendImmediate", false).toBool()); int numMemories = settings->beginReadArray("macros"); if(numMemories==10) { @@ -2965,6 +2967,8 @@ void wfmain::saveSettings() settings->endGroup(); settings->beginGroup("Keyer"); + settings->setValue("CutNumbers", cw->getCutNumbers()); + settings->setValue("SendImmediate", cw->getSendImmediate()); QStringList macroList = cw->getMacroText(); if(macroList.length() == 10) { @@ -9503,4 +9507,4 @@ void wfmain::receiveUsbSettings(quint8 bright, quint8 orient, quint8 speed, quin prefs.usbSpeed = speed; prefs.usbTimeout = timeout; prefs.usbColor = color; -} \ No newline at end of file +} diff --git a/wfserver.vcxproj.user b/wfserver.vcxproj.user index 5c869b5..bc8d004 100644 --- a/wfserver.vcxproj.user +++ b/wfserver.vcxproj.user @@ -2,15 +2,15 @@ - 2023-02-06T15:26:00.1276665Z + 2023-02-14T19:04:12.9338871Z - 2023-02-06T15:25:59.8598138Z + 2023-02-14T19:04:11.6802165Z - 2023-02-06T15:26:00.7293349Z + 2023-02-14T19:04:14.0213664Z - 2023-02-06T15:26:00.3825270Z + 2023-02-14T19:04:13.5068223Z \ No newline at end of file diff --git a/wfview.vcxproj.user b/wfview.vcxproj.user index 7c2d6bc..f9cc765 100644 --- a/wfview.vcxproj.user +++ b/wfview.vcxproj.user @@ -45,10 +45,10 @@ 2022-08-21T18:58:23.4329764Z - 2023-02-14T17:48:26.0594274Z + 2023-02-14T19:04:15.5036128Z - 2023-02-14T17:48:25.7629768Z + 2023-02-14T19:04:14.6701614Z 2022-08-22T10:47:49.1255783Z @@ -60,9 +60,9 @@ 2022-08-20T19:06:43.4553894Z - 2023-02-14T17:48:27.5731249Z + 2023-02-14T19:04:16.6120542Z - 2023-02-14T17:48:27.1219605Z + 2023-02-14T19:04:16.0046827Z \ No newline at end of file From 9eb89a9cb1279ee7e8badeba0230fce19baf77d6 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 13:58:02 +0000 Subject: [PATCH 03/27] First working cw sidetone Still needs better timing and volume --- cwsender.cpp | 128 +++++++++++++++++++++---- cwsender.h | 22 ++++- cwsender.ui | 76 ++++++++++++--- cwsidetone.cpp | 254 +++++++++++++++++++++++++++++++++++++++++++++++++ cwsidetone.h | 62 ++++++++++++ wfmain.cpp | 21 ++-- wfview.pro | 2 + 7 files changed, 525 insertions(+), 40 deletions(-) create mode 100644 cwsidetone.cpp create mode 100644 cwsidetone.h diff --git a/cwsender.cpp b/cwsender.cpp index 87d91f2..bfbd024 100644 --- a/cwsender.cpp +++ b/cwsender.cpp @@ -1,6 +1,8 @@ #include "cwsender.h" #include "ui_cwsender.h" +#include "logcategories.h" + cwSender::cwSender(QWidget *parent) : QMainWindow(parent), ui(new Ui::cwSender) @@ -16,11 +18,43 @@ cwSender::cwSender(QWidget *parent) : ui->statusbar->setToolTipDuration(3000); this->setToolTipDuration(3000); connect(ui->textToSendEdit->lineEdit(), &QLineEdit::textEdited, this, &cwSender::textChanged); + + toneThread = new QThread(this); + toneThread->setObjectName("sidetone()"); + + tone = new cwSidetone(sidetoneLevel, ui->wpmSpin->value(),ui->pitchSpin->value(),ui->dashSpin->value(),this); + tone->moveToThread(toneThread); + toneThread->start(); + + connect(toneThread, &QThread::finished, + [=]() { tone->deleteLater(); }); + connect(this, &cwSender::sidetone, + [=](const QString& text) { tone->send(text); }); + connect(this, &cwSender::setKeySpeed, + [=](const unsigned char& wpm) { tone->setSpeed(wpm); }); + connect(this, &cwSender::setDashRatio, + [=](const unsigned char& ratio) { tone->setRatio(ratio); }); + connect(this, &cwSender::setPitch, + [=](const unsigned char& pitch) { tone->setFrequency(pitch); }); + connect(this, &cwSender::setLevel, + [=](const unsigned char& level) { tone->setLevel(level); }); + + connect( this, SIGNAL( pitchChanged(int) ), ui->pitchSpin, SLOT( setValue(int) ) ); + connect( this, SIGNAL( dashChanged(int) ), ui->dashSpin, SLOT( setValue(int) ) ); + connect( this, SIGNAL( wpmChanged(int) ), ui->wpmSpin, SLOT( setValue(int) ) ); } cwSender::~cwSender() { qDebug(logCW()) << "Running CW Sender destructor."; + + if (toneThread != Q_NULLPTR) { + toneThread->quit(); + toneThread->wait(); + toneThread = Q_NULLPTR; + tone = Q_NULLPTR; + } + delete ui; } @@ -33,32 +67,53 @@ void cwSender::showEvent(QShowEvent *event) void cwSender::handleKeySpeed(unsigned char wpm) { - if ((wpm >= 6) && (wpm <= 48)) + if (wpm != ui->wpmSpin->value() && (wpm >= ui->wpmSpin->minimum()) && (wpm <= ui->wpmSpin->maximum())) { ui->wpmSpin->blockSignals(true); - ui->wpmSpin->setValue(wpm); + emit wpmChanged((int)wpm); ui->wpmSpin->blockSignals(false); +#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) + QMetaObject::invokeMethod(tone, [=]() { + tone->setSpeed(wpm); + }, Qt::QueuedConnection); +#else + emit setKeySpeed(ratio); +#endif } } void cwSender::handleDashRatio(unsigned char ratio) { double calc = double(ratio/10); - if ((calc >= 2.8) && (ratio <= 4.5)) + if (calc != ui->dashSpin->value() && (calc >= ui->dashSpin->minimum()) && (ratio <= ui->dashSpin->maximum())) { ui->dashSpin->blockSignals(true); - ui->dashSpin->setValue(calc); + emit dashChanged(calc); ui->dashSpin->blockSignals(false); +#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) + QMetaObject::invokeMethod(tone, [=]() { + tone->setRatio(ratio); + }, Qt::QueuedConnection); +#else + emit setDashRatio(ratio); +#endif } } void cwSender::handlePitch(unsigned char pitch) { - quint16 cwPitch = round((((600.0 / 255.0) * pitch) + 300) / 5.0) * 5.0; - if (cwPitch >= 300 && cwPitch <= 900) + int cwPitch = round((((600.0 / 255.0) * pitch) + 300) / 5.0) * 5.0; + if (cwPitch != ui->pitchSpin->value() && cwPitch >= ui->pitchSpin->minimum() && cwPitch <= ui->pitchSpin->maximum()) { ui->pitchSpin->blockSignals(true); - ui->pitchSpin->setValue(cwPitch); + emit pitchChanged(cwPitch); ui->pitchSpin->blockSignals(false); +#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) + QMetaObject::invokeMethod(tone, [=]() { + tone->setFrequency(pitch); + }, Qt::QueuedConnection); +#else + emit setPitch(tone); +#endif } } @@ -88,12 +143,18 @@ void cwSender::textChanged(QString text) { int toSend = text.mid(0, 30).size(); if (toSend > 0) { - emit sendCW(text.mid(0, 30)); ui->textToSendEdit->clearEditText(); - ui->transcriptText->moveCursor(QTextCursor::End); ui->transcriptText->insertPlainText(text.mid(0, 30).toUpper()); ui->transcriptText->moveCursor(QTextCursor::End); + + emit sendCW(text.mid(0, 30)); + emit sidetone(text.mid(0,30)); + + } + if( (currentMode != modeCW) && (currentMode != modeCW_R) ) + { + ui->statusbar->showMessage("Note: Mode needs to be set to CW or CW-R to send CW.", 3000); } } } @@ -103,7 +164,7 @@ void cwSender::on_sendBtn_clicked() if( (ui->textToSendEdit->currentText().length() > 0) && (ui->textToSendEdit->currentText().length() <= 30) ) { - emit sendCW(ui->textToSendEdit->currentText()); + QString text = ui->textToSendEdit->currentText(); ui->transcriptText->moveCursor(QTextCursor::End); ui->transcriptText->insertPlainText(ui->textToSendEdit->currentText().toUpper()+"\n"); @@ -122,10 +183,12 @@ void cwSender::on_sendBtn_clicked() ui->textToSendEdit->setFocus(); ui->statusbar->showMessage("Sending CW", 3000); + emit sendCW(text); + emit sidetone(text); } - if( (currentMode==modeCW) || (currentMode==modeCW_R) ) + + if( (currentMode != modeCW) && (currentMode != modeCW_R) ) { - } else { ui->statusbar->showMessage("Note: Mode needs to be set to CW or CW-R to send CW.", 3000); } } @@ -217,6 +280,18 @@ void cwSender::on_macro10btn_clicked() processMacroButton(10, ui->macro10btn); } +void cwSender::on_sidetoneEnableChk_clicked(bool clicked) +{ + ui->sidetoneLevelSlider->setEnabled(clicked); +} + +void cwSender::on_sidetoneLevelSlider_valueChanged(int val) +{ + sidetoneLevel = val; + emit setLevel(val); +} + + void cwSender::processMacroButton(int buttonNumber, QPushButton *btn) { if(ui->macroEditChk->isChecked()) @@ -250,14 +325,15 @@ void cwSender::runMacroButton(int buttonNumber) outText.replace("9", "N"); } - for (int i = 0; i < outText.size(); i = i + 30) { - emit sendCW(outText.mid(i,30)); - } - ui->transcriptText->moveCursor(QTextCursor::End); ui->transcriptText->insertPlainText(outText.toUpper()+"\n"); ui->transcriptText->moveCursor(QTextCursor::End); + for (int i = 0; i < outText.size(); i = i + 30) { + emit sendCW(outText.mid(i,30)); + emit sidetone(outText.mid(i,30)); + } + ui->textToSendEdit->setFocus(); @@ -332,6 +408,16 @@ bool cwSender::getSendImmediate() return ui->sendImmediateChk->isChecked(); } +bool cwSender::getSidetoneEnable() +{ + return ui->sidetoneEnableChk->isChecked(); +} + +int cwSender::getSidetoneLevel() +{ + return ui->sidetoneLevelSlider->value(); +} + void cwSender::setCutNumbers(bool val) { ui->cutNumbersChk->setChecked(val); @@ -342,6 +428,16 @@ void cwSender::setSendImmediate(bool val) ui->sendImmediateChk->setChecked(val); } +void cwSender::setSidetoneEnable(bool val) +{ + ui->sidetoneEnableChk->setChecked(val); +} + +void cwSender::setSidetoneLevel(int val) +{ + ui->sidetoneLevelSlider->setValue(val); +} + QStringList cwSender::getMacroText() { // This is for preference saving: diff --git a/cwsender.h b/cwsender.h index 56165e0..26d1c90 100644 --- a/cwsender.h +++ b/cwsender.h @@ -6,11 +6,10 @@ #include #include #include +#include #include +#include "cwsidetone.h" #include "wfviewtypes.h" -#include "logcategories.h" - - namespace Ui { class cwSender; @@ -27,8 +26,12 @@ public: void setMacroText(QStringList macros); void setCutNumbers(bool val); void setSendImmediate(bool val); + void setSidetoneEnable(bool val); + void setSidetoneLevel(int val); bool getCutNumbers(); bool getSendImmediate(); + bool getSidetoneEnable(); + int getSidetoneLevel(); signals: void sendCW(QString cwMessage); @@ -36,8 +39,13 @@ signals: void setKeySpeed(unsigned char wpm); void setDashRatio(unsigned char ratio); void setPitch(unsigned char pitch); + void setLevel(int level); void setBreakInMode(unsigned char b); void getCWSettings(); + void sidetone(QString text); + void pitchChanged(int val); + void dashChanged(int val); + void wpmChanged(int val); public slots: void handleKeySpeed(unsigned char wpm); @@ -86,16 +94,24 @@ private slots: void on_sequenceSpin_valueChanged(int arg1); + void on_sidetoneEnableChk_clicked(bool clicked); + + void on_sidetoneLevelSlider_valueChanged(int val); + private: Ui::cwSender *ui; QString macroText[11]; int sequenceNumber = 1; int lastSentPos = 0; mode_kind currentMode; + int sidetoneLevel=0; void processMacroButton(int buttonNumber, QPushButton *btn); void runMacroButton(int buttonNumber); void editMacroButton(int buttonNumber, QPushButton *btn); void setMacroButtonText(QString btnText, QPushButton *btn); + cwSidetone* tone=Q_NULLPTR; + QThread* toneThread = Q_NULLPTR; + }; #endif // CWSENDER_H diff --git a/cwsender.ui b/cwsender.ui index 8d72739..d2035bd 100644 --- a/cwsender.ui +++ b/cwsender.ui @@ -192,11 +192,56 @@ 0 - - - - - + + + + + + 100 + 0 + + + + + true + + + + Stop sending CW + + + false + + + Stop + + + + + + + Local Sidetone Level + + + + + + + 100 + + + Qt::Horizontal + + + + + + + Enable + + + + @@ -214,6 +259,17 @@ + + + 100 + 0 + + + + + true + + Send @@ -225,16 +281,6 @@ - - - - Stop sending CW - - - Stop - - - diff --git a/cwsidetone.cpp b/cwsidetone.cpp new file mode 100644 index 0000000..207e680 --- /dev/null +++ b/cwsidetone.cpp @@ -0,0 +1,254 @@ +#include "cwsidetone.h" + +#include "logcategories.h" +#include "qapplication.h" + +cwSidetone::cwSidetone(int level, int speed, int freq, double ratio, QWidget* parent) : + parent(parent), + volume(level), + speed(speed), + frequency(freq), + ratio(ratio) +{ + + /* + * Characters to match Icom table + * Unknown characters will return '?' + */ + cwTable.clear(); + cwTable['0'] = "-----"; + cwTable['1'] = ".----"; + cwTable['2'] = "..---"; + cwTable['3'] = "...--"; + cwTable['4'] = "....-"; + cwTable['5'] = "....."; + cwTable['6'] = "-...."; + cwTable['7'] = "--..."; + cwTable['8'] = "---.."; + cwTable['9'] = "----."; + + cwTable['A'] = ".-"; + cwTable['B'] = "-..."; + cwTable['C'] = "-.-."; + cwTable['D'] = "-.."; + cwTable['E'] = "."; + cwTable['F'] = "..-."; + cwTable['G'] = "--."; + cwTable['H'] = "...."; + cwTable['I'] = ".."; + cwTable['J'] = ".---"; + cwTable['K'] = "-.-"; + cwTable['L'] = ".-.."; + cwTable['M'] = "--"; + cwTable['N'] = "-."; + cwTable['O'] = "---"; + cwTable['P'] = ".--."; + cwTable['Q'] = "--.-"; + cwTable['R'] = ".-."; + cwTable['S'] = "..."; + cwTable['T'] = "-"; + cwTable['U'] = "..-"; + cwTable['V'] = "...-"; + cwTable['W'] = ".--"; + cwTable['X'] = "-..-"; + cwTable['Y'] = "-.--"; + cwTable['Z'] = "--.."; + + cwTable['/'] = "-..-."; + cwTable['?'] = "..--.."; + cwTable['.'] = ".-.-.-"; + cwTable['-'] = "-....-"; + cwTable[','] = "--..--"; + cwTable[':'] = "---..."; + cwTable['\''] = ".----."; + cwTable['('] = "-.--.-"; + cwTable[')'] = "-.--.-"; + cwTable['='] = "-...-"; + cwTable['+'] = ".-.-."; + cwTable['"'] = ".-..-."; + + cwTable[' '] = " "; + + init(); +} + +cwSidetone::~cwSidetone() +{ + output->stop(); + delete output; +} + +void cwSidetone::init() +{ + format.setSampleRate(44100); + format.setChannelCount(1); +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) + format.setCodec("audio/pcm"); + format.setSampleSize(16); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::SignedInt); + QAudioDeviceInfo device(QAudioDeviceInfo::defaultOutputDevice()); +#else + format.setSampleFormat(QAudioFormat::Int16); + QAudioDevice device = QMediaDevices::defaultAudioOutput(); +#endif + + if (!device.isFormatSupported(format)) { + qWarning(logCW()) << "Default format not supported, using preferred"; + format = device.preferredFormat(); + } + +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) + output = new QAudioOutput(device,format); +#else + output = new QAudioSink(device,format); +#endif + output->setVolume((qreal)volume/100.0); +} + +void cwSidetone::send(QString text) +{ + text=text.simplified(); + buffer.clear(); + QString currentChar; + int pos = 0; + while (pos < text.size()) + { + QChar ch = text.at(pos).toUpper(); + if (ch == NULL) + { + currentChar = cwTable[' ']; + } + else if (this->cwTable.contains(ch)) + { + currentChar = cwTable[ch]; + } + else + { + currentChar=cwTable['?']; + } + generateMorse(currentChar); + pos++; + } + outputDevice = output->start(); + if (outputDevice) { + qint64 written = outputDevice->write(buffer); + while (written < buffer.size()) + { + written += outputDevice->write(buffer.data()+written, buffer.size() - written); + QApplication::processEvents(); + } + } + //qInfo(logCW()) << "Sending" << this->currentChar; + emit finished(); + return; +} + +void cwSidetone::generateMorse(QString morse) +{ + + int dit = int(double(SIDETONE_MULTIPLIER / this->speed * SIDETONE_MULTIPLIER)); + int dah = int(dit * this->ratio); + + for (int i=0;ifrequency)); + } else if (c == '.') + { + buffer.append(generateData(dit,this->frequency)); + } else // Space char + { + buffer.append(generateData(dah+dit,0)); + } + + if (i+1(data.data()); + int sampleIndex = 0; + + while (length) { + const qreal x = qSin(2 * M_PI * freq * qreal(sampleIndex % sampleRate) / sampleRate); + for (int i=0; i((1.0 + x) / 2 * 255); + *reinterpret_cast(ptr) = value; + +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) + } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) +#else + } else if (format.sampleFormat() == QAudioFormat::Int16) +#endif + { + qint16 value = static_cast(x * 32767); + qToLittleEndian(value, ptr); + } + + ptr += channelBytes; + length -= channelBytes; + } + ++sampleIndex; + } + + return data; +} + +void cwSidetone::setSpeed(unsigned char speed) +{ + this->speed = (int)speed; +} + +void cwSidetone::setFrequency(unsigned char frequency) +{ + this->frequency = round((((600.0 / 255.0) * frequency) + 300) / 5.0) * 5.0; +} + +void cwSidetone::setRatio(unsigned char ratio) +{ + this->ratio = (double)ratio/10.0; +} + +void cwSidetone::setLevel(int level) { + volume = level; + if (output != Q_NULLPTR) { + output->setVolume((qreal)level/100.0); + } + +} diff --git a/cwsidetone.h b/cwsidetone.h new file mode 100644 index 0000000..e2a416a --- /dev/null +++ b/cwsidetone.h @@ -0,0 +1,62 @@ +#ifndef CWSIDETONE_H +#define CWSIDETONE_H + +#include +#include +#include + +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) +#include +#include +#else +#include +#include +#include +#endif + +#include +#include +#include + +#define SIDETONE_MULTIPLIER 386.0 + +class cwSidetone : public QObject +{ + Q_OBJECT +public: + explicit cwSidetone(int level, int speed, int freq, double ratio, QWidget *parent = 0); + ~cwSidetone(); + +signals: + void finished(); +public slots: + void send(QString text); + void setSpeed(unsigned char speed); + void setFrequency(unsigned char frequency); + void setRatio(unsigned char ratio); + void setLevel(int level); +private: + void init(); + + void generateMorse(QString morse); + QByteArray generateData(qint64 len, qint64 freq); + QByteArray buffer; + QMap< QChar, QString> cwTable; + int position = 0; + int charSpace = 20; + int wordSpace = 60; + QWidget* parent; + int volume; + int speed; + int frequency; + double ratio; + QAudioFormat format; +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) + QAudioOutput* output = Q_NULLPTR; +#else + QAudioSink* output = Q_NULLPTR; +#endif + QIODevice* outputDevice = Q_NULLPTR; +}; + +#endif // CWSIDETONE_H diff --git a/wfmain.cpp b/wfmain.cpp index e060f64..1a9e0b0 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -2439,6 +2439,8 @@ void wfmain::loadSettings() settings->beginGroup("Keyer"); cw->setCutNumbers(settings->value("CutNumbers", false).toBool()); cw->setSendImmediate(settings->value("SendImmediate", false).toBool()); + cw->setSidetoneEnable(settings->value("SidetoneEnabled", false).toBool()); + cw->setSidetoneLevel(settings->value("SidetoneLevel", 0).toInt()); int numMemories = settings->beginReadArray("macros"); if(numMemories==10) { @@ -2969,6 +2971,8 @@ void wfmain::saveSettings() settings->beginGroup("Keyer"); settings->setValue("CutNumbers", cw->getCutNumbers()); settings->setValue("SendImmediate", cw->getSendImmediate()); + settings->setValue("SidetoneEnabled", cw->getSidetoneEnable()); + settings->setValue("SidetoneLevel", cw->getSidetoneLevel()); QStringList macroList = cw->getMacroText(); if(macroList.length() == 10) { @@ -5695,11 +5699,15 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter) if (currentModeInfo.mk != (mode_kind)mode || currentModeInfo.filter != filter) { - removePeriodicRapidCmd(cmdGetCwPitch); + // Remove all "Slow" commands (they will be added later if needed) + removeSlowPeriodicCommand(cmdGetCwPitch); + removeSlowPeriodicCommand(cmdGetDashRatio); + removeSlowPeriodicCommand(cmdGetKeySpeed); removeSlowPeriodicCommand(cmdGetPassband); removeSlowPeriodicCommand(cmdGetTPBFInner); removeSlowPeriodicCommand(cmdGetTPBFOuter); + quint16 maxPassbandHz = 0; switch ((mode_kind)mode) { case modeFM: @@ -5714,8 +5722,9 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter) break; case modeCW: case modeCW_R: - insertPeriodicRapidCmdUnique(cmdGetCwPitch); - issueDelayedCommandUnique(cmdGetCwPitch); + insertSlowPeriodicCommand(cmdGetCwPitch,128); + insertSlowPeriodicCommand(cmdGetDashRatio,128); + insertSlowPeriodicCommand(cmdGetKeySpeed,128); maxPassbandHz = 3600; break; case modeAM: @@ -5770,9 +5779,9 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter) if (currentModeInfo.mk != modeFM) { - insertSlowPeriodicCommand(cmdGetPassband, 128); - insertSlowPeriodicCommand(cmdGetTPBFInner, 128); - insertSlowPeriodicCommand(cmdGetTPBFOuter, 128); + insertSlowPeriodicCommand(cmdGetPassband,128); + insertSlowPeriodicCommand(cmdGetTPBFInner,128); + insertSlowPeriodicCommand(cmdGetTPBFOuter,128); issueDelayedCommandUnique(cmdGetPassband); issueDelayedCommandUnique(cmdGetTPBFInner); issueDelayedCommandUnique(cmdGetTPBFOuter); diff --git a/wfview.pro b/wfview.pro index 704e091..01311e9 100644 --- a/wfview.pro +++ b/wfview.pro @@ -218,6 +218,7 @@ INCLUDEPATH += resampler SOURCES += main.cpp\ cwsender.cpp \ + cwsidetone.cpp \ loggingwindow.cpp \ wfmain.cpp \ commhandler.cpp \ @@ -256,6 +257,7 @@ HEADERS += wfmain.h \ colorprefs.h \ commhandler.h \ cwsender.h \ + cwsidetone.h \ loggingwindow.h \ prefs.h \ printhex.h \ From 3ce35500b9f3861f3aea00f2becbf3e43d861826 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 14:01:09 +0000 Subject: [PATCH 04/27] Fix Qt5 compile (hopefully) --- cwsidetone.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index 207e680..c778e92 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -180,11 +180,10 @@ QByteArray cwSidetone::generateData(qint64 len, qint64 freq) { QByteArray data; + const int channels = format.channelCount(); #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) - const int channels = format.channels(); const int channelBytes = format.sampleSize() / 8; #else - const int channels = format.channelCount(); const int channelBytes = format.bytesPerSample(); #endif From e594efdbbc9dd0e0e88eb4eb9d5a49a622a2fc83 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 14:30:22 +0000 Subject: [PATCH 05/27] Try to stop crash if there is no default audio device --- cwsender.cpp | 14 ++++------ cwsidetone.cpp | 74 ++++++++++++++++++++++++++------------------------ 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/cwsender.cpp b/cwsender.cpp index bfbd024..ea03702 100644 --- a/cwsender.cpp +++ b/cwsender.cpp @@ -38,10 +38,6 @@ cwSender::cwSender(QWidget *parent) : [=](const unsigned char& pitch) { tone->setFrequency(pitch); }); connect(this, &cwSender::setLevel, [=](const unsigned char& level) { tone->setLevel(level); }); - - connect( this, SIGNAL( pitchChanged(int) ), ui->pitchSpin, SLOT( setValue(int) ) ); - connect( this, SIGNAL( dashChanged(int) ), ui->dashSpin, SLOT( setValue(int) ) ); - connect( this, SIGNAL( wpmChanged(int) ), ui->wpmSpin, SLOT( setValue(int) ) ); } cwSender::~cwSender() @@ -70,7 +66,7 @@ void cwSender::handleKeySpeed(unsigned char wpm) if (wpm != ui->wpmSpin->value() && (wpm >= ui->wpmSpin->minimum()) && (wpm <= ui->wpmSpin->maximum())) { ui->wpmSpin->blockSignals(true); - emit wpmChanged((int)wpm); + QMetaObject::invokeMethod(ui->wpmSpin, "setValue", Qt::QueuedConnection, Q_ARG(int, wpm)); ui->wpmSpin->blockSignals(false); #if (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) QMetaObject::invokeMethod(tone, [=]() { @@ -88,7 +84,7 @@ void cwSender::handleDashRatio(unsigned char ratio) if (calc != ui->dashSpin->value() && (calc >= ui->dashSpin->minimum()) && (ratio <= ui->dashSpin->maximum())) { ui->dashSpin->blockSignals(true); - emit dashChanged(calc); + QMetaObject::invokeMethod(ui->dashSpin, "setValue", Qt::QueuedConnection, Q_ARG(double, calc)); ui->dashSpin->blockSignals(false); #if (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) QMetaObject::invokeMethod(tone, [=]() { @@ -105,7 +101,7 @@ void cwSender::handlePitch(unsigned char pitch) { if (cwPitch != ui->pitchSpin->value() && cwPitch >= ui->pitchSpin->minimum() && cwPitch <= ui->pitchSpin->maximum()) { ui->pitchSpin->blockSignals(true); - emit pitchChanged(cwPitch); + QMetaObject::invokeMethod(ui->pitchSpin, "setValue", Qt::QueuedConnection, Q_ARG(int, cwPitch)); ui->pitchSpin->blockSignals(false); #if (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) QMetaObject::invokeMethod(tone, [=]() { @@ -313,7 +309,7 @@ void cwSender::runMacroButton(int buttonNumber) outText = macroText[buttonNumber].arg(sequenceNumber, 3, 10, QChar('0')); sequenceNumber++; ui->sequenceSpin->blockSignals(true); - ui->sequenceSpin->setValue(sequenceNumber); + QMetaObject::invokeMethod(ui->sequenceSpin, "setValue", Qt::QueuedConnection, Q_ARG(int, sequenceNumber)); ui->sequenceSpin->blockSignals(false); } else { outText = macroText[buttonNumber]; @@ -435,7 +431,7 @@ void cwSender::setSidetoneEnable(bool val) void cwSender::setSidetoneLevel(int val) { - ui->sidetoneLevelSlider->setValue(val); + QMetaObject::invokeMethod(ui->sidetoneLevelSlider, "setValue", Qt::QueuedConnection, Q_ARG(int, val)); } QStringList cwSender::getMacroText() diff --git a/cwsidetone.cpp b/cwsidetone.cpp index c778e92..815c61b 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -92,51 +92,55 @@ void cwSidetone::init() format.setSampleFormat(QAudioFormat::Int16); QAudioDevice device = QMediaDevices::defaultAudioOutput(); #endif - - if (!device.isFormatSupported(format)) { - qWarning(logCW()) << "Default format not supported, using preferred"; - format = device.preferredFormat(); - } + if (device.isDefault()) { + if (!device.isFormatSupported(format)) { + qWarning(logCW()) << "Default format not supported, using preferred"; + format = device.preferredFormat(); + } #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) - output = new QAudioOutput(device,format); + output = new QAudioOutput(device,format); #else - output = new QAudioSink(device,format); + output = new QAudioSink(device,format); #endif - output->setVolume((qreal)volume/100.0); + + output->setVolume((qreal)volume/100.0); + } } void cwSidetone::send(QString text) { - text=text.simplified(); - buffer.clear(); - QString currentChar; - int pos = 0; - while (pos < text.size()) - { - QChar ch = text.at(pos).toUpper(); - if (ch == NULL) + if (output != Q_NULLPTR) { + text=text.simplified(); + buffer.clear(); + QString currentChar; + int pos = 0; + while (pos < text.size()) { - currentChar = cwTable[' ']; + QChar ch = text.at(pos).toUpper(); + if (ch == NULL) + { + currentChar = cwTable[' ']; + } + else if (this->cwTable.contains(ch)) + { + currentChar = cwTable[ch]; + } + else + { + currentChar=cwTable['?']; + } + generateMorse(currentChar); + pos++; } - else if (this->cwTable.contains(ch)) - { - currentChar = cwTable[ch]; - } - else - { - currentChar=cwTable['?']; - } - generateMorse(currentChar); - pos++; - } - outputDevice = output->start(); - if (outputDevice) { - qint64 written = outputDevice->write(buffer); - while (written < buffer.size()) - { - written += outputDevice->write(buffer.data()+written, buffer.size() - written); - QApplication::processEvents(); + outputDevice = output->start(); + if (outputDevice != Q_NULLPTR) { + qint64 written = outputDevice->write(buffer); + while (written < buffer.size()) + { + written += outputDevice->write(buffer.data()+written, buffer.size() - written); + QApplication::processEvents(); + } } } //qInfo(logCW()) << "Sending" << this->currentChar; From 97ed3f6f424494c4305588558a32e6b79a4e68ef Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 14:34:08 +0000 Subject: [PATCH 06/27] Fix compile in linux --- cwsidetone.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index 815c61b..918e50f 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -92,7 +92,7 @@ void cwSidetone::init() format.setSampleFormat(QAudioFormat::Int16); QAudioDevice device = QMediaDevices::defaultAudioOutput(); #endif - if (device.isDefault()) { + if (!device.isNull()) { if (!device.isFormatSupported(format)) { qWarning(logCW()) << "Default format not supported, using preferred"; format = device.preferredFormat(); From 1177fa34198fbe5aac589242d99445d939593616 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 16:28:56 +0000 Subject: [PATCH 07/27] Disable sidetone if unchecked --- cwsender.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cwsender.cpp b/cwsender.cpp index ea03702..6b60b59 100644 --- a/cwsender.cpp +++ b/cwsender.cpp @@ -145,7 +145,8 @@ void cwSender::textChanged(QString text) ui->transcriptText->moveCursor(QTextCursor::End); emit sendCW(text.mid(0, 30)); - emit sidetone(text.mid(0,30)); + if (ui->sidetoneEnableChk->isChecked()) + emit sidetone(text.mid(0,30)); } if( (currentMode != modeCW) && (currentMode != modeCW_R) ) @@ -179,8 +180,10 @@ void cwSender::on_sendBtn_clicked() ui->textToSendEdit->setFocus(); ui->statusbar->showMessage("Sending CW", 3000); + emit sendCW(text); - emit sidetone(text); + if (ui->sidetoneEnableChk->isChecked()) + emit sidetone(text); } if( (currentMode != modeCW) && (currentMode != modeCW_R) ) @@ -327,7 +330,8 @@ void cwSender::runMacroButton(int buttonNumber) for (int i = 0; i < outText.size(); i = i + 30) { emit sendCW(outText.mid(i,30)); - emit sidetone(outText.mid(i,30)); + if (ui->sidetoneEnableChk->isChecked()) + emit sidetone(outText.mid(i,30)); } ui->textToSendEdit->setFocus(); From acaed4601e215b13766cd69f9f7805809cfa4150 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 16:49:19 +0000 Subject: [PATCH 08/27] Hopefully fix audio. --- cwsidetone.cpp | 3 ++- wfmain.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index 918e50f..0e55ade 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -115,6 +115,7 @@ void cwSidetone::send(QString text) buffer.clear(); QString currentChar; int pos = 0; + outputDevice = output->start(); while (pos < text.size()) { QChar ch = text.at(pos).toUpper(); @@ -133,7 +134,6 @@ void cwSidetone::send(QString text) generateMorse(currentChar); pos++; } - outputDevice = output->start(); if (outputDevice != Q_NULLPTR) { qint64 written = outputDevice->write(buffer); while (written < buffer.size()) @@ -145,6 +145,7 @@ void cwSidetone::send(QString text) } //qInfo(logCW()) << "Sending" << this->currentChar; emit finished(); + output->stop(); return; } diff --git a/wfmain.cpp b/wfmain.cpp index 1a9e0b0..2eec7e8 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -2439,8 +2439,8 @@ void wfmain::loadSettings() settings->beginGroup("Keyer"); cw->setCutNumbers(settings->value("CutNumbers", false).toBool()); cw->setSendImmediate(settings->value("SendImmediate", false).toBool()); - cw->setSidetoneEnable(settings->value("SidetoneEnabled", false).toBool()); - cw->setSidetoneLevel(settings->value("SidetoneLevel", 0).toInt()); + cw->setSidetoneEnable(settings->value("SidetoneEnabled", true).toBool()); + cw->setSidetoneLevel(settings->value("SidetoneLevel", 100).toInt()); int numMemories = settings->beginReadArray("macros"); if(numMemories==10) { From f9ca8e7e844d99fa14a8c36597ad454176a903cb Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 16:56:01 +0000 Subject: [PATCH 09/27] Restart audio device if stopped/suspended --- cwsidetone.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index 0e55ade..1e21fce 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -105,17 +105,20 @@ void cwSidetone::init() #endif output->setVolume((qreal)volume/100.0); + outputDevice = output->start(); } } void cwSidetone::send(QString text) { - if (output != Q_NULLPTR) { + if (output != Q_NULLPTR && outputDevice != Q_NULLPTR) { text=text.simplified(); buffer.clear(); QString currentChar; int pos = 0; - outputDevice = output->start(); + if (output->state() == QAudio::StoppedState || output->state() == QAudio::SuspendedState) { + output->resume(); + } while (pos < text.size()) { QChar ch = text.at(pos).toUpper(); @@ -145,7 +148,6 @@ void cwSidetone::send(QString text) } //qInfo(logCW()) << "Sending" << this->currentChar; emit finished(); - output->stop(); return; } From 71fd70f78bb512c9b3118bd450f888c173752abf Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 17:26:21 +0000 Subject: [PATCH 10/27] Sample type fixes --- cwsidetone.cpp | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index 1e21fce..c11fa74 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -89,7 +89,7 @@ void cwSidetone::init() format.setSampleType(QAudioFormat::SignedInt); QAudioDeviceInfo device(QAudioDeviceInfo::defaultOutputDevice()); #else - format.setSampleFormat(QAudioFormat::Int16); + format.setSampleFormat(QAudioFormat::Float); QAudioDevice device = QMediaDevices::defaultAudioOutput(); #endif if (!device.isNull()) { @@ -105,6 +105,16 @@ void cwSidetone::init() #endif output->setVolume((qreal)volume/100.0); + +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) + qInfo(logCW()) << QString("Sidetone Output: %0 (volume: %1 rate: %2 size: %3 type: %4)") + .arg(device.deviceName()).arg(volume).arg(format.sampleRate()).arg(format.sampleSize()).arg(format.sampleType()); +#else + qInfo(logCW()) << QString("Sidetone Output: %0 (volume: %1 rate: %2 type: %3") + .arg(device.description()).arg(volume).arg(format.sampleRate()).arg(format.sampleFormat()); +#endif + + outputDevice = output->start(); } } @@ -217,6 +227,22 @@ QByteArray cwSidetone::generateData(qint64 len, qint64 freq) const quint8 value = static_cast((1.0 + x) / 2 * 255); *reinterpret_cast(ptr) = value; +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) + } else if (format.sampleType() == QAudioFormat::Float) +#else + } else if (format.sampleFormat() == QAudioFormat::Float) +#endif + { + float value = static_cast(x); + qToLittleEndian(value, ptr); +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) + } else if (format.sampleSize() == 32 && format.sampleType() == QAudioFormat::SignedInt) +#else + } else if (format.sampleFormat() == QAudioFormat::Int32) +#endif + { + qint32 value = static_cast(x); + qToLittleEndian(value, ptr); #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) #else @@ -226,7 +252,13 @@ QByteArray cwSidetone::generateData(qint64 len, qint64 freq) qint16 value = static_cast(x * 32767); qToLittleEndian(value, ptr); } - + else { +#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) + qWarning(logCW()) << QString("Unsupported sample size: %0 type: %1").arg(format.sampleSize()).arg(format.sampleType()); +#else + qWarning(logCW()) << QString("Unsupported sample format: %0").arg(format.sampleFormat()); +#endif + } ptr += channelBytes; length -= channelBytes; } From 67685dc100affd1376085764c9f813044bf0b986 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 17:46:12 +0000 Subject: [PATCH 11/27] Stop writing sidetone audio on error --- cwsidetone.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index c11fa74..a9e7a56 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -148,8 +148,8 @@ void cwSidetone::send(QString text) pos++; } if (outputDevice != Q_NULLPTR) { - qint64 written = outputDevice->write(buffer); - while (written < buffer.size()) + qint64 written = 0; + while (written != -1 && written < buffer.size()) { written += outputDevice->write(buffer.data()+written, buffer.size() - written); QApplication::processEvents(); From 18254cad1006292e75c29c67e886fcb138efe7d0 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 17:56:10 +0000 Subject: [PATCH 12/27] Log if write fails --- cwsidetone.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index a9e7a56..c8252b5 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -151,9 +151,13 @@ void cwSidetone::send(QString text) qint64 written = 0; while (written != -1 && written < buffer.size()) { - written += outputDevice->write(buffer.data()+written, buffer.size() - written); + written += outputDevice->write(buffer.data() + written, buffer.size() - written); QApplication::processEvents(); } + if (written == -1) + { + qWarning(logCW()) << QString("Sidetone sending error occurred, aborting (%0 bytes of %1 remaining)").arg(buffer.size()-written).arg(buffer.size()); + } } } //qInfo(logCW()) << "Sending" << this->currentChar; From 428ea9156c03d85abe9fdb88d514e6e8601785f9 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 18:08:44 +0000 Subject: [PATCH 13/27] Change way we set sidetone volume --- cwsidetone.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index c8252b5..8425b7d 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -104,8 +104,6 @@ void cwSidetone::init() output = new QAudioSink(device,format); #endif - output->setVolume((qreal)volume/100.0); - #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) qInfo(logCW()) << QString("Sidetone Output: %0 (volume: %1 rate: %2 size: %3 type: %4)") .arg(device.deviceName()).arg(volume).arg(format.sampleRate()).arg(format.sampleSize()).arg(format.sampleType()); @@ -220,7 +218,7 @@ QByteArray cwSidetone::generateData(qint64 len, qint64 freq) int sampleIndex = 0; while (length) { - const qreal x = qSin(2 * M_PI * freq * qreal(sampleIndex % sampleRate) / sampleRate); + const qreal x = (qSin(2 * M_PI * freq * qreal(sampleIndex % sampleRate) / sampleRate)) * qreal(volume/100.0); for (int i=0; isetVolume((qreal)level/100.0); - } - } From acec37ea17161ff0a7e6c30e5fcf0997f5217ed1 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 23:21:29 +0000 Subject: [PATCH 14/27] Improve timing --- cwsidetone.cpp | 13 ++++++++----- cwsidetone.h | 3 ++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index 8425b7d..956b510 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -175,15 +175,17 @@ void cwSidetone::generateMorse(QString morse) if (c == '-') { buffer.append(generateData(dah,this->frequency)); - } else if (c == '.') + } + else if (c == '.') { buffer.append(generateData(dit,this->frequency)); - } else // Space char + } + else // Space char { - buffer.append(generateData(dah+dit,0)); + buffer.append(generateData(dit,0)); } - if (i+1 #include -#define SIDETONE_MULTIPLIER 386.0 +//#define SIDETONE_MULTIPLIER 386.0 +#define SIDETONE_MULTIPLIER 1095.46 class cwSidetone : public QObject { From ed1e8c3a8e87e2811639c5f4d989530c49890c10 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Fri, 17 Feb 2023 23:57:53 +0000 Subject: [PATCH 15/27] Add message stacking --- cwsidetone.cpp | 28 +++++++++++++++++++--------- cwsidetone.h | 3 +++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index 956b510..b17e0e6 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -119,17 +119,26 @@ void cwSidetone::init() void cwSidetone::send(QString text) { - if (output != Q_NULLPTR && outputDevice != Q_NULLPTR) { - text=text.simplified(); - buffer.clear(); - QString currentChar; + messages.push_back(text.simplified()); + + if (messages.size() > 1) { + // There are already queued messages so just return + return; + } + + QString currentChar; + if (output->state() == QAudio::StoppedState || output->state() == QAudio::SuspendedState) { + output->resume(); + } + + for (auto txt = messages.begin(); txt != messages.end();) + { int pos = 0; - if (output->state() == QAudio::StoppedState || output->state() == QAudio::SuspendedState) { - output->resume(); - } - while (pos < text.size()) + buffer.clear(); + + while (pos < txt->size()) { - QChar ch = text.at(pos).toUpper(); + QChar ch = txt->at(pos).toUpper(); if (ch == NULL) { currentChar = cwTable[' ']; @@ -157,6 +166,7 @@ void cwSidetone::send(QString text) qWarning(logCW()) << QString("Sidetone sending error occurred, aborting (%0 bytes of %1 remaining)").arg(buffer.size()-written).arg(buffer.size()); } } + txt = messages.erase(txt); } //qInfo(logCW()) << "Sending" << this->currentChar; emit finished(); diff --git a/cwsidetone.h b/cwsidetone.h index a09d5af..e43ec97 100644 --- a/cwsidetone.h +++ b/cwsidetone.h @@ -18,6 +18,8 @@ #include #include +#include + //#define SIDETONE_MULTIPLIER 386.0 #define SIDETONE_MULTIPLIER 1095.46 @@ -52,6 +54,7 @@ private: int frequency; double ratio; QAudioFormat format; + std::deque messages; #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) QAudioOutput* output = Q_NULLPTR; #else From 9f97df0ea5ea01d032c264619bbd929e122346b8 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Sat, 18 Feb 2023 11:03:13 +0000 Subject: [PATCH 16/27] Make generateData more readable --- cwsidetone.cpp | 53 +++++++++++++++++--------------------------------- 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index b17e0e6..a34b771 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -235,45 +235,28 @@ QByteArray cwSidetone::generateData(qint64 len, qint64 freq) for (int i=0; i((1.0 + x) / 2 * 255); - *reinterpret_cast(ptr) = value; - -#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) - } else if (format.sampleType() == QAudioFormat::Float) -#else - } else if (format.sampleFormat() == QAudioFormat::Float) -#endif - { - float value = static_cast(x); - qToLittleEndian(value, ptr); -#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) - } else if (format.sampleSize() == 32 && format.sampleType() == QAudioFormat::SignedInt) -#else - } else if (format.sampleFormat() == QAudioFormat::Int32) -#endif - { - qint32 value = static_cast(x); - qToLittleEndian(value, ptr); -#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) - } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) -#else - } else if (format.sampleFormat() == QAudioFormat::Int16) -#endif - { - qint16 value = static_cast(x * 32767); - qToLittleEndian(value, ptr); - } - else { -#if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) + *reinterpret_cast(ptr) = static_cast((1.0 + x) / 2 * 255); + else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) + *reinterpret_cast(ptr) = static_cast(x * 32767); + else if (format.sampleSize() == 32 && format.sampleType() == QAudioFormat::SignedInt) + *reinterpret_cast(ptr) = static_cast(x * std::numeric_limits::max()); + else if (format.sampleType() == QAudioFormat::Float) + *reinterpret_cast(ptr) = x; + else qWarning(logCW()) << QString("Unsupported sample size: %0 type: %1").arg(format.sampleSize()).arg(format.sampleType()); #else + if (format.sampleFormat() == QAudioFormat::UInt8) + *reinterpret_cast(ptr) = static_cast((1.0 + x) / 2 * 255); + else if (format.sampleFormat() == QAudioFormat::Int16) + *reinterpret_cast(ptr) = static_cast(x * 32767); + else if (format.sampleFormat() == QAudioFormat::Int32) + *reinterpret_cast(ptr) = static_cast(x * std::numeric_limits::max()); + else if (format.sampleFormat() == QAudioFormat::Float) + *reinterpret_cast(ptr) = x; + else qWarning(logCW()) << QString("Unsupported sample format: %0").arg(format.sampleFormat()); #endif - } + ptr += channelBytes; length -= channelBytes; } From 62f923d8ad38f4823d62569df71d8726c01616cd Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Sat, 18 Feb 2023 13:18:42 +0000 Subject: [PATCH 17/27] Add support for push audio and various other fixes --- cwsender.cpp | 2 + cwsidetone.cpp | 134 +++++++++++++++++++++++++++++-------------------- cwsidetone.h | 31 ++++++------ 3 files changed, 98 insertions(+), 69 deletions(-) diff --git a/cwsender.cpp b/cwsender.cpp index 6b60b59..d31d384 100644 --- a/cwsender.cpp +++ b/cwsender.cpp @@ -38,6 +38,8 @@ cwSender::cwSender(QWidget *parent) : [=](const unsigned char& pitch) { tone->setFrequency(pitch); }); connect(this, &cwSender::setLevel, [=](const unsigned char& level) { tone->setLevel(level); }); + connect(this, &cwSender::stopCW, + [=]() { tone->stopSending(); }); } cwSender::~cwSender() diff --git a/cwsidetone.cpp b/cwsidetone.cpp index a34b771..b8542a7 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -1,7 +1,6 @@ #include "cwsidetone.h" #include "logcategories.h" -#include "qapplication.h" cwSidetone::cwSidetone(int level, int speed, int freq, double ratio, QWidget* parent) : parent(parent), @@ -74,8 +73,8 @@ cwSidetone::cwSidetone(int level, int speed, int freq, double ratio, QWidget* pa cwSidetone::~cwSidetone() { + this->stop(); output->stop(); - delete output; } void cwSidetone::init() @@ -89,7 +88,7 @@ void cwSidetone::init() format.setSampleType(QAudioFormat::SignedInt); QAudioDeviceInfo device(QAudioDeviceInfo::defaultOutputDevice()); #else - format.setSampleFormat(QAudioFormat::Float); + format.setSampleFormat(QAudioFormat::Int16); QAudioDevice device = QMediaDevices::defaultAudioOutput(); #endif if (!device.isNull()) { @@ -99,9 +98,9 @@ void cwSidetone::init() } #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) - output = new QAudioOutput(device,format); + output.reset(new QAudioOutput(device,format)); #else - output = new QAudioSink(device,format); + output.reset(new QAudioSink(device,format)); #endif #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) @@ -110,75 +109,93 @@ void cwSidetone::init() #else qInfo(logCW()) << QString("Sidetone Output: %0 (volume: %1 rate: %2 type: %3") .arg(device.description()).arg(volume).arg(format.sampleRate()).arg(format.sampleFormat()); -#endif - - - outputDevice = output->start(); +#endif } + this->start(); // Start QIODevice } void cwSidetone::send(QString text) { - messages.push_back(text.simplified()); - - if (messages.size() > 1) { - // There are already queued messages so just return - return; - } + text=text.simplified(); QString currentChar; - if (output->state() == QAudio::StoppedState || output->state() == QAudio::SuspendedState) { - output->resume(); - } - for (auto txt = messages.begin(); txt != messages.end();) + int pos = 0; + while (pos < text.size()) { - int pos = 0; - buffer.clear(); - - while (pos < txt->size()) + QChar ch = text.at(pos).toUpper(); + if (ch == NULL) { - QChar ch = txt->at(pos).toUpper(); - if (ch == NULL) - { - currentChar = cwTable[' ']; - } - else if (this->cwTable.contains(ch)) - { - currentChar = cwTable[ch]; - } - else - { - currentChar=cwTable['?']; - } - generateMorse(currentChar); - pos++; + currentChar = cwTable[' ']; } - if (outputDevice != Q_NULLPTR) { - qint64 written = 0; - while (written != -1 && written < buffer.size()) - { - written += outputDevice->write(buffer.data() + written, buffer.size() - written); - QApplication::processEvents(); - } - if (written == -1) - { - qWarning(logCW()) << QString("Sidetone sending error occurred, aborting (%0 bytes of %1 remaining)").arg(buffer.size()-written).arg(buffer.size()); - } + else if (this->cwTable.contains(ch)) + { + currentChar = cwTable[ch]; } - txt = messages.erase(txt); + else + { + currentChar=cwTable['?']; + } + generateMorse(currentChar); + pos++; } //qInfo(logCW()) << "Sending" << this->currentChar; - emit finished(); + if (output->state() == QAudio::StoppedState) + { + output->start(this); + } + + if (output->state() == QAudio::IdleState) { + output->suspend(); + output->resume(); + } return; } + +void cwSidetone::start() +{ + open(QIODevice::ReadOnly); +} + +void cwSidetone::stop() +{ + close(); +} + +qint64 cwSidetone::readData(char *data, qint64 len) +{ + QMutexLocker locker(&mutex); + const qint64 total = qMin((buffer.size()), len); + memcpy(data, buffer.constData(), total); + buffer.remove(0,total); + if (buffer.size() == 0) { + emit finished(); + } + return total; +} + +qint64 cwSidetone::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data); + Q_UNUSED(len); + + return 0; +} + +qint64 cwSidetone::bytesAvailable() const +{ + return buffer.size() + QIODevice::bytesAvailable(); +} + void cwSidetone::generateMorse(QString morse) { int dit = int(double(SIDETONE_MULTIPLIER / this->speed * SIDETONE_MULTIPLIER)); - int dah = int(dit * this->ratio); + int dah = int(double(dit * this->ratio)); + + QMutexLocker locker(&mutex); for (int i=0;i(ptr) = static_cast((1.0 + x) / 2 * 255); else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) - *reinterpret_cast(ptr) = static_cast(x * 32767); + *reinterpret_cast(ptr) = static_cast(x * std::numeric_limits::max()); else if (format.sampleSize() == 32 && format.sampleType() == QAudioFormat::SignedInt) *reinterpret_cast(ptr) = static_cast(x * std::numeric_limits::max()); else if (format.sampleType() == QAudioFormat::Float) @@ -248,7 +265,7 @@ QByteArray cwSidetone::generateData(qint64 len, qint64 freq) if (format.sampleFormat() == QAudioFormat::UInt8) *reinterpret_cast(ptr) = static_cast((1.0 + x) / 2 * 255); else if (format.sampleFormat() == QAudioFormat::Int16) - *reinterpret_cast(ptr) = static_cast(x * 32767); + *reinterpret_cast(ptr) = static_cast(x * std::numeric_limits::max()); else if (format.sampleFormat() == QAudioFormat::Int32) *reinterpret_cast(ptr) = static_cast(x * std::numeric_limits::max()); else if (format.sampleFormat() == QAudioFormat::Float) @@ -284,3 +301,10 @@ void cwSidetone::setRatio(unsigned char ratio) void cwSidetone::setLevel(int level) { volume = level; } + +void cwSidetone::stopSending() { + QMutexLocker locker(&mutex); + buffer.clear(); +} + + diff --git a/cwsidetone.h b/cwsidetone.h index e43ec97..5fb9436 100644 --- a/cwsidetone.h +++ b/cwsidetone.h @@ -4,6 +4,10 @@ #include #include #include +#include +#include +#include +#include #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) #include @@ -14,22 +18,24 @@ #include #endif -#include -#include -#include - -#include - //#define SIDETONE_MULTIPLIER 386.0 #define SIDETONE_MULTIPLIER 1095.46 -class cwSidetone : public QObject +class cwSidetone : public QIODevice { Q_OBJECT public: explicit cwSidetone(int level, int speed, int freq, double ratio, QWidget *parent = 0); ~cwSidetone(); + void start(); + void stop(); + + qint64 readData(char *data, qint64 maxlen) override; + qint64 writeData(const char *data, qint64 len) override; + qint64 bytesAvailable() const override; + qint64 size() const override { return buffer.size(); } + signals: void finished(); public slots: @@ -38,6 +44,7 @@ public slots: void setFrequency(unsigned char frequency); void setRatio(unsigned char ratio); void setLevel(int level); + void stopSending(); private: void init(); @@ -45,22 +52,18 @@ private: QByteArray generateData(qint64 len, qint64 freq); QByteArray buffer; QMap< QChar, QString> cwTable; - int position = 0; - int charSpace = 20; - int wordSpace = 60; QWidget* parent; int volume; int speed; int frequency; double ratio; QAudioFormat format; - std::deque messages; + QMutex mutex; #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) - QAudioOutput* output = Q_NULLPTR; + QScopedPointer output; #else - QAudioSink* output = Q_NULLPTR; + QScopedPointer output; #endif - QIODevice* outputDevice = Q_NULLPTR; }; #endif // CWSIDETONE_H From 5fb9588c4aee25d18a6b3bb2e644c2558020dc28 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Sat, 18 Feb 2023 14:25:36 +0000 Subject: [PATCH 18/27] Bit more tidying --- cwsidetone.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index b8542a7..7dacc6f 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -118,12 +118,10 @@ void cwSidetone::send(QString text) { text=text.simplified(); - QString currentChar; - - int pos = 0; - while (pos < text.size()) + for (int pos=0; pos < text.size(); pos++) { QChar ch = text.at(pos).toUpper(); + QString currentChar; if (ch == NULL) { currentChar = cwTable[' ']; @@ -137,15 +135,13 @@ void cwSidetone::send(QString text) currentChar=cwTable['?']; } generateMorse(currentChar); - pos++; } - //qInfo(logCW()) << "Sending" << this->currentChar; + if (output->state() == QAudio::StoppedState) { output->start(this); } - - if (output->state() == QAudio::IdleState) { + else if (output->state() == QAudio::IdleState) { output->suspend(); output->resume(); } From fe0fc0a5bb8f611004cdc3a8dac724e53276e309 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Sat, 18 Feb 2023 15:13:05 +0000 Subject: [PATCH 19/27] Compile issue --- cwsidetone.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index 7dacc6f..0654c43 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -162,7 +162,7 @@ void cwSidetone::stop() qint64 cwSidetone::readData(char *data, qint64 len) { QMutexLocker locker(&mutex); - const qint64 total = qMin((buffer.size()), len); + const int total = qMin(((int)buffer.size()), (int)len); memcpy(data, buffer.constData(), total); buffer.remove(0,total); if (buffer.size() == 0) { From e6644cdc1116e0ae22ca7464111ba26cf3ff96b7 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Sat, 18 Feb 2023 15:14:05 +0000 Subject: [PATCH 20/27] Update cwsidetone.cpp --- cwsidetone.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index 0654c43..0f2b185 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -162,7 +162,7 @@ void cwSidetone::stop() qint64 cwSidetone::readData(char *data, qint64 len) { QMutexLocker locker(&mutex); - const int total = qMin(((int)buffer.size()), (int)len); + const qint64 total = qMin(((qint64)buffer.size()), len); memcpy(data, buffer.constData(), total); buffer.remove(0,total); if (buffer.size() == 0) { From a6b1bce69eb4e196a815749dbb46bc0f67b4487a Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Mon, 20 Feb 2023 10:31:09 +0000 Subject: [PATCH 21/27] Disconnect signals when not in use --- cwsender.cpp | 75 +++++++++++++++++++++++++++++++------------------- cwsender.h | 4 ++- cwsidetone.cpp | 1 + 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/cwsender.cpp b/cwsender.cpp index d31d384..92b09ca 100644 --- a/cwsender.cpp +++ b/cwsender.cpp @@ -18,28 +18,6 @@ cwSender::cwSender(QWidget *parent) : ui->statusbar->setToolTipDuration(3000); this->setToolTipDuration(3000); connect(ui->textToSendEdit->lineEdit(), &QLineEdit::textEdited, this, &cwSender::textChanged); - - toneThread = new QThread(this); - toneThread->setObjectName("sidetone()"); - - tone = new cwSidetone(sidetoneLevel, ui->wpmSpin->value(),ui->pitchSpin->value(),ui->dashSpin->value(),this); - tone->moveToThread(toneThread); - toneThread->start(); - - connect(toneThread, &QThread::finished, - [=]() { tone->deleteLater(); }); - connect(this, &cwSender::sidetone, - [=](const QString& text) { tone->send(text); }); - connect(this, &cwSender::setKeySpeed, - [=](const unsigned char& wpm) { tone->setSpeed(wpm); }); - connect(this, &cwSender::setDashRatio, - [=](const unsigned char& ratio) { tone->setRatio(ratio); }); - connect(this, &cwSender::setPitch, - [=](const unsigned char& pitch) { tone->setFrequency(pitch); }); - connect(this, &cwSender::setLevel, - [=](const unsigned char& level) { tone->setLevel(level); }); - connect(this, &cwSender::stopCW, - [=]() { tone->stopSending(); }); } cwSender::~cwSender() @@ -47,10 +25,16 @@ cwSender::~cwSender() qDebug(logCW()) << "Running CW Sender destructor."; if (toneThread != Q_NULLPTR) { + for (auto conn: connections) + { + disconnect(conn); + } toneThread->quit(); toneThread->wait(); toneThread = Q_NULLPTR; tone = Q_NULLPTR; + /* Finally disconnect all connections */ + connections.clear(); } delete ui; @@ -147,9 +131,6 @@ void cwSender::textChanged(QString text) ui->transcriptText->moveCursor(QTextCursor::End); emit sendCW(text.mid(0, 30)); - if (ui->sidetoneEnableChk->isChecked()) - emit sidetone(text.mid(0,30)); - } if( (currentMode != modeCW) && (currentMode != modeCW_R) ) { @@ -184,8 +165,6 @@ void cwSender::on_sendBtn_clicked() ui->statusbar->showMessage("Sending CW", 3000); emit sendCW(text); - if (ui->sidetoneEnableChk->isChecked()) - emit sidetone(text); } if( (currentMode != modeCW) && (currentMode != modeCW_R) ) @@ -284,6 +263,45 @@ void cwSender::on_macro10btn_clicked() void cwSender::on_sidetoneEnableChk_clicked(bool clicked) { ui->sidetoneLevelSlider->setEnabled(clicked); + if (clicked && toneThread == Q_NULLPTR) + { + toneThread = new QThread(this); + toneThread->setObjectName("sidetone()"); + + tone = new cwSidetone(sidetoneLevel, ui->wpmSpin->value(),ui->pitchSpin->value(),ui->dashSpin->value(),this); + tone->moveToThread(toneThread); + toneThread->start(); + + connect(toneThread, &QThread::finished, + [=]() { tone->deleteLater(); }); + + connections.append(connect(this, &cwSender::sendCW, + [=](const QString& text) { tone->send(text); ui->sidetoneEnableChk->setEnabled(false); })); + connections.append(connect(this, &cwSender::setKeySpeed, + [=](const unsigned char& wpm) { tone->setSpeed(wpm); })); + connections.append(connect(this, &cwSender::setDashRatio, + [=](const unsigned char& ratio) { tone->setRatio(ratio); })); + connections.append(connect(this, &cwSender::setPitch, + [=](const unsigned char& pitch) { tone->setFrequency(pitch); })); + connections.append(connect(this, &cwSender::setLevel, + [=](const unsigned char& level) { tone->setLevel(level); })); + connections.append(connect(this, &cwSender::stopCW, + [=]() { tone->stopSending(); })); + connections.append(connect(tone, &cwSidetone::finished, + [=]() { ui->sidetoneEnableChk->setEnabled(true); })); + + } else if (!clicked && toneThread != Q_NULLPTR) { + /* disconnect all connections */ + for (auto conn: connections) + { + disconnect(conn); + } + connections.clear(); + toneThread->quit(); + toneThread->wait(); + toneThread = Q_NULLPTR; + tone = Q_NULLPTR; + } } void cwSender::on_sidetoneLevelSlider_valueChanged(int val) @@ -332,8 +350,6 @@ void cwSender::runMacroButton(int buttonNumber) for (int i = 0; i < outText.size(); i = i + 30) { emit sendCW(outText.mid(i,30)); - if (ui->sidetoneEnableChk->isChecked()) - emit sidetone(outText.mid(i,30)); } ui->textToSendEdit->setFocus(); @@ -433,6 +449,7 @@ void cwSender::setSendImmediate(bool val) void cwSender::setSidetoneEnable(bool val) { ui->sidetoneEnableChk->setChecked(val); + on_sidetoneEnableChk_clicked(val); } void cwSender::setSidetoneLevel(int val) diff --git a/cwsender.h b/cwsender.h index 26d1c90..5c4e0ed 100644 --- a/cwsender.h +++ b/cwsender.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "cwsidetone.h" #include "wfviewtypes.h" @@ -111,7 +112,8 @@ private: void setMacroButtonText(QString btnText, QPushButton *btn); cwSidetone* tone=Q_NULLPTR; QThread* toneThread = Q_NULLPTR; - + bool sidetoneWasEnabled=false; + QList connections; }; #endif // CWSENDER_H diff --git a/cwsidetone.cpp b/cwsidetone.cpp index 0f2b185..9cdb4d9 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -73,6 +73,7 @@ cwSidetone::cwSidetone(int level, int speed, int freq, double ratio, QWidget* pa cwSidetone::~cwSidetone() { + qInfo(logCW()) << "cwSidetone() finished"; this->stop(); output->stop(); } From c8b97e895286f1143c65e4e5c89d65185ed31304 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Mon, 20 Feb 2023 10:34:21 +0000 Subject: [PATCH 22/27] Emit finished() if sending is stopped prematurely --- cwsidetone.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/cwsidetone.cpp b/cwsidetone.cpp index 9cdb4d9..0bfecd4 100644 --- a/cwsidetone.cpp +++ b/cwsidetone.cpp @@ -302,6 +302,7 @@ void cwSidetone::setLevel(int level) { void cwSidetone::stopSending() { QMutexLocker locker(&mutex); buffer.clear(); + emit finished(); } From e49eb2878e941f52e6f75f97888ae09fd20c0791 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Mon, 20 Feb 2023 11:48:53 +0000 Subject: [PATCH 23/27] Rearrange signals --- cwsender.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/cwsender.cpp b/cwsender.cpp index 92b09ca..8307977 100644 --- a/cwsender.cpp +++ b/cwsender.cpp @@ -25,15 +25,15 @@ cwSender::~cwSender() qDebug(logCW()) << "Running CW Sender destructor."; if (toneThread != Q_NULLPTR) { - for (auto conn: connections) - { - disconnect(conn); - } toneThread->quit(); toneThread->wait(); toneThread = Q_NULLPTR; tone = Q_NULLPTR; /* Finally disconnect all connections */ + for (auto conn: connections) + { + disconnect(conn); + } connections.clear(); } @@ -272,9 +272,8 @@ void cwSender::on_sidetoneEnableChk_clicked(bool clicked) tone->moveToThread(toneThread); toneThread->start(); - connect(toneThread, &QThread::finished, - [=]() { tone->deleteLater(); }); - + connections.append(connect(toneThread, &QThread::finished, + [=]() { tone->deleteLater(); })); connections.append(connect(this, &cwSender::sendCW, [=](const QString& text) { tone->send(text); ui->sidetoneEnableChk->setEnabled(false); })); connections.append(connect(this, &cwSender::setKeySpeed, @@ -292,15 +291,15 @@ void cwSender::on_sidetoneEnableChk_clicked(bool clicked) } else if (!clicked && toneThread != Q_NULLPTR) { /* disconnect all connections */ + toneThread->quit(); + toneThread->wait(); + toneThread = Q_NULLPTR; + tone = Q_NULLPTR; for (auto conn: connections) { disconnect(conn); } connections.clear(); - toneThread->quit(); - toneThread->wait(); - toneThread = Q_NULLPTR; - tone = Q_NULLPTR; } } From 7901ceba79e4e28fddeaa134e213dc756173f747 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Mon, 20 Feb 2023 12:43:26 +0000 Subject: [PATCH 24/27] Add remaining rigctld commands (mainly unimplemented) --- rigctld.cpp | 1651 ++++++++++++++++++++++++++++----------------------- rigstate.h | 3 +- 2 files changed, 925 insertions(+), 729 deletions(-) diff --git a/rigctld.cpp b/rigctld.cpp index a6168b3..a90f09e 100644 --- a/rigctld.cpp +++ b/rigctld.cpp @@ -183,201 +183,7 @@ void rigCtlClient::socketReadyRead() QStringList command = commands.mid(num).split(" "); - if (command[0] == '\xf0' || command[0] == "chk_vfo") - { - chkVfoEecuted = true; - QString resp; - if (longReply) { - resp.append(QString("ChkVFO: ")); - } - resp.append(QString("%1").arg(rigState->getChar(CURRENTVFO))); - response.append(resp); - } - else if (command[0] == "dump_state") - { - quint64 modes = getRadioModes(); - - // rigctld protocol version - response.append("1"); - // Radio model - response.append(QString("%1").arg(rigCaps.rigctlModel)); - // Print something (used to be ITU region) - response.append("0"); - // Supported RX bands (startf,endf,modes,low_power,high_power,vfo,ant) - quint32 lowFreq = 0; - quint32 highFreq = 0; - for (bandType band : rigCaps.bands) - { - if (lowFreq == 0 || band.lowFreq < lowFreq) - lowFreq = band.lowFreq; - if (band.highFreq > highFreq) - highFreq = band.highFreq; - } - response.append(QString("%1.000000 %2.000000 0x%3 %4 %5 0x%6 0x%7").arg(lowFreq).arg(highFreq) - .arg(modes, 0, 16).arg(-1).arg(-1).arg(0x16000000, 0, 16).arg(getAntennas(), 0, 16)); - response.append("0 0 0 0 0 0 0"); - - if (rigCaps.hasTransmit) { - // Supported TX bands (startf,endf,modes,low_power,high_power,vfo,ant) - for (bandType band : rigCaps.bands) - { - response.append(QString("%1.000000 %2.000000 0x%3 %4 %5 0x%6 0x%7").arg(band.lowFreq).arg(band.highFreq) - .arg(modes, 0, 16).arg(2000).arg(100000).arg(0x16000000, 0, 16).arg(getAntennas(), 0, 16)); - } - } - response.append("0 0 0 0 0 0 0"); - - response.append(QString("0x%1 1").arg(modes, 0, 16)); - response.append(QString("0x%1 10").arg(modes, 0, 16)); - response.append(QString("0x%1 100").arg(modes, 0, 16)); - response.append(QString("0x%1 1000").arg(modes, 0, 16)); - response.append(QString("0x%1 2500").arg(modes, 0, 16)); - response.append(QString("0x%1 5000").arg(modes, 0, 16)); - response.append(QString("0x%1 6125").arg(modes, 0, 16)); - response.append(QString("0x%1 8333").arg(modes, 0, 16)); - response.append(QString("0x%1 10000").arg(modes, 0, 16)); - response.append(QString("0x%1 12500").arg(modes, 0, 16)); - response.append(QString("0x%1 25000").arg(modes, 0, 16)); - response.append(QString("0x%1 100000").arg(modes, 0, 16)); - response.append(QString("0x%1 250000").arg(modes, 0, 16)); - response.append(QString("0x%1 1000000").arg(modes, 0, 16)); - response.append("0 0"); - - modes = getRadioModes("SB"); - if (modes) { - response.append(QString("0x%1 3000").arg(modes, 0, 16)); - response.append(QString("0x%1 2400").arg(modes, 0, 16)); - response.append(QString("0x%1 1800").arg(modes, 0, 16)); - } - modes = getRadioModes("AM"); - if (modes) { - response.append(QString("0x%1 9000").arg(modes, 0, 16)); - response.append(QString("0x%1 6000").arg(modes, 0, 16)); - response.append(QString("0x%1 3000").arg(modes, 0, 16)); - } - modes = getRadioModes("CW"); - if (modes) { - response.append(QString("0x%1 1200").arg(modes, 0, 16)); - response.append(QString("0x%1 500").arg(modes, 0, 16)); - response.append(QString("0x%1 200").arg(modes, 0, 16)); - } - modes = getRadioModes("FM"); - if (modes) { - response.append(QString("0x%1 15000").arg(modes, 0, 16)); - response.append(QString("0x%1 10000").arg(modes, 0, 16)); - response.append(QString("0x%1 7000").arg(modes, 0, 16)); - } - modes = getRadioModes("RTTY"); - if (modes) { - response.append(QString("0x%1 2400").arg(modes, 0, 16)); - response.append(QString("0x%1 500").arg(modes, 0, 16)); - response.append(QString("0x%1 250").arg(modes, 0, 16)); - } - modes = getRadioModes("PSK"); - if (modes) { - response.append(QString("0x%1 1200").arg(modes, 0, 16)); - response.append(QString("0x%1 500").arg(modes, 0, 16)); - response.append(QString("0x%1 250").arg(modes, 0, 16)); - } - response.append("0 0"); - response.append("9900"); - response.append("9900"); - response.append("10000"); - response.append("0"); - QString preamps=""; - if (rigCaps.hasPreamp) { - for (quint8 pre : rigCaps.preamps) - { - if (pre == 0) - continue; - preamps.append(QString("%1 ").arg(pre*10)); - } - if (preamps.endsWith(" ")) - preamps.chop(1); - } - else { - preamps = "0"; - } - response.append(preamps); - - QString attens = ""; - if (rigCaps.hasAttenuator) { - for (quint8 att : rigCaps.attenuators) - { - if (att == 0) - continue; - attens.append(QString("%1 ").arg(att,0,16)); - } - if (attens.endsWith(" ")) - attens.chop(1); - } - else { - attens = "0"; - } - response.append(attens); - - response.append("0xffffffffffffffff"); - response.append("0xffffffffffffffff"); - response.append("0xffffffffffffffff"); - response.append("0xffffffffffffffff"); - response.append("0xffffffffffffffff"); - response.append("0xffffffffffffffff"); - - if (chkVfoEecuted) { - response.append(QString("vfo_ops=0x%1").arg(255, 0, 16)); - response.append(QString("ptt_type=0x%1").arg(rigCaps.hasTransmit, 0, 16)); - response.append(QString("has_set_vfo=0x%1").arg(1, 0, 16)); - response.append(QString("has_get_vfo=0x%1").arg(1, 0, 16)); - response.append(QString("has_set_freq=0x%1").arg(1, 0, 16)); - response.append(QString("has_get_freq=0x%1").arg(1, 0, 16)); - response.append(QString("has_set_conf=0x%1").arg(1, 0, 16)); - response.append(QString("has_get_conf=0x%1").arg(1, 0, 16)); - response.append(QString("has_power2mW=0x%1").arg(1, 0, 16)); - response.append(QString("has_mW2power=0x%1").arg(1, 0, 16)); - response.append(QString("timeout=0x%1").arg(1000, 0, 16)); - response.append("done"); - } - } - - else if (command[0] == "fmv") { - QString resp; - - if (rigState->getChar(CURRENTVFO) == 0) { - resp.append(QString("%1").arg(rigState->getInt64(VFOAFREQ))); - } - else { - resp.append(QString("%1").arg(rigState->getInt64(VFOBFREQ))); - } - response.append(resp); - resp = ""; - response.append(QString("%1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); - response.append(QString("%1").arg(rigState->getUInt16(PASSBAND))); - - if (rigState->getChar(CURRENTVFO) == 0) { - resp.append("VFOA"); - } - else { - resp.append("VFOB"); - } - response.append(resp); - } - else if (command[0] == "f" || command[0] == "get_freq") - { - QString resp; - if (longReply) { - resp.append(QString("Frequency: ")); - } - - if (rigState->getChar(CURRENTVFO)==0) { - resp.append(QString("%1").arg(rigState->getInt64(VFOAFREQ))); - } - else { - resp.append(QString("%1").arg(rigState->getInt64(VFOBFREQ))); - } - - response.append(resp); - } - else if (command[0] == "F" || command[0] == "set_freq") + if (command[0] == "F" || command[0] == "set_freq") { setCommand = true; freqt freq; @@ -388,7 +194,7 @@ void rigCtlClient::socketReadyRead() { newFreq = command[1].toDouble(&ok); } - else if (command.length() == 3) // Includes VFO + else if (command.length() == 3) // Includes VFO { newFreq = command[2].toDouble(&ok); if (command[1] == "VFOB") @@ -408,224 +214,21 @@ void rigCtlClient::socketReadyRead() } } } - else if (command[0] == "1" || command[0] == "dump_caps") - { - response.append(QString("Caps dump for model: %1").arg(rigCaps.modelID)); - response.append(QString("Model Name:\t%1").arg(rigCaps.modelName)); - response.append(QString("Mfg Name:\tIcom")); - response.append(QString("Backend version:\t0.1")); - response.append(QString("Backend copyright:\t2021")); - if (rigCaps.hasTransmit) { - response.append(QString("Rig type:\tTransceiver")); - } - else - { - response.append(QString("Rig type:\tReceiver")); - } - if (rigCaps.hasPTTCommand) { - response.append(QString("PTT type:\tRig capable")); - } - response.append(QString("DCD type:\tRig capable")); - response.append(QString("Port type:\tNetwork link")); - } - else if (command[0] == "t" || command[0] == "get_ptt") - { - if (rigCaps.hasPTTCommand) { - QString resp; - if (longReply) { - resp.append(QString("PTT: ")); - } - resp.append(QString("%1").arg(rigState->getBool(PTT))); - response.append(resp); - } - else - { - responseCode = -1; - } - } - else if (command.length() > 1 && (command[0] == "T" || command[0] == "set_ptt")) - { - setCommand = true; - if (rigCaps.hasPTTCommand) { - rigState->set(PTT, (bool)command[1].toInt(), true); - } - else - { - responseCode = -1; - } - } - else if (command[0] == "v" || command[0] == "v\nv" || command[0] == "get_vfo") - { - QString resp; - if (longReply) { - resp.append("VFO: "); - } - - if (rigState->getChar(CURRENTVFO) == 0) { - resp.append("VFOA"); - } - else if (rigState->getChar(CURRENTVFO) == 1) { - resp.append("VFOB"); - } - else if (rigState->getChar(CURRENTVFO) == 2) { - resp.append("MEM"); - } - - response.append(resp); - } - else if (command.length() > 1 && (command[0] == "V" || command[0] == "set_vfo")) - { - setCommand = true; - if (command[1] == "?") { - response.append("set_vfo: ?"); - response.append("VFOA"); - response.append("VFOB"); - response.append("Sub"); - response.append("Main"); - response.append("MEM"); - } - else if (command[1] == "VFOA" || command[1] == "Main") - { - rigState->set(CURRENTVFO, (quint8)0, true); - } - else if (command[1] == "VFOB" || command[1] == "Sub") - { - rigState->set(CURRENTVFO, (quint8)1, true); - } - else if (command[1] == "MEM") - { - rigState->set(CURRENTVFO, (quint8)2, true); - } - } - else if (command[0] == "s" || command[0] == "get_split_vfo") - { - - if (longReply) { - response.append(QString("Split: %1").arg(rigState->getChar(DUPLEX))); - } - else { - response.append(QString("%1").arg(rigState->getChar(DUPLEX))); - } - - QString resp; - if (longReply) { - resp.append("TX VFO: "); - } - - - if (rigState->getChar(CURRENTVFO) == 0) - { - resp.append(QString("%1").arg("VFOB")); - } - else { - resp.append(QString("%1").arg("VFOA")); - } - - response.append(resp); - } - else if (command.length() > 1 && (command[0] == "S" || command[0] == "set_split_vfo")) - { - setCommand = true; - - if (command[1] == "1") - { - rigState->set(DUPLEX, dmSplitOn, true); - } - else { - rigState->set(DUPLEX, dmSplitOff, true); - } - } - else if (command[0] == "\xf3" || command[0] == "get_vfo_info") - { - if (longReply) { - if (command[1] == "?") { - if (rigState->getChar(CURRENTVFO) == 0) { - response.append(QString("set_vfo: VFOA")); - } - else - { - response.append(QString("set_vfo: VFOB")); - } - } - if (command[1] == "VFOB") { - response.append(QString("Freq: %1").arg(rigState->getInt64(VFOBFREQ))); - } - else { - response.append(QString("Freq: %1").arg(rigState->getInt64(VFOAFREQ))); - } - response.append(QString("Mode: %1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); - response.append(QString("Width: %1").arg(rigState->getUInt16(PASSBAND))); - - response.append(QString("Split: %1").arg(rigState->getDuplex(DUPLEX))); - response.append(QString("SatMode: %1").arg(0)); // Need to get satmode - } - else { - if (command[1] == "VFOB") { - response.append(QString("%1").arg(rigState->getInt64(VFOBFREQ))); - } - else { - response.append(QString("%1").arg(rigState->getInt64(VFOAFREQ))); - } - response.append(QString("%1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); - response.append(QString("%1").arg(rigState->getUInt16(PASSBAND))); - - } - } - else if (command[0] == "i" || command[0] == "get_split_freq") + else if (command[0] == "f" || command[0] == "get_freq") { QString resp; if (longReply) { - resp.append("TX VFO: "); + resp.append(QString("Frequency: ")); } - - if (rigState->getInt64(CURRENTVFO) == 0) { - resp.append(QString("%1").arg(rigState->getInt64(VFOBFREQ))); - } - else { + + if (rigState->getChar(CURRENTVFO)==0) { resp.append(QString("%1").arg(rigState->getInt64(VFOAFREQ))); } - - response.append(resp); - } - else if (command.length() > 1 && (command[0] == "I" || command[0] == "set_split_freq")) - { - setCommand = true; - bool ok = false; - double newFreq = 0.0f; - newFreq = command[1].toDouble(&ok); - if (ok) { - qDebug(logRigCtlD()) << QString("set_split_freq: %1 (%2)").arg(newFreq).arg(command[1]); - rigState->set(VFOBFREQ, static_cast(newFreq),false); - } - } - else if (command.length() > 2 && (command[0] == "X" || command[0] == "set_split_mode")) - { - setCommand = true; - } - - else if (command.length() > 0 && (command[0] == "x" || command[0] == "get_split_mode")) - { - if (longReply) { - response.append(QString("TX Mode: %1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); - response.append(QString("TX Passband: %1").arg(rigState->getUInt16(PASSBAND))); - } - else { - response.append(QString("%1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); - response.append(QString("%1").arg(rigState->getUInt16(PASSBAND))); - } - } - - else if (command[0] == "m" || command[0] == "get_mode") - { - if (longReply) { - response.append(QString("TX Mode: %1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); - response.append(QString("TX Passband: %1").arg(rigState->getUInt16(PASSBAND))); - } else { - response.append(QString("%1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); - response.append(QString("%1").arg(rigState->getUInt16(PASSBAND))); + resp.append(QString("%1").arg(rigState->getInt64(VFOBFREQ))); } - //qDebug(logRigCtlD()) << QString("get_mode: %1 passband: %2").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE))).arg(rigState->getUInt16(PASSBAND)); + + response.append(resp); } else if (command[0] == "M" || command[0] == "set_mode") { @@ -722,6 +325,66 @@ void rigCtlClient::socketReadyRead() rigState->set(PASSBAND, passband, true); } } + else if (command[0] == "m" || command[0] == "get_mode") + { + if (longReply) { + response.append(QString("TX Mode: %1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); + response.append(QString("TX Passband: %1").arg(rigState->getUInt16(PASSBAND))); + } + else { + response.append(QString("%1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); + response.append(QString("%1").arg(rigState->getUInt16(PASSBAND))); + } + //qDebug(logRigCtlD()) << QString("get_mode: %1 passband: %2").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE))).arg(rigState->getUInt16(PASSBAND)); + } + else if (command.length() > 1 && (command[0] == "V" || command[0] == "set_vfo")) + { + setCommand = true; + if (command[1] == "?") { + response.append("set_vfo: ?"); + response.append("VFOA"); + response.append("VFOB"); + response.append("Sub"); + response.append("Main"); + response.append("MEM"); + } + else if (command[1] == "VFOA" || command[1] == "Main") + { + rigState->set(CURRENTVFO, (quint8)0, true); + } + else if (command[1] == "VFOB" || command[1] == "Sub") + { + rigState->set(CURRENTVFO, (quint8)1, true); + } + else if (command[1] == "MEM") + { + rigState->set(CURRENTVFO, (quint8)2, true); + } + } + else if (command[0] == "v" || command[0] == "v\nv" || command[0] == "get_vfo") + { + QString resp; + if (longReply) { + resp.append("VFO: "); + } + + if (rigState->getChar(CURRENTVFO) == 0) { + resp.append("VFOA"); + } + else if (rigState->getChar(CURRENTVFO) == 1) { + resp.append("VFOB"); + } + else if (rigState->getChar(CURRENTVFO) == 2) { + resp.append("MEM"); + } + + response.append(resp); + } + else if (command[0] == "J" || command[0] == "set_rit") + { + rigState->set(RITVALUE, command[1].toInt(),true); + setCommand = true; + } else if (command[0] == "j" || command[0] == "get_rit") { QString resp; @@ -731,35 +394,9 @@ void rigCtlClient::socketReadyRead() resp.append(QString("%1").arg(rigState->getInt32(RITVALUE))); response.append(resp); } - else if (command[0] == "J" || command[0] == "set_rit") - { - rigState->set(RITVALUE, command[1].toInt(),true); - setCommand = true; - } - else if (command[0] == "y" || command[0] == "get_ant") - { - qInfo(logRigCtlD()) << "get_ant:"; - - if (command.length() > 1) { - if (longReply) { - response.append(QString("AntCurr: %1").arg(getAntName((quint8)command[1].toInt()))); - response.append(QString("Option: %1").arg(0)); - response.append(QString("AntTx: %1").arg(getAntName(rigState->getChar(ANTENNA)))); - response.append(QString("AntRx: %1").arg(getAntName(rigState->getChar(ANTENNA)))); - } - else { - response.append(QString("%1").arg(getAntName((quint8)command[1].toInt()))); - response.append(QString("%1").arg(0)); - response.append(QString("%1").arg(getAntName(rigState->getChar(ANTENNA)))); - response.append(QString("%1").arg(getAntName(rigState->getChar(ANTENNA)))); - } - } - } - else if (command.length() > 1 && (command[0] == "Y" || command[0] == "set_ant")) + else if (command[0] == "Z" || command[0] == "set_xit") { setCommand = true; - qInfo(logRigCtlD()) << "set_ant:" << command[1]; - rigState->set(ANTENNA,antFromName(command[1]),true); } else if (command[0] == "z" || command[0] == "get_xit") { @@ -770,187 +407,306 @@ void rigCtlClient::socketReadyRead() resp.append(QString("%1").arg(0)); response.append(resp); } - else if (command[0] == "Z" || command[0] == "set_xit") + else if (command.length() > 1 && (command[0] == "T" || command[0] == "set_ptt")) { setCommand = true; + if (rigCaps.hasPTTCommand) { + rigState->set(PTT, (bool)command[1].toInt(), true); + } + else + { + responseCode = -1; + } } - else if (command.length() > 1 && (command[0] == "l" || command[0] == "get_level")) + else if (command[0] == "t" || command[0] == "get_ptt") + { + if (rigCaps.hasPTTCommand) { + QString resp; + if (longReply) { + resp.append(QString("PTT: ")); + } + resp.append(QString("%1").arg(rigState->getBool(PTT))); + response.append(resp); + } + else + { + responseCode = -1; + } + } + else if (command.length() > 0 && (command[0] == "0x0b" || command[0] == "get_dcd")) + { + response.append(QString("%1").arg((float)rigState->getChar(SQUELCH) / 255.0)); + } + else if (command.length() > 0 && (command[0] == "R" || command[0] == "set_rptr_shift")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "r" || command[0] == "get_rptr_shift")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "O" || command[0] == "set_rptr_offs")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "o" || command[0] == "get_rptr_offs")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "C" || command[0] == "set_ctcss_tone")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "c" || command[0] == "get_ctcss_tone")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "D" || command[0] == "set_dcs_tone")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "d" || command[0] == "get_dcs_tone")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "\x90" || command[0] == "set_ctcss_sql")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "\x91" || command[0] == "get_ctcss_sql")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "\x92" || command[0] == "set_dcs_sql")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "\x93" || command[0] == "get_dcs_sql")) + { + responseCode = -11; + } + else if (command[0] == "i" || command[0] == "get_split_freq") { QString resp; - int value = 0; if (longReply) { - resp.append("Level Value: "); + resp.append("TX VFO: "); } - if (command[1] == "STRENGTH") { - - if (rigCaps.model == model7610) - value = getCalibratedValue(rigState->getChar(SMETER), IC7610_STR_CAL); - else if (rigCaps.model == model7850) - value = getCalibratedValue(rigState->getChar(SMETER), IC7850_STR_CAL); - else - value = getCalibratedValue(rigState->getChar(SMETER), IC7300_STR_CAL); - //qInfo(logRigCtlD()) << "Calibration IN:" << rigState->sMeter << "OUT" << value; - resp.append(QString("%1").arg(value)); - } - - else if (command[1] == "AF") { - resp.append(QString("%1").arg((float)rigState->getChar(AFGAIN) / 255.0)); - } - else if (command[1] == "RF") { - resp.append(QString("%1").arg((float)rigState->getChar(RFGAIN) / 255.0)); - } - else if (command[1] == "SQL") { - resp.append(QString("%1").arg((float)rigState->getChar(SQUELCH) / 255.0)); - } - else if (command[1] == "COMP") { - resp.append(QString("%1").arg((float)rigState->getChar(COMPLEVEL) / 255.0)); - } - else if (command[1] == "MICGAIN") { - resp.append(QString("%1").arg((float)rigState->getChar(MICGAIN) / 255.0)); - } - else if (command[1] == "MON") { - resp.append(QString("%1").arg((float)rigState->getChar(MONITORLEVEL) / 255.0)); - } - else if (command[1] == "VOXGAIN") { - resp.append(QString("%1").arg((float)rigState->getChar(VOXGAIN) / 255.0)); - } - else if (command[1] == "ANTIVOX") { - resp.append(QString("%1").arg((float)rigState->getChar(ANTIVOXGAIN) / 255.0)); - } - else if (command[1] == "RFPOWER") { - resp.append(QString("%1").arg((float)rigState->getChar(RFPOWER) / 255.0)); - } - else if (command[1] == "PREAMP") { - resp.append(QString("%1").arg(rigState->getChar(PREAMP)*10)); - } - else if (command[1] == "ATT") { - resp.append(QString("%1").arg(rigState->getChar(ATTENUATOR))); - } - else if (command[1] == "CWPITCH") { - resp.append(QString("%1").arg(rigState->getInt16(CWPITCH))); - } - else if (command[1] == "NOTCHF") { - resp.append(QString("%1").arg(rigState->getInt16(NOTCHF))); - } - else if (command[1] == "IF") { - resp.append(QString("%1").arg(rigState->getInt16(IF))); - } - else if (command[1] == "PBT_IN") { - resp.append(QString("%1").arg((float)rigState->getChar(PBTIN) / 255.0)); - } - else if (command[1] == "PBT_OUT") { - resp.append(QString("%1").arg((float)rigState->getChar(PBTOUT) / 255.0)); - } - else if (command[1] == "APF") { - resp.append(QString("%1").arg((float)rigState->getChar(APF) / 255.0)); - } - else if (command[1] == "NR") { - resp.append(QString("%1").arg((float)rigState->getChar(NR) / 255.0)); - } - else if (command[1] == "BAL") { - resp.append(QString("%1").arg((float)rigState->getChar(BAL) / 255.0)); - } - else if (command[1] == "KEYSPD") { - resp.append(QString("%1").arg(rigState->getChar(KEYSPD)/5.1)); + if (rigState->getInt64(CURRENTVFO) == 0) { + resp.append(QString("%1").arg(rigState->getInt64(VFOBFREQ))); } else { - resp.append(QString("%1").arg(value)); + resp.append(QString("%1").arg(rigState->getInt64(VFOAFREQ))); } - + response.append(resp); } - else if (command.length() > 2 && (command[0] == "L" || command[0] == "set_level")) + else if (command.length() > 1 && (command[0] == "I" || command[0] == "set_split_freq")) { - int value=0; setCommand = true; - if (command[1] == "AF") { - value = command[2].toFloat() * 255; - rigState->set(AFGAIN, quint8(value), true); + bool ok = false; + double newFreq = 0.0f; + newFreq = command[1].toDouble(&ok); + if (ok) { + qDebug(logRigCtlD()) << QString("set_split_freq: %1 (%2)").arg(newFreq).arg(command[1]); + rigState->set(VFOBFREQ, static_cast(newFreq),false); } - else if (command[1] == "RF") { - value = command[2].toFloat() * 255; - rigState->set(RFGAIN, quint8(value), true); + } + else if (command.length() > 2 && (command[0] == "X" || command[0] == "set_split_mode")) + { + setCommand = true; + } + + else if (command.length() > 0 && (command[0] == "x" || command[0] == "get_split_mode")) + { + if (longReply) { + response.append(QString("TX Mode: %1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); + response.append(QString("TX Passband: %1").arg(rigState->getUInt16(PASSBAND))); } - else if (command[1] == "RFPOWER") { - value = command[2].toFloat() * 255; - rigState->set(RFPOWER, quint8(value), true); + else { + response.append(QString("%1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); + response.append(QString("%1").arg(rigState->getUInt16(PASSBAND))); } - else if (command[1] == "SQL") { - value = command[2].toFloat() * 255; - rigState->set(SQUELCH, quint8(value), true); + } + else if (command.length() > 1 && (command[0] == "S" || command[0] == "set_split_vfo")) + { + setCommand = true; + + if (command[1] == "1") + { + rigState->set(DUPLEX, dmSplitOn, true); } - else if (command[1] == "COMP") { - value = command[2].toFloat() * 255; - rigState->set(COMPLEVEL, quint8(value), true); + else { + rigState->set(DUPLEX, dmSplitOff, true); } - else if (command[1] == "MICGAIN") { - value = command[2].toFloat() * 255; - rigState->set(MICGAIN, quint8(value), true); + } + else if (command[0] == "s" || command[0] == "get_split_vfo") + { + + if (longReply) { + response.append(QString("Split: %1").arg(rigState->getChar(DUPLEX))); } - else if (command[1] == "MON") { - value = command[2].toFloat() * 255; - rigState->set(MONITORLEVEL, quint8(value), true); - } - else if (command[1] == "VOXGAIN") { - value = command[2].toFloat() * 255; - rigState->set(VOXGAIN, quint8(value), true); - } - else if (command[1] == "ANTIVOX") { - value = command[2].toFloat() * 255; - rigState->set(ANTIVOXGAIN, quint8(value), true); - } - else if (command[1] == "ATT") { - value = command[2].toInt(); - rigState->set(ATTENUATOR, quint8(value), true); - } - else if (command[1] == "PREAMP") { - value = command[2].toFloat() / 10; - rigState->set(PREAMP, quint8(value), true); - } - else if (command[1] == "AGC") { - value = command[2].toFloat() * 255; - rigState->set(AGC, quint8(value), true); - } - else if (command[1] == "CWPITCH") { - value = command[2].toInt(); - rigState->set(CWPITCH, value, true); - } - else if (command[1] == "NOTCHF") { - value = command[2].toInt(); - rigState->set(NOTCHF, value, true); - } - else if (command[1] == "IF") { - value = command[2].toInt(); - rigState->set(IF, qint16(value), true); - } - else if (command[1] == "PBT_IN") { - value = command[2].toFloat() * 255; - rigState->set(PBTIN, quint8(value), true); - } - else if (command[1] == "PBT_OUT") { - value = command[2].toFloat() * 255; - rigState->set(PBTOUT, quint8(value), true); - } - else if (command[1] == "APF") { - value = command[2].toFloat() * 255; - rigState->set(APF, quint8(value), true); - } - else if (command[1] == "NR") { - value = command[2].toFloat() * 255; - rigState->set(NR, quint8(value), true); - } - else if (command[1] == "BAL") { - value = command[2].toFloat() * 255; - rigState->set(BAL, quint8(value), true); - } - else if (command[1] == "KEYSPD") { - value = command[2].toInt() * 5.1; - rigState->set(KEYSPD, quint8(value), true); + else { + response.append(QString("%1").arg(rigState->getChar(DUPLEX))); } - qInfo(logRigCtlD()) << "Setting:" << command[1] << command[2] << value; + QString resp; + if (longReply) { + resp.append("TX VFO: "); + } + + if (rigState->getChar(CURRENTVFO) == 0) + { + resp.append(QString("%1").arg("VFOB")); + } + else { + resp.append(QString("%1").arg("VFOA")); + } + + response.append(resp); + } + else if (command.length() > 0 && (command[0] == "N" || command[0] == "set_ts")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "n" || command[0] == "get_ts")) + { + responseCode = -11; + } + else if (command.length() >2 && (command[0] == "U" || command[0] == "set_func")) + { + setCommand = true; + + if (command[1] == "FAGC") + { + rigState->set(FAGCFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "NB") + { + rigState->set(NBFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "COMP") + { + rigState->set(COMPFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "VOX") + { + rigState->set(VOXFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "TONE") + { + rigState->set(TONEFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "TSQL") + { + rigState->set(TSQLFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "SBKIN") + { + rigState->set(SBKINFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "FBKIN") + { + rigState->set(FBKINFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "ANF") + { + rigState->set(ANFFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "NR") + { + rigState->set(NRFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "AIP") + { + rigState->set(AIPFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "APF") + { + rigState->set(APFFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "MON") + { + rigState->set(MONFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "MN") + { + rigState->set(MNFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "RF") + { + rigState->set(RFFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "ARO") + { + rigState->set(AROFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "MUTE") + { + rigState->set(MUTEFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "VSC") + { + rigState->set(VSCFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "REV") + { + rigState->set(REVFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "SQL") + { + rigState->set(SQLFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "ABM") + { + rigState->set(ABMFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "BC") + { + rigState->set(BCFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "MBC") + { + rigState->set(MBCFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "RIT") + { + rigState->set(RITFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "AFC") + { + rigState->set(AFCFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "SATMODE") + { + rigState->set(SATMODEFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "SCOPE") + { + rigState->set(SCOPEFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "RESUME") + { + rigState->set(RESUMEFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "TBURST") + { + rigState->set(TBURSTFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "TUNER") + { + rigState->set(TUNERFUNC, (quint8)command[2].toInt(), true); + } + else if (command[1] == "LOCK") + { + rigState->set(LOCKFUNC, (quint8)command[2].toInt(), true); + } + else { + qInfo(logRigCtlD()) << "Unimplemented func:" << command[0] << command[1] << command[2]; + } + + qInfo(logRigCtlD()) << "Setting:" << command[1] << command[2]; } else if (command.length()>1 && (command[0] == "u" || command[0] == "get_func")) { @@ -960,7 +716,7 @@ void rigCtlClient::socketReadyRead() resp.append(QString("Func Status: ")); } if (command[1] == "FAGC") - { + { result=rigState->getBool(FAGCFUNC); } else if (command[1] == "NB") @@ -1086,174 +842,364 @@ void rigCtlClient::socketReadyRead() else { qInfo(logRigCtlD()) << "Unimplemented func:" << command[0] << command[1]; } - + resp.append(QString("%1").arg(result)); response.append(resp); } - else if (command.length() >2 && (command[0] == "U" || command[0] == "set_func")) + else if (command.length() > 2 && (command[0] == "L" || command[0] == "set_level")) { + int value=0; setCommand = true; - - if (command[1] == "FAGC") - { - rigState->set(FAGCFUNC, (quint8)command[2].toInt(), true); + if (command[1] == "AF") { + value = command[2].toFloat() * 255; + rigState->set(AFGAIN, quint8(value), true); } - else if (command[1] == "NB") - { - rigState->set(NBFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "RF") { + value = command[2].toFloat() * 255; + rigState->set(RFGAIN, quint8(value), true); } - else if (command[1] == "COMP") - { - rigState->set(COMPFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "RFPOWER") { + value = command[2].toFloat() * 255; + rigState->set(RFPOWER, quint8(value), true); } - else if (command[1] == "VOX") - { - rigState->set(VOXFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "SQL") { + value = command[2].toFloat() * 255; + rigState->set(SQUELCH, quint8(value), true); } - else if (command[1] == "TONE") - { - rigState->set(TONEFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "COMP") { + value = command[2].toFloat() * 255; + rigState->set(COMPLEVEL, quint8(value), true); } - else if (command[1] == "TSQL") - { - rigState->set(TSQLFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "MICGAIN") { + value = command[2].toFloat() * 255; + rigState->set(MICGAIN, quint8(value), true); } - else if (command[1] == "SBKIN") - { - rigState->set(SBKINFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "MON") { + value = command[2].toFloat() * 255; + rigState->set(MONITORLEVEL, quint8(value), true); } - else if (command[1] == "FBKIN") - { - rigState->set(FBKINFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "VOXGAIN") { + value = command[2].toFloat() * 255; + rigState->set(VOXGAIN, quint8(value), true); } - else if (command[1] == "ANF") - { - rigState->set(ANFFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "ANTIVOX") { + value = command[2].toFloat() * 255; + rigState->set(ANTIVOXGAIN, quint8(value), true); } - else if (command[1] == "NR") - { - rigState->set(NRFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "ATT") { + value = command[2].toInt(); + rigState->set(ATTENUATOR, quint8(value), true); } - else if (command[1] == "AIP") - { - rigState->set(AIPFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "PREAMP") { + value = command[2].toFloat() / 10; + rigState->set(PREAMP, quint8(value), true); } - else if (command[1] == "APF") - { - rigState->set(APFFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "AGC") { + value = command[2].toFloat() * 255; + rigState->set(AGC, quint8(value), true); } - else if (command[1] == "MON") - { - rigState->set(MONFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "CWPITCH") { + value = command[2].toInt(); + rigState->set(CWPITCH, value, true); } - else if (command[1] == "MN") - { - rigState->set(MNFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "NOTCHF") { + value = command[2].toInt(); + rigState->set(NOTCHF, value, true); } - else if (command[1] == "RF") - { - rigState->set(RFFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "IF") { + value = command[2].toInt(); + rigState->set(IF, qint16(value), true); } - else if (command[1] == "ARO") - { - rigState->set(AROFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "PBT_IN") { + value = command[2].toFloat() * 255; + rigState->set(PBTIN, quint8(value), true); } - else if (command[1] == "MUTE") - { - rigState->set(MUTEFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "PBT_OUT") { + value = command[2].toFloat() * 255; + rigState->set(PBTOUT, quint8(value), true); } - else if (command[1] == "VSC") - { - rigState->set(VSCFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "APF") { + value = command[2].toFloat() * 255; + rigState->set(APF, quint8(value), true); } - else if (command[1] == "REV") - { - rigState->set(REVFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "NR") { + value = command[2].toFloat() * 255; + rigState->set(NR, quint8(value), true); } - else if (command[1] == "SQL") - { - rigState->set(SQLFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "BAL") { + value = command[2].toFloat() * 255; + rigState->set(BAL, quint8(value), true); } - else if (command[1] == "ABM") - { - rigState->set(ABMFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "KEYSPD") { + value = command[2].toInt() * 5.1; + rigState->set(KEYSPD, quint8(value), true); } - else if (command[1] == "BC") - { - rigState->set(BCFUNC, (quint8)command[2].toInt(), true); + + qInfo(logRigCtlD()) << "Setting:" << command[1] << command[2] << value; + + } + else if (command.length() > 1 && (command[0] == "l" || command[0] == "get_level")) + { + QString resp; + int value = 0; + if (longReply) { + resp.append("Level Value: "); } - else if (command[1] == "MBC") - { - rigState->set(MBCFUNC, (quint8)command[2].toInt(), true); + + if (command[1] == "STRENGTH") { + + if (rigCaps.model == model7610) + value = getCalibratedValue(rigState->getChar(SMETER), IC7610_STR_CAL); + else if (rigCaps.model == model7850) + value = getCalibratedValue(rigState->getChar(SMETER), IC7850_STR_CAL); + else + value = getCalibratedValue(rigState->getChar(SMETER), IC7300_STR_CAL); + //qInfo(logRigCtlD()) << "Calibration IN:" << rigState->sMeter << "OUT" << value; + resp.append(QString("%1").arg(value)); } - else if (command[1] == "RIT") - { - rigState->set(RITFUNC, (quint8)command[2].toInt(), true); + + else if (command[1] == "AF") { + resp.append(QString("%1").arg((float)rigState->getChar(AFGAIN) / 255.0)); } - else if (command[1] == "AFC") - { - rigState->set(AFCFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "RF") { + resp.append(QString("%1").arg((float)rigState->getChar(RFGAIN) / 255.0)); } - else if (command[1] == "SATMODE") - { - rigState->set(SATMODEFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "SQL") { + resp.append(QString("%1").arg((float)rigState->getChar(SQUELCH) / 255.0)); } - else if (command[1] == "SCOPE") - { - rigState->set(SCOPEFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "COMP") { + resp.append(QString("%1").arg((float)rigState->getChar(COMPLEVEL) / 255.0)); } - else if (command[1] == "RESUME") - { - rigState->set(RESUMEFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "MICGAIN") { + resp.append(QString("%1").arg((float)rigState->getChar(MICGAIN) / 255.0)); } - else if (command[1] == "TBURST") - { - rigState->set(TBURSTFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "MON") { + resp.append(QString("%1").arg((float)rigState->getChar(MONITORLEVEL) / 255.0)); } - else if (command[1] == "TUNER") - { - rigState->set(TUNERFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "VOXGAIN") { + resp.append(QString("%1").arg((float)rigState->getChar(VOXGAIN) / 255.0)); } - else if (command[1] == "LOCK") - { - rigState->set(LOCKFUNC, (quint8)command[2].toInt(), true); + else if (command[1] == "ANTIVOX") { + resp.append(QString("%1").arg((float)rigState->getChar(ANTIVOXGAIN) / 255.0)); + } + else if (command[1] == "RFPOWER") { + resp.append(QString("%1").arg((float)rigState->getChar(RFPOWER) / 255.0)); + } + else if (command[1] == "PREAMP") { + resp.append(QString("%1").arg(rigState->getChar(PREAMP)*10)); + } + else if (command[1] == "ATT") { + resp.append(QString("%1").arg(rigState->getChar(ATTENUATOR))); + } + else if (command[1] == "CWPITCH") { + resp.append(QString("%1").arg(rigState->getInt16(CWPITCH))); + } + else if (command[1] == "NOTCHF") { + resp.append(QString("%1").arg(rigState->getInt16(NOTCHF))); + } + else if (command[1] == "IF") { + resp.append(QString("%1").arg(rigState->getInt16(IF))); + } + else if (command[1] == "PBT_IN") { + resp.append(QString("%1").arg((float)rigState->getChar(PBTIN) / 255.0)); + } + else if (command[1] == "PBT_OUT") { + resp.append(QString("%1").arg((float)rigState->getChar(PBTOUT) / 255.0)); + } + else if (command[1] == "APF") { + resp.append(QString("%1").arg((float)rigState->getChar(APF) / 255.0)); + } + else if (command[1] == "NR") { + resp.append(QString("%1").arg((float)rigState->getChar(NR) / 255.0)); + } + else if (command[1] == "BAL") { + resp.append(QString("%1").arg((float)rigState->getChar(BAL) / 255.0)); + } + else if (command[1] == "KEYSPD") { + resp.append(QString("%1").arg(rigState->getChar(KEYSPD)/5.1)); } else { - qInfo(logRigCtlD()) << "Unimplemented func:" << command[0] << command[1] << command[2]; + resp.append(QString("%1").arg(value)); } - - qInfo(logRigCtlD()) << "Setting:" << command[1] << command[2]; - } - else if (command.length() > 0 && (command[0] == '\x88' || command[0] == "get_powerstat")) - { - - QString resp; - if (longReply) { - resp.append(QString("Power Status: ")); - } - resp.append(QString("%1").arg(1)); // Always reply with ON - response.append(resp); + response.append(resp); + } + + else if (command.length() > 2 && (command[0] == "P" || command[0] == "set_parm")) + { + int value=0; + setCommand = true; + if (command[1] == "ANN") { + value = command[2].toFloat() * 255; + rigState->set(ANN, quint8(value), true); + } + else if (command[1] == "APO") { + value = command[2].toFloat() * 255; + rigState->set(APO, quint8(value), true); + } + else if (command[1] == "BACKLIGHT") { + value = command[2].toFloat() * 255; + rigState->set(BACKLIGHT, quint8(value), true); + } + else if (command[1] == "BEEP") { + value = command[2].toFloat() * 255; + rigState->set(BEEP, quint8(value), true); + } + else if (command[1] == "TIME") { + value = command[2].toLongLong(); + rigState->set(TIME, value, true); + } + else if (command[1] == "BAT") { + value = command[2].toFloat() * 255; + rigState->set(BAT, quint8(value), true); + } + else if (command[1] == "KEYLIGHT") { + value = command[2].toFloat() * 255; + rigState->set(KEYLIGHT, quint8(value), true); + } + else { + qInfo(logRigCtlD()) << "Unimplemented parm:" << command[0] << command[1]; + } + + qInfo(logRigCtlD()) << "Setting:" << command[1] << command[2] << value; + + } + else if (command.length() > 1 && (command[0] == "p" || command[0] == "get_parm")) + { + QString resp; + if (longReply) { + resp.append("Level Value: "); + } + + if (command[1] == "ANN") { + resp.append(QString("%1").arg((float)rigState->getChar(ANN) / 255.0)); + } + else if (command[1] == "APO") { + resp.append(QString("%1").arg((float)rigState->getChar(APO) / 255.0)); + } + else if (command[1] == "BACKLIGHT") { + resp.append(QString("%1").arg((float)rigState->getChar(BACKLIGHT) / 255.0)); + } + else if (command[1] == "BEEP") { + resp.append(QString("%1").arg((float)rigState->getChar(BEEP) / 255.0)); + } + else if (command[1] == "TIME") { + resp.append(QString("%1").arg(rigState->getInt64(TIME))); + } + else if (command[1] == "BAT") { + resp.append(QString("%1").arg((float)rigState->getChar(BAT) / 255.0)); + } + else if (command[1] == "KEYLIGHT") { + resp.append(QString("%1").arg((float)rigState->getChar(KEYLIGHT) / 255.0)); + } + else { + qInfo(logRigCtlD()) << "Unimplemented parm:" << command[0] << command[1]; + } + + response.append(resp); + } + else if (command.length() > 0 && (command[0] == "B" || command[0] == "set_bank")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "b" || command[0] == "get_bank")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "E" || command[0] == "set_mem")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "e" || command[0] == "get_mem")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "G" || command[0] == "vfo_op")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "g" || command[0] == "scan")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "H" || command[0] == "set_channel")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "A" || command[0] == "set_trn")) + { + responseCode = -11; + } + else if (command.length() > 0 && (command[0] == "a" || command[0] == "get_trn")) + { + responseCode = -11; + } + else if (command.length() > 1 && (command[0] == "Y" || command[0] == "set_ant")) + { + setCommand = true; + qInfo(logRigCtlD()) << "set_ant:" << command[1]; + rigState->set(ANTENNA,antFromName(command[1]),true); + } + else if (command[0] == "y" || command[0] == "get_ant") + { + qInfo(logRigCtlD()) << "get_ant:"; + + if (command.length() > 1) { + if (longReply) { + response.append(QString("AntCurr: %1").arg(getAntName((quint8)command[1].toInt()))); + response.append(QString("Option: %1").arg(0)); + response.append(QString("AntTx: %1").arg(getAntName(rigState->getChar(ANTENNA)))); + response.append(QString("AntRx: %1").arg(getAntName(rigState->getChar(ANTENNA)))); + } + else { + response.append(QString("%1").arg(getAntName((quint8)command[1].toInt()))); + response.append(QString("%1").arg(0)); + response.append(QString("%1").arg(getAntName(rigState->getChar(ANTENNA)))); + response.append(QString("%1").arg(getAntName(rigState->getChar(ANTENNA)))); + } + } + } + else if (command.length() > 0 && (command[0] == "*" || command[0] == "reset")) + { + responseCode = -11; //Unimplemented + } + else if (command.length() > 0 && (command[0] == "b" || command[0] == "send_morse")) + { + responseCode = -11; //Unimplemented } else if (command.length() > 1 && (command[0] == '\x87' || command[0] == "set_powerstat")) { - setCommand = true; - if (command[1] == "0") + setCommand = true; + if (command[1] == "0") + { + rigState->set(POWERONOFF, false, true); + } + else { + rigState->set(POWERONOFF, true, true); + } + } + else if (command.length() > 0 && (command[0] == '\x88' || command[0] == "get_powerstat")) { - rigState->set(POWERONOFF, false, true); + + QString resp; + if (longReply) { + resp.append(QString("Power Status: ")); + } + resp.append(QString("%1").arg(1)); // Always reply with ON + response.append(resp); + } - else { - rigState->set(POWERONOFF, true, true); - } - } - else if (command.length() > 0 && (command[0] == '\xa3' || command[0] == "get_lock_mode")) + else if (command.length() > 0 && (command[0] == "\x89" || command[0] == "send_dtmf")) { - QString resp; - if (longReply) { - resp.append(QString("Locked: ")); + responseCode = -11; //Unimplemented } - resp.append(QString("%1").arg(0)); // Always reply with RIG_OK (0) - response.append(resp); + else if (command.length() > 0 && (command[0] == "\x8a" || command[0] == "recv_dtmf")) + { + responseCode = -11; //Unimplemented + } + else if (command.length() > 0 && (command[0] == "_" || command[0] == "get_info")) + { + response.append("None"); } else if (command.length() > 0 && (command[0] == '\xf5' || command[0] == "get_rig_info")) { @@ -1265,34 +1211,283 @@ void rigCtlClient::socketReadyRead() QString resp = QString("VFO=%0 Freq=%1 Mode=%2 Width=%3 RX=%4 TX=%5\nVFO=%6 Freq=%7 Mode=%8 Width=%9 RX=%10 TX=%11\nSplit=%12 SatMode=%13\nRig=%14\nApp=wfview\nVersion=%15\n") .arg(getVfoName(0)).arg(rigState->getInt64(VFOAFREQ)).arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE))).arg(rigState->getUInt16(PASSBAND)).arg(rxa).arg(txa) .arg(getVfoName(1)).arg(rigState->getInt64(VFOBFREQ)).arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE))).arg(rigState->getUInt16(PASSBAND)).arg(rxb).arg(txb) - .arg(split).arg(rigState->getChar(SATMODEFUNC)).arg(rigCaps.modelName).arg(WFVIEW_VERSION); + .arg(split).arg(rigState->getChar(SATMODEFUNC)).arg(rigCaps.modelName).arg(WFVIEW_VERSION); unsigned long crc = doCrc((unsigned char*)resp.toStdString().c_str(), resp.length()); resp = resp + QString("CRC=0x%0").arg(crc, 8, 16, QLatin1Char('0')); response.append(resp); } - else if (command.length() > 0 && (command[0] == "a" || command[0] == "get_trn")) + else if (command[0] == "\xf3" || command[0] == "get_vfo_info") { - responseCode = -18; //Deprecated + if (longReply) { + if (command[1] == "?") { + if (rigState->getChar(CURRENTVFO) == 0) { + response.append(QString("set_vfo: VFOA")); + } + else + { + response.append(QString("set_vfo: VFOB")); + } + } + if (command[1] == "VFOB") { + response.append(QString("Freq: %1").arg(rigState->getInt64(VFOBFREQ))); + } + else { + response.append(QString("Freq: %1").arg(rigState->getInt64(VFOAFREQ))); + } + response.append(QString("Mode: %1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); + response.append(QString("Width: %1").arg(rigState->getUInt16(PASSBAND))); + + response.append(QString("Split: %1").arg(rigState->getDuplex(DUPLEX))); + response.append(QString("SatMode: %1").arg(0)); // Need to get satmode + } + else { + if (command[1] == "VFOB") { + response.append(QString("%1").arg(rigState->getInt64(VFOBFREQ))); + } + else { + response.append(QString("%1").arg(rigState->getInt64(VFOAFREQ))); + } + response.append(QString("%1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); + response.append(QString("%1").arg(rigState->getUInt16(PASSBAND))); + + } } - else if (command.length() > 0 && (command[0] == "A" || command[0] == "set_trn")) + else if (command[0] == "dump_state") { - responseCode = -18; //Deprecated + quint64 modes = getRadioModes(); + + // rigctld protocol version + response.append("1"); + // Radio model + response.append(QString("%1").arg(rigCaps.rigctlModel)); + // Print something (used to be ITU region) + response.append("0"); + // Supported RX bands (startf,endf,modes,low_power,high_power,vfo,ant) + quint32 lowFreq = 0; + quint32 highFreq = 0; + for (bandType band : rigCaps.bands) + { + if (lowFreq == 0 || band.lowFreq < lowFreq) + lowFreq = band.lowFreq; + if (band.highFreq > highFreq) + highFreq = band.highFreq; + } + response.append(QString("%1.000000 %2.000000 0x%3 %4 %5 0x%6 0x%7").arg(lowFreq).arg(highFreq) + .arg(modes, 0, 16).arg(-1).arg(-1).arg(0x16000000, 0, 16).arg(getAntennas(), 0, 16)); + response.append("0 0 0 0 0 0 0"); + + if (rigCaps.hasTransmit) { + // Supported TX bands (startf,endf,modes,low_power,high_power,vfo,ant) + for (bandType band : rigCaps.bands) + { + response.append(QString("%1.000000 %2.000000 0x%3 %4 %5 0x%6 0x%7").arg(band.lowFreq).arg(band.highFreq) + .arg(modes, 0, 16).arg(2000).arg(100000).arg(0x16000000, 0, 16).arg(getAntennas(), 0, 16)); + } + } + response.append("0 0 0 0 0 0 0"); + + response.append(QString("0x%1 1").arg(modes, 0, 16)); + response.append(QString("0x%1 10").arg(modes, 0, 16)); + response.append(QString("0x%1 100").arg(modes, 0, 16)); + response.append(QString("0x%1 1000").arg(modes, 0, 16)); + response.append(QString("0x%1 2500").arg(modes, 0, 16)); + response.append(QString("0x%1 5000").arg(modes, 0, 16)); + response.append(QString("0x%1 6125").arg(modes, 0, 16)); + response.append(QString("0x%1 8333").arg(modes, 0, 16)); + response.append(QString("0x%1 10000").arg(modes, 0, 16)); + response.append(QString("0x%1 12500").arg(modes, 0, 16)); + response.append(QString("0x%1 25000").arg(modes, 0, 16)); + response.append(QString("0x%1 100000").arg(modes, 0, 16)); + response.append(QString("0x%1 250000").arg(modes, 0, 16)); + response.append(QString("0x%1 1000000").arg(modes, 0, 16)); + response.append("0 0"); + + modes = getRadioModes("SB"); + if (modes) { + response.append(QString("0x%1 3000").arg(modes, 0, 16)); + response.append(QString("0x%1 2400").arg(modes, 0, 16)); + response.append(QString("0x%1 1800").arg(modes, 0, 16)); + } + modes = getRadioModes("AM"); + if (modes) { + response.append(QString("0x%1 9000").arg(modes, 0, 16)); + response.append(QString("0x%1 6000").arg(modes, 0, 16)); + response.append(QString("0x%1 3000").arg(modes, 0, 16)); + } + modes = getRadioModes("CW"); + if (modes) { + response.append(QString("0x%1 1200").arg(modes, 0, 16)); + response.append(QString("0x%1 500").arg(modes, 0, 16)); + response.append(QString("0x%1 200").arg(modes, 0, 16)); + } + modes = getRadioModes("FM"); + if (modes) { + response.append(QString("0x%1 15000").arg(modes, 0, 16)); + response.append(QString("0x%1 10000").arg(modes, 0, 16)); + response.append(QString("0x%1 7000").arg(modes, 0, 16)); + } + modes = getRadioModes("RTTY"); + if (modes) { + response.append(QString("0x%1 2400").arg(modes, 0, 16)); + response.append(QString("0x%1 500").arg(modes, 0, 16)); + response.append(QString("0x%1 250").arg(modes, 0, 16)); + } + modes = getRadioModes("PSK"); + if (modes) { + response.append(QString("0x%1 1200").arg(modes, 0, 16)); + response.append(QString("0x%1 500").arg(modes, 0, 16)); + response.append(QString("0x%1 250").arg(modes, 0, 16)); + } + response.append("0 0"); + response.append("9900"); + response.append("9900"); + response.append("10000"); + response.append("0"); + QString preamps=""; + if (rigCaps.hasPreamp) { + for (quint8 pre : rigCaps.preamps) + { + if (pre == 0) + continue; + preamps.append(QString("%1 ").arg(pre*10)); + } + if (preamps.endsWith(" ")) + preamps.chop(1); + } + else { + preamps = "0"; + } + response.append(preamps); + + QString attens = ""; + if (rigCaps.hasAttenuator) { + for (quint8 att : rigCaps.attenuators) + { + if (att == 0) + continue; + attens.append(QString("%1 ").arg(att,0,16)); + } + if (attens.endsWith(" ")) + attens.chop(1); + } + else { + attens = "0"; + } + response.append(attens); + + response.append("0xffffffffffffffff"); + response.append("0xffffffffffffffff"); + response.append("0xffffffffffffffff"); + response.append("0xffffffffffffffff"); + response.append("0xffffffffffffffff"); + response.append("0xffffffffffffffff"); + + if (chkVfoEecuted) { + response.append(QString("vfo_ops=0x%1").arg(255, 0, 16)); + response.append(QString("ptt_type=0x%1").arg(rigCaps.hasTransmit, 0, 16)); + response.append(QString("has_set_vfo=0x%1").arg(1, 0, 16)); + response.append(QString("has_get_vfo=0x%1").arg(1, 0, 16)); + response.append(QString("has_set_freq=0x%1").arg(1, 0, 16)); + response.append(QString("has_get_freq=0x%1").arg(1, 0, 16)); + response.append(QString("has_set_conf=0x%1").arg(1, 0, 16)); + response.append(QString("has_get_conf=0x%1").arg(1, 0, 16)); + response.append(QString("has_power2mW=0x%1").arg(1, 0, 16)); + response.append(QString("has_mW2power=0x%1").arg(1, 0, 16)); + response.append(QString("timeout=0x%1").arg(1000, 0, 16)); + response.append("done"); + } } - else if (command.length() > 0 && (command[0] == "G" || command[0] == "vfo_op")) - { - responseCode = -11; //Not implemented + + /* Fake command to resolve parsing error */ + else if (command[0] == "fmv") { + QString resp; + + if (rigState->getChar(CURRENTVFO) == 0) { + resp.append(QString("%1").arg(rigState->getInt64(VFOAFREQ))); + } + else { + resp.append(QString("%1").arg(rigState->getInt64(VFOBFREQ))); + } + response.append(resp); + resp = ""; + response.append(QString("%1").arg(getMode(rigState->getChar(MODE), rigState->getBool(DATAMODE)))); + response.append(QString("%1").arg(rigState->getUInt16(PASSBAND))); + + if (rigState->getChar(CURRENTVFO) == 0) { + resp.append("VFOA"); + } + else { + resp.append("VFOB"); + } + response.append(resp); } - else if (command.length() > 0 && (command[0] == "u" || command[0] == "get_func")) + else if (command[0] == "1" || command[0] == "dump_caps") { - responseCode = -11; //Not implemented + response.append(QString("Caps dump for model: %1").arg(rigCaps.modelID)); + response.append(QString("Model Name:\t%1").arg(rigCaps.modelName)); + response.append(QString("Mfg Name:\tIcom")); + response.append(QString("Backend version:\t0.1")); + response.append(QString("Backend copyright:\t2021")); + if (rigCaps.hasTransmit) { + response.append(QString("Rig type:\tTransceiver")); + } + else + { + response.append(QString("Rig type:\tReceiver")); + } + if (rigCaps.hasPTTCommand) { + response.append(QString("PTT type:\tRig capable")); + } + response.append(QString("DCD type:\tRig capable")); + response.append(QString("Port type:\tNetwork link")); } - else if (command.length() > 0 && (command[0] == "U" || command[0] == "set_func")) + else if (command.length() > 0 && (command[0] == "2" || command[0] == "power2mW")) { - responseCode = -11; //Not implemented + responseCode = -11; //Unimplemented } - else if (command.length() > 0 && (command[0] == "_" || command[0] == "get_info")) + else if (command.length() > 0 && (command[0] == "3" || command[0] == "mW2power")) { - response.append("None"); + responseCode = -11; //Unimplemented + } + else if (command.length() > 0 && (command[0] == "set_clock")) + { + responseCode = -11; //Unimplemented + } + else if (command.length() > 0 && (command[0] == "get_clock")) + { + responseCode = -11; //Unimplemented + } + else if (command[0] == '\xf0' || command[0] == "chk_vfo") + { + chkVfoEecuted = true; + QString resp; + if (longReply) { + resp.append(QString("ChkVFO: ")); + } + resp.append(QString("%1").arg(rigState->getChar(CURRENTVFO))); + response.append(resp); + } + else if (command.length() > 0 && (command[0] == "set_vfo_opt")) + { + responseCode = -11; //Unimplemented + } + else if (command.length() > 0 && (command[0] == '\xa2' || command[0] == "set_lock_mode")) + { + responseCode = -11; //Unimplemented + } + else if (command.length() > 0 && (command[0] == '\xa3' || command[0] == "get_lock_mode")) + { + QString resp; + if (longReply) { + resp.append(QString("Locked: ")); + } + resp.append(QString("%1").arg(0)); // Always reply with RIG_OK (0) + response.append(resp); + } + + else if (command.length() > 0 && (command[0] == "w" || command[0] == "send_cmd")) + { + responseCode = -11; //Unimplemented } else { qInfo(logRigCtlD()) << "Unimplemented command" << commands; @@ -1686,4 +1881,4 @@ void rigCtlClient::genCrc(unsigned long crcTable[]) } crcTable[(size_t)b] = remainder; } -} \ No newline at end of file +} diff --git a/rigstate.h b/rigstate.h index a4b1ad2..6ed0657 100644 --- a/rigstate.h +++ b/rigstate.h @@ -16,7 +16,8 @@ enum stateTypes { VFOAFREQ, VFOBFREQ, CURRENTVFO, PTT, MODE, FILTER, PASSBAND, D PREAMP, AGC, ATTENUATOR, MODINPUT, AFGAIN, RFGAIN, SQUELCH, RFPOWER, MICGAIN, COMPLEVEL, MONITORLEVEL, BAL, KEYSPD, VOXGAIN, ANTIVOXGAIN, CWPITCH, NOTCHF, IF, PBTIN, PBTOUT, APF, NR, NB, NBDEPTH, NBWIDTH, RIGINPUT, POWERONOFF, RITVALUE, FAGCFUNC, NBFUNC, COMPFUNC, VOXFUNC, TONEFUNC, TSQLFUNC, SBKINFUNC, FBKINFUNC, ANFFUNC, NRFUNC, AIPFUNC, APFFUNC, MONFUNC, MNFUNC,RFFUNC, - AROFUNC, MUTEFUNC, VSCFUNC, REVFUNC, SQLFUNC, ABMFUNC, BCFUNC, MBCFUNC, RITFUNC, AFCFUNC, SATMODEFUNC, SCOPEFUNC, + AROFUNC, MUTEFUNC, VSCFUNC, REVFUNC, SQLFUNC, ABMFUNC, BCFUNC, MBCFUNC, RITFUNC, AFCFUNC, SATMODEFUNC, SCOPEFUNC, + ANN, APO, BACKLIGHT, BEEP, TIME, BAT, KEYLIGHT, RESUMEFUNC, TBURSTFUNC, TUNERFUNC, LOCKFUNC, SMETER, POWERMETER, SWRMETER, ALCMETER, COMPMETER, VOLTAGEMETER, CURRENTMETER, }; From b738a38cbe1f2bce23088946898aab01b5470e8e Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Tue, 21 Feb 2023 10:53:58 +0000 Subject: [PATCH 25/27] fix compile warnings from rigctl --- rigcommander.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/rigcommander.cpp b/rigcommander.cpp index 3737ea4..454f356 100644 --- a/rigcommander.cpp +++ b/rigcommander.cpp @@ -5535,6 +5535,16 @@ void rigCommander::stateUpdated() } getDialLock(); break; + + case ANN: + case APO: + case BACKLIGHT: + case BEEP: + case TIME: + case BAT: + case KEYLIGHT: + break; + } } ++i; From 87a261be1220bc2e3908d274b77ce961912e6f90 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Tue, 21 Feb 2023 11:11:55 +0000 Subject: [PATCH 26/27] Move periodic pbt/passband to rapid queue --- wfmain.cpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/wfmain.cpp b/wfmain.cpp index 2eec7e8..8ec53c6 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -5700,13 +5700,12 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter) { // Remove all "Slow" commands (they will be added later if needed) - removeSlowPeriodicCommand(cmdGetCwPitch); - removeSlowPeriodicCommand(cmdGetDashRatio); - removeSlowPeriodicCommand(cmdGetKeySpeed); - removeSlowPeriodicCommand(cmdGetPassband); - removeSlowPeriodicCommand(cmdGetTPBFInner); - removeSlowPeriodicCommand(cmdGetTPBFOuter); - + removePeriodicRapidCmd(cmdGetCwPitch); + removePeriodicRapidCmd(cmdGetDashRatio); + removePeriodicRapidCmd(cmdGetKeySpeed); + removePeriodicRapidCmd(cmdGetPassband); + removePeriodicRapidCmd(cmdGetTPBFInner); + removePeriodicRapidCmd(cmdGetTPBFOuter); quint16 maxPassbandHz = 0; switch ((mode_kind)mode) { @@ -5722,9 +5721,9 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter) break; case modeCW: case modeCW_R: - insertSlowPeriodicCommand(cmdGetCwPitch,128); - insertSlowPeriodicCommand(cmdGetDashRatio,128); - insertSlowPeriodicCommand(cmdGetKeySpeed,128); + insertPeriodicRapidCmd(cmdGetCwPitch); + insertPeriodicRapidCmd(cmdGetDashRatio); + insertPeriodicRapidCmd(cmdGetKeySpeed); maxPassbandHz = 3600; break; case modeAM: @@ -5779,12 +5778,10 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter) if (currentModeInfo.mk != modeFM) { - insertSlowPeriodicCommand(cmdGetPassband,128); - insertSlowPeriodicCommand(cmdGetTPBFInner,128); - insertSlowPeriodicCommand(cmdGetTPBFOuter,128); - issueDelayedCommandUnique(cmdGetPassband); - issueDelayedCommandUnique(cmdGetTPBFInner); - issueDelayedCommandUnique(cmdGetTPBFOuter); + + insertPeriodicRapidCmd(cmdGetPassband); + insertPeriodicRapidCmd(cmdGetTPBFInner); + insertPeriodicRapidCmd(cmdGetTPBFOuter); } // Note: we need to know if the DATA mode is active to reach mode-D From 5328838c7399c943d8ac4556c8071157c38d267c Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Tue, 21 Feb 2023 11:46:14 +0000 Subject: [PATCH 27/27] better control of rapid commands when mode changes --- wfmain.cpp | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/wfmain.cpp b/wfmain.cpp index 8ec53c6..21e07d9 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -4864,6 +4864,13 @@ void wfmain::initPeriodicCommands() rapidPollCmdQueueEnabled = false; rapidPollCmdQueue.clear(); rapidPollCmdQueueEnabled = true; + + if (rigCaps.hasSpectrum) { + insertPeriodicRapidCmdUnique(cmdGetTPBFInner); + insertPeriodicRapidCmdUnique(cmdGetTPBFOuter); + insertPeriodicRapidCmdUnique(cmdGetPassband); + } + } void wfmain::insertPeriodicRapidCmd(cmds cmd) @@ -5700,12 +5707,6 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter) { // Remove all "Slow" commands (they will be added later if needed) - removePeriodicRapidCmd(cmdGetCwPitch); - removePeriodicRapidCmd(cmdGetDashRatio); - removePeriodicRapidCmd(cmdGetKeySpeed); - removePeriodicRapidCmd(cmdGetPassband); - removePeriodicRapidCmd(cmdGetTPBFInner); - removePeriodicRapidCmd(cmdGetTPBFOuter); quint16 maxPassbandHz = 0; switch ((mode_kind)mode) { @@ -5718,12 +5719,15 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter) passbandWidth = 0.007; passbandCenterFrequency = 0.0; maxPassbandHz = 10E3; + removePeriodicRapidCmd(cmdGetPassband); + removePeriodicRapidCmd(cmdGetTPBFInner); + removePeriodicRapidCmd(cmdGetTPBFOuter); break; case modeCW: case modeCW_R: - insertPeriodicRapidCmd(cmdGetCwPitch); - insertPeriodicRapidCmd(cmdGetDashRatio); - insertPeriodicRapidCmd(cmdGetKeySpeed); + insertPeriodicRapidCmdUnique(cmdGetCwPitch); + insertPeriodicRapidCmdUnique(cmdGetDashRatio); + insertPeriodicRapidCmdUnique(cmdGetKeySpeed); maxPassbandHz = 3600; break; case modeAM: @@ -5741,6 +5745,23 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter) break; } + if ((mode_kind)mode != modeFM && currentModeInfo.mk == modeFM) + { + /* mode was FM but now isn't so insert commands */ + insertPeriodicRapidCmdUnique(cmdGetPassband); + insertPeriodicRapidCmdUnique(cmdGetTPBFInner); + insertPeriodicRapidCmdUnique(cmdGetTPBFOuter); + } + + + if (((mode_kind)mode != modeCW && (mode_kind)mode != modeCW_R) && (currentModeInfo.mk == modeCW || currentModeInfo.mk == modeCW_R)) + { + /* mode was CW/CWR but now isn't so remove CW commands */ + removePeriodicRapidCmd(cmdGetCwPitch); + removePeriodicRapidCmd(cmdGetDashRatio); + removePeriodicRapidCmd(cmdGetKeySpeed); + } + for (int i = 0; i < ui->modeSelectCombo->count(); i++) { if (ui->modeSelectCombo->itemData(i).toInt() == mode) @@ -5775,14 +5796,6 @@ void wfmain::receiveMode(unsigned char mode, unsigned char filter) { trxadj->setMaxPassband(maxPassbandHz); } - - if (currentModeInfo.mk != modeFM) - { - - insertPeriodicRapidCmd(cmdGetPassband); - insertPeriodicRapidCmd(cmdGetTPBFInner); - insertPeriodicRapidCmd(cmdGetTPBFOuter); - } // Note: we need to know if the DATA mode is active to reach mode-D // some kind of queued query: