mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-09 15:17:24 -05:00
#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:
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user