Fixed issue with compound directed calls with numerical values

This commit is contained in:
Jordan Sherer 2018-08-04 11:19:07 -04:00
parent c2bda71da5
commit 883cb99c0f
4 changed files with 93 additions and 72 deletions

View File

@ -130,7 +130,7 @@ bool DecodedText::tryUnpackBeacon(){
cmp.append(parts.at(1));
}
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;
return true;
}

View File

@ -5876,6 +5876,7 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){
* -> One standard compound frame, followed by a compound directed frame
* -> <KN4CRD/P EM73> then <J1Y/P ACK>
**/
bool shouldUseStandardFrame = true;
if(compound || dirToCompound){
// Cases 1, 2, 3 all send a standard compound frame first...
QString deCompoundMessage = QString("<%1 %2>").arg(mycall).arg(mygrid);
@ -5890,7 +5891,10 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){
if(!dirCompoundFrame.isEmpty()){
frames.append(dirCompoundFrame);
}
} else {
shouldUseStandardFrame = false;
}
if(shouldUseStandardFrame) {
// otherwise, just send the standard directed frame
frames.append(frame);
}
@ -5925,7 +5929,8 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){
#if 1
qDebug() << "parsed frames:";
foreach(auto frame, frames){
qDebug() << "->" << frame << DecodedText(frame).message();
auto dt = DecodedText(frame);
qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType());
}
#endif
@ -6134,7 +6139,7 @@ void MainWindow::prepareBacon(){
lines.append(beacon);
// 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
enqueueMessage(PriorityLow, lines.join(QChar('\n')), currentFreq(), nullptr);
@ -7262,11 +7267,7 @@ void MainWindow::on_clearAction_triggered(QObject * sender){
void MainWindow::on_cqMacroButton_clicked(){
QString call = m_config.my_callsign();
QString grid = m_config.my_grid().left(4);
if(call != Radio::base_callsign(call)){
grid = "";
}
QString text = QString("CQ %1 %2").arg(call).arg(grid);
QString text = QString("%1: CQCQCQ %2").arg(call).arg(grid).trimmed();
addMessageText(text);
}
@ -7475,7 +7476,7 @@ void MainWindow::buildQueryMenu(QMenu * menu){
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](){
QString selectedCall = callsignSelected();
@ -7487,31 +7488,18 @@ void MainWindow::buildQueryMenu(QMenu * menu){
toggleTx(true);
});
auto ackAction = menu->addAction("ACK - I acknowledge your last transmission");
connect(ackAction, &QAction::triggered, this, [this](){
auto qslAction = menu->addAction("QSL - I confirm I received your last transmission");
connect(qslAction, &QAction::triggered, this, [this](){
QString selectedCall = callsignSelected();
if(selectedCall.isEmpty()){
return;
}
addMessageText(QString("%1 ACK").arg(selectedCall), true);
addMessageText(QString("%1 QSL").arg(selectedCall), 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");
connect(yesAction, &QAction::triggered, this, [this](){

View File

@ -45,23 +45,23 @@ QMap<QString, int> directed_cmds = {
{"$", 3 }, // query station(s) heard
// {"^", 4 }, // query ack
{"%", 5 }, // query pwr
{"|", 6 }, // relay message?
{"!", 7 }, // alert message?
{"|", 6 }, // retransmit message
{"!", 7 }, // alert message
{"#", 8 }, // all or nothing message
// {"=", 9 }, // unused? (can we even use equals?)
// {"/", 10 }, // unused? (can we even use stroke?)
// directed responses
{" QSL?", 21 }, // do you copy?
{" QSL", 22 }, // i copy
{" ACK", 23 }, // acknowledged
{" RR", 21 }, // roger roger (not visible in UI but still exists)
{" QSL?", 22 }, // do you copy?
{" QSL", 23 }, // i copy
{" PWR", 24 }, // power level
{" SNR", 25 }, // seen a station at the provided snr
{" NO", 26 }, // negative confirm
{" YES", 27 }, // confirm
{" 73", 28 }, // best regards, end of contact
{" RR", 29 }, // confirm message
{" ACK", 29 }, // acknowledge
{" AGN?", 30 }, // repeat message
{" ", 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};
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_pwr_pattern = QString("(?<pwr>\\s?\\d+\\s?[KM]?W)?");
QString optional_num_pattern = QString("(?<num>\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
QString optional_pwr_pattern = QString("(?<pwr>(?<=PWR)\\s?\\d+\\s?[KM]?W)?");
QString optional_num_pattern = QString("(?<num>(?<=SNR)\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
QRegularExpression directed_re("^" +
callsign_pattern +
@ -82,14 +82,16 @@ QRegularExpression directed_re("^" +
optional_pwr_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("^[<]" +
callsign_pattern +
optional_grid_pattern +
optional_cmd_pattern +
optional_pwr_pattern +
optional_num_pattern +
QRegularExpression compound_re("^[<]" +
callsign_pattern +
"(?<extra>" +
optional_grid_pattern +
optional_cmd_pattern +
optional_pwr_pattern +
optional_num_pattern +
")" +
"[>]");
QMap<QString, QString> hufftable = {
@ -323,8 +325,7 @@ quint16 nmaxgrid = (1<<15)-1;
QMap<QString, quint32> basecalls = {
{ "<....>", nbasecall + 1 }, // incomplete callsign
{ "CQCQCQ", nbasecall + 2 },
{ "ALLCALL", nbasecall + 3 },
{ "ALLCALL", nbasecall + 2 },
};
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
quint8 Varicode::packCmd(quint8 cmd, quint8 num){
quint8 Varicode::packCmd(quint8 cmd, quint8 num, bool *pPackedNum){
//quint8 allowed = nmaxgrid - nbasegrid - 1;
// 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 = value + num;
if(pPackedNum) *pPackedNum = true;
} else {
value = cmd & ((1<<7)-1);
if(pPackedNum) *pPackedNum = false;
}
return value;
@ -1067,8 +1070,8 @@ bool Varicode::isCommandBuffered(const QString &cmd){
return directed_cmds.contains(cmd) && buffered_cmds.contains(directed_cmds[cmd]);
}
// ALLCALL CQ EM73
// ALLCALL BCN EM73
// CQCQCQ EM73
// BEACON EM73
QString Varicode::packBeaconMessage(QString const &text, const QString &callsign, int *n){
QString frame;
@ -1082,11 +1085,11 @@ QString Varicode::packBeaconMessage(QString const &text, const QString &callsign
// Beacon Alt Type
// ---------------
// 1 0 BCN
// 1 1 CQ
// 1 0 BEACON
// 1 1 CQCQCQ
auto type = parsedText.captured("type");
auto isAlt = type == "CQ";
auto isAlt = type.startsWith("CQ");
auto parsedCall = QRegularExpression(compound_callsign_pattern).match(callsign);
if(!parsedCall.hasMatch()){
@ -1162,35 +1165,42 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
QString num = parsedText.captured("num").trimmed();
QString pwr = parsedText.captured("pwr").trimmed().toUpper();
auto parsedCall = QRegularExpression(compound_callsign_pattern).match(callsign);
if(!parsedCall.hasMatch()){
if(n) *n = 0;
return frame;
}
auto base = parsedCall.captured("base");
QString base;
QString fix;
bool isPrefix = false;
auto fix = parsedCall.captured("prefix");
if(!fix.isEmpty()){
isPrefix = true;
}
if(!isPrefix){
fix = parsedCall.captured("suffix");
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);
if(!parsedCall.hasMatch()){
if(n) *n = 0;
return frame;
}
base = parsedCall.captured("base");
fix = parsedCall.captured("prefix");
if(!fix.isEmpty()){
isPrefix = true;
}
if(!isPrefix){
fix = parsedCall.captured("suffix");
}
}
quint8 type = FrameCompound;
quint16 extra = nmaxgrid;
if (!cmd.isEmpty() && directed_cmds.contains(cmd) && Varicode::isCommandAllowed(cmd)){
bool packedNum = false;
qint8 inum = Varicode::packNum(num, nullptr);
if(cmd.trimmed() == "PWR"){
if(cmd == " PWR"){
inum = Varicode::packPwr(pwr, nullptr);
}
extra = nusergrid + Varicode::packCmd(directed_cmds[cmd], inum);
extra = nusergrid + Varicode::packCmd(directed_cmds[cmd], inum, &packedNum);
type = FrameCompoundDirected;
} else if(!grid.isEmpty()){
@ -1343,7 +1353,9 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
return frame;
}
if(parsedTo.hasMatch()){
if(basecalls.contains(to)){
if(pTo) *pTo = to;
} else if(parsedTo.hasMatch()){
if(pTo) *pTo = parsedTo.captured(0);
auto parsedBase = parsedTo.captured("base");
@ -1352,6 +1364,7 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
}
}
// validate command
if(!Varicode::isCommandAllowed(cmd)){
if(n) *n = 0;
@ -1435,7 +1448,7 @@ QStringList Varicode::unpackDirectedMessage(const QString &text, quint8 *pType){
} else if(packed_cmd == directed_cmds[" SNR"]) {
unpacked.append(Varicode::formatSNR((int)num-31));
} else {
unpacked.append(QString("%1").arg(num));
unpacked.append(QString("%1").arg(num-31));
}
}

View File

@ -35,9 +35,29 @@ public:
FrameDirectedNegative = 4, // [100]
FrameDataUnpadded = 5, // [101]
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();
static QString formatSNR(int snr);
@ -95,7 +115,7 @@ public:
static quint8 packNum(QString const &num, 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 bool isCommandAllowed(const QString &cmd);