/** \file * @brief member function of the UI_Constructor class * process Rx queue activity */ #include "JS8_UI/mainwindow.h" void UI_Constructor::processRxActivity() { if (m_rxActivityQueue.isEmpty()) { return; } int freqOffset = freq(); qCDebug(mainwindow_js8) << m_messageBuffer.count() << "message buffers open"; while (!m_rxActivityQueue.isEmpty()) { ActivityDetail d = m_rxActivityQueue.dequeue(); if (canSendNetworkMessage()) { sendNetworkMessage( "RX.ACTIVITY", d.text, {{"_ID", QVariant(-1)}, {"FREQ", QVariant(d.dial + d.offset)}, {"DIAL", QVariant(d.dial)}, {"OFFSET", QVariant(d.offset)}, {"SNR", QVariant(d.snr)}, {"SPEED", QVariant(d.submode)}, {"TDRIFT", QVariant(d.tdrift)}, {"UTC", QVariant(d.utcTimestamp.toMSecsSinceEpoch())}, {"BITS", QVariant(d.bits)}}); } // use the actual frequency and check its delta from our current // frequency meaning, if our current offset is 1502 and the d.freq is // 1492, the delta is <= 10; bool shouldDisplay = abs(d.offset - freqOffset) <= JS8::Submode::rxThreshold(d.submode); int prevOffset = d.offset; if (hasExistingMessageBuffer(d.submode, d.offset, false, &prevOffset) && ((m_messageBuffer[prevOffset].cmd.to == m_config.my_callsign()) || // (isAllCallIncluded(m_messageBuffer[prevOffset].cmd.to)) || // // uncomment this if we want to incrementally print allcalls (isGroupCallIncluded(m_messageBuffer[prevOffset].cmd.to)))) { d.isBuffered = true; shouldDisplay = true; if (!m_messageBuffer[prevOffset].compound.isEmpty()) { // qCDebug(mainwindow_js8) << "should display compound too // because at this point it hasn't been displayed" << // m_messageBuffer[prevOffset].compound.last().call; auto lastCompound = m_messageBuffer[prevOffset].compound.last(); // fixup compound call incremental text d.text = QString("%1: %2").arg(lastCompound.call).arg(d.text); d.utcTimestamp = qMin(d.utcTimestamp, lastCompound.utcTimestamp); } } else if (hasClosedExistingMessageBuffer(d.offset)) { // incremental typeahead should just be displayed... // TODO: should the buffer be reopened? shouldDisplay = true; } else if (d.isDirected && d.text.contains("<....>")) { // if this is a _partial_ directed message, skip until the complete // call comes through. continue; } else if (d.isDirected && (d.text.contains(": HB ") || d.text.contains(": @ALLCALL HB"))) { // TODO: HEARTBEAT // if this is a heartbeat, process elsewhere... continue; } // if this is the first data frame of a standard message, parse the // first word callsigns and spot them :) if ((d.bits & Varicode::JS8CallFirst) == Varicode::JS8CallFirst && !d.isDirected && !d.isCompound) { auto calls = Varicode::parseCallsigns(d.text); if (!calls.isEmpty()) { auto theirCall = calls.first(); if (d.text.startsWith(theirCall) && d.text.mid(theirCall.length(), 1) == ":") { CallDetail cd = {}; cd.call = theirCall; cd.dial = d.dial; cd.offset = d.offset; cd.snr = d.snr; cd.bits = d.bits; cd.tdrift = d.tdrift; cd.utcTimestamp = d.utcTimestamp; cd.submode = d.submode; logCallActivity(cd, true); } } } // TODO: incremental printing of directed messages // Display if: // 1) this is a directed message header "to" us and should be // buffered... 2) or, this is a buffered message frame for a buffer with // us as the recipient. if (!shouldDisplay) { continue; } bool isFirst = (d.bits & Varicode::JS8CallFirst) == Varicode::JS8CallFirst; bool isLast = (d.bits & Varicode::JS8CallLast) == Varicode::JS8CallLast; // if we're the last message, let's display our EOT character if (isLast) { d.text = QString("%1 %2 ") .arg(Varicode::rstrip(d.text)) .arg(m_config.eot()); } // log it to the display! displayTextForFreq(d.text, d.offset, d.utcTimestamp, false, isFirst, isLast); // If we've received a message to be displayed, we should no longer call // CQ. if (m_cq_loop->isActive()) { qCDebug(mainwindow_js8) << "Canceling calling CQ loop to priorize incoming messages."; m_cq_loop->onLoopCancel(); } if (isLast) { clearOffsetDirected(d.offset); } if (isLast && !d.isBuffered) { // buffered commands need the rxFrameBlockNumbers cache so it can // fixup its display all other "last" data frames can clear the // rxFrameBlockNumbers cache so the next message will be on a new // line. m_rxFrameBlockNumbers.remove(d.offset); } } #if 0 // TODO: this works but should also print in the rx window. foreach(auto offset, m_bandActivity.keys()){ if(seen.contains(offset)){ continue; } if(m_bandActivity[offset].isEmpty()){ continue; } auto last = m_bandActivity[offset].last(); if((last.bits & Varicode::JS8CallLast) == Varicode::JS8CallLast){ continue; } auto now = DriftingDateTime::currentDateTimeUtc(); if(last.utcTimestamp.secsTo(now) < m_TRperiod){ continue; } ActivityDetail d = {}; d.text = " . . . "; d.utcTimestamp = now; d.snr = -99; m_bandActivity[offset].append(d); } #endif }