From 5d64ac37c52763679a336c284d07d06b37ae2255 Mon Sep 17 00:00:00 2001 From: Jordan Sherer Date: Mon, 30 Jul 2018 17:16:45 -0400 Subject: [PATCH] Restructured building frames and decoding for better support of compound callsigns --- decodedtext.cpp | 23 ++- decodedtext.h | 7 + mainwindow.cpp | 370 +++++++++++++++++++++++++++++++++--------------- mainwindow.h | 7 +- varicode.cpp | 31 ++-- varicode.h | 2 +- 6 files changed, 310 insertions(+), 130 deletions(-) diff --git a/decodedtext.cpp b/decodedtext.cpp index 3d6772b..87a2dbe 100644 --- a/decodedtext.cpp +++ b/decodedtext.cpp @@ -106,14 +106,29 @@ bool DecodedText::tryUnpackBeacon(){ return false; } - auto extra = parts.at(2); - + // Beacon Alt Type + // --------------- + // 1 0 BCN + // 1 1 CQ + // 0 0 DE + // 0 1 TO + isBeacon_ = isBeacon; + isAlt_ = isAlt; + extra_ = parts.at(2); compound_ = QStringList{ parts.at(0), parts.at(1) }.join("/"); + // BCN|CQ if(isBeacon){ - message_ = QString("%1: BCN %2 ").arg(compound_).arg(extra); + message_ = QString("%1: %2 %3 ").arg(compound_).arg(isAlt ? "CQ" : "BCN").arg(extra_); } else { - message_ = QString("%1: ").arg(compound_); + // :TO + if(isAlt){ + message_ = QString("%1").arg(compound_); + } + // DE: + else { + message_ = QString("%1: ").arg(compound_); + } } return true; diff --git a/decodedtext.h b/decodedtext.h index 33c3d01..2aa39b8 100644 --- a/decodedtext.h +++ b/decodedtext.h @@ -41,6 +41,10 @@ public: QString compoundCall() const { return compound_; } bool isCompoundMessage() const { return !compound_.isEmpty(); } + QString extra() const { return extra_; } + bool isBeacon() const { return isBeacon_; } + bool isAlt() const { return isAlt_; } + QStringList directedMessage() const { return directed_; } bool isDirectedMessage() const { return !directed_.isEmpty() && directed_.length() > 2; } @@ -91,7 +95,10 @@ private: column_mode = 19, column_qsoText = 22 }; + bool isBeacon_; + bool isAlt_; QString compound_; + QString extra_; QStringList directed_; QString string_; int padding_; diff --git a/mainwindow.cpp b/mainwindow.cpp index 27ebe8e..e18d411 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -3299,14 +3299,21 @@ void MainWindow::readFromStdout() //readFromStdout m_config.color_DXCC(), m_config.color_NewCall(), m_config.ppfx(),(ui->cbCQonly->isVisible() and ui->cbCQonly->isChecked())); + + + + + // Parse General Activity - if(decodedtext.messageWords().length() > 0){ +#if 1 + bool shouldParseGeneralActivity = true; + if(shouldParseGeneralActivity && !decodedtext.messageWords().isEmpty()){ int offset = decodedtext.frequencyOffset(); if(!m_bandActivity.contains(offset)){ QList offsets = { - offset - 1, offset - 2, offset - 3, offset - 4, offset - 5, - offset + 1, offset + 2, offset + 3, offset + 4, offset + 5}; + offset - 1, offset - 2, offset - 3, offset - 4, offset - 5, offset - 6, + offset + 1, offset + 2, offset + 3, offset + 4, offset + 5, offset + 6}; foreach(int prevOffset, offsets){ if(!m_bandActivity.contains(prevOffset)){ continue; } m_bandActivity[offset] = m_bandActivity[prevOffset]; @@ -3321,13 +3328,14 @@ void MainWindow::readFromStdout() //readFromStdout d.isCompound = decodedtext.isCompoundMessage(); d.bits = decodedtext.bits(); d.freq = offset; - d.text = decodedtext.message(); //decodedtext.messageWords().isEmpty() ? "" : decodedtext.messageWords().first().trimmed(); + d.text = decodedtext.message(); d.utcTimestamp = QDateTime::currentDateTimeUtc(); d.snr = decodedtext.snr(); m_bandActivity[offset].append(d); - if(m_messageBuffer.contains(d.freq/10*10)){ - qDebug() << "buffering" << (d.freq/10*10) << d.text; + // if we have a data frame, and a message buffer has been established, buffer it... + if(m_messageBuffer.contains(d.freq/10*10) && !decodedtext.isCompoundMessage() && !decodedtext.isDirectedMessage()){ + qDebug() << "buffering data" << (d.freq/10*10) << d.text; m_messageBuffer[d.freq/10*10].msgs.append(d); } @@ -3335,23 +3343,123 @@ void MainWindow::readFromStdout() //readFromStdout m_bandActivity[offset].removeFirst(); } } +#endif + + + // Process compound callsign commands (put them in cache)" +#if 1 + bool shouldProcessCompound = true; + if(shouldProcessCompound && decodedtext.isCompoundMessage()){ +#if ALIAS_COMPOUND_CALLS + QString compoundCall = decodedtext.compoundCall(); + m_compoundCallCache[Radio::base_callsign(compoundCall)] = compoundCall; +#endif + + CallDetail cd; + cd.call = decodedtext.compoundCall(); + cd.grid = decodedtext.extra(); // compound calls via beacons may contain grid... + cd.snr = decodedtext.snr(); + cd.freq = decodedtext.frequencyOffset(); + cd.utcTimestamp = QDateTime::currentDateTimeUtc(); + cd.bits = decodedtext.bits(); + + if(!decodedtext.isBeacon()){ + qDebug() << "buffering compound call" << cd.call << cd.bits; + m_messageBuffer[cd.freq/10*10].compound.append(cd); + } + /* + // DISABLED FOR NOW... + else { + logCallActivity(cd); + } + */ + + // + } +#endif + + // Parse commands + // KN4CRD K1JT ? +#if 1 + bool shouldProcessDirected = true; + if(shouldProcessDirected && decodedtext.isDirectedMessage()){ + auto parts = decodedtext.directedMessage(); + + CommandDetail d; +#if ALIAS_COMPOUND_CALLS + d.from = lookupCallInCompoundCache(parts.at(0)); +#endif + d.from = parts.at(0); + d.to = parts.at(1); + d.cmd = parts.at(2); + d.freq = decodedtext.frequencyOffset(); + d.snr = decodedtext.snr(); + d.utcTimestamp = QDateTime::currentDateTimeUtc(); + d.bits = decodedtext.bits(); + + // if the command is a buffered command OR we have from or to in a separate message (compound) + if(Varicode::isCommandBuffered(d.cmd) || d.from == "<....>" || d.to == "<....>"){ + qDebug() << "buffering cmd" << d.cmd << d.from << d.to; + m_messageBuffer[d.freq/10*10].cmd = d; + m_messageBuffer[d.freq/10*10].msgs.clear(); + } else { + m_rxCommandQueue.append(d); + } + + /* + // DISABLED FOR NOW... + CallDetail cd; + cd.bits = d.bits; + cd.call = d.from; + cd.grid = ""; + cd.snr = d.snr; + cd.freq = d.freq; + cd.utcTimestamp = d.utcTimestamp; + logCallActivity(cd); + */ + +#if 0 + bool shouldCaptureThirdPartyCallsigns = false; + // check to see if this is a station we've heard 3rd party + if(shouldCaptureThirdPartyCallsigns && Radio::base_callsign(d.to) != Radio::base_callsign(m_config.my_callsign())){ + QString relayCall = QString("%1|%2").arg(Radio::base_callsign(d.from)).arg(Radio::base_callsign(d.to)); + int snr = -100; + if(parts.length() == 4){ + snr = QString(parts.at(3)).toInt(); + } + CallDetail td; + td.through = d.from; + td.call = d.to; + td.grid = ""; + td.snr = snr; + td.freq = d.freq; + td.utcTimestamp = d.utcTimestamp; + m_callActivity[relayCall] = td; + } +#endif + } +#endif // Parse CQs - QString cqCall = decodedtext.CQersCall(); - if(!cqCall.isEmpty()){ - QString theircall; - QString theirgrid; - decodedtext.deCallAndGrid(/*out*/theircall,theirgrid); +#if 0 + bool shouldParseCQs = false; + if(shouldParseCQs){ + QString cqCall = decodedtext.CQersCall(); + if(!cqCall.isEmpty()){ + QString theircall; + QString theirgrid; + decodedtext.deCallAndGrid(/*out*/theircall,theirgrid); - CallDetail d; - d.call = theircall; - d.grid = theirgrid; - d.snr = decodedtext.snr(); - d.freq = decodedtext.frequencyOffset(); - d.utcTimestamp = QDateTime::currentDateTimeUtc(); - m_callActivity[Radio::base_callsign(cqCall)] = d; // original call is stored in CallDetail. + CallDetail d; + d.call = theircall; + d.grid = theirgrid; + d.snr = decodedtext.snr(); + d.freq = decodedtext.frequencyOffset(); + d.utcTimestamp = QDateTime::currentDateTimeUtc(); + m_callActivity[Radio::base_callsign(cqCall)] = d; // original call is stored in CallDetail. + } } - +#endif // Parse standard message callsigns // K1JT KN4CRD EM73 @@ -3359,7 +3467,8 @@ void MainWindow::readFromStdout() //readFromStdout // K1JT KN4CRD R-12 // DE KN4CRD // KN4CRD - bool shouldParseCallsigns = true; +#if 0 + bool shouldParseCallsigns = false; if(shouldParseCallsigns){ QStringList callsigns = Varicode::parseCallsigns(decodedtext.message()); if(!callsigns.isEmpty()){ @@ -3390,76 +3499,7 @@ void MainWindow::readFromStdout() //readFromStdout } } } - - // Parse commands - // KN4CRD K1JT ? - bool shouldProcessDirected = true; - if(shouldProcessDirected && decodedtext.isDirectedMessage()){ - auto parts = decodedtext.directedMessage(); - - CommandDetail d; - d.from = lookupCallInCompoundCache(parts.at(0)); - d.to = parts.at(1); - d.cmd = parts.at(2); - d.freq = decodedtext.frequencyOffset(); - d.snr = decodedtext.snr(); - d.utcTimestamp = QDateTime::currentDateTimeUtc(); - - if(Varicode::isCommandBuffered(d.cmd)){ - m_messageBuffer[d.freq/10*10].cmd = d; - m_messageBuffer[d.freq/10*10].msgs.clear(); - } else { - m_rxCommandQueue.append(d); - } - - CallDetail cd; - cd.call = d.from; - cd.grid = ""; - cd.snr = d.snr; - cd.freq = d.freq; - cd.utcTimestamp = d.utcTimestamp; - m_callActivity[Radio::base_callsign(cd.call)] = cd; - - bool shouldCaptureThirdPartyCallsigns = false; - // check to see if this is a station we've heard 3rd party - if(shouldCaptureThirdPartyCallsigns && Radio::base_callsign(d.to) != Radio::base_callsign(m_config.my_callsign())){ - QString relayCall = QString("%1|%2").arg(Radio::base_callsign(d.from)).arg(Radio::base_callsign(d.to)); - int snr = -100; - if(parts.length() == 4){ - snr = QString(parts.at(3)).toInt(); - } - CallDetail td; - td.through = d.from; - td.call = d.to; - td.grid = ""; - td.snr = snr; - td.freq = d.freq; - td.utcTimestamp = d.utcTimestamp; - m_callActivity[relayCall] = td; - } - - int nsec=QDateTime::currentMSecsSinceEpoch()/1000-m_secBandChanged; - bool okToPost=(nsec>(4*m_TRperiod)/5); - if (okToPost){ - pskSetLocal(); - pskLogReport("FT8Call", d.freq, d.snr, d.from, ""); - } - } - - // Process compound callsign commands (put them in cache)" - bool shouldProcessCompound = true; - if(shouldProcessCompound && decodedtext.isCompoundMessage()){ - QString compoundCall = decodedtext.compoundCall(); - m_compoundCallCache[Radio::base_callsign(compoundCall)] = compoundCall; - - CallDetail cd; - cd.call = compoundCall; - cd.grid = ""; // compound calls via beacons contain grid... - cd.snr = decodedtext.snr(); - cd.freq = decodedtext.frequencyOffset(); - cd.utcTimestamp = QDateTime::currentDateTimeUtc(); - m_callActivity[Radio::base_callsign(cd.call)] = cd; - } +#endif } } @@ -3490,6 +3530,7 @@ void MainWindow::readFromStdout() //readFromStdout bDisplayRight=true; } +#if 0 if(isRecentOffset(audioFreq) || isAllCallIncluded(decodedtext.message())){ // TODO: jsherer - create a method for bumping this... m_rxRecentCache.insert(audioFreq/10*10, new QDateTime(QDateTime::currentDateTimeUtc()), 25); @@ -3500,6 +3541,7 @@ void MainWindow::readFromStdout() //readFromStdout m_rxDirectedCache.insert(audioFreq/10*10, new QDateTime(QDateTime::currentDateTimeUtc()), 25); bDisplayRight = true; } +#endif if (bDisplayRight) { // This msg is within 10 hertz of our tuned frequency, or a JT4 or JT65 avg, @@ -3515,6 +3557,7 @@ void MainWindow::readFromStdout() //readFromStdout } m_QSOText = decodedtext.string ().trimmed (); +#if 0 // TODO: jsherer - parse decode... ActivityDetail d; d.isFree = !decodedtext.isStandardMessage(); @@ -3524,6 +3567,7 @@ void MainWindow::readFromStdout() //readFromStdout d.text = decodedtext.message(); d.utcTimestamp = QDateTime::currentDateTimeUtc(); m_rxFrameQueue.append(d); +#endif } if(m_mode=="FT8" and m_config.bHound()) { @@ -3605,6 +3649,21 @@ void MainWindow::readFromStdout() //readFromStdout // See MainWindow::postDecode for displaying the latest decodes } + +void MainWindow::logCallActivity(CallDetail d){ + if(m_callActivity.contains(d.call)){ + // update (keep grid) + CallDetail old = m_callActivity[d.call]; + if(!old.grid.isEmpty()){ + d.grid = old.grid; + } + m_callActivity[d.call] = d; + } else { + // create + m_callActivity[d.call] = d; + } +} + QString MainWindow::lookupCallInCompoundCache(QString const &call){ QString myBaseCall = Radio::base_callsign(m_config.my_callsign()); if(call == myBaseCall){ @@ -5575,6 +5634,7 @@ void MainWindow::clearActivity(){ int MainWindow::logRxTxMessageText(QDateTime date, QString text, int freq, bool tx, int block){ auto c = ui->textEditRX->textCursor(); +#if ALIAS_COMPOUND_CALLS // fixup compound callsigns cache / aliases... // ensure our callsign is cached... QString myCall = m_config.my_callsign(); @@ -5587,6 +5647,7 @@ int MainWindow::logRxTxMessageText(QDateTime date, QString text, int freq, bool QRegularExpression re(QString(R"((? MainWindow::buildFT8MessageFrames(QString const& text){ +QStringList MainWindow::buildFT8MessageFrames(QString const& text){ QStringList frames; - QStringList lines; // prepare compound bool compoundSent = false; @@ -5779,6 +5843,9 @@ QPair MainWindow::buildFT8MessageFrames(QString const& QString mygrid = m_config.my_grid(); QString mycall = m_config.my_callsign(); QString basecall = Radio::base_callsign(m_config.my_callsign()); + if(basecall != mycall){ + basecall = "<....>"; + } QString fix = QString(m_config.my_callsign()).replace(basecall, ""); bool prefix = !fix.startsWith("/"); fix = fix.replace("/", ""); @@ -5811,10 +5878,11 @@ QPair MainWindow::buildFT8MessageFrames(QString const& int n = 0; QString dirCmd; - QString dirFrame = Varicode::packDirectedMessage(line, basecall, &dirCmd, &n); + QString dirTo; + QString dirFrame = Varicode::packDirectedMessage(line, basecall, &dirTo, &dirCmd, &n); + // packDataMessage can output a new line to datLineOut (huff escaping special characters) int m = 0; - // packDataMessage can output a new line (huff escaping special characters) QString datLineOut; QString datFrame = Varicode::packDataMessage(line.left(21) + "\x04", &datLineOut, &m); // 63 / 3 = 21 (maximum number of 3bit chars we could possibly stuff in here) @@ -5850,7 +5918,6 @@ QPair MainWindow::buildFT8MessageFrames(QString const& break; } frames.append(frame); - lines.append(line.left(frame.length()) + " "); if(!line.startsWith(frame)){ line = ( @@ -5864,30 +5931,35 @@ QPair MainWindow::buildFT8MessageFrames(QString const& if(useBcn){ frames.append(frame); - lines.append(QString("%1: ").arg(mycall) + line.left(l) + " "); line = line.mid(l); } if(useDir){ - if(compound && !compoundSent){ + // from compound callsign + if(compound){ QString compoundMessage = QString("DE %1").arg(mygrid); QString beaconFrame = Varicode::packBeaconMessage(compoundMessage, mycall, nullptr); if(!beaconFrame.isEmpty()){ frames.append(beaconFrame); - lines.append(QString("%1: ").arg(mycall)); } } frames.append(frame); - // TODO: jsherer - would be nice to clean this up and have an object that can just decode the actual transmitted frames instead. - if(!line.startsWith(basecall) && !compound){ - lines.append(QString("%1: ").arg(lookupCallInCompoundCache(basecall))); + // to compound callsign + if(!dirTo.isEmpty()){ + if(dirTo.contains("/")){ + QString compoundMessage = QString("TO"); + QString beaconFrame = Varicode::packBeaconMessage(compoundMessage, dirTo, nullptr); + if(!beaconFrame.isEmpty()){ + frames.append(beaconFrame); + } + } } - lines.append(line.left(n) + " "); line = line.mid(n); + // generate a checksum for buffered commands with line data if(Varicode::isCommandBuffered(dirCmd) && !line.isEmpty()){ // strip leading whitespace after a buffered directed command line = lstrip(line); @@ -5900,7 +5972,6 @@ QPair MainWindow::buildFT8MessageFrames(QString const& if(useDat){ frames.append(frame); - lines.append(line.left(m)); line = line.mid(m); } } @@ -5909,16 +5980,11 @@ QPair MainWindow::buildFT8MessageFrames(QString const& #if 1 qDebug() << "parsed frames:"; foreach(auto frame, frames){ - qDebug() << "->" << frame << Varicode::unpackDataMessage(frame) << Varicode::unpackDirectedMessage(frame) << Varicode::unpackCompoundFrame(frame, nullptr) << Varicode::unpackBeaconMessage(frame, nullptr); - } - - qDebug() << "lines:"; - foreach(auto line, lines){ - qDebug() << "->" << line; + qDebug() << "->" << frame << Varicode::unpackDataMessage(frame) << Varicode::unpackDirectedMessage(frame) << Varicode::unpackCompoundFrame(frame, nullptr, nullptr) << Varicode::unpackBeaconMessage(frame, nullptr, nullptr); } #endif - return {frames,lines}; + return frames; } @@ -8634,6 +8700,10 @@ void MainWindow::displayActivity(bool force){ return; } + // Is it ok to post spots to PSKReporter? + int nsec=QDateTime::currentMSecsSinceEpoch()/1000-m_secBandChanged; + bool okToPost=(nsec>(4*m_TRperiod)/5); + // Selected Rows int selectedOffset = -1; auto selectedItems = ui->tableWidgetRXAll->selectedItems(); @@ -8826,6 +8896,64 @@ void MainWindow::displayActivity(bool force){ // Grouped Compound Activity // TODO: jsherer - group compound callsign and directed commands together. + foreach(auto freq, m_messageBuffer.keys()){ + QMap::iterator i = m_messageBuffer.find(freq); + + MessageBuffer &buffer = i.value(); + + qDebug() << "-> grouping buffer for freq" << freq; + + if(buffer.compound.isEmpty()){ + qDebug() << "-> buffer.compound is empty...skip"; + continue; + } + + // if we don't have an initialized command, skip... + if(buffer.cmd.bits != Varicode::FT8Call && buffer.cmd.bits != Varicode::FT8CallLast){ + qDebug() << "-> buffer.cmd bits is invalid...skip"; + continue; + } + + // if we need two compound calls, but less than two have arrived...skip + if(buffer.cmd.from == "<....>" && buffer.cmd.to == "<....>" && buffer.compound.length() < 2){ + qDebug() << "-> buffer needs two compound, but has less...skip"; + continue; + } + + // if we need one compound call, but non have arrived...skip + if((buffer.cmd.from == "<....>" || buffer.cmd.to == "<....>") && buffer.compound.length() < 1){ + qDebug() << "-> buffer needs one compound, but has less...skip"; + continue; + } + + if(buffer.cmd.from == "<....>"){ + auto d = buffer.compound.dequeue(); + buffer.cmd.from = d.call; + + if(d.bits == Varicode::FT8CallLast){ + buffer.cmd.bits = d.bits; + } + } + + if(buffer.cmd.to == "<....>"){ + auto d = buffer.compound.dequeue(); + buffer.cmd.to = d.call; + + if(d.bits == Varicode::FT8CallLast){ + buffer.cmd.bits = d.bits; + } + } + + if(buffer.cmd.bits != Varicode::FT8CallLast){ + qDebug() << "-> still not last message...skip"; + continue; + } + + qDebug() << "buffered compound command ready" << buffer.cmd.from << buffer.cmd.to << buffer.cmd.cmd; + + m_rxCommandQueue.append(buffer.cmd); + m_messageBuffer.remove(freq); + } // Buffered Activity foreach(auto freq, m_messageBuffer.keys()){ @@ -8879,6 +9007,11 @@ void MainWindow::displayActivity(bool force){ qDebug() << "processing command" << d.from << d.to << d.cmd << d.freq; #endif + // if we need a compound callsign but never got one...skip + if(d.from == "<....>" || d.to == "<....>"){ + continue; + } + // we're only processing a subset of queries at this point if(!Varicode::isCommandAllowed(d.cmd)){ continue; @@ -8894,9 +9027,14 @@ void MainWindow::displayActivity(bool force){ continue; } - // construct reply - QString reply; + // record the spot to PSKReporter + if (okToPost){ + pskSetLocal(); + pskLogReport("FT8Call", d.freq, d.snr, d.from, ""); + } + // construct a reply + QString reply; // QUERIED SNR if(d.cmd == "?"){ diff --git a/mainwindow.h b/mainwindow.h index a54710a..9a2a641 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -90,6 +90,7 @@ class MainWindow : public QMainWindow { Q_OBJECT; + struct CallDetail; public: using Frequency = Radio::Frequency; using FrequencyDelta = Radio::FrequencyDelta; @@ -121,6 +122,7 @@ public slots: void msgAvgDecode2(); void fastPick(int x0, int x1, int y); + void logCallActivity(CallDetail d); QString lookupCallInCompoundCache(QString const &call); void clearActivity(); int logRxTxMessageText(QDateTime date, QString text, int freq, bool tx, int block=-1); @@ -257,7 +259,7 @@ private slots: void on_extFreeTextMsgEdit_currentTextChanged (QString const&); int currentFreq(); int countFT8MessageFrames(QString const& text); - QPair buildFT8MessageFrames(QString const& text); + QStringList buildFT8MessageFrames(QString const& text); QString parseFT8Message(QString input, bool *isFree); bool prepareNextMessageFrame(); bool isFreqOffsetFree(int f, int bw); @@ -648,6 +650,7 @@ private: int freq; QDateTime utcTimestamp; int snr; + int bits; }; struct CommandDetail @@ -658,6 +661,7 @@ private: int freq; QDateTime utcTimestamp; int snr; + int bits; QString text; }; @@ -674,6 +678,7 @@ private: }; struct MessageBuffer { + QQueue compound; CommandDetail cmd; QList msgs; }; diff --git a/varicode.cpp b/varicode.cpp index 828dca0..abdbea3 100644 --- a/varicode.cpp +++ b/varicode.cpp @@ -809,20 +809,33 @@ bool Varicode::isCommandBuffered(const QString &cmd){ QString Varicode::packBeaconMessage(QString const &text, const QString &callsign, int *n){ QString frame; - auto parsedText = QRegularExpression(R"(^(?BCN|DE)\s(?[A-Z]{2}[0-9]{2})\b)").match(text); + auto parsedText = QRegularExpression(R"(^(?BCN|CQ|DE|TO)(?:\s(?[A-Z]{2}[0-9]{2}))?\b)").match(text); if(!parsedText.hasMatch()){ if(n) *n = 0; return frame; } auto extra = parsedText.captured("grid"); + + /* if(extra.isEmpty()){ if(n) *n = 0; return frame; } + */ - auto isBeacon = parsedText.captured("type") == "BCN"; - auto isAlt = false; + // Beacon Alt Type + // --------------- + // 1 0 BCN + // 1 1 CQ + // 0 0 DE + // 0 1 TO + + auto type = parsedText.captured("type"); + auto isBeacon = type == "BCN" || type == "CQ"; + auto isAlt = type == "CQ" || type == "TO"; + auto isDe = type == "DE"; + Q_UNUSED(isDe); auto parsedCall = QRegularExpression(compound_callsign_pattern).match(callsign); if(!parsedCall.hasMatch()){ @@ -953,7 +966,7 @@ QStringList Varicode::unpackCompoundFrame(const QString &text, bool *isBeacon, q return unpacked; } -QString Varicode::packDirectedMessage(const QString &text, const QString &baseCallsign, QString * pCmd, int *n){ +QString Varicode::packDirectedMessage(const QString &text, const QString &callsign, QString *pTo, QString * pCmd, int *n){ QString frame; auto match = directed_re.match(text); @@ -962,24 +975,26 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &baseCa return frame; } - QString from = baseCallsign; + QString from = callsign; QString to = match.captured("to"); QString cmd = match.captured("cmd"); QString num = match.captured("num").trimmed(); QString pwr = match.captured("pwr").trimmed().toUpper(); - // validate callsign + // validate "to" callsign auto parsedTo = QRegularExpression(compound_callsign_pattern).match(to); - bool validToCallsign = (to != baseCallsign) && (basecalls.contains(to) || parsedTo.hasMatch()); + bool validToCallsign = (to != callsign) && (basecalls.contains(to) || parsedTo.hasMatch()); if(!validToCallsign){ if(n) *n = 0; return frame; } if(parsedTo.hasMatch()){ + if(pTo) *pTo = parsedTo.captured(0); + auto parsedBase = parsedTo.captured("base"); if(parsedBase.length() != to.length()){ - to = parsedBase; + to = "<....>"; // parsedBase; } } diff --git a/varicode.h b/varicode.h index 5d3ae45..c60f6c5 100644 --- a/varicode.h +++ b/varicode.h @@ -101,7 +101,7 @@ public: static QString packCompoundFrame(const QString &baseCallsign, const QString &fix, bool isPrefix, bool isBeacon, quint16 num); static QStringList unpackCompoundFrame(const QString &text, bool *isBeacon, quint16 *pNum); - static QString packDirectedMessage(QString const& text, QString const& callsign, QString * pCmd, int *n); + static QString packDirectedMessage(QString const& text, QString const& callsign, QString *pTo, QString * pCmd, int *n); static QStringList unpackDirectedMessage(QString const& text); static QString packDataMessage(QString const& text, QString *out, int *n);