Restructured data frame packing so we can send more over the wire in fewer frames

This commit is contained in:
Jordan Sherer 2018-10-29 03:26:10 -04:00
parent 38fc98702b
commit 440311a75b
6 changed files with 102 additions and 74 deletions

View File

@ -24,6 +24,7 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString
, frameType_(Varicode::FrameUnknown) , frameType_(Varicode::FrameUnknown)
, isHeartbeat_(false) , isHeartbeat_(false)
, isAlt_(false) , isAlt_(false)
, bits_{0}
{ {
if(message_.length() >= 1) { if(message_.length() >= 1) {
message_ = message_.left (21).remove (QRegularExpression {"[<>]"}); message_ = message_.left (21).remove (QRegularExpression {"[<>]"});
@ -58,14 +59,17 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString
} }
} }
bits_ = bits();
tryUnpack(); tryUnpack();
} }
DecodedText::DecodedText (QString const& js8callmessage): DecodedText::DecodedText (QString const& js8callmessage, int bits):
frameType_(Varicode::FrameUnknown), frameType_(Varicode::FrameUnknown),
message_(js8callmessage), message_(js8callmessage),
isHeartbeat_(false), isHeartbeat_(false),
isAlt_(false) isAlt_(false),
bits_(bits)
{ {
is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch(); is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch();
@ -79,6 +83,10 @@ bool DecodedText::tryUnpack(){
} }
bool unpacked = false; bool unpacked = false;
if(!unpacked){
unpacked = tryUnpackData();
}
if(!unpacked){ if(!unpacked){
unpacked = tryUnpackHeartbeat(); unpacked = tryUnpackHeartbeat();
} }
@ -91,10 +99,6 @@ bool DecodedText::tryUnpack(){
unpacked = tryUnpackDirected(); unpacked = tryUnpackDirected();
} }
if(!unpacked){
unpacked = tryUnpackData();
}
return unpacked; return unpacked;
} }
@ -212,6 +216,10 @@ bool DecodedText::tryUnpackData(){
return false; return false;
} }
if((bits_ & Varicode::JS8CallData) != Varicode::JS8CallData){
return false;
}
quint8 type = Varicode::FrameUnknown; quint8 type = Varicode::FrameUnknown;
QString data = Varicode::unpackDataMessage(m, &type); QString data = Varicode::unpackDataMessage(m, &type);

View File

@ -31,7 +31,7 @@ class DecodedText
{ {
public: public:
explicit DecodedText (QString const& message, bool, QString const& my_grid); explicit DecodedText (QString const& message, bool, QString const& my_grid);
explicit DecodedText (QString const& js8callmessage); explicit DecodedText (QString const& js8callmessage, int bits);
bool tryUnpack(); bool tryUnpack();
bool tryUnpackHeartbeat(); bool tryUnpackHeartbeat();
@ -109,6 +109,7 @@ private:
bool contest_mode_; bool contest_mode_;
QString message_; QString message_;
bool is_standard_; bool is_standard_;
int bits_;
}; };
#endif // DECODEDTEXT_H #endif // DECODEDTEXT_H

View File

