#1340 Updates tuner and frequency controllers to apply locking to ensure multi-threaded access to freuqency control planes doesn't allow center tuned frequency to become indeterminant which can result in channels being mistuned and stop decoding. (#1341)

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
Denny Sheirer
2022-11-20 07:55:30 -05:00
committed by GitHub
parent ac61b681e6
commit a24c3736f4
14 changed files with 299 additions and 128 deletions

2
.idea/misc.xml generated
View File

@@ -4,7 +4,7 @@
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_19" default="true" project-jdk-name="liberica-19.0.1.fx" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="liberica-19.0.1.fx" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@@ -197,7 +197,7 @@ public class SourceEvent
/**
* Creates a new locked state change event
*/
public static SourceEvent lockedState()
public static SourceEvent lockedSampleRateState()
{
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_LOCKED, 1);
}
@@ -205,7 +205,7 @@ public class SourceEvent
/**
* Creates a new unlocked state change event
*/
public static SourceEvent unlockedState()
public static SourceEvent unlockedSampleRateState()
{
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_UNLOCKED, 0);
}

View File

@@ -36,11 +36,11 @@ import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
import io.github.dsheirer.source.tuner.frequency.FrequencyController;
import io.github.dsheirer.source.tuner.frequency.FrequencyController.Tunable;
import io.github.dsheirer.source.tuner.manager.FrequencyErrorCorrectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import java.util.SortedSet;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener,
INativeBufferProvider, Listener<INativeBuffer>, ITunerErrorListener
@@ -70,6 +70,17 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
mFrequencyErrorCorrectionManager = new FrequencyErrorCorrectionManager(this);
}
/**
* Lock for the frequency controller. This should only be used by the channel source manager to lock access to the
* frequency controller while creating a channel source, to block multi-threaded access to the frequency controller
* which might put the center tuned frequency value in an indeterminant state.
* @return frequency controller lock
*/
public ReentrantLock getFrequencyControllerLock()
{
return mFrequencyController.getFrequencyControllerLock();
}
/**
* Frequency correction manager for this tuner controller.
*/
@@ -182,29 +193,30 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
}
/**
* Indicates if the frequency and sample rate controls are locked by another process. User interface controls
* should monitor source events and check the locked state via this method to correctly render the enabled state
* of the frequency and sample rate controls.
* Indicates if the sample rate control is locked by another process. User interface controls should monitor source
* events and check the locked state via this method to correctly render the enabled state of the sample rate control.
*
* @return true if the tuner controller is locked.
*/
public boolean isLocked()
public boolean isLockedSampleRate()
{
return mFrequencyController.isLocked();
//Note: this access is not protected by the mFrequencyControllerLock
return mFrequencyController.isSampleRateLocked();
}
/**
* Sets the frequency and sample rate locked state to the locked argument value. This should only be changed
* by a downstream consumer of samples to prevent users or other processes from modifying the center frequency
* and/or sample rate of the tuner while processing samples.
* Sets the sample rate locked state to the locked argument value. This should only be changed by a downstream
* consumer of samples to prevent users or other processes from modifying the sample rate of the tuner while
* processing samples.
*
* @param locked true to indicate the tuner controller is in a locked state, otherwise false.
*/
public void setLocked(boolean locked)
public void setLockedSampleRate(boolean locked)
{
try
{
mFrequencyController.setLocked(locked);
//Note: this access is not protected by the mFrequencyControllerLock
mFrequencyController.setSampleRateLocked(locked);
}
catch(SourceException se)
{
@@ -214,6 +226,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
public int getBandwidth()
{
//Note: this access is not protected by the mFrequencyControllerLock
return mFrequencyController.getBandwidth();
}
@@ -225,7 +238,15 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public void setFrequency(long frequency) throws SourceException
{
mFrequencyController.setFrequency(frequency);
try
{
getFrequencyControllerLock().lock();
mFrequencyController.setFrequency(frequency);
}
finally
{
getFrequencyControllerLock().unlock();
}
}
/**
@@ -235,28 +256,73 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public long getFrequency()
{
return mFrequencyController.getFrequency();
long frequency;
try
{
getFrequencyControllerLock().lock();
frequency = mFrequencyController.getFrequency();
}
finally
{
getFrequencyControllerLock().unlock();
}
return frequency;
}
@Override
public boolean canTune(long frequency)
{
return mFrequencyController.canTune(frequency);
boolean canTune;
try
{
getFrequencyControllerLock().lock();
canTune = mFrequencyController.canTune(frequency);
}
finally
{
getFrequencyControllerLock().unlock();
}
return canTune;
}
public double getSampleRate()
{
//Note: this access is not protected by the mFrequencyControllerLock
return mFrequencyController.getSampleRate();
}
public double getFrequencyCorrection()
{
return mFrequencyController.getFrequencyCorrection();
double correction;
try
{
getFrequencyControllerLock().lock();
correction = mFrequencyController.getFrequencyCorrection();
}
finally
{
getFrequencyControllerLock().unlock();
}
return correction;
}
public void setFrequencyCorrection(double correction) throws SourceException
{
mFrequencyController.setFrequencyCorrection(correction);
try
{
getFrequencyControllerLock().lock();
mFrequencyController.setFrequencyCorrection(correction);
}
finally
{
getFrequencyControllerLock().unlock();
}
}
/**
@@ -265,7 +331,19 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public long getMinimumFrequency()
{
return mFrequencyController.getMinimumFrequency();
long minimum;
try
{
getFrequencyControllerLock().lock();
minimum = mFrequencyController.getMinimumFrequency();
}
finally
{
getFrequencyControllerLock().unlock();
}
return minimum;
}
/**
@@ -274,7 +352,15 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public void setMinimumFrequency(long minimum)
{
mFrequencyController.setMinimumFrequency(minimum);
try
{
getFrequencyControllerLock().lock();
mFrequencyController.setMinimumFrequency(minimum);
}
finally
{
getFrequencyControllerLock().unlock();
}
}
/**
@@ -283,7 +369,19 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public long getMaximumFrequency()
{
return mFrequencyController.getMaximumFrequency();
long maximum;
try
{
getFrequencyControllerLock().lock();
maximum = mFrequencyController.getMaximumFrequency();
}
finally
{
getFrequencyControllerLock().unlock();
}
return maximum;
}
/**
@@ -292,17 +390,49 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public void setMaximumFrequency(long maximum)
{
mFrequencyController.setMaximumFrequency(maximum);
try
{
getFrequencyControllerLock().lock();
mFrequencyController.setMaximumFrequency(maximum);
}
finally
{
getFrequencyControllerLock().unlock();
}
}
public long getMinTunedFrequency() throws SourceException
{
return mFrequencyController.getFrequency() - (getUsableBandwidth() / 2);
long minTuned;
try
{
getFrequencyControllerLock().lock();
minTuned = mFrequencyController.getFrequency() - (getUsableBandwidth() / 2);
}
finally
{
getFrequencyControllerLock().unlock();
}
return minTuned;
}
public long getMaxTunedFrequency() throws SourceException
{
return mFrequencyController.getFrequency() + (getUsableBandwidth() / 2);
long maxTuned;
try
{
getFrequencyControllerLock().lock();
maxTuned = mFrequencyController.getFrequency() + (getUsableBandwidth() / 2);
}
finally
{
getFrequencyControllerLock().unlock();
}
return maxTuned;
}
/**
@@ -425,7 +555,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public void addListener( ISourceEventProcessor processor )
{
mFrequencyController.addListener(processor);
mFrequencyController.addSourceEventProcessor(processor);
}
/**
@@ -433,7 +563,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
public void removeListener( ISourceEventProcessor processor )
{
mFrequencyController.removeFrequencyChangeProcessor(processor);
mFrequencyController.removeSourceEventProcessor(processor);
}
/**

View File

@@ -25,6 +25,9 @@ import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.tuner.manager.TunerStatus;
import io.github.dsheirer.source.tuner.ui.TunerEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,9 +43,6 @@ import javax.swing.JSlider;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
/**
* Airspy tuner editor/controller
@@ -102,7 +102,7 @@ public class AirspyTunerEditor extends TunerEditor<AirspyTuner, AirspyTunerConfi
getTunerStatusLabel().setText(status);
getButtonPanel().updateControls();
getFrequencyPanel().updateControls();
getSampleRateCombo().setEnabled(hasTuner() && !getTuner().getTunerController().isLocked());
getSampleRateCombo().setEnabled(hasTuner() && !getTuner().getTunerController().isLockedSampleRate());
getTunerInfoButton().setEnabled(hasTuner());
updateGainComponents((hasTuner() && hasConfiguration()) ? getConfiguration().getGain() : null);
@@ -626,7 +626,7 @@ public class AirspyTunerEditor extends TunerEditor<AirspyTuner, AirspyTunerConfi
*/
private void updateSampleRateToolTip()
{
if(hasTuner() && getTuner().getController().isLocked())
if(hasTuner() && getTuner().getController().isLockedSampleRate())
{
mSampleRateCombo.setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
}

View File

@@ -22,12 +22,11 @@ import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.InvalidFrequencyException;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FrequencyController
{
@@ -40,8 +39,12 @@ public class FrequencyController
private long mMaximumFrequency = 0;
private double mFrequencyCorrection = 0.0d;
private double mSampleRate = 0.0d;
private boolean mLocked = false;
private boolean mSampleRateLocked = false;
private List<ISourceEventProcessor> mProcessors = new ArrayList<>();
/**
* Lock protecting access to frequency control plane, source event processor subscriptions and event broadcasting
*/
private ReentrantLock mLock = new ReentrantLock();
/**
@@ -53,6 +56,15 @@ public class FrequencyController
mTunable = tunable;
}
/**
* Lock for controlling access to frequency control plane, event processor subscriptions and source event broadcasts.
*/
public ReentrantLock getFrequencyControllerLock()
{
return mLock;
}
/**
* Prepare for disposal of this instance.
*/
@@ -63,36 +75,36 @@ public class FrequencyController
}
/**
* Indicates if this frequency controller is locked by a remote process. A locked state indicates that neither
* the frequency nor the sample rate should be changed. The remote process will typically be a downstream
* Indicates if the sample rate for this frequency controller is locked by a remote process. A locked state
* indicates that the sample rate cannot be changed. The remote process will typically be a downstream
* consumer of the data produced by the device being controlled (ie polyphase channelizer) that does not want
* the sample rate or frequency to be changed while processing is ongoing.
* the sample rate to be changed while processing (ie channels have been allocated) is ongoing.
*
* @return true if locked or false if not locked.
*/
public boolean isLocked()
public boolean isSampleRateLocked()
{
return mLocked;
return mSampleRateLocked;
}
/**
* Sets the lock state for this frequency controller. Set to true when a consumer process requires that the
* frequency and sample rate controls be locked so that only the singular consumer process makes changes. This
* sample rate control be locked so that only the single consumer process makes changes to the sample rate. This
* is primarily to lock down user interface controls when the polyphase channelizer is producing channels.
*
* @param locked state
* @param sampleRateLocked state
*/
public void setLocked(boolean locked) throws SourceException
public void setSampleRateLocked(boolean sampleRateLocked) throws SourceException
{
mLocked = locked;
mSampleRateLocked = sampleRateLocked;
if(mLocked)
if(mSampleRateLocked)
{
broadcast(SourceEvent.lockedState());
broadcast(SourceEvent.lockedSampleRateState());
}
else
{
broadcast(SourceEvent.unlockedState());
broadcast(SourceEvent.unlockedSampleRateState());
}
}
@@ -111,7 +123,7 @@ public class FrequencyController
{
if(sampleRate != mSampleRate)
{
if(!mLocked)
if(!mSampleRateLocked)
{
mSampleRate = sampleRate;
@@ -284,7 +296,7 @@ public class FrequencyController
/**
* Adds listener to receive frequency change events
*/
public void addListener(ISourceEventProcessor processor)
public void addSourceEventProcessor(ISourceEventProcessor processor)
{
mLock.lock();
@@ -304,7 +316,7 @@ public class FrequencyController
/**
* Removes listener from receiving frequency change events
*/
public void removeFrequencyChangeProcessor(ISourceEventProcessor processor)
public void removeSourceEventProcessor(ISourceEventProcessor processor)
{
mLock.lock();

View File

@@ -120,7 +120,7 @@ public class HackRFTunerEditor extends TunerEditor<HackRFTuner,HackRFTunerConfig
getTunerStatusLabel().setText(status);
getButtonPanel().updateControls();
getFrequencyPanel().updateControls();
getSampleRateCombo().setEnabled(hasTuner() && !getTuner().getTunerController().isLocked());
getSampleRateCombo().setEnabled(hasTuner() && !getTuner().getTunerController().isLockedSampleRate());
updateSampleRateToolTip();
getTunerInfoButton().setEnabled(hasTuner());
@@ -295,7 +295,7 @@ public class HackRFTunerEditor extends TunerEditor<HackRFTuner,HackRFTunerConfig
*/
private void updateSampleRateToolTip()
{
if(hasTuner() && getTuner().getController().isLocked())
if(hasTuner() && getTuner().getController().isLockedSampleRate())
{
mSampleRateCombo.setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
}

View File

@@ -93,38 +93,48 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
return null;
}
if(CenterFrequencyCalculator.canTune(tunerChannel, mTunerController, mTunerChannels))
TunerChannelSource source = null;
try
{
try
mTunerController.getFrequencyControllerLock().lock();
if(CenterFrequencyCalculator.canTune(tunerChannel, mTunerController, mTunerChannels))
{
//Attempt to create the channel source first, in case we get a filter design exception
HalfBandTunerChannelSource tunerChannelSource = new HalfBandTunerChannelSource(mChannelSourceEventProcessor,
tunerChannel, mTunerController.getSampleRate(), channelSpecification);
try
{
//Attempt to create the channel source first, in case we get a filter design exception
HalfBandTunerChannelSource tunerChannelSource = new HalfBandTunerChannelSource(mChannelSourceEventProcessor,
tunerChannel, mTunerController.getSampleRate(), channelSpecification);
//Add to the list of channel sources so that it will receive the tuner frequency change
mChannelSources.add(tunerChannelSource);
//Add to the list of channel sources so that it will receive the tuner frequency change
mChannelSources.add(tunerChannelSource);
//Set the current tuner frequency
tunerChannelSource.setFrequency(mTunerController.getFrequency());
//Set the current tuner frequency
tunerChannelSource.setFrequency(mTunerController.getFrequency());
//Add to the channel list and update the tuner center frequency as needed
mTunerChannels.add(tunerChannel);
updateTunerFrequency();
//Add to the channel list and update the tuner center frequency as needed
mTunerChannels.add(tunerChannel);
updateTunerFrequency();
//Lock the tuner controller frequency and sample rate
mTunerController.setLocked(true);
//Lock the tuner controller frequency and sample rate
mTunerController.setLockedSampleRate(true);
broadcast(SourceEvent.channelCountChange(getTunerChannelCount()));
broadcast(SourceEvent.channelCountChange(getTunerChannelCount()));
return tunerChannelSource;
}
catch(FilterDesignException fde)
{
mLog.error("Error creating CIC tuner channel source - couldn't design cleanup filter", fde);
source = tunerChannelSource;
}
catch(FilterDesignException fde)
{
mLog.error("Error creating CIC tuner channel source - couldn't design cleanup filter", fde);
}
}
}
finally
{
mTunerController.getFrequencyControllerLock().unlock();
}
return null;
return source;
}
@Override
@@ -294,7 +304,7 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
//Unlock the tuner controller if there are no more channels
if(getTunerChannelCount() == 0)
{
mTunerController.setLocked(false);
mTunerController.setLockedSampleRate(false);
}
broadcast(SourceEvent.channelCountChange(getTunerChannelCount()));
}

View File

@@ -82,18 +82,30 @@ public class PassThroughSourceManager extends ChannelSourceManager
@Override
public TunerChannelSource getSource(TunerChannel tunerChannel, ChannelSpecification channelSpecification)
{
if(!mRunning)
{
return null;
}
PassThroughChannelSource channelSource = new PassThroughChannelSource(new SourceEventProxy(),
mTunerController, tunerChannel);
TunerChannelSource source = null;
mTunerChannels.add(tunerChannel);
mTunerChannelSources.add(channelSource);
try
{
mTunerController.getFrequencyControllerLock().lock();
PassThroughChannelSource channelSource = new PassThroughChannelSource(new SourceEventProxy(),
mTunerController, tunerChannel);
return channelSource;
mTunerChannels.add(tunerChannel);
mTunerChannelSources.add(channelSource);
source = channelSource;
}
finally
{
mTunerController.getFrequencyControllerLock().unlock();
}
return source;
}
@Override

View File

@@ -25,12 +25,11 @@ import io.github.dsheirer.source.tuner.TunerController;
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
import java.util.SortedSet;
import org.apache.commons.math3.util.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.SortedSet;
/**
* PolyphaseChannelSourceManager is responsible for managing the tuner's center tuned frequency and providing access to
* polyphase tuner channel sources (ie DDCs). This class is responsible for determining IF a requested channel can
@@ -416,48 +415,56 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
@Override
public TunerChannelSource getSource(TunerChannel tunerChannel, ChannelSpecification channelSpecification)
{
if(isTunable(tunerChannel))
TunerChannelSource tunerChannelSource = null;
try
{
//Get a new set of currently tuned channels
SortedSet<TunerChannel> tunerChannels = getTunerChannels();
//Add the requested channel to the list
tunerChannels.add(tunerChannel);
if(canTune(tunerChannels))
mTunerController.getFrequencyControllerLock().lock();
if(isTunable(tunerChannel))
{
long currentCenterFrequency = mTunerController.getFrequency();
long updatedCenterFrequency = 0;
//Get a new set of currently tuned channels
SortedSet<TunerChannel> tunerChannels = getTunerChannels();
//Attempt to adjust the center frequency before we allocate the channel
try
//Add the requested channel to the list
tunerChannels.add(tunerChannel);
if(canTune(tunerChannels))
{
updatedCenterFrequency = getCenterFrequency(tunerChannels, currentCenterFrequency);
long currentCenterFrequency = mTunerController.getFrequency();
long updatedCenterFrequency = 0;
if(updatedCenterFrequency != currentCenterFrequency && updatedCenterFrequency != 0)
//Attempt to adjust the center frequency before we allocate the channel
try
{
mTunerController.setFrequency(updatedCenterFrequency);
}
updatedCenterFrequency = getCenterFrequency(tunerChannels, currentCenterFrequency);
//If we're successful to here, allocate the channel
return mPolyphaseChannelManager.getChannel(tunerChannel);
}
catch(SourceException se)
{
//Tuner controller threw an error trying to tune to the updated frequency
mLog.error("Error while updating tuner controller with new center frequency [" +
updatedCenterFrequency + "] - unable to allocate new tuner channel", se);
}
catch(IllegalArgumentException iae)
{
//Center frequency calculation failed
// mLog.debug("Couldn't calculate new tuner center frequency for new tuner channel [" +
// tunerChannel + "] unable to allocate new tuner channel");
if(updatedCenterFrequency != currentCenterFrequency && updatedCenterFrequency != 0)
{
mTunerController.setFrequency(updatedCenterFrequency);
}
//If we're successful to here, allocate the channel
tunerChannelSource = mPolyphaseChannelManager.getChannel(tunerChannel);
}
catch(SourceException se)
{
//Tuner controller threw an error trying to tune to the updated frequency
mLog.error("Error while updating tuner controller with new center frequency [" +
updatedCenterFrequency + "] - unable to allocate new tuner channel", se);
}
catch(IllegalArgumentException iae)
{
//Center frequency calculation failed
}
}
}
}
finally
{
mTunerController.getFrequencyControllerLock().unlock();
}
return null;
return tunerChannelSource;
}
/**
@@ -474,7 +481,7 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
broadcast(sourceEvent);
//Lock the frequency and sample rate controls on the tuner controller so users can't change them
//when the polyphase manager has channels allocated
mTunerController.setLocked(getTunerChannelCount() > 0);
mTunerController.setLockedSampleRate(getTunerChannelCount() > 0);
break;
case NOTIFICATION_MEASURED_FREQUENCY_ERROR_SYNC_LOCKED:
//Rebroadcast these frequency measurement errors to the tuner and tuner controller

View File

@@ -29,6 +29,8 @@ import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KGain;
import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KLNAGain;
import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KMixerGain;
import io.github.dsheirer.source.tuner.ui.TunerEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,8 +43,6 @@ import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import javax.swing.SpinnerNumberModel;
import javax.usb.UsbException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* E4000 tuner editor
@@ -383,7 +383,7 @@ public class E4KTunerEditor extends TunerEditor<RTL2832Tuner, E4KTunerConfigurat
*/
private void updateSampleRateToolTip()
{
if(hasTuner() && getTuner().getTunerController().isLocked())
if(hasTuner() && getTuner().getTunerController().isLockedSampleRate())
{
getSampleRateCombo().setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
}

View File

@@ -416,7 +416,7 @@ public class R820TTunerEditor extends TunerEditor<RTL2832Tuner,R820TTunerConfigu
*/
private void updateSampleRateToolTip()
{
if(hasTuner() && getTuner().getTunerController().isLocked())
if(hasTuner() && getTuner().getTunerController().isLockedSampleRate())
{
getSampleRateCombo().setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
}

View File

@@ -25,10 +25,6 @@ import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
import io.github.dsheirer.source.tuner.manager.DiscoveredUSBTuner;
import io.github.dsheirer.source.tuner.manager.IDiscoveredTunerStatusListener;
import io.github.dsheirer.source.tuner.manager.TunerStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.table.AbstractTableModel;
import java.awt.EventQueue;
import java.text.DecimalFormat;
import java.util.ArrayList;
@@ -36,6 +32,10 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.table.AbstractTableModel;
/**
* Model for discovered tuners
@@ -449,7 +449,7 @@ public class DiscoveredTunerModel extends AbstractTableModel implements Listener
if(discoveredTuner.hasTuner())
{
int channelCount = discoveredTuner.getTuner().getChannelSourceManager().getTunerChannelCount();
return channelCount + " (" + (discoveredTuner.getTuner().getTunerController().isLocked() ? "LOCKED)" : "UNLOCKED)");
return channelCount + " (" + (discoveredTuner.getTuner().getTunerController().isLockedSampleRate() ? "LOCKED)" : "UNLOCKED)");
}
else
{

View File

@@ -619,8 +619,8 @@ public abstract class TunerEditor<T extends Tuner,C extends TunerConfiguration>
{
getFrequencyControl().clearListeners();
getFrequencyControl().addListener(mFrequencyAndCorrectionChangeListener);
getFrequencyControl().setEnabled(hasTuner() && !getTuner().getTunerController().isLocked());
getTunerLockedStatusLabel().setVisible(hasTuner() && getTuner().getTunerController().isLocked());
getFrequencyControl().setEnabled(hasTuner() && !getTuner().getTunerController().isLockedSampleRate());
getTunerLockedStatusLabel().setVisible(hasTuner() && getTuner().getTunerController().isLockedSampleRate());
getFrequencyCorrectionSpinner().setEnabled(hasTuner());
getAutoPPMCheckBox().setEnabled(hasTuner());

View File

@@ -143,7 +143,7 @@ public class TunerViewPanel extends JPanel
if(selectedTuner != null && selectedTuner.hasTuner() && tunerEvent.getTuner() == selectedTuner.getTuner())
{
mDiscoveredTunerEditor.setTunerLockState(selectedTuner.getTuner().getTunerController().isLocked());
mDiscoveredTunerEditor.setTunerLockState(selectedTuner.getTuner().getTunerController().isLockedSampleRate());
}
}
}