diff --git a/cwsender.cpp b/cwsender.cpp new file mode 100644 index 0000000..0dd8c9f --- /dev/null +++ b/cwsender.cpp @@ -0,0 +1,53 @@ +#include "cwsender.h" +#include "ui_cwsender.h" + +cwSender::cwSender(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::cwSender) +{ + ui->setupUi(this); + this->setWindowTitle("CW Sender"); + ui->textToSendEdit->setFocus(); + QFont f = QFont("Monospace"); + f.setStyleHint(QFont::TypeWriter); + ui->textToSendEdit->setFont(f); + ui->transcriptText->setFont(f); +} + +cwSender::~cwSender() +{ + delete ui; +} + +void cwSender::on_sendBtn_clicked() +{ + if( (ui->textToSendEdit->text().length() > 0) && + (ui->textToSendEdit->text().length() <= 30) ) + { + emit sendCW(ui->textToSendEdit->text()); + ui->transcriptText->appendPlainText(ui->textToSendEdit->text()); + ui->textToSendEdit->clear(); + ui->textToSendEdit->setFocus(); + } +} + +void cwSender::on_stopBtn_clicked() +{ + emit stopCW(); +} + +void cwSender::on_textToSendEdit_returnPressed() +{ + on_sendBtn_clicked(); +} + +void cwSender::on_breakinCombo_activated(int brkmode) +{ + // 0 = off, 1 = semi, 2 = full + emit setBreakInMode((unsigned char)brkmode); +} + +void cwSender::on_wpmSpin_valueChanged(int wpm) +{ + emit setKeySpeed((unsigned char)wpm); +} diff --git a/cwsender.h b/cwsender.h new file mode 100644 index 0000000..02bebfb --- /dev/null +++ b/cwsender.h @@ -0,0 +1,42 @@ +#ifndef CWSENDER_H +#define CWSENDER_H + +#include +#include +#include +#include "wfviewtypes.h" + + +namespace Ui { +class cwSender; +} + +class cwSender : public QMainWindow +{ + Q_OBJECT + +public: + explicit cwSender(QWidget *parent = 0); + ~cwSender(); +signals: + void sendCW(QString cwMessage); + void stopCW(); + void setKeySpeed(unsigned char wpm); + void setBreakInMode(unsigned char b); + +private slots: + void on_sendBtn_clicked(); + + void on_stopBtn_clicked(); + + void on_textToSendEdit_returnPressed(); + + void on_breakinCombo_activated(int index); + + void on_wpmSpin_valueChanged(int arg1); + +private: + Ui::cwSender *ui; +}; + +#endif // CWSENDER_H diff --git a/cwsender.ui b/cwsender.ui new file mode 100644 index 0000000..b85f8ce --- /dev/null +++ b/cwsender.ui @@ -0,0 +1,196 @@ + + + cwSender + + + + 0 + 0 + 855 + 491 + + + + MainWindow + + + + + + + WPM: + + + + + + + Qt::NoFocus + + + false + + + true + + + + + + + Macros + + + + + + Macro 5 + + + + + + + Macro 2 + + + + + + + Macro 4 + + + + + + + Edit Mode + + + + + + + Macro 7 + + + + + + + Macro 3 + + + + + + + Macro 6 + + + + + + + Macro 10 + + + + + + + Macro 9 + + + + + + + Macro 8 + + + + + + + Macro 1 + + + + + + + + + + Stop + + + + + + + Break In + + + + + + + 30 + + + Type here... + + + + + + + 6 + + + 48 + + + 20 + + + + + + + Send + + + true + + + + + + + + Off + + + + + Semi + + + + + Full + + + + + + + + + + + diff --git a/logcategories.cpp b/logcategories.cpp index 527f619..360d81e 100644 --- a/logcategories.cpp +++ b/logcategories.cpp @@ -6,6 +6,7 @@ Q_LOGGING_CATEGORY(logGui, "gui") Q_LOGGING_CATEGORY(logLogger, "log") Q_LOGGING_CATEGORY(logUser, "user") Q_LOGGING_CATEGORY(logRig, "rig") +Q_LOGGING_CATEGORY(logRigcommands, "rigCommands") Q_LOGGING_CATEGORY(logAudio, "audio") Q_LOGGING_CATEGORY(logUdp, "udp") Q_LOGGING_CATEGORY(logUdpServer, "udp.server") diff --git a/logcategories.h b/logcategories.h index 4aa6cfb..eac8d9d 100644 --- a/logcategories.h +++ b/logcategories.h @@ -9,6 +9,7 @@ Q_DECLARE_LOGGING_CATEGORY(logGui) Q_DECLARE_LOGGING_CATEGORY(logLogger) Q_DECLARE_LOGGING_CATEGORY(logUser) Q_DECLARE_LOGGING_CATEGORY(logRig) +Q_DECLARE_LOGGING_CATEGORY(rigCommands) Q_DECLARE_LOGGING_CATEGORY(logAudio) Q_DECLARE_LOGGING_CATEGORY(logUdp) Q_DECLARE_LOGGING_CATEGORY(logUdpServer) diff --git a/rigcommander.cpp b/rigcommander.cpp index d1d0eb5..71fba90 100644 --- a/rigcommander.cpp +++ b/rigcommander.cpp @@ -1164,6 +1164,52 @@ void rigCommander::setPTT(bool pttOn) } } +void rigCommander::sendCW(QString textToSend) +{ + if(textToSend.length() >30) + { + qCritical(logRig()).nospace() << "Cannot send CW message, length > 30 characters (" << textToSend.length() << ")"; + return; + } + + QByteArray textData = textToSend.toLocal8Bit(); + unsigned char p=0; + for(int c=0; c < textData.length(); c++) + { + p = textData.at(c); + if( ( (p >= 0x30) && (p <= 0x39) ) || + ( (p >= 0x41) && (p <= 0x5A) ) || + ( (p >= 0x61) && (p <= 0x7A) ) || + (p==0x2F) || (p==0x3F) || (p==0x2E) || + (p==0x2D) || (p==0x2C) || (p==0x3A) || + (p==0x27) || (p==0x28) || (p==0x29) || + (p==0x3D) || (p==0x2B) || (p==0x22) || + (p==0x40) || (p==0x20) ) + { + // Allowed character, continue + } else { + qWarning(logRig()) << "Invalid character detected in CW message at position " << c << ", the character is " << textToSend.at(c); + printHex(textData); + textData[c] = 0x3F; // "?" + } + } + + if(pttAllowed) + { + QByteArray payload("\x17", 1); + payload.append(textData); + prepDataAndSend(payload); + } + // Does it need to end in "FF" or is that implicit at the end of a message? +} + +void rigCommander::sendStopCW() +{ + QByteArray payload("\x17", 1); + payload.append("\xFF"); + prepDataAndSend(payload); +} + void rigCommander::setCIVAddr(unsigned char civAddr) { // Note: This sets the radio's CIV address @@ -4558,6 +4604,19 @@ void rigCommander::getBreakIn() prepDataAndSend(payload); } +void rigCommander::setKeySpeed(unsigned char wpm) +{ + // 0 = 6 WPM + // 255 = 48 WPM + + unsigned char wpmRadioSend = (wpm-6) * (6.071); + + QByteArray payload; + payload.setRawData("\x14\x0C", 2); + payload.append(wpmRadioSend); + prepDataAndSend(payload); +} + void rigCommander::setManualNotch(bool enabled) { QByteArray payload("\x16\x48"); @@ -4572,7 +4631,6 @@ void rigCommander::getManualNotch() prepDataAndSend(payload); } - void rigCommander::getRigID() { QByteArray payload; diff --git a/rigcommander.h b/rigcommander.h index 5edc132..24ee535 100644 --- a/rigcommander.h +++ b/rigcommander.h @@ -86,6 +86,8 @@ public slots: // PTT, ATU, ATT, Antenna, and Preamp: void getPTT(); void setPTT(bool pttOn); + void sendCW(QString textToSend); + void sendStopCW(); void startATU(); void setATU(bool enabled); void getATUStatus(); @@ -113,6 +115,7 @@ public slots: void getVox(); void setBreakIn(unsigned char type); void getBreakIn(); + void setKeySpeed(unsigned char wpm); void setManualNotch(bool enabled); void getManualNotch(); diff --git a/wfmain.cpp b/wfmain.cpp index 36855db..83d0419 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -48,6 +48,7 @@ wfmain::wfmain(const QString settingsFile, const QString logFile, bool debugMode rpt = new repeaterSetup(); sat = new satelliteSetup(); trxadj = new transceiverAdjustments(); + cw = new cwSender(); shut = new controllerSetup(); abtBox = new aboutbox(); selRad = new selectRadio(); @@ -341,6 +342,12 @@ void wfmain::rigConnections() connect(rig, SIGNAL(havePTTStatus(bool)), this, SLOT(receivePTTstatus(bool))); connect(this, SIGNAL(setPTT(bool)), rig, SLOT(setPTT(bool))); connect(this, SIGNAL(getPTT()), rig, SLOT(getPTT())); + + connect(this, SIGNAL(sendCW(QString)), rig, SLOT(sendCW(QString))); + connect(this, SIGNAL(stopCW()), rig, SLOT(sendStopCW())); + connect(this, SIGNAL(setKeySpeed(unsigned char)), rig, SLOT(setKeySpeed(unsigned char))); + connect(this, SIGNAL(setCWBreakMode(unsigned char)), rig, SLOT(setBreakIn(unsigned char))); + connect(rig, SIGNAL(haveBandStackReg(freqt,char,char,bool)), this, SLOT(receiveBandStackReg(freqt,char,char,bool))); connect(this, SIGNAL(setRitEnable(bool)), rig, SLOT(setRitEnable(bool))); connect(this, SIGNAL(setRitValue(int)), rig, SLOT(setRitValue(int))); @@ -1058,6 +1065,15 @@ void wfmain::setupMainUI() connect(this->trxadj, &transceiverAdjustments::setPassband, [=](const quint16 &passbandHz) { issueCmdUniquePriority(cmdSetPassband, passbandHz);} ); + + connect(this->cw, &cwSender::sendCW, + [=](const QString &cwMessage) { issueCmd(cmdSendCW, cwMessage);}); + connect(this->cw, &cwSender::stopCW, + [=]() { issueDelayedCommand(cmdStopCW);}); + connect(this->cw, &cwSender::setBreakInMode, + [=](const unsigned char &bmode) { issueCmd(cmdSetBreakMode, bmode);}); + connect(this->cw, &cwSender::setKeySpeed, + [=](const unsigned char &wpm) { issueCmd(cmdSetKeySpeed, wpm);}); } void wfmain::prepareSettingsWindow() @@ -3544,6 +3560,24 @@ void wfmain::doCmd(commandtype cmddata) } break; } + case cmdSendCW: + { + QString messageText = (*std::static_pointer_cast(data)); + emit sendCW(messageText); + break; + } + case cmdSetBreakMode: + { + unsigned char bmode = (*std::static_pointer_cast(data)); + emit setCWBreakMode(bmode); + break; + } + case cmdSetKeySpeed: + { + unsigned char wpm = (*std::static_pointer_cast(data)); + emit setKeySpeed(wpm); + break; + } case cmdSetATU: { bool atuOn = (*std::static_pointer_cast(data)); @@ -3775,12 +3809,21 @@ void wfmain::doCmd(cmds cmd) break; case cmdGetALCMeter: if(amTransmitting) - emit getMeters(meterALC); + emit getMeters(meterALC); break; case cmdGetCompMeter: if(amTransmitting) emit getMeters(meterComp); break; + case cmdGetKeySpeed: + emit getKeySpeed(); + break; + case cmdGetBreakMode: + emit getCWBreakMode(); + break; + case cmdStopCW: + emit stopCW(); + break; case cmdStartRegularPolling: runPeriodicCommands = true; break; @@ -3972,6 +4015,14 @@ void wfmain::issueCmd(cmds cmd, qint16 c) delayedCmdQue.push_back(cmddata); } +void wfmain::issueCmd(cmds cmd, QString s) +{ + commandtype cmddata; + cmddata.cmd = cmd; + cmddata.data = std::shared_ptr(new QString(s)); + delayedCmdQue.push_back(cmddata); +} + void wfmain::issueCmdUniquePriority(cmds cmd, bool b) { commandtype cmddata; @@ -4301,7 +4352,7 @@ void wfmain::initPeriodicCommands() } } -void wfmain::insertPeriodicCommand(cmds cmd, unsigned char priority) +void wfmain::insertPeriodicCommand(cmds cmd, unsigned char priority=100) { // TODO: meaningful priority // These commands get run at the fastest pace possible @@ -4339,7 +4390,7 @@ void wfmain::removePeriodicCommand(cmds cmd) } -void wfmain::insertSlowPeriodicCommand(cmds cmd, unsigned char priority) +void wfmain::insertSlowPeriodicCommand(cmds cmd, unsigned char priority=100) { // TODO: meaningful priority // These commands are run every 20 "ticks" of the primary radio command loop @@ -7339,7 +7390,7 @@ void wfmain::on_underlayAverageBuffer_toggled(bool checked) void wfmain::on_debugBtn_clicked() { qInfo(logSystem()) << "Debug button pressed."; - emit getRigID(); + cw->show(); } // ---------- color helper functions: ---------- // @@ -8109,12 +8160,15 @@ void wfmain::messageHandler(QtMsgType type, const QMessageLogContext& context, c out << context.category << ": " << msg << "\n"; out.flush(); // Clear the buffered data - text.append(context.category); - text.append(": "); - text.append(msg); - logTextMutex.lock(); - logStringBuffer.push_front(text); - logTextMutex.unlock(); + if(QString(context.category) != QString("rigCommands")) + { + text.append(context.category); + text.append(": "); + text.append(msg); + logTextMutex.lock(); + logStringBuffer.push_front(text); + logTextMutex.unlock(); + } } void wfmain::on_customEdgeBtn_clicked() diff --git a/wfmain.h b/wfmain.h index f5a26fd..b8f1a24 100644 --- a/wfmain.h +++ b/wfmain.h @@ -35,6 +35,7 @@ #include "repeatersetup.h" #include "satellitesetup.h" #include "transceiveradjustments.h" +#include "cwsender.h" #include "udpserver.h" #include "qledlabel.h" #include "rigctld.h" @@ -158,7 +159,7 @@ signals: // PTT, ATU, ATT, Antenna, Preamp: void getPTT(); - void setPTT(bool pttOn); + void setPTT(bool pttOn); void getAttenuator(); void getPreamp(); void getAntenna(); @@ -169,6 +170,14 @@ signals: void setATU(bool atuEnabled); void getATUStatus(); + // CW Keying: + void sendCW(QString message); + void stopCW(); + void getKeySpeed(); + void setKeySpeed(unsigned char wpm); + void setCWBreakMode(unsigned char breakMode); + void getCWBreakMode(); + // Time and date: void setTime(timekind t); void setDate(datekind d); @@ -889,7 +898,7 @@ private: cmdGetVdMeter, cmdGetIdMeter, cmdGetSMeter, cmdGetCenterMeter, cmdGetPowerMeter, cmdGetSWRMeter, cmdGetALCMeter, cmdGetCompMeter, cmdGetTxRxMeter, cmdGetTone, cmdGetTSQL, cmdGetDTCS, cmdGetRptAccessMode, cmdGetPreamp, cmdGetAttenuator, cmdGetAntenna, - cmdGetBandStackReg, + cmdGetBandStackReg, cmdGetKeySpeed, cmdSetKeySpeed, cmdGetBreakMode, cmdSetBreakMode, cmdSendCW, cmdStopCW, cmdSetTime, cmdSetDate, cmdSetUTCOffset}; struct commandtype { @@ -913,6 +922,7 @@ private: void issueCmd(cmds cmd, bool b); void issueCmd(cmds cmd, quint16 c); void issueCmd(cmds cmd, qint16 c); + void issueCmd(cmds cmd, QString s); // These commands pop_front and remove similar commands: void issueCmdUniquePriority(cmds cmd, bool b); @@ -1045,10 +1055,12 @@ private: unsigned char usbGain=0; unsigned char lanGain=0; + // Widgets and Special Windows: calibrationWindow *cal; repeaterSetup *rpt; satelliteSetup *sat; transceiverAdjustments *trxadj; + cwSender *cw; controllerSetup* shut; aboutbox *abtBox; selectRadio *selRad; diff --git a/wfview.pro b/wfview.pro index fd51296..84fd14f 100644 --- a/wfview.pro +++ b/wfview.pro @@ -197,6 +197,7 @@ win32:INCLUDEPATH += ../qcustomplot INCLUDEPATH += resampler SOURCES += main.cpp\ + cwsender.cpp \ loggingwindow.cpp \ wfmain.cpp \ commhandler.cpp \ @@ -234,6 +235,7 @@ SOURCES += main.cpp\ HEADERS += wfmain.h \ colorprefs.h \ commhandler.h \ + cwsender.h \ loggingwindow.h \ prefs.h \ rigcommander.h \ @@ -278,6 +280,7 @@ HEADERS += wfmain.h \ FORMS += wfmain.ui \ calibrationwindow.ui \ + cwsender.ui \ loggingwindow.ui \ satellitesetup.ui \ selectradio.ui \ diff --git a/wfviewtypes.h b/wfviewtypes.h index 9997aa9..d94b1a9 100644 --- a/wfviewtypes.h +++ b/wfviewtypes.h @@ -59,6 +59,12 @@ enum mode_kind { modeDCR }; +enum breakIn_t { + brkinOff = 0x00, + brkinSemi = 0x01, + brkinFull = 0x02 +}; + struct freqt { quint64 Hz; double MHzDouble;