Added background thread to compute message frames
This commit is contained in:
		
							parent
							
								
									862e702b2d
								
							
						
					
					
						commit
						2cb1665e2e
					
				
							
								
								
									
										364
									
								
								mainwindow.cpp
									
									
									
									
									
								
							
							
						
						
									
										364
									
								
								mainwindow.cpp
									
									
									
									
									
								
							@ -263,28 +263,6 @@ namespace
 | 
				
			|||||||
   return roundDown + multiple;
 | 
					   return roundDown + multiple;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  QString rstrip(const QString& str) {
 | 
					 | 
				
			||||||
    int n = str.size() - 1;
 | 
					 | 
				
			||||||
    for (; n >= 0; --n) {
 | 
					 | 
				
			||||||
      if (str.at(n).isSpace()) {
 | 
					 | 
				
			||||||
          continue;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return str.left(n + 1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return "";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  QString lstrip(const QString& str) {
 | 
					 | 
				
			||||||
    int len = str.size();
 | 
					 | 
				
			||||||
    for (int n = 0; n < len; n++) {
 | 
					 | 
				
			||||||
        if(str.at(n).isSpace()){
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return str.mid(n);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return "";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void setTextEditFont(QTextEdit *edit, QFont font){
 | 
					  void setTextEditFont(QTextEdit *edit, QFont font){
 | 
				
			||||||
    edit->setFont(font);
 | 
					    edit->setFont(font);
 | 
				
			||||||
    edit->setFontFamily(font.family());
 | 
					    edit->setFontFamily(font.family());
 | 
				
			||||||
@ -1417,6 +1395,10 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
  */
 | 
					  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  m_txTextDirtyDebounce.setSingleShot(true);
 | 
				
			||||||
 | 
					  m_txTextDirtyDebounce.setInterval(100);
 | 
				
			||||||
 | 
					  connect(&m_txTextDirtyDebounce, &QTimer::timeout, this, &MainWindow::buildMessageFramesAndUpdateCountDisplay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  QTimer::singleShot(0, this, &MainWindow::initializeDummyData);
 | 
					  QTimer::singleShot(0, this, &MainWindow::initializeDummyData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // this must be the last statement of constructor
 | 
					  // this must be the last statement of constructor
 | 
				
			||||||
@ -6060,7 +6042,7 @@ void MainWindow::createMessage(QString const& text){
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MainWindow::createMessageTransmitQueue(QString const& text){
 | 
					void MainWindow::createMessageTransmitQueue(QString const& text){
 | 
				
			||||||
  auto frames = buildFT8MessageFrames(text);
 | 
					  auto frames = buildMessageFrames(text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  m_txFrameQueue.append(frames);
 | 
					  m_txFrameQueue.append(frames);
 | 
				
			||||||
  m_txFrameCount = frames.length();
 | 
					  m_txFrameCount = frames.length();
 | 
				
			||||||
@ -6135,16 +6117,11 @@ int MainWindow::currentFreqOffset(){
 | 
				
			|||||||
    return ui->RxFreqSpinBox->value();
 | 
					    return ui->RxFreqSpinBox->value();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int MainWindow::countFT8MessageFrames(QString const& text){
 | 
					int MainWindow::countMessageFrames(QString const& text){
 | 
				
			||||||
    return buildFT8MessageFrames(text).length();
 | 
					    return buildMessageFrames(text).length();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QStringList MainWindow::buildFT8MessageFrames(QString const& text){
 | 
					QStringList MainWindow::buildMessageFrames(const QString &text){
 | 
				
			||||||
    #define ALLOW_SEND_COMPOUND 1
 | 
					 | 
				
			||||||
    #define AUTO_PREPEND_DIRECTED 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    QStringList frames;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // prepare selected callsign for directed message
 | 
					    // prepare selected callsign for directed message
 | 
				
			||||||
    QString selectedCall = callsignSelected();
 | 
					    QString selectedCall = callsignSelected();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -6157,226 +6134,10 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){
 | 
				
			|||||||
        basecall = "<....>";
 | 
					        basecall = "<....>";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    foreach(QString line, text.split(QRegExp("[\\r\\n]"), QString::SkipEmptyParts)){
 | 
					    auto frames = Varicode::buildMessageFrames(mycall, basecall, mygrid, compound, selectedCall, text);
 | 
				
			||||||
        // once we find a directed call, data encode the rest of the line.
 | 
					 | 
				
			||||||
        bool hasDirected = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // do the same for when we have sent data...
 | 
					 | 
				
			||||||
        bool hasData = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // remove our callsign from the start of the line...
 | 
					 | 
				
			||||||
        if(line.startsWith(mycall + ":") || line.startsWith(mycall + " ")){
 | 
					 | 
				
			||||||
            line = lstrip(line.mid(mycall.length() + 1));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(line.startsWith(basecall + ":") || line.startsWith(basecall + " ")){
 | 
					 | 
				
			||||||
            line = lstrip(line.mid(basecall.length() + 1));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // remove trailing whitespace as long as there are characters left afterwards
 | 
					 | 
				
			||||||
        auto rline = rstrip(line);
 | 
					 | 
				
			||||||
        if(!rline.isEmpty()){
 | 
					 | 
				
			||||||
            line = rline;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if AUTO_PREPEND_DIRECTED
 | 
					 | 
				
			||||||
        // see if we need to prepend the directed call to the line...
 | 
					 | 
				
			||||||
        // if we have a selected call and the text doesn't start with that call...
 | 
					 | 
				
			||||||
        // and if this isn't a raw message (starting with "<")... then...
 | 
					 | 
				
			||||||
        if(!selectedCall.isEmpty() && !line.startsWith(selectedCall) && !line.startsWith("<")){
 | 
					 | 
				
			||||||
            auto calls = Varicode::parseCallsigns(line);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            bool lineStartsWithBaseCall = (
 | 
					 | 
				
			||||||
                line.startsWith("ALLCALL") ||
 | 
					 | 
				
			||||||
                line.startsWith("BEACON")  ||
 | 
					 | 
				
			||||||
                Varicode::startsWithCQ(line)
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            bool lineStartsWithStandardCall = !calls.isEmpty() && line.startsWith(calls.first());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if(lineStartsWithBaseCall || lineStartsWithStandardCall){
 | 
					 | 
				
			||||||
                // pass
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                // if the message doesn't start with a base call
 | 
					 | 
				
			||||||
                // and if there are no other callsigns in this message
 | 
					 | 
				
			||||||
                // or if the first callsign in the message isn't at the beginning...
 | 
					 | 
				
			||||||
                // then we should be auto-prefixing this line with the selected call
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                line = QString("%1 %2").arg(selectedCall).arg(line);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while(line.size() > 0){
 | 
					 | 
				
			||||||
          QString frame;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          bool useStd = false;
 | 
					 | 
				
			||||||
          bool useBcn = false;
 | 
					 | 
				
			||||||
#if ALLOW_SEND_COMPOUND
 | 
					 | 
				
			||||||
          bool useCmp = false;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
          bool useDir = false;
 | 
					 | 
				
			||||||
          bool useDat = false;
 | 
					 | 
				
			||||||
          bool isFree = false;
 | 
					 | 
				
			||||||
          QString stdFrame = parseFT8Message(line, &isFree);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          int l = 0;
 | 
					 | 
				
			||||||
          QString bcnFrame = Varicode::packBeaconMessage(line, mycall, &l);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if ALLOW_SEND_COMPOUND
 | 
					 | 
				
			||||||
          int o = 0;
 | 
					 | 
				
			||||||
          QString cmpFrame = Varicode::packCompoundMessage(line, &o);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          int n = 0;
 | 
					 | 
				
			||||||
          QString dirCmd;
 | 
					 | 
				
			||||||
          QString dirTo;
 | 
					 | 
				
			||||||
          QString dirNum;
 | 
					 | 
				
			||||||
          QString dirFrame = Varicode::packDirectedMessage(line, basecall, &dirTo, &dirCmd, &dirNum, &n);
 | 
					 | 
				
			||||||
          bool dirToCompound = dirTo.contains("/");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          int m = 0;
 | 
					 | 
				
			||||||
          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)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          // if this parses to a standard FT8 free text message
 | 
					 | 
				
			||||||
          // but it can be parsed as a directed message, then we
 | 
					 | 
				
			||||||
          // should send the directed version. if we've already sent
 | 
					 | 
				
			||||||
          // a directed message or a data frame, we will only follow it
 | 
					 | 
				
			||||||
          // with more data frames.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          if(isFree && !hasDirected && !hasData && l > 0){
 | 
					 | 
				
			||||||
              useBcn = true;
 | 
					 | 
				
			||||||
              hasDirected = false;
 | 
					 | 
				
			||||||
              frame = bcnFrame;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
#if ALLOW_SEND_COMPOUND
 | 
					 | 
				
			||||||
          else if(isFree && !hasDirected && !hasData && o > 0){
 | 
					 | 
				
			||||||
              useCmp = true;
 | 
					 | 
				
			||||||
              hasDirected = false;
 | 
					 | 
				
			||||||
              frame = cmpFrame;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
          else if(isFree && !hasDirected && !hasData && n > 0){
 | 
					 | 
				
			||||||
              useDir = true;
 | 
					 | 
				
			||||||
              hasDirected = true;
 | 
					 | 
				
			||||||
              frame = dirFrame;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          else if ((isFree || hasDirected) && m > 0) {
 | 
					 | 
				
			||||||
              useDat = true;
 | 
					 | 
				
			||||||
              hasData = true;
 | 
					 | 
				
			||||||
              frame = datFrame;
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
              useStd = true;
 | 
					 | 
				
			||||||
              frame = stdFrame;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          if(useStd){
 | 
					 | 
				
			||||||
              if(frame.isEmpty()){
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
              frames.append(frame);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
              if(!line.startsWith(frame)){
 | 
					 | 
				
			||||||
                  line = (
 | 
					 | 
				
			||||||
                    line.left(frame.length()).replace(':', ' ') + // is this the only case where we could have a mismatch?
 | 
					 | 
				
			||||||
                    line.mid(frame.length())
 | 
					 | 
				
			||||||
                  ).trimmed();
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
              line = line.mid(frame.length()).trimmed();
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          if(useBcn){
 | 
					 | 
				
			||||||
              frames.append(frame);
 | 
					 | 
				
			||||||
              line = line.mid(l);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if ALLOW_SEND_COMPOUND
 | 
					 | 
				
			||||||
          if(useCmp){
 | 
					 | 
				
			||||||
              frames.append(frame);
 | 
					 | 
				
			||||||
              line = line.mid(o);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          if(useDir){
 | 
					 | 
				
			||||||
              /**
 | 
					 | 
				
			||||||
               * We have a few special cases when we are sending to a compound call, or our call is a compound call, or both.
 | 
					 | 
				
			||||||
               * CASE 0: Non-compound:       KN4CRD: J1Y ACK
 | 
					 | 
				
			||||||
               * -> One standard directed message frame
 | 
					 | 
				
			||||||
               *
 | 
					 | 
				
			||||||
               * 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>
 | 
					 | 
				
			||||||
               **/
 | 
					 | 
				
			||||||
              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);
 | 
					 | 
				
			||||||
                  QString deCompoundFrame = Varicode::packCompoundMessage(deCompoundMessage, nullptr);
 | 
					 | 
				
			||||||
                  if(!deCompoundFrame.isEmpty()){
 | 
					 | 
				
			||||||
                      frames.append(deCompoundFrame);
 | 
					 | 
				
			||||||
                  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                  // Followed, by a standard OR compound directed message...
 | 
					 | 
				
			||||||
                  QString dirCompoundMessage = QString("<%1%2%3>").arg(dirTo).arg(dirCmd).arg(dirNum);
 | 
					 | 
				
			||||||
                  QString dirCompoundFrame = Varicode::packCompoundMessage(dirCompoundMessage, nullptr);
 | 
					 | 
				
			||||||
                  if(!dirCompoundFrame.isEmpty()){
 | 
					 | 
				
			||||||
                      frames.append(dirCompoundFrame);
 | 
					 | 
				
			||||||
                  }
 | 
					 | 
				
			||||||
                  shouldUseStandardFrame = false;
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
              if(shouldUseStandardFrame) {
 | 
					 | 
				
			||||||
                  // otherwise, just send the standard directed frame
 | 
					 | 
				
			||||||
                  frames.append(frame);
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
              line = line.mid(n);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
              // generate a checksum for buffered commands with line data
 | 
					 | 
				
			||||||
              if(Varicode::isCommandBuffered(dirCmd) && !line.isEmpty()){
 | 
					 | 
				
			||||||
                  qDebug() << "generating checksum for line" << line << line.mid(1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                  // strip leading whitespace after a buffered directed command
 | 
					 | 
				
			||||||
                  line = lstrip(line);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                  qDebug() << "before:" << line;
 | 
					 | 
				
			||||||
                  int checksumSize = Varicode::isCommandChecksumed(dirCmd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                  if(checksumSize == 32){
 | 
					 | 
				
			||||||
                      line = line + " " + Varicode::checksum32(line);
 | 
					 | 
				
			||||||
                  } else if (checksumSize == 16) {
 | 
					 | 
				
			||||||
                      line = line + " " + Varicode::checksum16(line);
 | 
					 | 
				
			||||||
                  } else if (checksumSize == 0) {
 | 
					 | 
				
			||||||
                      // pass
 | 
					 | 
				
			||||||
                  }
 | 
					 | 
				
			||||||
                  qDebug() << "after:" << line;
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
              // APRS:
 | 
					 | 
				
			||||||
              if(dirCmd.trimmed() == "APRS:" && !m_aprsClient->isPasscodeValid()){
 | 
					 | 
				
			||||||
                  MessageBox::warning_message(this, tr ("Please enter a valid APRS passcode in the settings to send an APRS packet."));
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          if(useDat){
 | 
					 | 
				
			||||||
              frames.append(frame);
 | 
					 | 
				
			||||||
              line = line.mid(m);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if 1
 | 
					#if 1
 | 
				
			||||||
    qDebug() << "parsed frames:";
 | 
					    qDebug() << "frames:";
 | 
				
			||||||
    foreach(auto frame, frames){
 | 
					    foreach(auto frame, frames){
 | 
				
			||||||
        auto dt = DecodedText(frame);
 | 
					        auto dt = DecodedText(frame);
 | 
				
			||||||
        qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType());
 | 
					        qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType());
 | 
				
			||||||
@ -6386,60 +6147,6 @@ QStringList MainWindow::buildFT8MessageFrames(QString const& text){
 | 
				
			|||||||
    return frames;
 | 
					    return frames;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
QString MainWindow::parseFT8Message(QString input, bool *isFree){
 | 
					 | 
				
			||||||
  if(isFree) *isFree = true;
 | 
					 | 
				
			||||||
  return input;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
  char message[29];
 | 
					 | 
				
			||||||
  char msgsent[29];
 | 
					 | 
				
			||||||
  char volatile ft8msgbits[75 + 12];
 | 
					 | 
				
			||||||
  int volatile itone[NUM_ISCAT_SYMBOLS];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  QByteArray ba = input.toLocal8Bit();
 | 
					 | 
				
			||||||
  ba2msg(ba,message);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  qint32  i3bit = 0;
 | 
					 | 
				
			||||||
  bool bcontest = false;
 | 
					 | 
				
			||||||
  char MyGrid[6];
 | 
					 | 
				
			||||||
  strncpy(MyGrid, (m_config.my_grid()+"      ").toLatin1(),6);
 | 
					 | 
				
			||||||
  genft8_(message, MyGrid, &bcontest, &i3bit, msgsent, const_cast<char *> (ft8msgbits),
 | 
					 | 
				
			||||||
        const_cast<int *> (itone), 22, 6, 22);
 | 
					 | 
				
			||||||
  msgsent[22]=0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // decode the msg bits into 6-bit bytes so we can check to see if its a free text message or not...
 | 
					 | 
				
			||||||
  // see extractmessage1764.f90 for the original implementation. we could technically add a boolean output
 | 
					 | 
				
			||||||
  // from the fortran code, but this avoids having to modify that so we can easily apply updates to the
 | 
					 | 
				
			||||||
  // signal functions in the future without incurring too much cognitive overhead of merge conflicts.
 | 
					 | 
				
			||||||
  char msgbytes[12];
 | 
					 | 
				
			||||||
  for(int ibyte = 1; ibyte <= 12; ibyte++){
 | 
					 | 
				
			||||||
      int itmp = 0;
 | 
					 | 
				
			||||||
      for(int ibit = 1; ibit <= 6; ibit++){
 | 
					 | 
				
			||||||
          itmp = (itmp << 1) + (1 & (ft8msgbits[((ibyte-1) * 6 + ibit)-1]));
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      msgbytes[ibyte-1] = itmp;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int a = msgbytes[9];
 | 
					 | 
				
			||||||
  int b = msgbytes[10];
 | 
					 | 
				
			||||||
  int c = msgbytes[11];
 | 
					 | 
				
			||||||
  int d = ((a & 15) << 12) + (b << 6) + c;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  QString output = QString::fromLatin1(msgsent);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if(isFree){
 | 
					 | 
				
			||||||
      // TODO: jsherer - lets figure out a better way to detect this for the case:
 | 
					 | 
				
			||||||
      //    KN4CRD 16
 | 
					 | 
				
			||||||
      // this gets encoded as a standard message, but doesn't seem to make sense as to why...
 | 
					 | 
				
			||||||
      // see decodedtext.cpp for the alternate decoding side of this...
 | 
					 | 
				
			||||||
      *isFree = (d >= 32768) || !QRegularExpression("^(CQ|DE|QRZ)\\s").match(output).hasMatch();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return output.trimmed();
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool MainWindow::prepareNextMessageFrame()
 | 
					bool MainWindow::prepareNextMessageFrame()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  m_i3bit = Varicode::FT8Call;
 | 
					  m_i3bit = Varicode::FT8Call;
 | 
				
			||||||
@ -8997,10 +8704,50 @@ void MainWindow::updateButtonDisplay(){
 | 
				
			|||||||
        ui->startTxButton->setText(m_tune ? "Tuning" : QString("Sending (%1/%2)").arg(sent).arg(count));
 | 
					        ui->startTxButton->setText(m_tune ? "Tuning" : QString("Sending (%1/%2)").arg(sent).arg(count));
 | 
				
			||||||
    } else if(m_txTextDirty) {
 | 
					    } else if(m_txTextDirty) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TODO: only if text changed
 | 
					        // TODO: maybe add debounce?
 | 
				
			||||||
 | 
					        if(m_txTextDirtyDebounce.isActive()){
 | 
				
			||||||
 | 
					            m_txTextDirtyDebounce.stop();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        m_txTextDirtyDebounce.start(100);
 | 
				
			||||||
 | 
					        m_txTextDirty = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWindow::buildMessageFramesAndUpdateCountDisplay(){
 | 
				
			||||||
 | 
					    qDebug() << "buildMessageFramesAndUpdateCountDisplay";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto text = ui->extFreeTextMsgEdit->toPlainText();
 | 
					    auto text = ui->extFreeTextMsgEdit->toPlainText();
 | 
				
			||||||
        int count = countFT8MessageFrames(text);
 | 
					
 | 
				
			||||||
 | 
					#if USE_SYNC_FRAME_COUNT
 | 
				
			||||||
 | 
					    int count = countMessageFrames(text);
 | 
				
			||||||
 | 
					    updateFrameCountDisplay(text, count);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    // prepare selected callsign for directed message
 | 
				
			||||||
 | 
					    QString selectedCall = callsignSelected();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // prepare compound
 | 
				
			||||||
 | 
					    bool compound = Radio::is_compound_callsign(m_config.my_callsign());
 | 
				
			||||||
 | 
					    QString mygrid = m_config.my_grid().left(4);
 | 
				
			||||||
 | 
					    QString mycall = m_config.my_callsign();
 | 
				
			||||||
 | 
					    QString basecall = Radio::base_callsign(m_config.my_callsign());
 | 
				
			||||||
 | 
					    if(basecall != mycall){
 | 
				
			||||||
 | 
					        basecall = "<....>";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BuildMessageFramesThread *t = new BuildMessageFramesThread(
 | 
				
			||||||
 | 
					        mycall, basecall, mygrid, compound, selectedCall, text
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    connect(t, &BuildMessageFramesThread::finished, t, &QObject::deleteLater);
 | 
				
			||||||
 | 
					    connect(t, &BuildMessageFramesThread::resultReady, this, [this, text](const QStringList frames){
 | 
				
			||||||
 | 
					        updateFrameCountDisplay(text, frames.length());
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    t->start();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MainWindow::updateFrameCountDisplay(QString text, int count){
 | 
				
			||||||
    if(count > 0){
 | 
					    if(count > 0){
 | 
				
			||||||
        ui->startTxButton->setText(QString("Send (%1)").arg(count));
 | 
					        ui->startTxButton->setText(QString("Send (%1)").arg(count));
 | 
				
			||||||
        ui->startTxButton->setEnabled(true);
 | 
					        ui->startTxButton->setEnabled(true);
 | 
				
			||||||
@ -9009,14 +8756,13 @@ void MainWindow::updateButtonDisplay(){
 | 
				
			|||||||
        auto wpm = QString::number(words/(count/4.0), 'f', 1);
 | 
					        auto wpm = QString::number(words/(count/4.0), 'f', 1);
 | 
				
			||||||
        auto cpm = QString::number(text.length()/(count/4.0), 'f', 0);
 | 
					        auto cpm = QString::number(text.length()/(count/4.0), 'f', 0);
 | 
				
			||||||
        wpm_label.setText(QString("%1wpm / %2cpm").arg(wpm).arg(cpm));
 | 
					        wpm_label.setText(QString("%1wpm / %2cpm").arg(wpm).arg(cpm));
 | 
				
			||||||
 | 
					        wpm_label.setVisible(true);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        ui->startTxButton->setText("Send");
 | 
					        ui->startTxButton->setText("Send");
 | 
				
			||||||
        ui->startTxButton->setEnabled(false);
 | 
					        ui->startTxButton->setEnabled(false);
 | 
				
			||||||
 | 
					        wpm_label.setVisible(false);
 | 
				
			||||||
        wpm_label.clear();
 | 
					        wpm_label.clear();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        m_txTextDirty = false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QString MainWindow::callsignSelected(){
 | 
					QString MainWindow::callsignSelected(){
 | 
				
			||||||
@ -9344,7 +9090,7 @@ void MainWindow::processBufferedActivity() {
 | 
				
			|||||||
        foreach(auto part, buffer.msgs) {
 | 
					        foreach(auto part, buffer.msgs) {
 | 
				
			||||||
            message.append(part.text);
 | 
					            message.append(part.text);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        message = rstrip(message);
 | 
					        message = Varicode::rstrip(message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        QString checksum;
 | 
					        QString checksum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								mainwindow.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								mainwindow.h
									
									
									
									
									
								
							@ -95,6 +95,7 @@ class DecodedText;
 | 
				
			|||||||
using namespace std;
 | 
					using namespace std;
 | 
				
			||||||
typedef std::function<void()> Callback;
 | 
					typedef std::function<void()> Callback;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MainWindow : public QMainWindow
 | 
					class MainWindow : public QMainWindow
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  Q_OBJECT;
 | 
					  Q_OBJECT;
 | 
				
			||||||
@ -294,9 +295,8 @@ 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();
 | 
				
			||||||
  int countFT8MessageFrames(QString const& text);
 | 
					  int countMessageFrames(QString const& text);
 | 
				
			||||||
  QStringList buildFT8MessageFrames(QString const& text);
 | 
					  QStringList buildMessageFrames(QString const& text);
 | 
				
			||||||
  QString parseFT8Message(QString input, bool *isFree);
 | 
					 | 
				
			||||||
  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);
 | 
				
			||||||
@ -383,6 +383,7 @@ private slots:
 | 
				
			|||||||
  void expiry_warning_message ();
 | 
					  void expiry_warning_message ();
 | 
				
			||||||
  void not_GA_warning_message ();
 | 
					  void not_GA_warning_message ();
 | 
				
			||||||
  void clearCallsignSelected();
 | 
					  void clearCallsignSelected();
 | 
				
			||||||
 | 
					  void buildMessageFramesAndUpdateCountDisplay();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo,
 | 
					  Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo,
 | 
				
			||||||
@ -646,7 +647,6 @@ private:
 | 
				
			|||||||
  QTimer splashTimer;
 | 
					  QTimer splashTimer;
 | 
				
			||||||
  QTimer p1Timer;
 | 
					  QTimer p1Timer;
 | 
				
			||||||
  QTimer beaconTimer;
 | 
					  QTimer beaconTimer;
 | 
				
			||||||
  QTimer selectedCallTimer;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  QString m_path;
 | 
					  QString m_path;
 | 
				
			||||||
  QString m_baseCall;
 | 
					  QString m_baseCall;
 | 
				
			||||||
@ -728,6 +728,7 @@ private:
 | 
				
			|||||||
  bool m_rxDirty;
 | 
					  bool m_rxDirty;
 | 
				
			||||||
  bool m_rxDisplayDirty;
 | 
					  bool m_rxDisplayDirty;
 | 
				
			||||||
  int m_txFrameCount;
 | 
					  int m_txFrameCount;
 | 
				
			||||||
 | 
					  QTimer m_txTextDirtyDebounce;
 | 
				
			||||||
  bool m_txTextDirty;
 | 
					  bool m_txTextDirty;
 | 
				
			||||||
  QString m_lastTxMessage;
 | 
					  QString m_lastTxMessage;
 | 
				
			||||||
  QDateTime m_lastTxTime;
 | 
					  QDateTime m_lastTxTime;
 | 
				
			||||||
@ -877,9 +878,11 @@ private:
 | 
				
			|||||||
  void postDecode (bool is_new, QString const& message);
 | 
					  void postDecode (bool is_new, QString const& message);
 | 
				
			||||||
  void displayTransmit();
 | 
					  void displayTransmit();
 | 
				
			||||||
  void updateButtonDisplay();
 | 
					  void updateButtonDisplay();
 | 
				
			||||||
 | 
					  void updateFrameCountDisplay(QString text, int count);
 | 
				
			||||||
  bool isMyCallIncluded(QString const &text);
 | 
					  bool isMyCallIncluded(QString const &text);
 | 
				
			||||||
  bool isAllCallIncluded(QString const &text);
 | 
					  bool isAllCallIncluded(QString const &text);
 | 
				
			||||||
  QString callsignSelected();
 | 
					  QString callsignSelected();
 | 
				
			||||||
 | 
					  void clearCallsignSelected();
 | 
				
			||||||
  bool isRecentOffset(int offset);
 | 
					  bool isRecentOffset(int offset);
 | 
				
			||||||
  void markOffsetRecent(int offset);
 | 
					  void markOffsetRecent(int offset);
 | 
				
			||||||
  bool isDirectedOffset(int offset, bool *pIsAllCall);
 | 
					  bool isDirectedOffset(int offset, bool *pIsAllCall);
 | 
				
			||||||
@ -936,7 +939,6 @@ private:
 | 
				
			|||||||
  void write_transmit_entry (QString const& file_name);
 | 
					  void write_transmit_entry (QString const& file_name);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
extern int killbyname(const char* progName);
 | 
					extern int killbyname(const char* progName);
 | 
				
			||||||
extern void getDev(int* numDevices,char hostAPI_DeviceName[][50],
 | 
					extern void getDev(int* numDevices,char hostAPI_DeviceName[][50],
 | 
				
			||||||
                   int minChan[], int maxChan[],
 | 
					                   int minChan[], int maxChan[],
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										261
									
								
								varicode.cpp
									
									
									
									
									
								
							
							
						
						
									
										261
									
								
								varicode.cpp
									
									
									
									
									
								
							@ -438,6 +438,28 @@ int dbmTomwatts(int dbm){
 | 
				
			|||||||
    return iter.value();
 | 
					    return iter.value();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QString Varicode::rstrip(const QString& str) {
 | 
				
			||||||
 | 
					  int n = str.size() - 1;
 | 
				
			||||||
 | 
					  for (; n >= 0; --n) {
 | 
				
			||||||
 | 
					    if (str.at(n).isSpace()) {
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return str.left(n + 1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return "";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QString Varicode::lstrip(const QString& str) {
 | 
				
			||||||
 | 
					  int len = str.size();
 | 
				
			||||||
 | 
					  for (int n = 0; n < len; n++) {
 | 
				
			||||||
 | 
					      if(str.at(n).isSpace()){
 | 
				
			||||||
 | 
					          continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return str.mid(n);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return "";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * VARICODE
 | 
					 * VARICODE
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@ -1642,3 +1664,242 @@ QString Varicode::unpackDataMessage(const QString &text, quint8 *pType){
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return unpacked;
 | 
					    return unpacked;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: remove the dependence on providing all this data?
 | 
				
			||||||
 | 
					QStringList Varicode::buildMessageFrames(
 | 
				
			||||||
 | 
					    QString const& mycall,
 | 
				
			||||||
 | 
					    QString const& basecall,
 | 
				
			||||||
 | 
					    QString const& mygrid,
 | 
				
			||||||
 | 
					    bool compound,
 | 
				
			||||||
 | 
					    QString const& selectedCall,
 | 
				
			||||||
 | 
					    QString const& text
 | 
				
			||||||
 | 
					){
 | 
				
			||||||
 | 
					    #define ALLOW_SEND_COMPOUND 1
 | 
				
			||||||
 | 
					    #define AUTO_PREPEND_DIRECTED 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QStringList frames;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    foreach(QString line, text.split(QRegExp("[\\r\\n]"), QString::SkipEmptyParts)){
 | 
				
			||||||
 | 
					        // once we find a directed call, data encode the rest of the line.
 | 
				
			||||||
 | 
					        bool hasDirected = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // do the same for when we have sent data...
 | 
				
			||||||
 | 
					        bool hasData = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // remove our callsign from the start of the line...
 | 
				
			||||||
 | 
					        if(line.startsWith(mycall + ":") || line.startsWith(mycall + " ")){
 | 
				
			||||||
 | 
					            line = lstrip(line.mid(mycall.length() + 1));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(line.startsWith(basecall + ":") || line.startsWith(basecall + " ")){
 | 
				
			||||||
 | 
					            line = lstrip(line.mid(basecall.length() + 1));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // remove trailing whitespace as long as there are characters left afterwards
 | 
				
			||||||
 | 
					        auto rline = rstrip(line);
 | 
				
			||||||
 | 
					        if(!rline.isEmpty()){
 | 
				
			||||||
 | 
					            line = rline;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if AUTO_PREPEND_DIRECTED
 | 
				
			||||||
 | 
					        // see if we need to prepend the directed call to the line...
 | 
				
			||||||
 | 
					        // if we have a selected call and the text doesn't start with that call...
 | 
				
			||||||
 | 
					        // and if this isn't a raw message (starting with "<")... then...
 | 
				
			||||||
 | 
					        if(!selectedCall.isEmpty() && !line.startsWith(selectedCall) && !line.startsWith("<")){
 | 
				
			||||||
 | 
					            auto calls = Varicode::parseCallsigns(line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            bool lineStartsWithBaseCall = (
 | 
				
			||||||
 | 
					                line.startsWith("ALLCALL") ||
 | 
				
			||||||
 | 
					                line.startsWith("BEACON")  ||
 | 
				
			||||||
 | 
					                Varicode::startsWithCQ(line)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            bool lineStartsWithStandardCall = !calls.isEmpty() && line.startsWith(calls.first());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(lineStartsWithBaseCall || lineStartsWithStandardCall){
 | 
				
			||||||
 | 
					                // pass
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // if the message doesn't start with a base call
 | 
				
			||||||
 | 
					                // and if there are no other callsigns in this message
 | 
				
			||||||
 | 
					                // or if the first callsign in the message isn't at the beginning...
 | 
				
			||||||
 | 
					                // then we should be auto-prefixing this line with the selected call
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                line = QString("%1 %2").arg(selectedCall).arg(line);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while(line.size() > 0){
 | 
				
			||||||
 | 
					          QString frame;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          bool useBcn = false;
 | 
				
			||||||
 | 
					#if ALLOW_SEND_COMPOUND
 | 
				
			||||||
 | 
					          bool useCmp = false;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					          bool useDir = false;
 | 
				
			||||||
 | 
					          bool useDat = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          int l = 0;
 | 
				
			||||||
 | 
					          QString bcnFrame = Varicode::packBeaconMessage(line, mycall, &l);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if ALLOW_SEND_COMPOUND
 | 
				
			||||||
 | 
					          int o = 0;
 | 
				
			||||||
 | 
					          QString cmpFrame = Varicode::packCompoundMessage(line, &o);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          int n = 0;
 | 
				
			||||||
 | 
					          QString dirCmd;
 | 
				
			||||||
 | 
					          QString dirTo;
 | 
				
			||||||
 | 
					          QString dirNum;
 | 
				
			||||||
 | 
					          QString dirFrame = Varicode::packDirectedMessage(line, basecall, &dirTo, &dirCmd, &dirNum, &n);
 | 
				
			||||||
 | 
					          bool dirToCompound = dirTo.contains("/");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          int m = 0;
 | 
				
			||||||
 | 
					          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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          // if this parses to a standard FT8 free text message
 | 
				
			||||||
 | 
					          // but it can be parsed as a directed message, then we
 | 
				
			||||||
 | 
					          // should send the directed version. if we've already sent
 | 
				
			||||||
 | 
					          // a directed message or a data frame, we will only follow it
 | 
				
			||||||
 | 
					          // with more data frames.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if(!hasDirected && !hasData && l > 0){
 | 
				
			||||||
 | 
					              useBcn = true;
 | 
				
			||||||
 | 
					              hasDirected = false;
 | 
				
			||||||
 | 
					              frame = bcnFrame;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					#if ALLOW_SEND_COMPOUND
 | 
				
			||||||
 | 
					          else if(!hasDirected && !hasData && o > 0){
 | 
				
			||||||
 | 
					              useCmp = true;
 | 
				
			||||||
 | 
					              hasDirected = false;
 | 
				
			||||||
 | 
					              frame = cmpFrame;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					          else if(!hasDirected && !hasData && n > 0){
 | 
				
			||||||
 | 
					              useDir = true;
 | 
				
			||||||
 | 
					              hasDirected = true;
 | 
				
			||||||
 | 
					              frame = dirFrame;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          else if (m > 0) {
 | 
				
			||||||
 | 
					              useDat = true;
 | 
				
			||||||
 | 
					              hasData = true;
 | 
				
			||||||
 | 
					              frame = datFrame;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if(useBcn){
 | 
				
			||||||
 | 
					              frames.append(frame);
 | 
				
			||||||
 | 
					              line = line.mid(l);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if ALLOW_SEND_COMPOUND
 | 
				
			||||||
 | 
					          if(useCmp){
 | 
				
			||||||
 | 
					              frames.append(frame);
 | 
				
			||||||
 | 
					              line = line.mid(o);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if(useDir){
 | 
				
			||||||
 | 
					              /**
 | 
				
			||||||
 | 
					               * We have a few special cases when we are sending to a compound call, or our call is a compound call, or both.
 | 
				
			||||||
 | 
					               * CASE 0: Non-compound:       KN4CRD: J1Y ACK
 | 
				
			||||||
 | 
					               * -> One standard directed message frame
 | 
				
			||||||
 | 
					               *
 | 
				
			||||||
 | 
					               * 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>
 | 
				
			||||||
 | 
					               **/
 | 
				
			||||||
 | 
					              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);
 | 
				
			||||||
 | 
					                  QString deCompoundFrame = Varicode::packCompoundMessage(deCompoundMessage, nullptr);
 | 
				
			||||||
 | 
					                  if(!deCompoundFrame.isEmpty()){
 | 
				
			||||||
 | 
					                      frames.append(deCompoundFrame);
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  // Followed, by a standard OR compound directed message...
 | 
				
			||||||
 | 
					                  QString dirCompoundMessage = QString("<%1%2%3>").arg(dirTo).arg(dirCmd).arg(dirNum);
 | 
				
			||||||
 | 
					                  QString dirCompoundFrame = Varicode::packCompoundMessage(dirCompoundMessage, nullptr);
 | 
				
			||||||
 | 
					                  if(!dirCompoundFrame.isEmpty()){
 | 
				
			||||||
 | 
					                      frames.append(dirCompoundFrame);
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  shouldUseStandardFrame = false;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              if(shouldUseStandardFrame) {
 | 
				
			||||||
 | 
					                  // otherwise, just send the standard directed frame
 | 
				
			||||||
 | 
					                  frames.append(frame);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              line = line.mid(n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              // generate a checksum for buffered commands with line data
 | 
				
			||||||
 | 
					              if(Varicode::isCommandBuffered(dirCmd) && !line.isEmpty()){
 | 
				
			||||||
 | 
					                  qDebug() << "generating checksum for line" << line << line.mid(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  // strip leading whitespace after a buffered directed command
 | 
				
			||||||
 | 
					                  line = lstrip(line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  qDebug() << "before:" << line;
 | 
				
			||||||
 | 
					                  int checksumSize = Varicode::isCommandChecksumed(dirCmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  if(checksumSize == 32){
 | 
				
			||||||
 | 
					                      line = line + " " + Varicode::checksum32(line);
 | 
				
			||||||
 | 
					                  } else if (checksumSize == 16) {
 | 
				
			||||||
 | 
					                      line = line + " " + Varicode::checksum16(line);
 | 
				
			||||||
 | 
					                  } else if (checksumSize == 0) {
 | 
				
			||||||
 | 
					                      // pass
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  qDebug() << "after:" << line;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					              // APRS:
 | 
				
			||||||
 | 
					              if(dirCmd.trimmed() == "APRS:" && !m_aprsClient->isPasscodeValid()){
 | 
				
			||||||
 | 
					                  MessageBox::warning_message(this, tr ("Please enter a valid APRS passcode in the settings to send an APRS packet."));
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if(useDat){
 | 
				
			||||||
 | 
					              frames.append(frame);
 | 
				
			||||||
 | 
					              line = line.mid(m);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return frames;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BuildMessageFramesThread::BuildMessageFramesThread(const QString &mycall, const QString &basecall, const QString &mygrid, bool compound, const QString &selectedCall, const QString &text, QObject *parent):
 | 
				
			||||||
 | 
					    QThread(parent),
 | 
				
			||||||
 | 
					    m_mycall{mycall},
 | 
				
			||||||
 | 
					    m_basecall{basecall},
 | 
				
			||||||
 | 
					    m_mygrid{mygrid},
 | 
				
			||||||
 | 
					    m_compound{compound},
 | 
				
			||||||
 | 
					    m_selectedCall{selectedCall},
 | 
				
			||||||
 | 
					    m_text{text}
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BuildMessageFramesThread::run(){
 | 
				
			||||||
 | 
					    auto results = Varicode::buildMessageFrames(
 | 
				
			||||||
 | 
					        m_mycall,
 | 
				
			||||||
 | 
					        m_basecall,
 | 
				
			||||||
 | 
					        m_mygrid,
 | 
				
			||||||
 | 
					        m_compound,
 | 
				
			||||||
 | 
					        m_selectedCall,
 | 
				
			||||||
 | 
					        m_text
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    emit resultReady(results);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										38
									
								
								varicode.h
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								varicode.h
									
									
									
									
									
								
							@ -10,6 +10,7 @@
 | 
				
			|||||||
#include <QRegExp>
 | 
					#include <QRegExp>
 | 
				
			||||||
#include <QString>
 | 
					#include <QString>
 | 
				
			||||||
#include <QVector>
 | 
					#include <QVector>
 | 
				
			||||||
 | 
					#include <QThread>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Varicode
 | 
					class Varicode
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -56,6 +57,9 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    //Varicode();
 | 
					    //Varicode();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static QString rstrip(const QString& str);
 | 
				
			||||||
 | 
					    static QString lstrip(const QString& str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static QMap<QString, QString> defaultHuffTable();
 | 
					    static QMap<QString, QString> defaultHuffTable();
 | 
				
			||||||
    static QMap<QString, QString> defaultHuffTableEscaped();
 | 
					    static QMap<QString, QString> defaultHuffTableEscaped();
 | 
				
			||||||
    static QString cqString(int number);
 | 
					    static QString cqString(int number);
 | 
				
			||||||
@ -142,6 +146,40 @@ 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(
 | 
				
			||||||
 | 
					        QString const& mycall,
 | 
				
			||||||
 | 
					        QString const& basecall,
 | 
				
			||||||
 | 
					        QString const& mygrid,
 | 
				
			||||||
 | 
					        bool compound,
 | 
				
			||||||
 | 
					        QString const& selectedCall,
 | 
				
			||||||
 | 
					        QString const& text
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BuildMessageFramesThread : public QThread
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Q_OBJECT
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    BuildMessageFramesThread(QString const& mycall,
 | 
				
			||||||
 | 
					                             QString const& basecall,
 | 
				
			||||||
 | 
					                             QString const& mygrid,
 | 
				
			||||||
 | 
					                             bool compound,
 | 
				
			||||||
 | 
					                             QString const& selectedCall,
 | 
				
			||||||
 | 
					                             QString const& text,
 | 
				
			||||||
 | 
					                             QObject *parent=nullptr);
 | 
				
			||||||
 | 
					    void run() override;
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
					    void resultReady(const QStringList s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    QString m_mycall;
 | 
				
			||||||
 | 
					    QString m_basecall;
 | 
				
			||||||
 | 
					    QString m_mygrid;
 | 
				
			||||||
 | 
					    bool m_compound;
 | 
				
			||||||
 | 
					    QString m_selectedCall;
 | 
				
			||||||
 | 
					    QString m_text;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // VARICODE_H
 | 
					#endif // VARICODE_H
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user