Fixed issue with compound directed calls with numerical values
This commit is contained in:
parent
c2bda71da5
commit
883cb99c0f
@ -130,7 +130,7 @@ bool DecodedText::tryUnpackBeacon(){
|
|||||||
cmp.append(parts.at(1));
|
cmp.append(parts.at(1));
|
||||||
}
|
}
|
||||||
compound_ = cmp.join("/");
|
compound_ = cmp.join("/");
|
||||||
message_ = QString("%1: ALLCALL %2 %3 ").arg(compound_).arg(isAlt ? "CQ" : "BCN").arg(extra_);
|
message_ = QString("%1: %2 %3 ").arg(compound_).arg(isAlt ? "CQCQCQ" : "BEACON").arg(extra_);
|
||||||
frameType_ = type;
|
frameType_ = type;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -5876,6 +5876,7 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){
|
|||||||
* -> One standard compound frame, followed by a compound directed frame
|
* -> One standard compound frame, followed by a compound directed frame
|
||||||
* -> <KN4CRD/P EM73> then <J1Y/P ACK>
|
* -> <KN4CRD/P EM73> then <J1Y/P ACK>
|
||||||
**/
|
**/
|
||||||
|
bool shouldUseStandardFrame = true;
|
||||||
if(compound || dirToCompound){
|
if(compound || dirToCompound){
|
||||||
// Cases 1, 2, 3 all send a standard compound frame first...
|
// Cases 1, 2, 3 all send a standard compound frame first...
|
||||||
QString deCompoundMessage = QString("<%1 %2>").arg(mycall).arg(mygrid);
|
QString deCompoundMessage = QString("<%1 %2>").arg(mycall).arg(mygrid);
|
||||||
@ -5890,7 +5891,10 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){
|
|||||||
if(!dirCompoundFrame.isEmpty()){
|
if(!dirCompoundFrame.isEmpty()){
|
||||||
frames.append(dirCompoundFrame);
|
frames.append(dirCompoundFrame);
|
||||||
}
|
}
|
||||||
} else {
|
shouldUseStandardFrame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(shouldUseStandardFrame) {
|
||||||
// otherwise, just send the standard directed frame
|
// otherwise, just send the standard directed frame
|
||||||
frames.append(frame);
|
frames.append(frame);
|
||||||
}
|
}
|
||||||
@ -5925,7 +5929,8 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){
|
|||||||
#if 1
|
#if 1
|
||||||
qDebug() << "parsed frames:";
|
qDebug() << "parsed frames:";
|
||||||
foreach(auto frame, frames){
|
foreach(auto frame, frames){
|
||||||
qDebug() << "->" << frame << DecodedText(frame).message();
|
auto dt = DecodedText(frame);
|
||||||
|
qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -6134,7 +6139,7 @@ void MainWindow::prepareBacon(){
|
|||||||
lines.append(beacon);
|
lines.append(beacon);
|
||||||
|
|
||||||
// FT8Call Style
|
// FT8Call Style
|
||||||
lines.append(QString("%1: BCN %2").arg(call).arg(grid));
|
lines.append(QString("%1: BEACON %2").arg(call).arg(grid));
|
||||||
|
|
||||||
// Queue the beacon
|
// Queue the beacon
|
||||||
enqueueMessage(PriorityLow, lines.join(QChar('\n')), currentFreq(), nullptr);
|
enqueueMessage(PriorityLow, lines.join(QChar('\n')), currentFreq(), nullptr);
|
||||||
@ -7262,11 +7267,7 @@ void MainWindow::on_clearAction_triggered(QObject * sender){
|
|||||||
void MainWindow::on_cqMacroButton_clicked(){
|
void MainWindow::on_cqMacroButton_clicked(){
|
||||||
QString call = m_config.my_callsign();
|
QString call = m_config.my_callsign();
|
||||||
QString grid = m_config.my_grid().left(4);
|
QString grid = m_config.my_grid().left(4);
|
||||||
if(call != Radio::base_callsign(call)){
|
QString text = QString("%1: CQCQCQ %2").arg(call).arg(grid).trimmed();
|
||||||
grid = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString text = QString("CQ %1 %2").arg(call).arg(grid);
|
|
||||||
addMessageText(text);
|
addMessageText(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7475,7 +7476,7 @@ void MainWindow::buildQueryMenu(QMenu * menu){
|
|||||||
toggleTx(true);
|
toggleTx(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto qslQueryAction = menu->addAction("QSL? - Did you copy my last transmission?");
|
auto qslQueryAction = menu->addAction("QSL? - Did you receive my last transmission?");
|
||||||
connect(qslQueryAction, &QAction::triggered, this, [this](){
|
connect(qslQueryAction, &QAction::triggered, this, [this](){
|
||||||
|
|
||||||
QString selectedCall = callsignSelected();
|
QString selectedCall = callsignSelected();
|
||||||
@ -7487,31 +7488,18 @@ void MainWindow::buildQueryMenu(QMenu * menu){
|
|||||||
toggleTx(true);
|
toggleTx(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto ackAction = menu->addAction("ACK - I acknowledge your last transmission");
|
auto qslAction = menu->addAction("QSL - I confirm I received your last transmission");
|
||||||
connect(ackAction, &QAction::triggered, this, [this](){
|
connect(qslAction, &QAction::triggered, this, [this](){
|
||||||
|
|
||||||
QString selectedCall = callsignSelected();
|
QString selectedCall = callsignSelected();
|
||||||
if(selectedCall.isEmpty()){
|
if(selectedCall.isEmpty()){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
addMessageText(QString("%1 ACK").arg(selectedCall), true);
|
addMessageText(QString("%1 QSL").arg(selectedCall), true);
|
||||||
toggleTx(true);
|
toggleTx(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto rrAction = menu->addAction("RR - I received your last transmission");
|
|
||||||
connect(rrAction, &QAction::triggered, this, [this](){
|
|
||||||
|
|
||||||
QString selectedCall = callsignSelected();
|
|
||||||
if(selectedCall.isEmpty()){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
addMessageText(QString("%1 RR").arg(selectedCall), true);
|
|
||||||
toggleTx(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
auto yesAction = menu->addAction("YES - I confirm your last inquiry");
|
auto yesAction = menu->addAction("YES - I confirm your last inquiry");
|
||||||
connect(yesAction, &QAction::triggered, this, [this](){
|
connect(yesAction, &QAction::triggered, this, [this](){
|
||||||
|
|
||||||
|
71
varicode.cpp
71
varicode.cpp
@ -45,23 +45,23 @@ QMap<QString, int> directed_cmds = {
|
|||||||
{"$", 3 }, // query station(s) heard
|
{"$", 3 }, // query station(s) heard
|
||||||
// {"^", 4 }, // query ack
|
// {"^", 4 }, // query ack
|
||||||
{"%", 5 }, // query pwr
|
{"%", 5 }, // query pwr
|
||||||
{"|", 6 }, // relay message?
|
{"|", 6 }, // retransmit message
|
||||||
{"!", 7 }, // alert message?
|
{"!", 7 }, // alert message
|
||||||
{"#", 8 }, // all or nothing message
|
{"#", 8 }, // all or nothing message
|
||||||
|
|
||||||
// {"=", 9 }, // unused? (can we even use equals?)
|
// {"=", 9 }, // unused? (can we even use equals?)
|
||||||
// {"/", 10 }, // unused? (can we even use stroke?)
|
// {"/", 10 }, // unused? (can we even use stroke?)
|
||||||
|
|
||||||
// directed responses
|
// directed responses
|
||||||
{" QSL?", 21 }, // do you copy?
|
{" RR", 21 }, // roger roger (not visible in UI but still exists)
|
||||||
{" QSL", 22 }, // i copy
|
{" QSL?", 22 }, // do you copy?
|
||||||
{" ACK", 23 }, // acknowledged
|
{" QSL", 23 }, // i copy
|
||||||
{" PWR", 24 }, // power level
|
{" PWR", 24 }, // power level
|
||||||
{" SNR", 25 }, // seen a station at the provided snr
|
{" SNR", 25 }, // seen a station at the provided snr
|
||||||
{" NO", 26 }, // negative confirm
|
{" NO", 26 }, // negative confirm
|
||||||
{" YES", 27 }, // confirm
|
{" YES", 27 }, // confirm
|
||||||
{" 73", 28 }, // best regards, end of contact
|
{" 73", 28 }, // best regards, end of contact
|
||||||
{" RR", 29 }, // confirm message
|
{" ACK", 29 }, // acknowledge
|
||||||
{" AGN?", 30 }, // repeat message
|
{" AGN?", 30 }, // repeat message
|
||||||
{" ", 31 }, // send freetext
|
{" ", 31 }, // send freetext
|
||||||
};
|
};
|
||||||
@ -71,10 +71,10 @@ QSet<int> allowed_cmds = {0, 1, 2, 3, 4, 5, 6, 7, 8, 21, 22, 23, 24, 25, 26, 27,
|
|||||||
QSet<int> buffered_cmds = {6, 7, 8};
|
QSet<int> buffered_cmds = {6, 7, 8};
|
||||||
|
|
||||||
QString callsign_pattern = QString("(?<callsign>[A-Z0-9/]+)");
|
QString callsign_pattern = QString("(?<callsign>[A-Z0-9/]+)");
|
||||||
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:AGN[?]|QSL[?]?|RR|73|YES|NO|SNR|PWR|ACK|[?@&$^%|!# ]))?");
|
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:AGN[?]|QSL[?]?|ACK|RR|73|YES|NO|SNR|PWR|[?@&$^%|!# ]))?");
|
||||||
QString optional_grid_pattern = QString("(?<grid>\\s?[A-R]{2}[0-9]{2})?");
|
QString optional_grid_pattern = QString("(?<grid>\\s?[A-R]{2}[0-9]{2})?");
|
||||||
QString optional_pwr_pattern = QString("(?<pwr>\\s?\\d+\\s?[KM]?W)?");
|
QString optional_pwr_pattern = QString("(?<pwr>(?<=PWR)\\s?\\d+\\s?[KM]?W)?");
|
||||||
QString optional_num_pattern = QString("(?<num>\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
|
QString optional_num_pattern = QString("(?<num>(?<=SNR)\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
|
||||||
|
|
||||||
QRegularExpression directed_re("^" +
|
QRegularExpression directed_re("^" +
|
||||||
callsign_pattern +
|
callsign_pattern +
|
||||||
@ -82,14 +82,16 @@ QRegularExpression directed_re("^" +
|
|||||||
optional_pwr_pattern +
|
optional_pwr_pattern +
|
||||||
optional_num_pattern);
|
optional_num_pattern);
|
||||||
|
|
||||||
QRegularExpression beacon_re(R"(^ALLCALL\s(?<type>CQ|BCN)(?:\s(?<grid>[A-Z]{2}[0-9]{2}))?\b)");
|
QRegularExpression beacon_re(R"(^(?<type>CQCQCQ|BEACON)(?:\s(?<grid>[A-Z]{2}[0-9]{2}))?\b)");
|
||||||
|
|
||||||
QRegularExpression compound_re("^[<]" +
|
QRegularExpression compound_re("^[<]" +
|
||||||
callsign_pattern +
|
callsign_pattern +
|
||||||
|
"(?<extra>" +
|
||||||
optional_grid_pattern +
|
optional_grid_pattern +
|
||||||
optional_cmd_pattern +
|
optional_cmd_pattern +
|
||||||
optional_pwr_pattern +
|
optional_pwr_pattern +
|
||||||
optional_num_pattern +
|
optional_num_pattern +
|
||||||
|
")" +
|
||||||
"[>]");
|
"[>]");
|
||||||
|
|
||||||
QMap<QString, QString> hufftable = {
|
QMap<QString, QString> hufftable = {
|
||||||
@ -323,8 +325,7 @@ quint16 nmaxgrid = (1<<15)-1;
|
|||||||
|
|
||||||
QMap<QString, quint32> basecalls = {
|
QMap<QString, quint32> basecalls = {
|
||||||
{ "<....>", nbasecall + 1 }, // incomplete callsign
|
{ "<....>", nbasecall + 1 }, // incomplete callsign
|
||||||
{ "CQCQCQ", nbasecall + 2 },
|
{ "ALLCALL", nbasecall + 2 },
|
||||||
{ "ALLCALL", nbasecall + 3 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QMap<int, int> dbm2mw = {
|
QMap<int, int> dbm2mw = {
|
||||||
@ -1020,7 +1021,7 @@ quint8 Varicode::packPwr(QString const &pwr, bool *ok){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// pack a reduced fidelity command and a number into the extra bits provided between nbasegrid and nmaxgrid
|
// pack a reduced fidelity command and a number into the extra bits provided between nbasegrid and nmaxgrid
|
||||||
quint8 Varicode::packCmd(quint8 cmd, quint8 num){
|
quint8 Varicode::packCmd(quint8 cmd, quint8 num, bool *pPackedNum){
|
||||||
//quint8 allowed = nmaxgrid - nbasegrid - 1;
|
//quint8 allowed = nmaxgrid - nbasegrid - 1;
|
||||||
|
|
||||||
// if cmd == pwr || cmd == snr
|
// if cmd == pwr || cmd == snr
|
||||||
@ -1033,8 +1034,10 @@ quint8 Varicode::packCmd(quint8 cmd, quint8 num){
|
|||||||
|
|
||||||
value = ((1 << 1) + ((int)cmd == directed_cmds[" PWR"])) << 6;
|
value = ((1 << 1) + ((int)cmd == directed_cmds[" PWR"])) << 6;
|
||||||
value = value + num;
|
value = value + num;
|
||||||
|
if(pPackedNum) *pPackedNum = true;
|
||||||
} else {
|
} else {
|
||||||
value = cmd & ((1<<7)-1);
|
value = cmd & ((1<<7)-1);
|
||||||
|
if(pPackedNum) *pPackedNum = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@ -1067,8 +1070,8 @@ bool Varicode::isCommandBuffered(const QString &cmd){
|
|||||||
return directed_cmds.contains(cmd) && buffered_cmds.contains(directed_cmds[cmd]);
|
return directed_cmds.contains(cmd) && buffered_cmds.contains(directed_cmds[cmd]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ALLCALL CQ EM73
|
// CQCQCQ EM73
|
||||||
// ALLCALL BCN EM73
|
// BEACON EM73
|
||||||
QString Varicode::packBeaconMessage(QString const &text, const QString &callsign, int *n){
|
QString Varicode::packBeaconMessage(QString const &text, const QString &callsign, int *n){
|
||||||
QString frame;
|
QString frame;
|
||||||
|
|
||||||
@ -1082,11 +1085,11 @@ QString Varicode::packBeaconMessage(QString const &text, const QString &callsign
|
|||||||
|
|
||||||
// Beacon Alt Type
|
// Beacon Alt Type
|
||||||
// ---------------
|
// ---------------
|
||||||
// 1 0 BCN
|
// 1 0 BEACON
|
||||||
// 1 1 CQ
|
// 1 1 CQCQCQ
|
||||||
|
|
||||||
auto type = parsedText.captured("type");
|
auto type = parsedText.captured("type");
|
||||||
auto isAlt = type == "CQ";
|
auto isAlt = type.startsWith("CQ");
|
||||||
|
|
||||||
auto parsedCall = QRegularExpression(compound_callsign_pattern).match(callsign);
|
auto parsedCall = QRegularExpression(compound_callsign_pattern).match(callsign);
|
||||||
if(!parsedCall.hasMatch()){
|
if(!parsedCall.hasMatch()){
|
||||||
@ -1162,35 +1165,42 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
|
|||||||
QString num = parsedText.captured("num").trimmed();
|
QString num = parsedText.captured("num").trimmed();
|
||||||
QString pwr = parsedText.captured("pwr").trimmed().toUpper();
|
QString pwr = parsedText.captured("pwr").trimmed().toUpper();
|
||||||
|
|
||||||
|
QString base;
|
||||||
|
QString fix;
|
||||||
|
bool isPrefix = false;
|
||||||
|
|
||||||
|
if(basecalls.contains(callsign)){
|
||||||
|
// if it's a basecall, use it verbatim with no prefix/suffix
|
||||||
|
base = callsign;
|
||||||
|
fix = "";
|
||||||
|
} else {
|
||||||
|
// otherwise, parse the callsign for prefix/suffix
|
||||||
auto parsedCall = QRegularExpression(compound_callsign_pattern).match(callsign);
|
auto parsedCall = QRegularExpression(compound_callsign_pattern).match(callsign);
|
||||||
if(!parsedCall.hasMatch()){
|
if(!parsedCall.hasMatch()){
|
||||||
if(n) *n = 0;
|
if(n) *n = 0;
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto base = parsedCall.captured("base");
|
base = parsedCall.captured("base");
|
||||||
|
fix = parsedCall.captured("prefix");
|
||||||
bool isPrefix = false;
|
|
||||||
auto fix = parsedCall.captured("prefix");
|
|
||||||
if(!fix.isEmpty()){
|
if(!fix.isEmpty()){
|
||||||
isPrefix = true;
|
isPrefix = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isPrefix){
|
if(!isPrefix){
|
||||||
fix = parsedCall.captured("suffix");
|
fix = parsedCall.captured("suffix");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
quint8 type = FrameCompound;
|
quint8 type = FrameCompound;
|
||||||
quint16 extra = nmaxgrid;
|
quint16 extra = nmaxgrid;
|
||||||
|
|
||||||
if (!cmd.isEmpty() && directed_cmds.contains(cmd) && Varicode::isCommandAllowed(cmd)){
|
if (!cmd.isEmpty() && directed_cmds.contains(cmd) && Varicode::isCommandAllowed(cmd)){
|
||||||
|
bool packedNum = false;
|
||||||
qint8 inum = Varicode::packNum(num, nullptr);
|
qint8 inum = Varicode::packNum(num, nullptr);
|
||||||
if(cmd.trimmed() == "PWR"){
|
if(cmd == " PWR"){
|
||||||
inum = Varicode::packPwr(pwr, nullptr);
|
inum = Varicode::packPwr(pwr, nullptr);
|
||||||
}
|
}
|
||||||
|
extra = nusergrid + Varicode::packCmd(directed_cmds[cmd], inum, &packedNum);
|
||||||
extra = nusergrid + Varicode::packCmd(directed_cmds[cmd], inum);
|
|
||||||
|
|
||||||
type = FrameCompoundDirected;
|
type = FrameCompoundDirected;
|
||||||
} else if(!grid.isEmpty()){
|
} else if(!grid.isEmpty()){
|
||||||
@ -1343,7 +1353,9 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(parsedTo.hasMatch()){
|
if(basecalls.contains(to)){
|
||||||
|
if(pTo) *pTo = to;
|
||||||
|
} else if(parsedTo.hasMatch()){
|
||||||
if(pTo) *pTo = parsedTo.captured(0);
|
if(pTo) *pTo = parsedTo.captured(0);
|
||||||
|
|
||||||
auto parsedBase = parsedTo.captured("base");
|
auto parsedBase = parsedTo.captured("base");
|
||||||
@ -1352,6 +1364,7 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// validate command
|
// validate command
|
||||||
if(!Varicode::isCommandAllowed(cmd)){
|
if(!Varicode::isCommandAllowed(cmd)){
|
||||||
if(n) *n = 0;
|
if(n) *n = 0;
|
||||||
@ -1435,7 +1448,7 @@ QStringList Varicode::unpackDirectedMessage(const QString &text, quint8 *pType){
|
|||||||
} else if(packed_cmd == directed_cmds[" SNR"]) {
|
} else if(packed_cmd == directed_cmds[" SNR"]) {
|
||||||
unpacked.append(Varicode::formatSNR((int)num-31));
|
unpacked.append(Varicode::formatSNR((int)num-31));
|
||||||
} else {
|
} else {
|
||||||
unpacked.append(QString("%1").arg(num));
|
unpacked.append(QString("%1").arg(num-31));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
varicode.h
24
varicode.h
@ -35,9 +35,29 @@ public:
|
|||||||
FrameDirectedNegative = 4, // [100]
|
FrameDirectedNegative = 4, // [100]
|
||||||
FrameDataUnpadded = 5, // [101]
|
FrameDataUnpadded = 5, // [101]
|
||||||
FrameDataPadded = 6, // [110]
|
FrameDataPadded = 6, // [110]
|
||||||
FrameReservedX = 7, // [111]
|
FrameReserved = 7, // [111]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const quint8 FrameTypeMax = 7;
|
||||||
|
|
||||||
|
static QString frameTypeString(quint8 type) {
|
||||||
|
const char* FrameTypeStrings[] = {
|
||||||
|
"FrameBeacon",
|
||||||
|
"FrameCompound",
|
||||||
|
"FrameCompoundDirected",
|
||||||
|
"FrameDirectedPositive",
|
||||||
|
"FrameDirectedNegative",
|
||||||
|
"FrameDataUnpadded",
|
||||||
|
"FrameDataPadded",
|
||||||
|
"FrameReserved"
|
||||||
|
};
|
||||||
|
|
||||||
|
if(type > FrameTypeMax){
|
||||||
|
return "FrameUnknown";
|
||||||
|
}
|
||||||
|
return FrameTypeStrings[type];
|
||||||
|
}
|
||||||
|
|
||||||
//Varicode();
|
//Varicode();
|
||||||
|
|
||||||
static QString formatSNR(int snr);
|
static QString formatSNR(int snr);
|
||||||
@ -95,7 +115,7 @@ public:
|
|||||||
|
|
||||||
static quint8 packNum(QString const &num, bool *ok);
|
static quint8 packNum(QString const &num, bool *ok);
|
||||||
static quint8 packPwr(QString const &pwr, bool *ok);
|
static quint8 packPwr(QString const &pwr, bool *ok);
|
||||||
static quint8 packCmd(quint8 cmd, quint8 num);
|
static quint8 packCmd(quint8 cmd, quint8 num, bool *pPackedNum);
|
||||||
static quint8 unpackCmd(quint8 value, quint8 *pNum);
|
static quint8 unpackCmd(quint8 value, quint8 *pNum);
|
||||||
|
|
||||||
static bool isCommandAllowed(const QString &cmd);
|
static bool isCommandAllowed(const QString &cmd);
|
||||||
|
Loading…
Reference in New Issue
Block a user