Refactor compound call structure for directed messaging by using a new frame type FrameCompoundDirected. This allows us to send only two frames when each station has a compound callsign. No aliasing, full calls are sent with each transmission.
This commit is contained in:
		
							parent
							
								
									172e1df31d
								
							
						
					
					
						commit
						7a155a4820
					
				| @ -21,6 +21,9 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString | |||||||
|   , contest_mode_ {contest_mode} |   , contest_mode_ {contest_mode} | ||||||
|   , message_ {string_.mid (column_qsoText + padding_).trimmed ()} |   , message_ {string_.mid (column_qsoText + padding_).trimmed ()} | ||||||
|   , is_standard_ {false} |   , is_standard_ {false} | ||||||
|  |   , frameType_(Varicode::FrameUnknown) | ||||||
|  |   , isBeacon_(false) | ||||||
|  |   , isAlt_(false) | ||||||
| { | { | ||||||
|     if(message_.length() >= 1) { |     if(message_.length() >= 1) { | ||||||
|         message_ = message_.left (21).remove (QRegularExpression {"[<>]"}); |         message_ = message_.left (21).remove (QRegularExpression {"[<>]"}); | ||||||
| @ -58,8 +61,12 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString | |||||||
|     tryUnpack(); |     tryUnpack(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DecodedText::DecodedText (QString const& ft8callmessage){ | DecodedText::DecodedText (QString const& ft8callmessage): | ||||||
|     message_ = ft8callmessage; |     frameType_(Varicode::FrameUnknown), | ||||||
|  |     message_(ft8callmessage), | ||||||
|  |     isBeacon_(false), | ||||||
|  |     isAlt_(false) | ||||||
|  | { | ||||||
|     is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch(); |     is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch(); | ||||||
| 
 | 
 | ||||||
|     tryUnpack(); |     tryUnpack(); | ||||||
| @ -80,7 +87,6 @@ bool DecodedText::tryUnpack(){ | |||||||
|         unpacked = tryUnpackCompound(); |         unpacked = tryUnpackCompound(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     if(!unpacked){ |     if(!unpacked){ | ||||||
|         unpacked = tryUnpackDirected(); |         unpacked = tryUnpackDirected(); | ||||||
|     } |     } | ||||||
| @ -101,7 +107,8 @@ bool DecodedText::tryUnpackBeacon(){ | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool isAlt = false; |     bool isAlt = false; | ||||||
|     QStringList parts = Varicode::unpackBeaconMessage(m, &isAlt); |     quint8 type = Varicode::FrameUnknown; | ||||||
|  |     QStringList parts = Varicode::unpackBeaconMessage(m, &type, &isAlt); | ||||||
| 
 | 
 | ||||||
|     if(parts.isEmpty() || parts.length() < 2){ |     if(parts.isEmpty() || parts.length() < 2){ | ||||||
|         return false; |         return false; | ||||||
| @ -113,7 +120,7 @@ bool DecodedText::tryUnpackBeacon(){ | |||||||
|     // 1      1   CQ
 |     // 1      1   CQ
 | ||||||
|     isBeacon_ = true; |     isBeacon_ = true; | ||||||
|     isAlt_ = isAlt; |     isAlt_ = isAlt; | ||||||
|     extra_ = parts.at(2); |     extra_ = parts.length() < 3 ? "" : parts.at(2); | ||||||
| 
 | 
 | ||||||
|     QStringList cmp; |     QStringList cmp; | ||||||
|     if(!parts.at(0).isEmpty()){ |     if(!parts.at(0).isEmpty()){ | ||||||
| @ -124,7 +131,7 @@ bool DecodedText::tryUnpackBeacon(){ | |||||||
|     } |     } | ||||||
|     compound_ = cmp.join("/"); |     compound_ = cmp.join("/"); | ||||||
|     message_ = QString("%1: ALLCALL %2 %3 ").arg(compound_).arg(isAlt ? "CQ" : "BCN").arg(extra_); |     message_ = QString("%1: ALLCALL %2 %3 ").arg(compound_).arg(isAlt ? "CQ" : "BCN").arg(extra_); | ||||||
| 
 |     frameType_ = type; | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -135,15 +142,12 @@ bool DecodedText::tryUnpackCompound(){ | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto parts = Varicode::unpackCompoundMessage(m); |     quint8 type = Varicode::FrameUnknown; | ||||||
|  |     auto parts = Varicode::unpackCompoundMessage(m, &type); | ||||||
|     if(parts.isEmpty() || parts.length() < 2){ |     if(parts.isEmpty() || parts.length() < 2){ | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     isBeacon_ = false; |  | ||||||
| 
 |  | ||||||
|     extra_ = parts.at(2); |  | ||||||
| 
 |  | ||||||
|     QStringList cmp; |     QStringList cmp; | ||||||
|     if(!parts.at(0).isEmpty()){ |     if(!parts.at(0).isEmpty()){ | ||||||
|         cmp.append(parts.at(0)); |         cmp.append(parts.at(0)); | ||||||
| @ -152,13 +156,29 @@ bool DecodedText::tryUnpackCompound(){ | |||||||
|         cmp.append(parts.at(1)); |         cmp.append(parts.at(1)); | ||||||
|     } |     } | ||||||
|     compound_ = cmp.join("/"); |     compound_ = cmp.join("/"); | ||||||
|  |     extra_ = parts.length() < 3 ? "" : parts.mid(2).join(" "); | ||||||
| 
 | 
 | ||||||
|     if(extra_.isEmpty()){ |     bool hasPrefixSuffix = compound_.contains("/"); | ||||||
|         message_ = QString("<%1> ").arg(compound_); | 
 | ||||||
|     } else { |     if(type == Varicode::FrameCompound){ | ||||||
|         message_ = QString("<%1 %2> ").arg(compound_).arg(extra_); | #if COMPOUND_SHOW_GRID | ||||||
|  |         message_ = QString("<%1%2>:").arg(compound_).arg(extra_); | ||||||
|  | #endif | ||||||
|  |         if(hasPrefixSuffix){ | ||||||
|  |             message_ = QString("<%1>: ").arg(compound_); | ||||||
|  |         } else { | ||||||
|  |             message_ = QString("%1: ").arg(compound_); | ||||||
|  |         } | ||||||
|  |     } else if(type == Varicode::FrameCompoundDirected){ | ||||||
|  |         if(hasPrefixSuffix){ | ||||||
|  |             message_ = QString("<%1>%2").arg(compound_).arg(extra_); | ||||||
|  |         } else { | ||||||
|  |             message_ = QString("%1%2").arg(compound_).arg(extra_); | ||||||
|  |         } | ||||||
|  |         directed_ = QStringList{ "<....>", compound_ } + parts.mid(2); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     frameType_ = type; | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -170,7 +190,8 @@ bool DecodedText::tryUnpackDirected(){ | |||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     QStringList parts = Varicode::unpackDirectedMessage(m); |     quint8 type = Varicode::FrameUnknown; | ||||||
|  |     QStringList parts = Varicode::unpackDirectedMessage(m, &type); | ||||||
| 
 | 
 | ||||||
|     if(parts.isEmpty()){ |     if(parts.isEmpty()){ | ||||||
|       return false; |       return false; | ||||||
| @ -188,6 +209,7 @@ bool DecodedText::tryUnpackDirected(){ | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     directed_ = parts; |     directed_ = parts; | ||||||
|  |     frameType_ = type; | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -199,13 +221,15 @@ bool DecodedText::tryUnpackData(){ | |||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     QString data = Varicode::unpackDataMessage(m); |     quint8 type = Varicode::FrameUnknown; | ||||||
|  |     QString data = Varicode::unpackDataMessage(m, &type); | ||||||
| 
 | 
 | ||||||
|     if(data.isEmpty()){ |     if(data.isEmpty()){ | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     message_ = data; |     message_ = data; | ||||||
|  |     frameType_ = type; | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -39,10 +39,12 @@ public: | |||||||
|   bool tryUnpackDirected(); |   bool tryUnpackDirected(); | ||||||
|   bool tryUnpackData(); |   bool tryUnpackData(); | ||||||
| 
 | 
 | ||||||
|  |   quint8 frameType() const { return frameType_; } | ||||||
|  | 
 | ||||||
|  |   QString extra() const { return extra_; } | ||||||
|   QString compoundCall() const { return compound_; } |   QString compoundCall() const { return compound_; } | ||||||
|   bool isCompound() const { return !compound_.isEmpty(); } |   bool isCompound() const { return !compound_.isEmpty(); } | ||||||
| 
 | 
 | ||||||
|   QString extra() const { return extra_; } |  | ||||||
|   bool isBeacon() const { return isBeacon_; } |   bool isBeacon() const { return isBeacon_; } | ||||||
|   bool isAlt() const { return isAlt_; } |   bool isAlt() const { return isAlt_; } | ||||||
| 
 | 
 | ||||||
| @ -96,6 +98,7 @@ private: | |||||||
|       column_mode    = 19, |       column_mode    = 19, | ||||||
|       column_qsoText = 22 }; |       column_qsoText = 22 }; | ||||||
| 
 | 
 | ||||||
|  |   quint8 frameType_; | ||||||
|   bool isBeacon_; |   bool isBeacon_; | ||||||
|   bool isAlt_; |   bool isAlt_; | ||||||
|   QString compound_; |   QString compound_; | ||||||
|  | |||||||
| @ -3392,8 +3392,9 @@ void MainWindow::readFromStdout()                             //readFromStdout | |||||||
| 
 | 
 | ||||||
|           // Process compound callsign commands (put them in cache)"
 |           // Process compound callsign commands (put them in cache)"
 | ||||||
| #if 1 | #if 1 | ||||||
|  |           qDebug() << "decoded" << decodedtext.frameType() << decodedtext.isCompound() << decodedtext.isDirectedMessage() << decodedtext.isBeacon(); | ||||||
|           bool shouldProcessCompound = true; |           bool shouldProcessCompound = true; | ||||||
|           if(shouldProcessCompound && decodedtext.isCompound()){ |           if(shouldProcessCompound && decodedtext.isCompound() && !decodedtext.isDirectedMessage()){ | ||||||
|             CallDetail cd; |             CallDetail cd; | ||||||
|             cd.call = decodedtext.compoundCall(); |             cd.call = decodedtext.compoundCall(); | ||||||
|             cd.grid = decodedtext.extra(); // compound calls via beacons may contain grid...
 |             cd.grid = decodedtext.extra(); // compound calls via beacons may contain grid...
 | ||||||
| @ -5905,7 +5906,9 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){ | |||||||
| 
 | 
 | ||||||
|           bool useStd = false; |           bool useStd = false; | ||||||
|           bool useBcn = false; |           bool useBcn = false; | ||||||
|  | #if ALLOW_SEND_COMPOUND | ||||||
|           bool useCmp = false; |           bool useCmp = false; | ||||||
|  | #endif | ||||||
|           bool useDir = false; |           bool useDir = false; | ||||||
|           bool useDat = false; |           bool useDat = false; | ||||||
|           bool isFree = false; |           bool isFree = false; | ||||||
| @ -5914,18 +5917,20 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){ | |||||||
|           int l = 0; |           int l = 0; | ||||||
|           QString bcnFrame = Varicode::packBeaconMessage(line, mycall, &l); |           QString bcnFrame = Varicode::packBeaconMessage(line, mycall, &l); | ||||||
| 
 | 
 | ||||||
|  | #if ALLOW_SEND_COMPOUND | ||||||
|           int o = 0; |           int o = 0; | ||||||
|           QString cmpFrame = Varicode::packCompoundMessage(line, &o); |           QString cmpFrame = Varicode::packCompoundMessage(line, &o); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|           int n = 0; |           int n = 0; | ||||||
|           QString dirCmd; |           QString dirCmd; | ||||||
|           QString dirTo; |           QString dirTo; | ||||||
|           QString dirFrame = Varicode::packDirectedMessage(line, basecall, &dirTo, &dirCmd, &n); |           QString dirNum; | ||||||
|  |           QString dirFrame = Varicode::packDirectedMessage(line, basecall, &dirTo, &dirCmd, &dirNum, &n); | ||||||
|  |           bool dirToCompound = dirTo.contains("/"); | ||||||
| 
 | 
 | ||||||
|           // packDataMessage can output a new line to datLineOut (huff escaping special characters)
 |  | ||||||
|           int m = 0; |           int m = 0; | ||||||
|           QString datLineOut; |           QString datFrame = Varicode::packDataMessage(line.left(24) + "\x04", &m); //  66 / 3 + 2 = 22 (maximum number of 3bit chars we could possibly stuff in here plus 2 for good measure :P)
 | ||||||
|           QString datFrame = Varicode::packDataMessage(line.left(24) + "\x04", &datLineOut, &m); //  66 / 3 + 2 = 22 (maximum number of 3bit chars we could possibly stuff in here plus 2 for good measure :P)
 |  | ||||||
| 
 | 
 | ||||||
|           // if this parses to a standard FT8 free text message
 |           // if this parses to a standard FT8 free text message
 | ||||||
|           // but it can be parsed as a directed message, then we
 |           // but it can be parsed as a directed message, then we
 | ||||||
| @ -5938,11 +5943,13 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){ | |||||||
|               hasDirected = false; |               hasDirected = false; | ||||||
|               frame = bcnFrame; |               frame = bcnFrame; | ||||||
|           } |           } | ||||||
|  | #if ALLOW_SEND_COMPOUND | ||||||
|           else if(isFree && !hasDirected && !hasData && o > 0){ |           else if(isFree && !hasDirected && !hasData && o > 0){ | ||||||
|               useCmp = true; |               useCmp = true; | ||||||
|               hasDirected = false; |               hasDirected = false; | ||||||
|               frame = cmpFrame; |               frame = cmpFrame; | ||||||
|           } |           } | ||||||
|  | #endif | ||||||
|           else if(isFree && !hasDirected && !hasData && n > 0){ |           else if(isFree && !hasDirected && !hasData && n > 0){ | ||||||
|               useDir = true; |               useDir = true; | ||||||
|               hasDirected = true; |               hasDirected = true; | ||||||
| @ -5952,9 +5959,6 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){ | |||||||
|               useDat = true; |               useDat = true; | ||||||
|               hasData = true; |               hasData = true; | ||||||
|               frame = datFrame; |               frame = datFrame; | ||||||
|               if(!datLineOut.isEmpty()){ |  | ||||||
|                 line = datLineOut; |  | ||||||
|               } |  | ||||||
|           } else { |           } else { | ||||||
|               useStd = true; |               useStd = true; | ||||||
|               frame = stdFrame; |               frame = stdFrame; | ||||||
| @ -5981,32 +5985,52 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){ | |||||||
|               line = line.mid(l); |               line = line.mid(l); | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|  | #if ALLOW_SEND_COMPOUND | ||||||
|           if(useCmp){ |           if(useCmp){ | ||||||
|               frames.append(frame); |               frames.append(frame); | ||||||
|               line = line.mid(o); |               line = line.mid(o); | ||||||
|           } |           } | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|           if(useDir){ |           if(useDir){ | ||||||
|               // from compound callsign
 |               /**
 | ||||||
|               if(compound){ |                * We have a few special cases when we are sending to a compound call, or our call is a compound call, or both. | ||||||
|                   QString compoundMessage = QString("<%1 %2>").arg(mycall).arg(mygrid); |                * CASE 0: Non-compound:       KN4CRD: J1Y ACK | ||||||
|                   QString compoundFrame = Varicode::packCompoundMessage(compoundMessage, nullptr); |                * -> One standard directed message frame | ||||||
|                   if(!compoundFrame.isEmpty()){ |                * | ||||||
|                       frames.append(compoundFrame); |                * CASE 1: Compound From:      KN4CRD/P: J1Y ACK | ||||||
|  |                * -> One standard compound frame, followed by a standard directed message frame with placeholder | ||||||
|  |                * -> The second standard directed frame _could_ be replaced with a compound directed frame | ||||||
|  |                * -> <KN4CRD/P EM73> then <....>: J1Y ACK | ||||||
|  |                * -> <KN4CRD/P EM73> then <J1Y ACK> | ||||||
|  |                * | ||||||
|  |                * CASE 2: Compound To:        KN4CRD: J1Y/P ACK | ||||||
|  |                * -> One standard compound frame, followed by a compound directed frame | ||||||
|  |                * -> <KN4CRD EM73> then <J1Y/P ACK> | ||||||
|  |                * | ||||||
|  |                * CASE 3: Compound From & To: KN4CRD/P: J1Y/P ACK | ||||||
|  |                * -> One standard compound frame, followed by a compound directed frame | ||||||
|  |                * -> <KN4CRD/P EM73> then <J1Y/P ACK> | ||||||
|  |                **/ | ||||||
|  |               if(compound || dirToCompound){ | ||||||
|  |                   // Cases 1, 2, 3 all send a standard compound frame first...
 | ||||||
|  |                   QString deCompoundMessage = QString("<%1 %2>").arg(mycall).arg(mygrid); | ||||||
|  |                   QString deCompoundFrame = Varicode::packCompoundMessage(deCompoundMessage, nullptr); | ||||||
|  |                   if(!deCompoundFrame.isEmpty()){ | ||||||
|  |                       frames.append(deCompoundFrame); | ||||||
|                   } |                   } | ||||||
|               } |  | ||||||
| 
 | 
 | ||||||
|               // to compound callsign
 |                   // Followed, by a standard OR compound directed message...
 | ||||||
|               if(!dirTo.isEmpty() && dirTo.contains("/")){ |                   QString dirCompoundMessage = QString("<%1%2%3>").arg(dirTo).arg(dirCmd).arg(dirNum); | ||||||
|                   QString compoundMessage = QString("<%1>").arg(dirTo); |                   QString dirCompoundFrame = Varicode::packCompoundMessage(dirCompoundMessage, nullptr); | ||||||
|                   QString compoundFrame = Varicode::packCompoundMessage(compoundMessage, nullptr); |                   if(!dirCompoundFrame.isEmpty()){ | ||||||
|                   if(!compoundFrame.isEmpty()){ |                       frames.append(dirCompoundFrame); | ||||||
|                       frames.append(compoundFrame); |  | ||||||
|                   } |                   } | ||||||
|  |               } else { | ||||||
|  |                   // otherwise, just send the standard directed frame
 | ||||||
|  |                   frames.append(frame); | ||||||
|               } |               } | ||||||
| 
 | 
 | ||||||
|               frames.append(frame); |  | ||||||
| 
 |  | ||||||
|               line = line.mid(n); |               line = line.mid(n); | ||||||
| 
 | 
 | ||||||
|               // generate a checksum for buffered commands with line data
 |               // generate a checksum for buffered commands with line data
 | ||||||
| @ -6037,7 +6061,7 @@ 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 << Varicode::unpackDataMessage(frame) << Varicode::unpackDirectedMessage(frame) << Varicode::unpackCompoundFrame(frame, nullptr, nullptr) << Varicode::unpackBeaconMessage(frame, nullptr); |         qDebug() << "->" << frame << DecodedText(frame).message(); | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| @ -6283,10 +6307,11 @@ void MainWindow::prepareBacon(){ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| QString MainWindow::calculateDistance(QString const& grid) | QString MainWindow::calculateDistance(QString const& value) | ||||||
| { | { | ||||||
|     if(grid.isEmpty()){ |     QString grid = value.trimmed(); | ||||||
|         return QString(); |     if(grid.isEmpty() || grid.length() < 4){ | ||||||
|  |         return QString{}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     qint64 nsec = (QDateTime::currentMSecsSinceEpoch()/1000) % 86400; |     qint64 nsec = (QDateTime::currentMSecsSinceEpoch()/1000) % 86400; | ||||||
|  | |||||||
							
								
								
									
										234
									
								
								varicode.cpp
									
									
									
									
									
								
							
							
						
						
									
										234
									
								
								varicode.cpp
									
									
									
									
									
								
							| @ -68,16 +68,27 @@ QSet<int> allowed_cmds = {0, 1, 2, 3, 4, 5, 6, 7, 8, 23, 24, 25, 26, 27, 28, 29, | |||||||
| 
 | 
 | ||||||
| QSet<int> buffered_cmds = {6, 7, 8}; | QSet<int> buffered_cmds = {6, 7, 8}; | ||||||
| 
 | 
 | ||||||
| QRegularExpression directed_re("^" | QString callsign_pattern = QString("(?<callsign>[A-Z0-9/]+)"); | ||||||
|                                "(?<to>[A-Z0-9/]+)" | QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:AGN[?]|RR|73|YES|NO|SNR|PWR|ACK|[?@&$^%|!# ]))?"); | ||||||
|                                "(?<cmd>\\s?(?:AGN[?]|RR|73|YES|NO|SNR|PWR|ACK|[?@&$^%|!# ]))" | QString optional_grid_pattern = QString("(?<grid>\\s?[A-R]{2}[0-9]{2})?"); | ||||||
|                                "(?<pwr>\\s?\\d+\\s?[KM]?W)?" | QString optional_pwr_pattern = QString("(?<pwr>\\s?\\d+\\s?[KM]?W)?"); | ||||||
|                                "(?<num>\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?" | QString optional_num_pattern = QString("(?<num>\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?"); | ||||||
|                                ); | 
 | ||||||
|  | QRegularExpression directed_re("^"                    + | ||||||
|  |                                callsign_pattern       + | ||||||
|  |                                optional_cmd_pattern   + | ||||||
|  |                                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"(^ALLCALL\s(?<type>CQ|BCN)(?:\s(?<grid>[A-Z]{2}[0-9]{2}))?\b)"); | ||||||
| 
 | 
 | ||||||
| QRegularExpression compound_re(R"(^[<](?<callsign>[A-Z0-9/]+)(?:\s(?<grid>[A-Z]{2}[0-9]{2}))?[>])"); | QRegularExpression compound_re("^[<]"                + | ||||||
|  |                                callsign_pattern      + | ||||||
|  |                                optional_grid_pattern + | ||||||
|  |                                optional_cmd_pattern  + | ||||||
|  |                                optional_pwr_pattern  + | ||||||
|  |                                optional_num_pattern  + | ||||||
|  |                                "[>]"); | ||||||
| 
 | 
 | ||||||
| QMap<QString, QString> hufftable = { | QMap<QString, QString> hufftable = { | ||||||
|     // char   code                 weight
 |     // char   code                 weight
 | ||||||
| @ -305,6 +316,7 @@ QChar EOT = '\x04'; // EOT char | |||||||
| 
 | 
 | ||||||
| quint32 nbasecall = 37 * 36 * 10 * 27 * 27 * 27; | quint32 nbasecall = 37 * 36 * 10 * 27 * 27 * 27; | ||||||
| quint16 nbasegrid = 180 * 180; | quint16 nbasegrid = 180 * 180; | ||||||
|  | quint16 nusergrid = nbasegrid + 10; | ||||||
| quint16 nmaxgrid  = (1<<15)-1; | quint16 nmaxgrid  = (1<<15)-1; | ||||||
| 
 | 
 | ||||||
| QMap<QString, quint32> basecalls = { | QMap<QString, quint32> basecalls = { | ||||||
| @ -955,14 +967,12 @@ QPair<float, float> grid2deg(QString const &grid){ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // pack a 4-digit maidenhead grid locator into a 15-bit value
 | // pack a 4-digit maidenhead grid locator into a 15-bit value
 | ||||||
| quint16 Varicode::packGrid(QString const& grid){ | quint16 Varicode::packGrid(QString const& value){ | ||||||
|     // TODO: validate grid...
 |     QString grid = QString(value).trimmed(); | ||||||
|     if(grid.length() < 4){       |     if(grid.length() < 4){       | ||||||
|         return (1<<15)-1; |         return (1<<15)-1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO: encode non-grid data...
 |  | ||||||
| 
 |  | ||||||
|     auto pair = grid2deg(grid.left(4)); |     auto pair = grid2deg(grid.left(4)); | ||||||
|     int ilong = pair.first; |     int ilong = pair.first; | ||||||
|     int ilat = pair.second + 90; |     int ilat = pair.second + 90; | ||||||
| @ -971,8 +981,7 @@ quint16 Varicode::packGrid(QString const& grid){ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| QString Varicode::unpackGrid(quint16 value){ | QString Varicode::unpackGrid(quint16 value){ | ||||||
|     if(value > 180*180){ |     if(value > nbasegrid){ | ||||||
|         // TODO: decode non-grid data... for now just return an empty string...
 |  | ||||||
|         return ""; |         return ""; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -982,6 +991,81 @@ QString Varicode::unpackGrid(quint16 value){ | |||||||
|     return deg2grid(dlong, dlat).left(4); |     return deg2grid(dlong, dlat).left(4); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // pack a number or snr into an integer between 0 & 62
 | ||||||
|  | quint8 Varicode::packNum(QString const &num, bool *ok){ | ||||||
|  |     int inum = 0; | ||||||
|  |     if(num.isEmpty()){ | ||||||
|  |         if(ok) *ok = false; | ||||||
|  |         return inum; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inum = qMax(-30, qMin(num.toInt(ok, 10), 31)); | ||||||
|  |     return inum + 30 + 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // pack pwr string into a dbm between 0 and 62
 | ||||||
|  | quint8 Varicode::packPwr(QString const &pwr, bool *ok){ | ||||||
|  |     int ipwr = 0; | ||||||
|  |     if(pwr.isEmpty()){ | ||||||
|  |         if(ok) *ok = false; | ||||||
|  |         return ipwr; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     int factor = 1000; | ||||||
|  |     if(pwr.endsWith("KW")){ | ||||||
|  |         factor = 1000000; | ||||||
|  |     } | ||||||
|  |     else if(pwr.endsWith("MW")){ | ||||||
|  |         factor = 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ipwr = QString(pwr).replace(QRegExp("[KM]?W", Qt::CaseInsensitive), "").toInt() * factor; | ||||||
|  |     ipwr = mwattsToDbm(ipwr); | ||||||
|  | 
 | ||||||
|  |     if(ok) *ok = true; | ||||||
|  |     return ipwr + 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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 allowed = nmaxgrid - nbasegrid - 1;
 | ||||||
|  | 
 | ||||||
|  |     // if cmd == pwr || cmd == snr
 | ||||||
|  |     quint8 value = 0; | ||||||
|  |     if(cmd == directed_cmds[" PWR"] || cmd == directed_cmds[" SNR"]){ | ||||||
|  |         // 8 bits - 1 bit flag + 1 bit type + 6 bit number
 | ||||||
|  |         // [1][X][6]
 | ||||||
|  |         // X = 0 == SNR
 | ||||||
|  |         // X = 1 == PWR
 | ||||||
|  | 
 | ||||||
|  |         value = ((1 << 1) + ((int)cmd == directed_cmds[" PWR"])) << 6; | ||||||
|  |         value = value + num; | ||||||
|  |     } else { | ||||||
|  |         value = cmd & ((1<<7)-1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | quint8 Varicode::unpackCmd(quint8 value, quint8 *pNum){ | ||||||
|  |     // if the first bit is 1, the second bit will indicate if its pwr or snr...
 | ||||||
|  |     if(value & (1<<7)){ | ||||||
|  |         // either pwr or snr...
 | ||||||
|  |         bool pwr = value & (1<<6); | ||||||
|  | 
 | ||||||
|  |         if(pNum) *pNum = value & ((1<<6)-1); | ||||||
|  | 
 | ||||||
|  |         if(pwr){ | ||||||
|  |             return directed_cmds[" PWR"]; | ||||||
|  |         } else { | ||||||
|  |             return directed_cmds[" SNR"]; | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         if(pNum) *pNum = 0; | ||||||
|  |         return value & ((1<<7)-1); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool Varicode::isCommandAllowed(const QString &cmd){ | bool Varicode::isCommandAllowed(const QString &cmd){ | ||||||
|     return directed_cmds.contains(cmd) && allowed_cmds.contains(directed_cmds[cmd]); |     return directed_cmds.contains(cmd) && allowed_cmds.contains(directed_cmds[cmd]); | ||||||
| } | } | ||||||
| @ -1049,7 +1133,7 @@ QString Varicode::packBeaconMessage(QString const &text, const QString &callsign | |||||||
|     return frame; |     return frame; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| QStringList Varicode::unpackBeaconMessage(const QString &text, bool * isAlt){ | QStringList Varicode::unpackBeaconMessage(const QString &text, quint8 *pType, bool * isAlt){ | ||||||
|     quint8 type = FrameBeacon; |     quint8 type = FrameBeacon; | ||||||
|     quint16 num = nmaxgrid; |     quint16 num = nmaxgrid; | ||||||
| 
 | 
 | ||||||
| @ -1061,6 +1145,7 @@ QStringList Varicode::unpackBeaconMessage(const QString &text, bool * isAlt){ | |||||||
|     unpacked.append(Varicode::unpackGrid(num & ((1<<15)-1))); |     unpacked.append(Varicode::unpackGrid(num & ((1<<15)-1))); | ||||||
| 
 | 
 | ||||||
|     if(isAlt) *isAlt = (num & (1<<15)); |     if(isAlt) *isAlt = (num & (1<<15)); | ||||||
|  |     if(pType) *pType = type; | ||||||
| 
 | 
 | ||||||
|     return unpacked; |     return unpacked; | ||||||
| } | } | ||||||
| @ -1078,8 +1163,11 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){ | |||||||
|         return frame; |         return frame; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto callsign = parsedText.captured("callsign"); |     QString callsign = parsedText.captured("callsign"); | ||||||
|     auto grid = parsedText.captured("grid"); |     QString grid = parsedText.captured("grid"); | ||||||
|  |     QString cmd = parsedText.captured("cmd"); | ||||||
|  |     QString num = parsedText.captured("num").trimmed(); | ||||||
|  |     QString pwr = parsedText.captured("pwr").trimmed().toUpper(); | ||||||
| 
 | 
 | ||||||
|     auto parsedCall = QRegularExpression(compound_callsign_pattern).match(callsign); |     auto parsedCall = QRegularExpression(compound_callsign_pattern).match(callsign); | ||||||
|     if(!parsedCall.hasMatch()){ |     if(!parsedCall.hasMatch()){ | ||||||
| @ -1099,24 +1187,54 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){ | |||||||
|         fix = parsedCall.captured("suffix"); |         fix = parsedCall.captured("suffix"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     quint16 extra = Varicode::packGrid(grid); |     quint8 type = FrameCompound; | ||||||
|  |     quint16 extra = nmaxgrid; | ||||||
| 
 | 
 | ||||||
|     frame = Varicode::packCompoundFrame(base, fix, isPrefix, FrameCompound, extra); |     if (!cmd.isEmpty() && directed_cmds.contains(cmd) && Varicode::isCommandAllowed(cmd)){ | ||||||
|  | 
 | ||||||
|  |         qint8 inum = Varicode::packNum(num, nullptr); | ||||||
|  |         if(cmd.trimmed() == "PWR"){ | ||||||
|  |             inum = Varicode::packPwr(pwr, nullptr); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         extra = nusergrid + Varicode::packCmd(directed_cmds[cmd], inum); | ||||||
|  | 
 | ||||||
|  |         type = FrameCompoundDirected; | ||||||
|  |     } else if(!grid.isEmpty()){ | ||||||
|  |         extra = Varicode::packGrid(grid); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     frame = Varicode::packCompoundFrame(base, fix, isPrefix, type, extra); | ||||||
| 
 | 
 | ||||||
|     if(n) *n = parsedText.captured(0).length(); |     if(n) *n = parsedText.captured(0).length(); | ||||||
|     return frame; |     return frame; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| QStringList Varicode::unpackCompoundMessage(const QString &text){ | QStringList Varicode::unpackCompoundMessage(const QString &text, quint8 *pType){ | ||||||
|     quint8 type = FrameCompound; |     quint8 type = FrameCompound; | ||||||
|     quint16 num = nmaxgrid; |     quint16 extra = nmaxgrid; | ||||||
| 
 | 
 | ||||||
|     QStringList unpacked = unpackCompoundFrame(text, &type, &num); |     QStringList unpacked = unpackCompoundFrame(text, &type, &extra); | ||||||
|     if(unpacked.isEmpty() || type != FrameCompound){ |     if(unpacked.isEmpty() || (type != FrameCompound && type != FrameCompoundDirected)){ | ||||||
|         return QStringList {}; |         return QStringList {}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     unpacked.append(Varicode::unpackGrid(num & ((1<<15)-1))); |     if(extra <= nbasegrid){ | ||||||
|  |         unpacked.append(" " + Varicode::unpackGrid(extra)); | ||||||
|  |     } else if (nusergrid <= extra && extra < nmaxgrid) { | ||||||
|  |         quint8 num = 0; | ||||||
|  |         auto cmd = Varicode::unpackCmd(extra - nusergrid, &num); | ||||||
|  | 
 | ||||||
|  |         unpacked.append(directed_cmds.key(cmd)); | ||||||
|  | 
 | ||||||
|  |         if(cmd == directed_cmds[" PWR"]){ | ||||||
|  |             unpacked.append(Varicode::formatPWR(num - 1)); | ||||||
|  |         } else if(cmd == directed_cmds[" SNR"]){ | ||||||
|  |             unpacked.append(Varicode::formatSNR(num - 31)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(pType) *pType = type; | ||||||
| 
 | 
 | ||||||
|     return unpacked; |     return unpacked; | ||||||
| } | } | ||||||
| @ -1124,7 +1242,7 @@ QStringList Varicode::unpackCompoundMessage(const QString &text){ | |||||||
| QString Varicode::packCompoundFrame(const QString &baseCallsign, const QString &fix, bool isPrefix, quint8 type, quint16 num){ | QString Varicode::packCompoundFrame(const QString &baseCallsign, const QString &fix, bool isPrefix, quint8 type, quint16 num){ | ||||||
|     QString frame; |     QString frame; | ||||||
| 
 | 
 | ||||||
|     // needs to be a beacon type...
 |     // needs to be a compound type...
 | ||||||
|     if(type == FrameDataPadded || type == FrameDataUnpadded || type == FrameDirectedPositive || type == FrameDirectedNegative){ |     if(type == FrameDataPadded || type == FrameDataUnpadded || type == FrameDirectedPositive || type == FrameDirectedNegative){ | ||||||
|         return frame; |         return frame; | ||||||
|     } |     } | ||||||
| @ -1203,7 +1321,7 @@ QStringList Varicode::unpackCompoundFrame(const QString &text, quint8 *pType, qu | |||||||
| // J1Y?
 | // J1Y?
 | ||||||
| // KN4CRD: J1Y$
 | // KN4CRD: J1Y$
 | ||||||
| // KN4CRD: J1Y! HELLO WORLD
 | // KN4CRD: J1Y! HELLO WORLD
 | ||||||
| QString Varicode::packDirectedMessage(const QString &text, const QString &callsign, QString *pTo, QString * pCmd, int *n){ | QString Varicode::packDirectedMessage(const QString &text, const QString &callsign, QString *pTo, QString * pCmd, QString *pNum, int *n){ | ||||||
|     QString frame; |     QString frame; | ||||||
| 
 | 
 | ||||||
|     auto match = directed_re.match(text); |     auto match = directed_re.match(text); | ||||||
| @ -1213,11 +1331,17 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     QString from = callsign; |     QString from = callsign; | ||||||
|     QString to = match.captured("to"); |     QString to = match.captured("callsign"); | ||||||
|     QString cmd = match.captured("cmd"); |     QString cmd = match.captured("cmd"); | ||||||
|     QString num = match.captured("num").trimmed(); |     QString num = match.captured("num").trimmed(); | ||||||
|     QString pwr = match.captured("pwr").trimmed().toUpper(); |     QString pwr = match.captured("pwr").trimmed().toUpper(); | ||||||
| 
 | 
 | ||||||
|  |     // ensure we have a directed command
 | ||||||
|  |     if(cmd.isEmpty()){ | ||||||
|  |         if(n) *n = 0; | ||||||
|  |         return frame; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     // validate "to" callsign
 |     // validate "to" callsign
 | ||||||
|     auto parsedTo = QRegularExpression(compound_callsign_pattern).match(to); |     auto parsedTo = QRegularExpression(compound_callsign_pattern).match(to); | ||||||
|     bool validToCallsign = (to != callsign) && (basecalls.contains(to) || parsedTo.hasMatch()); |     bool validToCallsign = (to != callsign) && (basecalls.contains(to) || parsedTo.hasMatch()); | ||||||
| @ -1242,27 +1366,16 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // packing general number...
 |     // packing general number...
 | ||||||
|     int inum = -31; |     quint8 inum = 0; | ||||||
|     bool hasnum = false; | 
 | ||||||
|     if(!num.isEmpty()){ |     if(cmd.trimmed() == "PWR"){ | ||||||
|         inum = qMax(-30, qMin(num.toInt(&hasnum, 10), 30)); |         inum = Varicode::packPwr(pwr, nullptr); | ||||||
|  |         if(pNum) *pNum = pwr; | ||||||
|  |     } else { | ||||||
|  |         inum = Varicode::packNum(num, nullptr); | ||||||
|  |         if(pNum) *pNum = num; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // if we are packing a PWR command, pack pwr as dbm
 |  | ||||||
|     int ipwr = -31; |  | ||||||
|     if(!pwr.isEmpty() && cmd.trimmed() == "PWR"){ |  | ||||||
|         int factor = 1000; |  | ||||||
|         if(pwr.endsWith("KW")){ |  | ||||||
|             factor = 1000000; |  | ||||||
|         } |  | ||||||
|         else if(pwr.endsWith("MW")){ |  | ||||||
|             factor = 1; |  | ||||||
|         } |  | ||||||
|         ipwr = pwr.replace(QRegExp("[KM]?W", Qt::CaseInsensitive), "").toInt() * factor; |  | ||||||
|         inum = mwattsToDbm(ipwr) - 30; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     quint8 packed_flag = inum < 0 ? FrameDirectedNegative : FrameDirectedPositive; |  | ||||||
|     quint32 packed_from = Varicode::packCallsign(from); |     quint32 packed_from = Varicode::packCallsign(from); | ||||||
|     quint32 packed_to = Varicode::packCallsign(to); |     quint32 packed_to = Varicode::packCallsign(to); | ||||||
| 
 | 
 | ||||||
| @ -1272,7 +1385,8 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     quint8 packed_cmd = directed_cmds[cmd]; |     quint8 packed_cmd = directed_cmds[cmd]; | ||||||
|     quint8 packed_extra = qAbs(inum); |     quint8 packed_flag = inum < 31 ? FrameDirectedNegative : FrameDirectedPositive; | ||||||
|  |     quint8 packed_extra = inum < 31 ? inum : inum - 31; | ||||||
| 
 | 
 | ||||||
|     // [3][28][28][5],[5] = 69
 |     // [3][28][28][5],[5] = 69
 | ||||||
|     auto bits = ( |     auto bits = ( | ||||||
| @ -1287,7 +1401,7 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi | |||||||
|     return Varicode::pack64bits(Varicode::bitsToInt(bits)) + Varicode::pack5bits(packed_extra % 32); |     return Varicode::pack64bits(Varicode::bitsToInt(bits)) + Varicode::pack5bits(packed_extra % 32); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| QStringList Varicode::unpackDirectedMessage(const QString &text){ | QStringList Varicode::unpackDirectedMessage(const QString &text, quint8 *pType){ | ||||||
|     QStringList unpacked; |     QStringList unpacked; | ||||||
| 
 | 
 | ||||||
|     if(text.length() < 13 || text.contains(" ")){ |     if(text.length() < 13 || text.contains(" ")){ | ||||||
| @ -1301,9 +1415,9 @@ QStringList Varicode::unpackDirectedMessage(const QString &text){ | |||||||
|     int numSign = 0; |     int numSign = 0; | ||||||
|     quint8 packed_flag = Varicode::bitsToInt(Varicode::strToBits(bits.left(3))); |     quint8 packed_flag = Varicode::bitsToInt(Varicode::strToBits(bits.left(3))); | ||||||
|     if(packed_flag == FrameDirectedPositive){ |     if(packed_flag == FrameDirectedPositive){ | ||||||
|         numSign = 1; |         numSign = 31; | ||||||
|     } else if(packed_flag == FrameDirectedNegative){ |     } else if(packed_flag == FrameDirectedNegative){ | ||||||
|         numSign = -1; |         numSign = 0; | ||||||
|     } else { |     } else { | ||||||
|         return unpacked; |         return unpacked; | ||||||
|     } |     } | ||||||
| @ -1320,22 +1434,23 @@ QStringList Varicode::unpackDirectedMessage(const QString &text){ | |||||||
|     unpacked.append(to); |     unpacked.append(to); | ||||||
|     unpacked.append(cmd); |     unpacked.append(cmd); | ||||||
| 
 | 
 | ||||||
|     int num = numSign * extra; |     quint8 num = extra + numSign; | ||||||
|     if(num != -31){ |     if(num != 0){ | ||||||
|         // TODO: jsherer - should we decide which format to use on the command, or something else?
 |         // TODO: jsherer - should we decide which format to use on the command, or something else?
 | ||||||
|         if(packed_cmd == directed_cmds[" PWR"]){ |         if(packed_cmd == directed_cmds[" PWR"]){ | ||||||
|             unpacked.append(Varicode::formatPWR(num + 30)); |             unpacked.append(Varicode::formatPWR(num-1)); | ||||||
|         } else if(packed_cmd == directed_cmds[" SNR"]) { |         } else if(packed_cmd == directed_cmds[" SNR"]) { | ||||||
|             unpacked.append(Varicode::formatSNR(num)); |             unpacked.append(Varicode::formatSNR((int)num-31)); | ||||||
|         } else { |         } else { | ||||||
|             unpacked.append(QString("%1").arg(num)); |             unpacked.append(QString("%1").arg(num)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if(pType) *pType = packed_flag; | ||||||
|     return unpacked; |     return unpacked; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| QString Varicode::packDataMessage(const QString &input, QString * out, int *n){ | QString Varicode::packDataMessage(const QString &input, int *n){ | ||||||
|     QString frame; |     QString frame; | ||||||
| 
 | 
 | ||||||
|     // [3][66] = 69
 |     // [3][66] = 69
 | ||||||
| @ -1380,7 +1495,7 @@ QString Varicode::packDataMessage(const QString &input, QString * out, int *n){ | |||||||
|     return frame; |     return frame; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| QString Varicode::unpackDataMessage(const QString &text){ | QString Varicode::unpackDataMessage(const QString &text, quint8 *pType){ | ||||||
|     QString unpacked; |     QString unpacked; | ||||||
| 
 | 
 | ||||||
|     if(text.length() < 13 || text.contains(" ")){ |     if(text.length() < 13 || text.contains(" ")){ | ||||||
| @ -1389,11 +1504,10 @@ QString Varicode::unpackDataMessage(const QString &text){ | |||||||
| 
 | 
 | ||||||
|     auto bits = Varicode::intToBits(Varicode::unpack64bits(text.left(12)), 64) + Varicode::intToBits(Varicode::unpack5bits(text.right(1)), 5); |     auto bits = Varicode::intToBits(Varicode::unpack64bits(text.left(12)), 64) + Varicode::intToBits(Varicode::unpack5bits(text.right(1)), 5); | ||||||
| 
 | 
 | ||||||
|     quint8 flag = Varicode::bitsToInt(bits.mid(0, 3)); |     quint8 type = Varicode::bitsToInt(bits.mid(0, 3)); | ||||||
| 
 |     if(type == FrameDataUnpadded){ | ||||||
|     if(flag == FrameDataUnpadded){ |  | ||||||
|         bits = bits.mid(3); |         bits = bits.mid(3); | ||||||
|     } else if(flag == FrameDataPadded) { |     } else if(type == FrameDataPadded) { | ||||||
|         int n = bits.lastIndexOf(0); |         int n = bits.lastIndexOf(0); | ||||||
|         bits = bits.mid(3, n-3); |         bits = bits.mid(3, n-3); | ||||||
|     } else { |     } else { | ||||||
| @ -1406,5 +1520,7 @@ QString Varicode::unpackDataMessage(const QString &text){ | |||||||
|     // then... unescape special characters
 |     // then... unescape special characters
 | ||||||
|     unpacked = Varicode::huffUnescape(unpacked); |     unpacked = Varicode::huffUnescape(unpacked); | ||||||
| 
 | 
 | ||||||
|  |     if(pType) *pType = type; | ||||||
|  | 
 | ||||||
|     return unpacked; |     return unpacked; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										34
									
								
								varicode.h
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								varicode.h
									
									
									
									
									
								
							| @ -27,14 +27,15 @@ public: | |||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     enum FrameType { |     enum FrameType { | ||||||
|         FrameBeacon           = 0, // [000]
 |         FrameUnknown          = 255, // [11111111] <- only used as a sentinel
 | ||||||
|         FrameCompound         = 1, // [001]
 |         FrameBeacon           = 0,   // [000]
 | ||||||
|         FrameDirectedPositive = 2, // [010]
 |         FrameCompound         = 1,   // [001]
 | ||||||
|         FrameDirectedNegative = 3, // [011]
 |         FrameCompoundDirected = 2,   // [010]
 | ||||||
|         FrameDataUnpadded     = 4, // [100]
 |         FrameDirectedPositive = 3,   // [011]
 | ||||||
|         FrameDataPadded       = 5, // [101]
 |         FrameDirectedNegative = 4,   // [100]
 | ||||||
|         FrameReservedA        = 6, // [110]
 |         FrameDataUnpadded     = 5,   // [101]
 | ||||||
|         FrameReservedB        = 7, // [111]
 |         FrameDataPadded       = 6,   // [110]
 | ||||||
|  |         FrameReservedX        = 7,   // [111]
 | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     //Varicode();
 |     //Varicode();
 | ||||||
| @ -92,23 +93,28 @@ public: | |||||||
|     static quint16 packGrid(QString const& value); |     static quint16 packGrid(QString const& value); | ||||||
|     static QString unpackGrid(quint16 value); |     static QString unpackGrid(quint16 value); | ||||||
| 
 | 
 | ||||||
|  |     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 unpackCmd(quint8 value, quint8 *pNum); | ||||||
|  | 
 | ||||||
|     static bool isCommandAllowed(const QString &cmd); |     static bool isCommandAllowed(const QString &cmd); | ||||||
|     static bool isCommandBuffered(const QString &cmd); |     static bool isCommandBuffered(const QString &cmd); | ||||||
| 
 | 
 | ||||||
|     static QString packBeaconMessage(QString const &text, QString const&callsign, int *n); |     static QString packBeaconMessage(QString const &text, QString const&callsign, int *n); | ||||||
|     static QStringList unpackBeaconMessage(const QString &text, bool *isAlt); |     static QStringList unpackBeaconMessage(const QString &text, quint8 *pType, bool *isAlt); | ||||||
| 
 | 
 | ||||||
|     static QString packCompoundMessage(QString const &text, int *n); |     static QString packCompoundMessage(QString const &text, int *n); | ||||||
|     static QStringList unpackCompoundMessage(const QString &text); |     static QStringList unpackCompoundMessage(const QString &text, quint8 *pType); | ||||||
| 
 | 
 | ||||||
|     static QString packCompoundFrame(const QString &baseCallsign, const QString &fix, bool isPrefix, quint8 type, quint16 num); |     static QString packCompoundFrame(const QString &baseCallsign, const QString &fix, bool isPrefix, quint8 type, quint16 num); | ||||||
|     static QStringList unpackCompoundFrame(const QString &text, quint8 *pType, quint16 *pNum); |     static QStringList unpackCompoundFrame(const QString &text, quint8 *pType, quint16 *pNum); | ||||||
| 
 | 
 | ||||||
|     static QString packDirectedMessage(QString const& text, QString const& callsign, QString *pTo, QString * pCmd, int *n); |     static QString packDirectedMessage(QString const& text, QString const& callsign, QString *pTo, QString * pCmd, QString *pNum, int *n); | ||||||
|     static QStringList unpackDirectedMessage(QString const& text); |     static QStringList unpackDirectedMessage(QString const& text, quint8 *pType); | ||||||
| 
 | 
 | ||||||
|     static QString packDataMessage(QString const& text, QString *out, int *n); |     static QString packDataMessage(QString const& text, int *n); | ||||||
|     static QString unpackDataMessage(QString const& text); |     static QString unpackDataMessage(QString const& text, quint8 *pType); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #endif // VARICODE_H
 | #endif // VARICODE_H
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Jordan Sherer
						Jordan Sherer