diff --git a/lib/js8/js8b_params.f90 b/lib/js8/js8b_params.f90 index 1adbabb..1377fd3 100644 --- a/lib/js8/js8b_params.f90 +++ b/lib/js8/js8b_params.f90 @@ -19,7 +19,7 @@ ! parameter (NSPS=1920, NTXDUR=15, NDOWNSPS=32, NDD=100, JZ=116) ! 50 Hz 6.250 baud 16 wpm -25.0dB (1.0Eb/N0) 12.64s ! parameter (NSPS=4000, NTXDUR=30, NDOWNSPS=20, NDD=90, JZ=62) ! 24 Hz 3 baud 8 wpm -28.2dB (1.0Eb/N0) 26.33s -parameter (AZ=12000.0/(1.0*NSPS)*0.64d0) !Dedupe overlap in Hz +parameter (AZ=12000.0/(1.0*NSPS)*0.8d0) !Dedupe overlap in Hz parameter (ASTART=0.2) !Start delay in seconds parameter (ASYNCMIN=1.5) !Minimum Sync diff --git a/lib/js8/js8c_params.f90 b/lib/js8/js8c_params.f90 index caba06e..ae7ba98 100644 --- a/lib/js8/js8c_params.f90 +++ b/lib/js8/js8c_params.f90 @@ -19,7 +19,7 @@ ! parameter (NSPS=1920, NTXDUR=15, NDOWNSPS=32, NDD=100, JZ=116) ! 50 Hz 6.250 baud 16 wpm -25.0dB (1.0Eb/N0) 12.64s ! parameter (NSPS=4000, NTXDUR=30, NDOWNSPS=20, NDD=90, JZ=62) ! 24 Hz 3 baud 8 wpm -28.2dB (1.0Eb/N0) 26.33s -parameter (AZ=12000.0/(1.0*NSPS)*0.64d0) !Dedupe overlap in Hz +parameter (AZ=12000.0/(1.0*NSPS)*0.8d0) !Dedupe overlap in Hz parameter (ASTART=0.1) !Start delay in seconds parameter (ASYNCMIN=1.5) !Minimum Sync diff --git a/lib/js8/js8d_params.f90 b/lib/js8/js8d_params.f90 index 664e9c1..4711b9d 100644 --- a/lib/js8/js8d_params.f90 +++ b/lib/js8/js8d_params.f90 @@ -19,7 +19,7 @@ ! parameter (NSPS=1920, NTXDUR=15, NDOWNSPS=32, NDD=100, JZ=116) ! 50 Hz 6.250 baud 16 wpm -25.0dB (1.0Eb/N0) 12.64s ! parameter (NSPS=4000, NTXDUR=30, NDOWNSPS=40, NDD=90, JZ=116) ! 24 Hz 3 baud 8 wpm -28.2dB (1.0Eb/N0) 26.33s -parameter (AZ=12000.0/(1.0*NSPS)*0.64d0) !Dedupe overlap in Hz +parameter (AZ=12000.0/(1.0*NSPS)*0.8d0) !Dedupe overlap in Hz parameter (ASTART=0.1) !Start delay in seconds parameter (ASYNCMIN=1.5) !Minimum Sync diff --git a/lib/js8/syncjs8.f90 b/lib/js8/syncjs8.f90 index f4008bd..1635fa2 100644 --- a/lib/js8/syncjs8.f90 +++ b/lib/js8/syncjs8.f90 @@ -145,9 +145,13 @@ subroutine syncjs8(dd,nfa,nfb,syncmin,nfqso,s,candidate,ncand,sbase) enddo ncand=k -! Put nfqso at top of list, and save only the best of near-dupe freqs. +! Put nfqso at top of list do i=1,ncand if(abs(candidate0(1,i)-nfqso).lt.10.0) candidate0(1,i)=-candidate0(1,i) + enddo + +! Save only the best of near-dupe freqs. + do i=1,ncand if(i.ge.2) then do j=1,i-1 fdiff=abs(candidate0(1,i))-abs(candidate0(1,j)) diff --git a/mainwindow.cpp b/mainwindow.cpp index 6a755e4..54b65cd 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -4163,23 +4163,25 @@ QList generateOffsets(int minOffset, int maxOffset){ void MainWindow::readFromStdout() //readFromStdout { while(proc_js8.canReadLine()) { - QByteArray t=proc_js8.readLine(); - qDebug() << "JS8: " << QString(t); - bool bAvgMsg=false; - int navg=0; - if(t.indexOf("") >= 0) { - if(m_mode=="QRA64") m_wideGraph->drawRed(0,0); - m_bDecoded = t.mid(20).trimmed().toInt() > 0; - int mswait=3*1000*m_TRperiod/4; - if(!m_diskData) killFileTimer.start(mswait); //Kill in 3/4 period - decodeDone (); - m_startAnother=m_loopall; - if(m_bNoMoreFiles) { - MessageBox::information_message(this, tr("No more files to open.")); - m_bNoMoreFiles=false; + QByteArray t=proc_js8.readLine(); + qDebug() << "JS8: " << QString(t); + bool bAvgMsg=false; + int navg=0; + if(t.indexOf("") >= 0) { + if(m_mode=="QRA64") m_wideGraph->drawRed(0,0); + m_bDecoded = t.mid(20).trimmed().toInt() > 0; + int mswait=3*1000*m_TRperiod/4; + if(!m_diskData) killFileTimer.start(mswait); //Kill in 3/4 period + decodeDone (); + m_startAnother=m_loopall; + if(m_bNoMoreFiles) { + MessageBox::information_message(this, tr("No more files to open.")); + m_bNoMoreFiles=false; + } + m_messageDupeCache.clear(); + return; } - return; - } else { + if(m_mode=="JT4" or m_mode=="JT65" or m_mode=="QRA64" or m_mode=="FT8") { int n=t.indexOf("f"); if(n<0) n=t.indexOf("d"); @@ -4219,330 +4221,288 @@ void MainWindow::readFromStdout() //readFromStdout bool bValidFrame = decodedtext.snr() > -24; + // dupe check + auto frame = decodedtext.message(); + auto frameOffset = decodedtext.frequencyOffset(); + if(m_messageDupeCache.contains(frame)){ + // check to see if the frequency is near our previous frame + auto cachedFreq = m_messageDupeCache.value(frame, 0); + if(qAbs(cachedFreq - frameOffset) <= NEAR_THRESHOLD_RX){ + qDebug() << "duplicate frame from" << cachedFreq << "and" << frameOffset; + bValidFrame = false; + } + } else { + // cache for this decode cycle + m_messageDupeCache[frame] = frameOffset; + } + qDebug() << "valid" << bValidFrame << "decoded text" << decodedtext.message(); + // skip if invalid + if(!bValidFrame) { + continue; + } + ActivityDetail d = {}; CallDetail cd = {}; CommandDetail cmd = {}; CallDetail td = {}; - - //Left (Band activity) window - if(bValidFrame) { - // Parse General Activity + // Parse General Activity #if 1 - bool shouldParseGeneralActivity = true; - if(shouldParseGeneralActivity && !decodedtext.messageWords().isEmpty()){ - int offset = decodedtext.frequencyOffset(); + bool shouldParseGeneralActivity = true; + if(shouldParseGeneralActivity && !decodedtext.messageWords().isEmpty()){ + int offset = decodedtext.frequencyOffset(); - if(!m_bandActivity.contains(offset)){ - int range = 10; - if(m_nSubMode == Varicode::JS8CallFast){ range = 16; } - if(m_nSubMode == Varicode::JS8CallTurbo){ range = 32; } + if(!m_bandActivity.contains(offset)){ + int range = 10; + if(m_nSubMode == Varicode::JS8CallFast){ range = 16; } + if(m_nSubMode == Varicode::JS8CallTurbo){ range = 32; } - QList offsets = generateOffsets(offset-range, offset+range); + QList offsets = generateOffsets(offset-range, offset+range); - foreach(int prevOffset, offsets){ - if(!m_bandActivity.contains(prevOffset)){ continue; } - m_bandActivity[offset] = m_bandActivity[prevOffset]; - m_bandActivity.remove(prevOffset); - break; - } + foreach(int prevOffset, offsets){ + if(!m_bandActivity.contains(prevOffset)){ continue; } + m_bandActivity[offset] = m_bandActivity[prevOffset]; + m_bandActivity.remove(prevOffset); + break; } + } - //ActivityDetail d = {}; - d.isLowConfidence = decodedtext.isLowConfidence(); - d.isFree = !decodedtext.isStandardMessage(); - d.isCompound = decodedtext.isCompound(); - d.isDirected = decodedtext.isDirectedMessage(); - d.bits = decodedtext.bits(); - d.freq = offset; - d.text = decodedtext.message(); - d.utcTimestamp = DriftingDateTime::currentDateTimeUtc(); - d.snr = decodedtext.snr(); - d.isBuffered = false; - d.tdrift = decodedtext.dt(); - d.mode = currentMode(); + //ActivityDetail d = {}; + d.isLowConfidence = decodedtext.isLowConfidence(); + d.isFree = !decodedtext.isStandardMessage(); + d.isCompound = decodedtext.isCompound(); + d.isDirected = decodedtext.isDirectedMessage(); + d.bits = decodedtext.bits(); + d.freq = offset; + d.text = decodedtext.message(); + d.utcTimestamp = DriftingDateTime::currentDateTimeUtc(); + d.snr = decodedtext.snr(); + d.isBuffered = false; + d.tdrift = decodedtext.dt(); + d.mode = currentMode(); - // if we have any "first" frame, and a buffer is already established, clear it... - int prevBufferOffset = -1; - if(((d.bits & Varicode::JS8CallFirst) == Varicode::JS8CallFirst) && hasExistingMessageBuffer(d.freq, true, &prevBufferOffset)){ - qDebug() << "first message encountered, clearing existing buffer" << prevBufferOffset; - m_messageBuffer.remove(d.freq); - } + // if we have any "first" frame, and a buffer is already established, clear it... + int prevBufferOffset = -1; + if(((d.bits & Varicode::JS8CallFirst) == Varicode::JS8CallFirst) && hasExistingMessageBuffer(d.freq, true, &prevBufferOffset)){ + qDebug() << "first message encountered, clearing existing buffer" << prevBufferOffset; + m_messageBuffer.remove(d.freq); + } - // if we have a data frame, and a message buffer has been established, buffer it... - if(hasExistingMessageBuffer(d.freq, true, &prevBufferOffset) && !decodedtext.isCompound() && !decodedtext.isDirectedMessage()){ - qDebug() << "buffering data" << d.freq << d.text; - d.isBuffered = true; - m_messageBuffer[d.freq].msgs.append(d); - // TODO: incremental display if it's "to" me. - } + // if we have a data frame, and a message buffer has been established, buffer it... + if(hasExistingMessageBuffer(d.freq, true, &prevBufferOffset) && !decodedtext.isCompound() && !decodedtext.isDirectedMessage()){ + qDebug() << "buffering data" << d.freq << d.text; + d.isBuffered = true; + m_messageBuffer[d.freq].msgs.append(d); + // TODO: incremental display if it's "to" me. + } - m_rxActivityQueue.append(d); - m_bandActivity[offset].append(d); - while(m_bandActivity[offset].count() > 10){ - m_bandActivity[offset].removeFirst(); - } - } + m_rxActivityQueue.append(d); + m_bandActivity[offset].append(d); + while(m_bandActivity[offset].count() > 10){ + m_bandActivity[offset].removeFirst(); + } + } #endif - // Process compound callsign commands (put them in cache)" + // Process compound callsign commands (put them in cache)" #if 1 - qDebug() << "decoded" << decodedtext.frameType() << decodedtext.isCompound() << decodedtext.isDirectedMessage() << decodedtext.isHeartbeat(); - bool shouldProcessCompound = true; - if(shouldProcessCompound && decodedtext.isCompound() && !decodedtext.isDirectedMessage()){ - cd.call = decodedtext.compoundCall(); - cd.grid = decodedtext.extra(); // compound calls via pings may contain grid... - cd.snr = decodedtext.snr(); - cd.freq = decodedtext.frequencyOffset(); - cd.utcTimestamp = DriftingDateTime::currentDateTimeUtc(); - cd.bits = decodedtext.bits(); - cd.tdrift = decodedtext.dt(); - cd.mode = currentMode(); + qDebug() << "decoded" << decodedtext.frameType() << decodedtext.isCompound() << decodedtext.isDirectedMessage() << decodedtext.isHeartbeat(); + bool shouldProcessCompound = true; + if(shouldProcessCompound && decodedtext.isCompound() && !decodedtext.isDirectedMessage()){ + cd.call = decodedtext.compoundCall(); + cd.grid = decodedtext.extra(); // compound calls via pings may contain grid... + cd.snr = decodedtext.snr(); + cd.freq = decodedtext.frequencyOffset(); + cd.utcTimestamp = DriftingDateTime::currentDateTimeUtc(); + cd.bits = decodedtext.bits(); + cd.tdrift = decodedtext.dt(); + cd.mode = currentMode(); - // Only respond to HEARTBEATS...remember that CQ messages are "Alt" pings - if(decodedtext.isHeartbeat()){ - if(decodedtext.isAlt()){ - // this is a cq with a standard or compound call, ala "KN4CRD/P: CQCQCQ" - cd.cqTimestamp = DriftingDateTime::currentDateTimeUtc(); + // Only respond to HEARTBEATS...remember that CQ messages are "Alt" pings + if(decodedtext.isHeartbeat()){ + if(decodedtext.isAlt()){ + // this is a cq with a standard or compound call, ala "KN4CRD/P: CQCQCQ" + cd.cqTimestamp = DriftingDateTime::currentDateTimeUtc(); - // it is not processed elsewhere, so we need to just log it here. - logCallActivity(cd, true); + // it is not processed elsewhere, so we need to just log it here. + logCallActivity(cd, true); - // notification for cq - tryNotify("cq"); - - } else { - // convert HEARTBEAT to a directed command and process... - cmd.from = cd.call; - cmd.to = "@ALLCALL"; - cmd.cmd = " HB"; - cmd.snr = cd.snr; - cmd.bits = cd.bits; - cmd.grid = cd.grid; - cmd.freq = cd.freq; - cmd.utcTimestamp = cd.utcTimestamp; - cmd.tdrift = cd.tdrift; - cmd.mode = cd.mode; - m_rxCommandQueue.append(cmd); - - // notification for hb - tryNotify("hb"); - } + // notification for cq + tryNotify("cq"); } else { - qDebug() << "buffering compound call" << cd.freq << cd.call << cd.bits; - - hasExistingMessageBuffer(cd.freq, true, nullptr); - m_messageBuffer[cd.freq].compound.append(cd); - } - } -#endif - - // Parse commands - // KN4CRD K1JT ? -#if 1 - bool shouldProcessDirected = true; - if(shouldProcessDirected && decodedtext.isDirectedMessage()){ - auto parts = decodedtext.directedMessage(); - - cmd.from = parts.at(0); - cmd.to = parts.at(1); - cmd.cmd = parts.at(2); - cmd.freq = decodedtext.frequencyOffset(); - cmd.snr = decodedtext.snr(); - cmd.utcTimestamp = DriftingDateTime::currentDateTimeUtc(); - cmd.bits = decodedtext.bits(); - cmd.extra = parts.length() > 2 ? parts.mid(3).join(" ") : ""; - cmd.tdrift = decodedtext.dt(); - cmd.mode = currentMode(); - - // if the command is a buffered command and its not the last frame OR we have from or to in a separate message (compound call) - if((Varicode::isCommandBuffered(cmd.cmd) && (cmd.bits & Varicode::JS8CallLast) != Varicode::JS8CallLast) || cmd.from == "<....>" || cmd.to == "<....>"){ - qDebug() << "buffering cmd" << cmd.freq << cmd.cmd << cmd.from << cmd.to; - - // log complete buffered callsigns immediately - if(cmd.from != "<....>" && cmd.to != "<....>"){ - CallDetail cmdcd = {}; - cmdcd.call = cmd.from; - cmdcd.bits = cmd.bits; - cmdcd.snr = cmd.snr; - cmdcd.freq = cmd.freq; - cmdcd.utcTimestamp = cmd.utcTimestamp; - cmdcd.ackTimestamp = cmd.to == m_config.my_callsign() ? cmd.utcTimestamp : QDateTime{}; - cmdcd.tdrift = cmd.tdrift; - cmdcd.mode = currentMode(); - logCallActivity(cmdcd, false); - logHeardGraph(cmd.from, cmd.to); - } - - // merge any existing buffer to this frequency - hasExistingMessageBuffer(cmd.freq, true, nullptr); - - if(cmd.to == m_config.my_callsign()){ - d.shouldDisplay = true; - } - - m_messageBuffer[cmd.freq].cmd = cmd; - m_messageBuffer[cmd.freq].msgs.clear(); - } else { + // convert HEARTBEAT to a directed command and process... + cmd.from = cd.call; + cmd.to = "@ALLCALL"; + cmd.cmd = " HB"; + cmd.snr = cd.snr; + cmd.bits = cd.bits; + cmd.grid = cd.grid; + cmd.freq = cd.freq; + cmd.utcTimestamp = cd.utcTimestamp; + cmd.tdrift = cd.tdrift; + cmd.mode = cd.mode; m_rxCommandQueue.append(cmd); - } - // check to see if this is a station we've heard 3rd party - bool shouldCaptureThirdPartyCallsigns = false; - if(shouldCaptureThirdPartyCallsigns && Radio::base_callsign(cmd.to) != Radio::base_callsign(m_config.my_callsign())){ - QString relayCall = QString("%1|%2").arg(Radio::base_callsign(cmd.from)).arg(Radio::base_callsign(cmd.to)); - int snr = -100; - if(parts.length() == 4){ - snr = QString(parts.at(3)).toInt(); - } - - //CallDetail td = {}; - td.through = cmd.from; - td.call = cmd.to; - td.grid = ""; - td.snr = snr; - td.freq = cmd.freq; - td.utcTimestamp = cmd.utcTimestamp; - td.tdrift = cmd.tdrift; - td.mode = currentMode(); - logCallActivity(td, true); - logHeardGraph(cmd.from, cmd.to); - } - } -#endif - - - - - // Parse CQs -#if 0 - bool shouldParseCQs = true; - if(shouldParseCQs && decodedtext.isStandardMessage()){ - QString theircall; - QString theirgrid; - decodedtext.deCallAndGrid(theircall, theirgrid); - - QStringList calls = Varicode::parseCallsigns(theircall); - if(!calls.isEmpty() && !calls.first().isEmpty()){ - theircall = calls.first(); - - CallDetail d = {}; - d.bits = decodedtext.bits(); - d.call = theircall; - d.grid = theirgrid; - d.snr = decodedtext.snr(); - d.freq = decodedtext.frequencyOffset(); - d.utcTimestamp = DriftingDateTime::currentDateTimeUtc(); - m_callActivity[d.call] = d; - } - } -#endif - - // Parse standard message callsigns - // K1JT KN4CRD EM73 - // KN4CRD K1JT -21 - // K1JT KN4CRD R-12 - // DE KN4CRD - // KN4CRD -#if 0 - bool shouldParseCallsigns = false; - if(shouldParseCallsigns){ - QStringList callsigns = Varicode::parseCallsigns(decodedtext.message()); - if(!callsigns.isEmpty()){ - // one callsign - // de [from] - // cq [from] - - // two callsigns - // [from]: [to] ... - // [to] [from] [grid|signal] - - QStringList grids = Varicode::parseGrids(decodedtext.message()); - - // one callsigns are handled above... so we only need to handle two callsigns if it's a standard message - if(decodedtext.isStandardMessage()){ - if(callsigns.length() == 2){ - auto de_callsign = callsigns.last(); - - // TODO: jsherer - put this in a function to record a callsign... - CallDetail d; - d.call = de_callsign; - d.grid = !grids.empty() ? grids.first() : ""; - d.snr = decodedtext.snr(); - d.freq = decodedtext.frequencyOffset(); - d.utcTimestamp = DriftingDateTime::currentDateTimeUtc(); - m_callActivity[Radio::base_callsign(de_callsign)] = d; - } - } - } - } -#endif - } - -#if 0 - //Right (Rx Frequency) window - bool bDisplayRight=bAvgMsg; - int audioFreq=decodedtext.frequencyOffset(); - - if(abs(audioFreq - m_wideGraph->rxFreq()) <= 10){ - bDisplayRight=true; - } - - if (bDisplayRight) { - // This msg is within 10 hertz of our tuned frequency, or a JT4 or JT65 avg, - // or contains MyCall - ui->decodedTextBrowser2->displayDecodedText(decodedtext,m_baseCall,false, - m_logBook,m_config.color_CQ(),m_config.color_MyCall(), - m_config.color_DXCC(),m_config.color_NewCall(),m_config.ppfx()); - - if(m_mode!="JT4") { - bool b65=decodedtext.isJT65(); - if(b65 and m_modeTx!="JT65") on_pbTxMode_clicked(); - if(!b65 and m_modeTx=="JT65") on_pbTxMode_clicked(); - } - m_QSOText = decodedtext.string ().trimmed (); - } - - if(m_mode!="FT8" or !m_config.bHound()) { - postDecode (true, decodedtext.string ()); - - // find and extract any report for myCall, but save in m_rptRcvd only if it's from DXcall - QString rpt; - bool stdMsg = decodedtext.report(m_baseCall, - Radio::base_callsign(ui->dxCallEntry->text()), rpt); - QString deCall; - QString grid; - decodedtext.deCallAndGrid(/*out*/deCall,grid); - { - QString t=Radio::base_callsign(ui->dxCallEntry->text()); - if((t==deCall or t=="") and rpt!="") m_rptRcvd=rpt; - } - // extract details and send to PSKreporter - int nsec=DriftingDateTime::currentMSecsSinceEpoch()/1000-m_secBandChanged; - bool okToPost=(nsec>(4*m_TRperiod)/5); - - //if (stdMsg && okToPost) pskPost(decodedtext); - - if((m_mode=="JT4" or m_mode=="JT65" or m_mode=="QRA64") and m_msgAvgWidget!=NULL) { - if(m_msgAvgWidget->isVisible()) { - QFile f(m_config.temp_dir ().absoluteFilePath ("avemsg.txt")); - if(f.open(QIODevice::ReadOnly | QIODevice::Text)) { - QTextStream s(&f); - QString t=s.readAll(); - m_msgAvgWidget->displayAvg(t); + // notification for hb + tryNotify("hb"); } - } + + } else { + qDebug() << "buffering compound call" << cd.freq << cd.call << cd.bits; + + hasExistingMessageBuffer(cd.freq, true, nullptr); + m_messageBuffer[cd.freq].compound.append(cd); } } #endif - } + // Parse commands + // KN4CRD K1JT ? +#if 1 + bool shouldProcessDirected = true; + if(shouldProcessDirected && decodedtext.isDirectedMessage()){ + auto parts = decodedtext.directedMessage(); + + cmd.from = parts.at(0); + cmd.to = parts.at(1); + cmd.cmd = parts.at(2); + cmd.freq = decodedtext.frequencyOffset(); + cmd.snr = decodedtext.snr(); + cmd.utcTimestamp = DriftingDateTime::currentDateTimeUtc(); + cmd.bits = decodedtext.bits(); + cmd.extra = parts.length() > 2 ? parts.mid(3).join(" ") : ""; + cmd.tdrift = decodedtext.dt(); + cmd.mode = currentMode(); + + // if the command is a buffered command and its not the last frame OR we have from or to in a separate message (compound call) + if((Varicode::isCommandBuffered(cmd.cmd) && (cmd.bits & Varicode::JS8CallLast) != Varicode::JS8CallLast) || cmd.from == "<....>" || cmd.to == "<....>"){ + qDebug() << "buffering cmd" << cmd.freq << cmd.cmd << cmd.from << cmd.to; + + // log complete buffered callsigns immediately + if(cmd.from != "<....>" && cmd.to != "<....>"){ + CallDetail cmdcd = {}; + cmdcd.call = cmd.from; + cmdcd.bits = cmd.bits; + cmdcd.snr = cmd.snr; + cmdcd.freq = cmd.freq; + cmdcd.utcTimestamp = cmd.utcTimestamp; + cmdcd.ackTimestamp = cmd.to == m_config.my_callsign() ? cmd.utcTimestamp : QDateTime{}; + cmdcd.tdrift = cmd.tdrift; + cmdcd.mode = currentMode(); + logCallActivity(cmdcd, false); + logHeardGraph(cmd.from, cmd.to); + } + + // merge any existing buffer to this frequency + hasExistingMessageBuffer(cmd.freq, true, nullptr); + + if(cmd.to == m_config.my_callsign()){ + d.shouldDisplay = true; + } + + m_messageBuffer[cmd.freq].cmd = cmd; + m_messageBuffer[cmd.freq].msgs.clear(); + } else { + m_rxCommandQueue.append(cmd); + } + + // check to see if this is a station we've heard 3rd party + bool shouldCaptureThirdPartyCallsigns = false; + if(shouldCaptureThirdPartyCallsigns && Radio::base_callsign(cmd.to) != Radio::base_callsign(m_config.my_callsign())){ + QString relayCall = QString("%1|%2").arg(Radio::base_callsign(cmd.from)).arg(Radio::base_callsign(cmd.to)); + int snr = -100; + if(parts.length() == 4){ + snr = QString(parts.at(3)).toInt(); + } + + //CallDetail td = {}; + td.through = cmd.from; + td.call = cmd.to; + td.grid = ""; + td.snr = snr; + td.freq = cmd.freq; + td.utcTimestamp = cmd.utcTimestamp; + td.tdrift = cmd.tdrift; + td.mode = currentMode(); + logCallActivity(td, true); + logHeardGraph(cmd.from, cmd.to); + } + } +#endif + + + + + // Parse CQs +#if 0 + bool shouldParseCQs = true; + if(shouldParseCQs && decodedtext.isStandardMessage()){ + QString theircall; + QString theirgrid; + decodedtext.deCallAndGrid(theircall, theirgrid); + + QStringList calls = Varicode::parseCallsigns(theircall); + if(!calls.isEmpty() && !calls.first().isEmpty()){ + theircall = calls.first(); + + CallDetail d = {}; + d.bits = decodedtext.bits(); + d.call = theircall; + d.grid = theirgrid; + d.snr = decodedtext.snr(); + d.freq = decodedtext.frequencyOffset(); + d.utcTimestamp = DriftingDateTime::currentDateTimeUtc(); + m_callActivity[d.call] = d; + } + } +#endif + + // Parse standard message callsigns + // K1JT KN4CRD EM73 + // KN4CRD K1JT -21 + // K1JT KN4CRD R-12 + // DE KN4CRD + // KN4CRD +#if 0 + bool shouldParseCallsigns = false; + if(shouldParseCallsigns){ + QStringList callsigns = Varicode::parseCallsigns(decodedtext.message()); + if(!callsigns.isEmpty()){ + // one callsign + // de [from] + // cq [from] + + // two callsigns + // [from]: [to] ... + // [to] [from] [grid|signal] + + QStringList grids = Varicode::parseGrids(decodedtext.message()); + + // one callsigns are handled above... so we only need to handle two callsigns if it's a standard message + if(decodedtext.isStandardMessage()){ + if(callsigns.length() == 2){ + auto de_callsign = callsigns.last(); + + // TODO: jsherer - put this in a function to record a callsign... + CallDetail d; + d.call = de_callsign; + d.grid = !grids.empty() ? grids.first() : ""; + d.snr = decodedtext.snr(); + d.freq = decodedtext.frequencyOffset(); + d.utcTimestamp = DriftingDateTime::currentDateTimeUtc(); + m_callActivity[Radio::base_callsign(de_callsign)] = d; + } + } + } + } +#endif } + // See MainWindow::postDecode for displaying the latest decodes } diff --git a/mainwindow.h b/mainwindow.h index aea593c..875f408 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -836,6 +836,7 @@ private: QDateTime date; }; + QMap m_messageDupeCache; // message frame -> freq offset seen QMap m_showColumnsCache; // table column:key -> show boolean QMap m_sortCache; // table key -> sort by QPriorityQueue m_txMessageQueue; // messages to be sent