@ -2204,7 +2204,7 @@ void MainWindow::fastSink(qint64 frames)
m_config.color_NewCall(),m_config.ppfx()); m_config.color_NewCall(),m_config.ppfx());
m_bDecoded=true; m_bDecoded=true;
if (m_mode != "ISCAT") postDecode (true, decodedtext.string ()); if (m_mode != "ISCAT") postDecode (true, decodedtext.string ());
writeAllTxt(message); writeAllTxt(message, decodedtext.bits());
bool stdMsg = decodedtext.report(m_baseCall, bool stdMsg = decodedtext.report(m_baseCall,
Radio::base_callsign(ui->dxCallEntry->text()),m_rptRcvd); Radio::base_callsign(ui->dxCallEntry->text()),m_rptRcvd);
//if (stdMsg) pskPost (decodedtext); //if (stdMsg) pskPost (decodedtext);
@ -3445,7 +3445,7 @@ void::MainWindow::fast_decode_done()
m_bDecoded=true; m_bDecoded=true;
} }
postDecode (true, decodedtext.string ()); postDecode (true, decodedtext.string ());
writeAllTxt(message); writeAllTxt(message, decodedtext.bits());
if(m_mode=="JT9" or m_mode=="MSK144") { if(m_mode=="JT9" or m_mode=="MSK144") {
// find and extract any report for myCall // find and extract any report for myCall
@ -3462,7 +3462,7 @@ void::MainWindow::fast_decode_done()
m_bFastDone=false; m_bFastDone=false;
} }
void MainWindow::writeAllTxt(QString message) void MainWindow::writeAllTxt(QString message, int bits)
{ {
// Write decoded text to file "ALL.TXT". // Write decoded text to file "ALL.TXT".
QFile f {m_config.writeable_data_dir ().absoluteFilePath ("ALL.TXT")}; QFile f {m_config.writeable_data_dir ().absoluteFilePath ("ALL.TXT")};
@ -3474,7 +3474,7 @@ void MainWindow::writeAllTxt(QString message)
<< m_mode << endl; << m_mode << endl;
m_RxLog=0; m_RxLog=0;
} }
auto dt = DecodedText(message); auto dt = DecodedText(message, bits);
out << dt.message() << endl; out << dt.message() << endl;
f.close(); f.close();
} else { } else {
@ -3569,7 +3569,7 @@ void MainWindow::readFromStdout() //readFromStdout
(bits == Varicode::JS8Call || (bits == Varicode::JS8Call ||
((bits & Varicode::JS8CallFirst) == Varicode::JS8CallFirst) || ((bits & Varicode::JS8CallFirst) == Varicode::JS8CallFirst) ||
((bits & Varicode::JS8CallLast) == Varicode::JS8CallLast) || ((bits & Varicode::JS8CallLast) == Varicode::JS8CallLast) ||
((bits & Varicode::JS8CallReserved) == 0 /*Varicode::JS8CallReserved*/)) // This is unused...so is invalid at this time... ((bits & Varicode::JS8CallData) == Varicode::JS8CallData)) // This is unused...so is invalid at this time...
); );
qDebug() << "valid" << bValidFrame << "decoded text" << decodedtext.message(); qDebug() << "valid" << bValidFrame << "decoded text" << decodedtext.message();
@ -4023,6 +4023,7 @@ void MainWindow::guiUpdate()
static quint64 lastLoop; static quint64 lastLoop;
static char message[29]; static char message[29];
static char msgsent[29]; static char msgsent[29];
static int msgibits;
double txDuration; double txDuration;
QString rt; QString rt;
@ -4170,11 +4171,12 @@ void MainWindow::guiUpdate()
char ft8msgbits[75 + 12]; //packed 75 bit ft8 message plus 12-bit CRC char ft8msgbits[75 + 12]; //packed 75 bit ft8 message plus 12-bit CRC
genft8_(message, MyGrid, &bcontest, &m_i3bit, msgsent, const_cast<char *> (ft8msgbits), genft8_(message, MyGrid, &bcontest, &m_i3bit, msgsent, const_cast<char *> (ft8msgbits),
const_cast<int *> (itone), 22, 6, 22); const_cast<int *> (itone), 22, 6, 22);
msgibits = m_i3bit;
msgsent[22]=0; msgsent[22]=0;
} }
m_currentMessage = QString::fromLatin1(msgsent); m_currentMessage = QString::fromLatin1(msgsent);
m_currentMessageBits = msgibits;
m_bCallingCQ = CALLING == m_QSOProgress m_bCallingCQ = CALLING == m_QSOProgress
|| m_currentMessage.contains (QRegularExpression {"^(CQ|QRZ) "}); || m_currentMessage.contains (QRegularExpression {"^(CQ|QRZ) "});
if(m_mode=="FT8") { if(m_mode=="FT8") {
@ -4322,7 +4324,7 @@ void MainWindow::guiUpdate()
if(m_transmitting) { if(m_transmitting) {
char s[41]; char s[41];
auto dt = DecodedText(msgsent); auto dt = DecodedText(msgsent, msgibits);
sprintf(s,"Tx: %s", dt.message().toLocal8Bit().mid(0, 41).data()); sprintf(s,"Tx: %s", dt.message().toLocal8Bit().mid(0, 41).data());
m_nsendingsh=0; m_nsendingsh=0;
if(s[4]==64) m_nsendingsh=1; if(s[4]==64) m_nsendingsh=1;
@ -4486,7 +4488,7 @@ void MainWindow::startTx2()
void MainWindow::stopTx() void MainWindow::stopTx()
{ {
Q_EMIT endTransmitMessage (); Q_EMIT endTransmitMessage ();
auto dt = DecodedText(m_currentMessage.trimmed()); auto dt = DecodedText(m_currentMessage.trimmed(), m_currentMessageBits);
last_tx_label.setText("Last Tx: " + dt.message()); //m_currentMessage.trimmed()); last_tx_label.setText("Last Tx: " + dt.message()); //m_currentMessage.trimmed());
m_btxok = false; m_btxok = false;
@ -5301,7 +5303,7 @@ void MainWindow::createMessageTransmitQueue(QString const& text){
QStringList lines; QStringList lines;
foreach(auto frame, frames){ foreach(auto frame, frames){
auto dt = DecodedText(frame); auto dt = DecodedText(frame.first, frame.second);
lines.append(dt.message()); lines.append(dt.message());
} }
@ -5324,9 +5326,9 @@ void MainWindow::resetMessageTransmitQueue(){
m_txMessageQueue.clear(); m_txMessageQueue.clear();
} }
QString MainWindow::popMessageFrame(){ QPair<QString, int> MainWindow::popMessageFrame(){
if(m_txFrameQueue.isEmpty()){ if(m_txFrameQueue.isEmpty()){
return QString(); return QPair<QString, int>{};
} }
return m_txFrameQueue.dequeue(); return m_txFrameQueue.dequeue();
} }
@ -5371,7 +5373,7 @@ int MainWindow::currentFreqOffset(){
return ui->RxFreqSpinBox->value(); return ui->RxFreqSpinBox->value();
} }
QStringList MainWindow::buildMessageFrames(const QString &text){ QList<QPair<QString, int>> MainWindow::buildMessageFrames(const QString &text){
// prepare selected callsign for directed message // prepare selected callsign for directed message
QString selectedCall = callsignSelected(); QString selectedCall = callsignSelected();
@ -5395,7 +5397,7 @@ QStringList MainWindow::buildMessageFrames(const QString &text){
#if 0 #if 0
qDebug() << "frames:"; qDebug() << "frames:";
foreach(auto frame, frames){ foreach(auto frame, frames){
auto dt = DecodedText(frame); auto dt = DecodedText(frame.frame, frame.bits);
qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType()); qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType());
} }
#endif #endif
@ -5407,7 +5409,10 @@ bool MainWindow::prepareNextMessageFrame()
{ {
m_i3bit = Varicode::JS8Call; m_i3bit = Varicode::JS8Call;
QString frame = popMessageFrame(); QPair<QString, int> f = popMessageFrame();
auto frame = f.first;
auto bits = f.second;
if(frame.isEmpty()){ if(frame.isEmpty()){
ui->nextFreeTextMsg->clear(); ui->nextFreeTextMsg->clear();
updateTxButtonDisplay(); updateTxButtonDisplay();
@ -5416,6 +5421,7 @@ bool MainWindow::prepareNextMessageFrame()
} else { } else {
ui->nextFreeTextMsg->setText(frame); ui->nextFreeTextMsg->setText(frame);
/*
int count = m_txFrameCount; int count = m_txFrameCount;
int sent = count - m_txFrameQueue.count(); int sent = count - m_txFrameQueue.count();
@ -5425,6 +5431,9 @@ bool MainWindow::prepareNextMessageFrame()
if(count == sent){ if(count == sent){
m_i3bit |= Varicode::JS8CallLast; m_i3bit |= Varicode::JS8CallLast;
} }
*/
m_i3bit = bits;
updateTxButtonDisplay(); updateTxButtonDisplay();
@ -8011,8 +8020,8 @@ void MainWindow::refreshTextDisplay(){
QStringList textList; QStringList textList;
qDebug() << "frames:"; qDebug() << "frames:";
foreach(auto frame, frames){ foreach(Frame frame, frames){
auto dt = DecodedText(frame); auto dt = DecodedText(frame.frame, frame.bits);
qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType()); qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType());
textList.append(dt.message()); textList.append(dt.message());
} }
@ -8053,14 +8062,16 @@ void MainWindow::refreshTextDisplay(){
); );
connect(t, &BuildMessageFramesThread::finished, t, &QObject::deleteLater); connect(t, &BuildMessageFramesThread::finished, t, &QObject::deleteLater);
connect(t, &BuildMessageFramesThread::resultReady, this, [this, text](const QStringList frames){ connect(t, &BuildMessageFramesThread::resultReady, this, [this, text](QStringList frames, QList<int> bits){
QStringList textList; QStringList textList;
qDebug() << "frames:"; qDebug() << "frames:";
int i = 0;
foreach(auto frame, frames){ foreach(auto frame, frames){
auto dt = DecodedText(frame); auto dt = DecodedText(frame, bits.at(i));
qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType()); qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType());
textList.append(dt.message()); textList.append(dt.message());
i++;
} }
auto transmitText = textList.join(""); auto transmitText = textList.join("");
@ -8389,7 +8400,7 @@ void MainWindow::processCompoundActivity() {
bits == Varicode::JS8Call || bits == Varicode::JS8Call ||
((bits & Varicode::JS8CallFirst) == Varicode::JS8CallFirst) || ((bits & Varicode::JS8CallFirst) == Varicode::JS8CallFirst) ||
((bits & Varicode::JS8CallLast) == Varicode::JS8CallLast) || ((bits & Varicode::JS8CallLast) == Varicode::JS8CallLast) ||
((bits & Varicode::JS8CallReserved) == Varicode::JS8CallReserved) ((bits & Varicode::JS8CallData) == Varicode::JS8CallData)
); );
if (!validBits) { if (!validBits) {
qDebug() << "-> buffer.cmd bits is invalid...skip"; qDebug() << "-> buffer.cmd bits is invalid...skip";
@ -10346,7 +10357,7 @@ void MainWindow::write_transmit_entry (QString const& file_name)
QTextStream out(&f); QTextStream out(&f);
auto time = DriftingDateTime::currentDateTimeUtc (); auto time = DriftingDateTime::currentDateTimeUtc ();
time = time.addSecs (-(time.time ().second () % m_TRperiod)); time = time.addSecs (-(time.time ().second () % m_TRperiod));
auto dt = DecodedText(m_currentMessage); auto dt = DecodedText(m_currentMessage, m_currentMessageBits);
out << time.toString("yyyy-MM-dd hh:mm:ss") out << time.toString("yyyy-MM-dd hh:mm:ss")
<< " Transmitting " << qSetRealNumberPrecision (12) << (m_freqNominal / 1.e6) << " Transmitting " << qSetRealNumberPrecision (12) << (m_freqNominal / 1.e6)
<< " MHz " << QString(m_modeTx).replace("FT8", "JS8") << " MHz " << QString(m_modeTx).replace("FT8", "JS8")

View File

@ -155,7 +155,7 @@ public slots:
void createMessage(QString const& text); void createMessage(QString const& text);
void createMessageTransmitQueue(QString const& text); void createMessageTransmitQueue(QString const& text);
void resetMessageTransmitQueue(); void resetMessageTransmitQueue();
QString popMessageFrame(); QPair<QString, int> popMessageFrame();
protected: protected:
void keyPressEvent (QKeyEvent *) override; void keyPressEvent (QKeyEvent *) override;
void closeEvent(QCloseEvent *) override; void closeEvent(QCloseEvent *) override;
@ -298,7 +298,7 @@ private slots:
void on_nextFreeTextMsg_currentTextChanged (QString const&); void on_nextFreeTextMsg_currentTextChanged (QString const&);
void on_extFreeTextMsgEdit_currentTextChanged (QString const&); void on_extFreeTextMsgEdit_currentTextChanged (QString const&);
int currentFreqOffset(); int currentFreqOffset();
QStringList buildMessageFrames(QString const& text); QList<QPair<QString, int>> buildMessageFrames(QString const& text);
bool prepareNextMessageFrame(); bool prepareNextMessageFrame();
bool isFreqOffsetFree(int f, int bw); bool isFreqOffsetFree(int f, int bw);
int findFreeFreqOffset(int fmin, int fmax, int bw); int findFreeFreqOffset(int fmin, int fmax, int bw);
@ -415,7 +415,7 @@ private:
private: private:
void astroUpdate (); void astroUpdate ();
void writeAllTxt(QString message); void writeAllTxt(QString message, int bits);
void hideMenus(bool b); void hideMenus(bool b);
NetworkAccessManager m_network_manager; NetworkAccessManager m_network_manager;
@ -553,6 +553,7 @@ private:
bool m_sentFirst73; bool m_sentFirst73;
int m_currentMessageType; int m_currentMessageType;
QString m_currentMessage; QString m_currentMessage;
int m_currentMessageBits;
int m_lastMessageType; int m_lastMessageType;
QString m_lastMessageSent; QString m_lastMessageSent;
bool m_bShMsgs; bool m_bShMsgs;
@ -773,7 +774,7 @@ private:
QMap<QString, QVariant> m_showColumnsCache; // table column:key -> show boolean QMap<QString, QVariant> m_showColumnsCache; // table column:key -> show boolean
QMap<QString, QVariant> m_sortCache; // table key -> sort by QMap<QString, QVariant> m_sortCache; // table key -> sort by
QPriorityQueue<PrioritizedMessage> m_txMessageQueue; // messages to be sent QPriorityQueue<PrioritizedMessage> m_txMessageQueue; // messages to be sent
QQueue<QString> m_txFrameQueue; // frames to be sent QQueue<QPair<QString, int>> m_txFrameQueue; // frames to be sent
QQueue<ActivityDetail> m_rxActivityQueue; // all rx activity queue QQueue<ActivityDetail> m_rxActivityQueue; // all rx activity queue
QQueue<CommandDetail> m_rxCommandQueue; // command queue for processing commands QQueue<CommandDetail> m_rxCommandQueue; // command queue for processing commands
QQueue<CallDetail> m_rxCallQueue; // call detail queue for spots to pskreporter QQueue<CallDetail> m_rxCallQueue; // call detail queue for spots to pskreporter

View File

@ -104,7 +104,7 @@ QString callsign_pattern = QString("(?<callsign>[@]?[A-Z0-9/]+)");
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:HEARTBEAT (ACK|REQ)|AGN[?]|QSL[?]|HW CPY[?]|APRS[:]|QRZ[?]|SNR[?]|QTC[?]|QTH[?]|GRID[?]|STATUS[?]|(?:(?:ACK|73|YES|NO|SNR|QSL|RR|SK|FB|QTH|QTC|GRID|ACTIVE|IDLE)(?=[ ]|$))|[#> ]))?"); QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:HEARTBEAT (ACK|REQ)|AGN[?]|QSL[?]|HW CPY[?]|APRS[:]|QRZ[?]|SNR[?]|QTC[?]|QTH[?]|GRID[?]|STATUS[?]|(?:(?:ACK|73|YES|NO|SNR|QSL|RR|SK|FB|QTH|QTC|GRID|ACTIVE|IDLE)(?=[ ]|$))|[#> ]))?");
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_extended_grid_pattern = QString("^(?<grid>\\s?(?:[A-R]{2}[0-9]{2}(?:[A-X]{2}(?:[0-9]{2})?)*))?"); QString optional_extended_grid_pattern = QString("^(?<grid>\\s?(?:[A-R]{2}[0-9]{2}(?:[A-X]{2}(?:[0-9]{2})?)*))?");
QString optional_num_pattern = QString("(?<num>(?<=SNR|ACK)\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?"); QString optional_num_pattern = QString("(?<num>(?<=SNR|HEARTBEAT ACK)\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
QRegularExpression directed_re("^" + QRegularExpression directed_re("^" +
callsign_pattern + callsign_pattern +
@ -981,7 +981,7 @@ quint8 Varicode::packCmd(quint8 cmd, quint8 num, bool *pPackedNum){
// [1][X][6] // [1][X][6]
// X = 0 == SNR // X = 0 == SNR
// X = 1 == ACK // X = 1 == ACK
value = ((1 << 1) | (int)(cmdStr == " ACK")) << 6; value = ((1 << 1) | (int)(cmdStr == " HEARTBEAT ACK")) << 6;
value = value + (num & ((1<<6)-1)); value = value + (num & ((1<<6)-1));
if(pPackedNum) *pPackedNum = true; if(pPackedNum) *pPackedNum = true;
} else { } else {
@ -999,7 +999,7 @@ quint8 Varicode::unpackCmd(quint8 value, quint8 *pNum){
auto cmd = directed_cmds[" SNR"]; auto cmd = directed_cmds[" SNR"];
if(value & (1<<6)){ if(value & (1<<6)){
cmd = directed_cmds[" ACK"]; cmd = directed_cmds[" HEARTBEAT ACK"];
} }
return cmd; return cmd;
} else { } else {
@ -1459,12 +1459,10 @@ QStringList Varicode::unpackDirectedMessage(const QString &text, quint8 *pType){
QString packHuffMessage(const QString &input, int *n){ QString packHuffMessage(const QString &input, int *n){
static const int frameSize = 72; static const int frameSize = 72;
QString frame; QString frame = {false};
// [3][69] = 72 // [1][71] = 72
QVector<bool> frameDataBits; QVector<bool> frameBits = {false};
QVector<bool> frameHeaderBits = Varicode::intToBits(Varicode::FrameDataUncompressed, 3);
int i = 0; int i = 0;
@ -1474,6 +1472,7 @@ QString packHuffMessage(const QString &input, int *n){
for(it = input.constBegin(); it != input.constEnd(); it++){ for(it = input.constBegin(); it != input.constEnd(); it++){
auto ch = (*it).toUpper(); auto ch = (*it).toUpper();
if(!validChars.contains(ch)){ if(!validChars.contains(ch)){
if(n) *n = 0;
return frame; return frame;
} }
} }
@ -1482,32 +1481,28 @@ QString packHuffMessage(const QString &input, int *n){
foreach(auto pair, Varicode::huffEncode(Varicode::defaultHuffTable(), input)){ foreach(auto pair, Varicode::huffEncode(Varicode::defaultHuffTable(), input)){
auto charN = pair.first; auto charN = pair.first;
auto charBits = pair.second; auto charBits = pair.second;
if(frameHeaderBits.length() + frameDataBits.length() + charBits.length() < frameSize){ if(frameBits.length() + charBits.length() < frameSize){
frameDataBits += charBits; frameBits += charBits;
i += charN; i += charN;
continue; continue;
} }
break; break;
} }
QVector<bool> framePadBits; qDebug() << "Huff bits" << frameBits.length() << "chars" << i;
int pad = frameSize - frameHeaderBits.length() - frameDataBits.length(); int pad = frameSize - frameBits.length();
if(pad){ if(pad){
// the way we will pad is this... // the way we will pad is this...
// set the bit after the frame to 0 and every bit after that a 1 // set the bit after the frame to 0 and every bit after that a 1
// to unpad, seek from the end of the bits until you hit a zero... the rest is the actual frame. // to unpad, seek from the end of the bits until you hit a zero... the rest is the actual frame.
for(int i = 0; i < pad; i++){ for(int i = 0; i < pad; i++){
framePadBits.append(i == 0 ? (bool)0 : (bool)1); frameBits.append(i == 0 ? (bool)0 : (bool)1);
} }
} }
qDebug() << "Huff bits" << frameDataBits.length() << "chars" << i; quint64 value = Varicode::bitsToInt(frameBits.constBegin(), 64);
quint8 rem = (quint8)Varicode::bitsToInt(frameBits.constBegin() + 64, 8);
QVector<bool> allBits = frameHeaderBits + frameDataBits + framePadBits;
quint64 value = Varicode::bitsToInt(allBits.constBegin(), 64);
quint8 rem = (quint8)Varicode::bitsToInt(allBits.constBegin() + 64, 8);
frame = Varicode::pack72bits(value, rem); frame = Varicode::pack72bits(value, rem);
if(n) *n = i; if(n) *n = i;
@ -1520,9 +1515,8 @@ QString packCompressedMessage(const QString &input, int *n){
QString frame; QString frame;
QVector<bool> frameBits; // [1][71] = 72
QVector<bool> frameBits = {true};
frameBits.append(Varicode::intToBits(Varicode::FrameDataCompressed, 3));
int i = 0; int i = 0;
foreach(auto pair, JSC::compress(input)){ foreach(auto pair, JSC::compress(input)){
@ -1538,7 +1532,7 @@ QString packCompressedMessage(const QString &input, int *n){
break; break;
} }
qDebug() << "Compressed bits" << frameBits.length() - 3 << "chars" << i; qDebug() << "Compressed bits" << frameBits.length() << "chars" << i;
int pad = frameSize - frameBits.length(); int pad = frameSize - frameBits.length();
if(pad){ if(pad){
@ -1588,25 +1582,25 @@ QString Varicode::unpackDataMessage(const QString &text, quint8 *pType){
quint64 value = Varicode::unpack72bits(text, &rem); quint64 value = Varicode::unpack72bits(text, &rem);
auto bits = Varicode::intToBits(value, 64) + Varicode::intToBits(rem, 8); auto bits = Varicode::intToBits(value, 64) + Varicode::intToBits(rem, 8);
quint8 type = Varicode::bitsToInt(bits.mid(0, 3)); bool compressed = bits.at(0);
int n = bits.lastIndexOf(0); int n = bits.lastIndexOf(0);
bits = bits.mid(3, n-3); bits = bits.mid(1, n-1);
if(type == FrameDataUncompressed){ if(compressed){
unpacked = JSC::decompress(bits);
if(pType) *pType = Varicode::FrameDataCompressed;
} else {
// huff decode the bits (without escapes) // huff decode the bits (without escapes)
unpacked = Varicode::huffDecode(Varicode::defaultHuffTable(), bits); unpacked = Varicode::huffDecode(Varicode::defaultHuffTable(), bits);
if(pType) *pType = type; if(pType) *pType = Varicode::FrameDataUncompressed;
} else if(type == FrameDataCompressed) {
unpacked = JSC::decompress(bits);
if(pType) *pType = type;
} }
return unpacked; return unpacked;
} }
// TODO: remove the dependence on providing all this data? // TODO: remove the dependence on providing all this data?
QStringList Varicode::buildMessageFrames( QList<QPair<QString, int>> Varicode::buildMessageFrames(
QString const& mycall, QString const& mycall,
//QString const& basecall, //QString const& basecall,
QString const& mygrid, QString const& mygrid,
@ -1621,7 +1615,7 @@ QStringList Varicode::buildMessageFrames(
bool mycallCompound = Varicode::isCompoundCallsign(mycall); bool mycallCompound = Varicode::isCompoundCallsign(mycall);
QStringList frames; QList<QPair<QString, int>> frames;
foreach(QString line, text.split(QRegExp("[\\r\\n]"), QString::SkipEmptyParts)){ foreach(QString line, text.split(QRegExp("[\\r\\n]"), QString::SkipEmptyParts)){
// once we find a directed call, data encode the rest of the line. // once we find a directed call, data encode the rest of the line.
@ -1735,13 +1729,13 @@ QStringList Varicode::buildMessageFrames(
} }
if(useBcn){ if(useBcn){
frames.append(frame); frames.append({ frame, Varicode::JS8Call });
line = line.mid(l); line = line.mid(l);
} }
#if ALLOW_SEND_COMPOUND #if ALLOW_SEND_COMPOUND
if(useCmp){ if(useCmp){
frames.append(frame); frames.append({ frame, Varicode::JS8Call });
line = line.mid(o); line = line.mid(o);
} }
#endif #endif
@ -1775,14 +1769,14 @@ QStringList Varicode::buildMessageFrames(
QString deCompoundMessage = QString("`%1 %2").arg(mycall).arg(mygrid); QString deCompoundMessage = QString("`%1 %2").arg(mycall).arg(mygrid);
QString deCompoundFrame = Varicode::packCompoundMessage(deCompoundMessage, nullptr); QString deCompoundFrame = Varicode::packCompoundMessage(deCompoundMessage, nullptr);
if(!deCompoundFrame.isEmpty()){ if(!deCompoundFrame.isEmpty()){
frames.append(deCompoundFrame); frames.append({ deCompoundFrame, Varicode::JS8Call });
} }
// Followed, by a standard OR compound directed message... // Followed, by a standard OR compound directed message...
QString dirCompoundMessage = QString("`%1%2%3").arg(dirTo).arg(dirCmd).arg(dirNum); QString dirCompoundMessage = QString("`%1%2%3").arg(dirTo).arg(dirCmd).arg(dirNum);
QString dirCompoundFrame = Varicode::packCompoundMessage(dirCompoundMessage, nullptr); QString dirCompoundFrame = Varicode::packCompoundMessage(dirCompoundMessage, nullptr);
if(!dirCompoundFrame.isEmpty()){ if(!dirCompoundFrame.isEmpty()){
frames.append(dirCompoundFrame); frames.append({ dirCompoundFrame, Varicode::JS8Call });
} }
shouldUseStandardFrame = false; shouldUseStandardFrame = false;
} }
@ -1790,7 +1784,7 @@ QStringList Varicode::buildMessageFrames(
if(shouldUseStandardFrame) { if(shouldUseStandardFrame) {
// otherwise, just send the standard directed frame // otherwise, just send the standard directed frame
frames.append(frame); frames.append({ frame, Varicode::JS8Call });
} }
line = line.mid(n); line = line.mid(n);
@ -1818,12 +1812,17 @@ QStringList Varicode::buildMessageFrames(
} }
if(useDat){ if(useDat){
frames.append(frame); frames.append({ frame, Varicode::JS8CallData });
line = line.mid(m); line = line.mid(m);
} }
} }
} }
if(!frames.isEmpty()){
frames.first().second |= Varicode::JS8CallFirst;
frames.last().second |= Varicode::JS8CallLast;
}
return frames; return frames;
} }
@ -1854,5 +1853,12 @@ void BuildMessageFramesThread::run(){
m_text m_text
); );
emit resultReady(results); QList<QString> frames;
QList<int> bits;
foreach(auto pair, results){
frames.append(pair.first);
bits.append(pair.second);
}
emit resultReady(frames, bits);
} }

View File

@ -12,6 +12,7 @@
#include <QVector> #include <QVector>
#include <QThread> #include <QThread>
class Varicode class Varicode
{ {
public: public:
@ -20,12 +21,12 @@ public:
JS8Call = 0, // [000] <- any other frame of the message JS8Call = 0, // [000] <- any other frame of the message
JS8CallFirst = 1, // [001] <- the first frame of a message JS8CallFirst = 1, // [001] <- the first frame of a message
JS8CallLast = 2, // [010] <- the last frame of a message JS8CallLast = 2, // [010] <- the last frame of a message
JS8CallReserved = 4, // [100] <- a reserved flag for future use... JS8CallData = 4, // [100] <- raw data frame (no frame type header)
}; };
enum FrameType { enum FrameType {
FrameUnknown = 255, // [11111111] <- only used as a sentinel FrameUnknown = 255, // [11111111] <- only used as a sentinel
FrameHeartbeat = 0, // [000] FrameHeartbeat = 0, // [000]
FrameCompound = 1, // [001] FrameCompound = 1, // [001]
FrameCompoundDirected = 2, // [010] FrameCompoundDirected = 2, // [010]
FrameDirected = 3, // [011] FrameDirected = 3, // [011]
@ -147,7 +148,7 @@ public:
static QString packDataMessage(QString const& text, int *n); static QString packDataMessage(QString const& text, int *n);
static QString unpackDataMessage(QString const& text, quint8 *pType); static QString unpackDataMessage(QString const& text, quint8 *pType);
static QStringList buildMessageFrames( static QList<QPair<QString, int>> buildMessageFrames(
QString const& mycall, QString const& mycall,
//QString const& basecall, //QString const& basecall,
QString const& mygrid, QString const& mygrid,
@ -171,7 +172,7 @@ public:
QObject *parent=nullptr); QObject *parent=nullptr);
void run() override; void run() override;
signals: signals:
void resultReady(const QStringList s); void resultReady(QStringList, QList<int>);
private: private:
QString m_mycall; QString m_mycall;