#1397 Resolves issue where decoding channels go IDLE after period of time. Isolated the cause to a multi-threading issue where the polyphase channel manager receives notification that the tuner center frequency has changed and sets a flag to update each of the channels. This happens concurrent with a previous tuner center frequency change where the flag gets set and the second thread is updating the output processors with the previous frequency change and then unsets the frequency change flag, completely missing the second/latest frequency change update and causing the channels to all tune-out their desired signals as the tuner center frequency changes and the output channels continue mixing to the previous frequency. (#1407)

Identified and resolved issue where a 2-stream polyphase synthesizer was being updated with an incorrectly designed synthesis filter which was causing massive droop on the second half of the reconstructed channel.  Oddly enough, this didn't seem to impact the P25 decoders, but it may have impacted other decoding.

Identified and resolved issue with concurrent modification of the modules list in the processing chain associated with recent addition of the channel FFT view in the channel power tab.

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
Denny Sheirer
2023-01-15 04:12:42 -05:00
committed by GitHub
parent f97b2150b9
commit f0db2865f2
18 changed files with 412 additions and 99 deletions

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -52,6 +52,12 @@ public abstract class ChannelSourceManager implements ISourceEventProcessor
*/
public abstract SortedSet<TunerChannel> getTunerChannels();
/**
* State of this channel source manager for logging and debug purposes
* @return description of the state or configuration of this manager
*/
public abstract String getStateDescription();
/**
* Count of tuner channels being sourced by this source manager.
* @return

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -55,6 +55,27 @@ public abstract class DiscoveredTuner implements ITunerErrorListener
return mTunerStatus;
}
/**
* Logs current state of the tuner
*/
public void logState()
{
StringBuilder sb = new StringBuilder();
sb.append("Discovered Tuner: ").append(getId());
if(hasTuner())
{
sb.append("\n\tTuner - Frequency:").append(getTuner().getTunerController().getFrequency());
sb.append("\n\tChannel Manager:").append(getTuner().getChannelSourceManager().getStateDescription());
}
else
{
sb.append("\n\tTuner - no tuner");
}
mLog.info(sb.toString());
}
/**
* Sets the status of the discovered tuner and notifies registered listeners of the status change.
* @param tunerStatus to set

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -60,6 +60,23 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
mTunerController.addListener(this);
}
@Override
public String getStateDescription()
{
StringBuilder sb = new StringBuilder();
sb.append("Heterodyne Channel Source Manager Providing [").append(mTunerChannels.size()).append("] Channels");
sb.append("\n\tTuner Controller Frequency: ").append(mTunerController.getFrequency());
for(HalfBandTunerChannelSource channelSource: mChannelSources)
{
sb.append("\n\tChannel [").append(channelSource.getTunerChannel())
.append("] Frequency [").append(channelSource.getFrequency())
.append("] Mixer [").append(channelSource.getMixerFrequency())
.append("]");
}
return sb.toString();
}
@Override
public void stopAllChannels()
{

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -54,6 +54,19 @@ public class PassThroughSourceManager extends ChannelSourceManager
mTunerController = tunerController;
}
@Override
public String getStateDescription()
{
StringBuilder sb = new StringBuilder();
sb.append("Pass-Through Channel Source Manager Providing [").append(mTunerChannels.size()).append("] Channels");
for(TunerChannel channel: mTunerChannels)
{
sb.append("\n\tChannel: ").append(channel);
}
return sb.toString();
}
@Override
public void stopAllChannels()
{

View File

@@ -55,6 +55,17 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
mTunerController.addListener(mPolyphaseChannelManager);
}
@Override
public String getStateDescription()
{
StringBuilder sb = new StringBuilder();
sb.append("Polyphase Channel Source Manager");
sb.append("\n\tTuner Controller Frequency: ").append(mTunerController.getFrequency());
sb.append("\n\t").append(mPolyphaseChannelManager.getStateDescription());
return sb.toString();
}
@Override
public void stopAllChannels()
{
@@ -454,8 +465,13 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
}
catch(IllegalArgumentException iae)
{
mLog.error("Center frequency calculation failed", iae);
//Center frequency calculation failed
}
catch(Exception e)
{
mLog.error("Error getting source", e);
}
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -189,6 +189,7 @@ public class DiscoveredTunerModel extends AbstractTableModel implements Listener
*/
public void removeDiscoveredTuner(DiscoveredTuner discoveredTuner)
{
mLog.info("Removing discovered tuner: " + discoveredTuner.getId());
mLock.lock();
try

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,7 +39,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.JButton;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
@@ -115,6 +117,32 @@ public class TunerViewPanel extends JPanel
}
});
//Add support for right-click context menu to the tuner table
JPopupMenu popupMenu = new JPopupMenu();
JMenuItem logStateMenuItem = new JMenuItem("Log Tuner State");
logStateMenuItem.addActionListener(e -> {
int viewRow = mTunerTable.getSelectedRow();
DiscoveredTuner selected = null;
if(viewRow >= 0)
{
int modelRow = mTunerTable.convertRowIndexToModel(viewRow);
selected = mDiscoveredTunerModel.getDiscoveredTuner(modelRow);
}
if(selected != null)
{
selected.logState();
}
else
{
mLog.error("Can't log state - tuner not selected");
}
});
popupMenu.add(logStateMenuItem);
mTunerTable.setComponentPopupMenu(popupMenu);
//Monitor for tuner removal events so we can update the editor when our selected tuner is removed
mDiscoveredTunerModel.addTableModelListener(e ->
{