diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/AbstractComplexPolyphaseChannelizer.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/AbstractComplexPolyphaseChannelizer.java index 102f145b..09f6d34a 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/AbstractComplexPolyphaseChannelizer.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/AbstractComplexPolyphaseChannelizer.java @@ -68,9 +68,10 @@ public abstract class AbstractComplexPolyphaseChannelizer implements Listener 0.5) + //Channel calculator is always in sync with the tuner's current sample rate + double tunerSampleRate = mChannelCalculator.getSampleRate(); + + //If the channelizer is not setup, or setup to the wrong sample rate, recreate it + if(mPolyphaseChannelizer == null || Math.abs(mPolyphaseChannelizer.getSampleRate() - tunerSampleRate) > 0.5) { + if(mPolyphaseChannelizer != null && mPolyphaseChannelizer.getRegisteredChannelCount() > 0) + { + throw new IllegalStateException("Polyphase Channelizer cannot be changed to a new sample rate while " + + "channels are currently sourced. Ensure you remove all tuner channels before changing tuner " + + "sample rate. Current channel count:" + + (mPolyphaseChannelizer != null ? mPolyphaseChannelizer.getRegisteredChannelCount() : "0")); + } + try { - if(mPolyphaseChannelizer == null) - { - mPolyphaseChannelizer = new ComplexPolyphaseChannelizerM2(sampleRate, - POLYPHASE_CHANNELIZER_TAPS_PER_CHANNEL); - } - else - { - mPolyphaseChannelizer.setSampleRate(sampleRate); - } + mPolyphaseChannelizer = new ComplexPolyphaseChannelizerM2(tunerSampleRate, + POLYPHASE_CHANNELIZER_TAPS_PER_CHANNEL); } catch(IllegalArgumentException iae) { - mLog.error("Could not create polyphase channelizer for sample rate [" + sampleRate + "]", iae); + mLog.error("Could not create polyphase channelizer for sample rate [" + tunerSampleRate + "]", iae); } catch(FilterDesignException fde) { - mLog.error("Could not create filter for polyphase channelizer for sample rate [" + sampleRate + "]", fde); + mLog.error("Could not create filter for polyphase channelizer for sample rate [" + tunerSampleRate + "]", fde); } - //Clear the previous channel synthesis filters so they can be recreated for the new channel sample rate + //Clear any previous channel synthesis filters so they can be recreated for the new channel sample rate mOutputProcessorFilters.clear(); - - //Broadcast the new channel sample rate - double updatedChannelSampleRate = mChannelCalculator.getChannelSampleRate(); - updateOutputProcessors(SourceEvent.sampleRateChange(updatedChannelSampleRate, "Channelizer Sample Rate Update")); } } @@ -600,9 +598,6 @@ public class PolyphaseChannelManager implements ISourceEventProcessor //Don't send the tuner's frequency change event down to the channels - it would cause chaos updateOutputProcessors(null); break; - case NOTIFICATION_SAMPLE_RATE_CHANGE: - updateChannelizerSampleRate(queuedSourceEvent.getValue().intValue()); - break; } queuedSourceEvent = mQueuedSourceEvents.poll(); diff --git a/src/main/java/io/github/dsheirer/gui/control/JFrequencyControl.java b/src/main/java/io/github/dsheirer/gui/control/JFrequencyControl.java index bd6c4162..e0e7cc9b 100644 --- a/src/main/java/io/github/dsheirer/gui/control/JFrequencyControl.java +++ b/src/main/java/io/github/dsheirer/gui/control/JFrequencyControl.java @@ -125,6 +125,8 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor mBlankCursor = Toolkit.getDefaultToolkit() .createCustomCursor(cursorImage, new Point(0, 0), "cursor"); + setTooltip(false); + revalidate(); } @@ -139,6 +141,26 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor } } + private void setTooltip(boolean locked) + { + String tooltip = null; + + if(locked) + { + tooltip = "Frequency control is locked. Disable decoding channels to unlock."; + } + else + { + tooltip = "Click on a frequency digit and type a frequency value, or click the upper/lower digits to " + + "change the value"; + } + + for(Digit digit: mDigits.values()) + { + digit.setToolTipText(tooltip); + } + } + /** * Receives a frequency change event invoked by another control. We don't * rebroadcast this event, just set the control to indicate the new frequency. @@ -165,6 +187,7 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor public void run() { setEnabled(false); + setTooltip(true); } }); break; @@ -175,6 +198,7 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor public void run() { setEnabled(true); + setTooltip(false); } }); break; diff --git a/src/main/java/io/github/dsheirer/source/tuner/Tuner.java b/src/main/java/io/github/dsheirer/source/tuner/Tuner.java index 66c30bf7..915290b1 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/Tuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/Tuner.java @@ -65,6 +65,10 @@ public abstract class Tuner implements ISourceEventProcessor case NOTIFICATION_SAMPLE_RATE_CHANGE: broadcast(new TunerEvent(Tuner.this, Event.SAMPLE_RATE)); break; + case NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_LOCKED: + case NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_UNLOCKED: + broadcast(new TunerEvent(Tuner.this, Event.LOCK_STATE_CHANGE)); + break; default: break; } diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerEvent.java b/src/main/java/io/github/dsheirer/source/tuner/TunerEvent.java index 3a0e0111..95fcee04 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerEvent.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerEvent.java @@ -2,33 +2,34 @@ package io.github.dsheirer.source.tuner; public class TunerEvent { - private Tuner mTuner; - private Event mEvent; - - public TunerEvent( Tuner tuner, Event event ) - { - mTuner = tuner; - mEvent = event; - } - - public Tuner getTuner() - { - return mTuner; - } + private Tuner mTuner; + private Event mEvent; - public Event getEvent() - { - return mEvent; - } - - public enum Event - { - ADD, - REMOVE, - CHANNEL_COUNT, - FREQUENCY, - SAMPLE_RATE, - REQUEST_MAIN_SPECTRAL_DISPLAY, - REQUEST_NEW_SPECTRAL_DISPLAY; - } + public TunerEvent(Tuner tuner, Event event) + { + mTuner = tuner; + mEvent = event; + } + + public Tuner getTuner() + { + return mTuner; + } + + public Event getEvent() + { + return mEvent; + } + + public enum Event + { + ADD, + LOCK_STATE_CHANGE, + REMOVE, + CHANNEL_COUNT, + FREQUENCY, + SAMPLE_RATE, + REQUEST_MAIN_SPECTRAL_DISPLAY, + REQUEST_NEW_SPECTRAL_DISPLAY; + } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerModel.java b/src/main/java/io/github/dsheirer/source/tuner/TunerModel.java index 615e20bb..77f028d0 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerModel.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerModel.java @@ -257,7 +257,16 @@ public class TunerModel extends AbstractTableModel implements Listener 0) + { + return channelCount + " (LOCKED)"; + } + else + { + return "0"; + } case SPECTRAL_DISPLAY_MAIN: return "Main"; case SPECTRAL_DISPLAY_NEW: diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerViewPanel.java b/src/main/java/io/github/dsheirer/source/tuner/TunerViewPanel.java index f919377d..c6f79799 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerViewPanel.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerViewPanel.java @@ -1,17 +1,17 @@ /******************************************************************************* * SDR Trunk * Copyright (C) 2014-2016 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 * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ @@ -19,18 +19,27 @@ package io.github.dsheirer.source.tuner; import com.jidesoft.swing.JideSplitPane; +import io.github.dsheirer.sample.Listener; import io.github.dsheirer.source.tuner.TunerEvent.Event; import net.miginfocom.swing.MigLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.swing.*; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.RowSorter; +import javax.swing.SortOrder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableRowSorter; -import java.awt.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; @@ -38,129 +47,150 @@ import java.util.List; public class TunerViewPanel extends JPanel { - private static final long serialVersionUID = 1L; - private final static Logger mLog = LoggerFactory.getLogger( TunerViewPanel.class ); + private static final long serialVersionUID = 1L; + private final static Logger mLog = LoggerFactory.getLogger(TunerViewPanel.class); - private TunerModel mTunerModel; - private JTable mTunerTable; - private TableRowSorter mRowSorter; - private JideSplitPane mSplitPane; - private TunerEditor mTunerEditor; - - public TunerViewPanel( TunerModel tunerModel ) - { - mTunerModel = tunerModel; - mTunerEditor = new TunerEditor( mTunerModel.getTunerConfigurationModel() ); - - init(); - } - - private void init() - { - setLayout( new MigLayout( "insets 0 0 0 0", "[fill,grow]", "[fill,grow]" ) ); + private TunerModel mTunerModel; + private JTable mTunerTable; + private TableRowSorter mRowSorter; + private JideSplitPane mSplitPane; + private TunerEditor mTunerEditor; - mRowSorter = new TableRowSorter<>( mTunerModel ); - List sortKeys = new ArrayList<>(); - sortKeys.add( new RowSorter.SortKey( TunerModel.TUNER_TYPE, SortOrder.ASCENDING ) ); - sortKeys.add( new RowSorter.SortKey( TunerModel.TUNER_ID, SortOrder.ASCENDING ) ); - mRowSorter.setSortKeys( sortKeys ); - - mTunerTable = new JTable( mTunerModel ); - mTunerTable.setRowSorter( mRowSorter ); - mTunerTable.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); - mTunerTable.getSelectionModel().addListSelectionListener( new ListSelectionListener() - { - @Override - public void valueChanged( ListSelectionEvent event ) - { - if( !event.getValueIsAdjusting() ) - { - int row = mTunerTable.getSelectedRow(); - int modelRow = mTunerTable.convertRowIndexToModel( row ); + public TunerViewPanel(TunerModel tunerModel) + { + mTunerModel = tunerModel; + mTunerEditor = new TunerEditor(mTunerModel.getTunerConfigurationModel()); - mTunerEditor.setItem( mTunerModel.getTuner( modelRow ) ); - } - } - } ); - mTunerTable.addMouseListener( new MouseAdapter() - { - @Override - public void mouseClicked( MouseEvent e ) - { - int column = mTunerTable.columnAtPoint( e.getPoint() ); + init(); + } - if( column == TunerModel.SPECTRAL_DISPLAY_MAIN ) - { - int tableRow = mTunerTable.rowAtPoint( e.getPoint() ); - int modelRow = mTunerTable.convertRowIndexToModel( tableRow ); - - Tuner tuner = mTunerModel.getTuner( modelRow ); - - if( tuner != null ) - { - mTunerModel.broadcast( new TunerEvent( tuner, - Event.REQUEST_MAIN_SPECTRAL_DISPLAY ) ); - } - } - else if( column == TunerModel.SPECTRAL_DISPLAY_NEW ) - { - int tableRow = mTunerTable.rowAtPoint( e.getPoint() ); - int modelRow = mTunerTable.convertRowIndexToModel( tableRow ); - - Tuner tuner = mTunerModel.getTuner( modelRow ); - - if( tuner != null ) - { - mTunerModel.broadcast( new TunerEvent( tuner, - Event.REQUEST_NEW_SPECTRAL_DISPLAY ) ); - } - } - } - } ); - - TableCellRenderer renderer = new LinkCellRenderer(); - - mTunerTable.getColumnModel().getColumn( 5 ).setCellRenderer( renderer ); - mTunerTable.getColumnModel().getColumn( 6 ).setCellRenderer( renderer ); - - JScrollPane listScroller = new JScrollPane( mTunerTable ); - listScroller.setPreferredSize( new Dimension( 400, 20 ) ); + private void init() + { + setLayout(new MigLayout("insets 0 0 0 0", "[fill,grow]", "[fill,grow]")); - JScrollPane editorScroller = new JScrollPane( mTunerEditor ); - editorScroller.setPreferredSize( new Dimension( 400, 80 ) ); - - mSplitPane = new JideSplitPane(); - mSplitPane.setOrientation( JideSplitPane.VERTICAL_SPLIT ); - mSplitPane.add( listScroller ); - mSplitPane.add( editorScroller ); - - add( mSplitPane ); - } - - public class LinkCellRenderer extends DefaultTableCellRenderer - { - private static final long serialVersionUID = 1L; + mRowSorter = new TableRowSorter<>(mTunerModel); + List sortKeys = new ArrayList<>(); + sortKeys.add(new RowSorter.SortKey(TunerModel.TUNER_TYPE, SortOrder.ASCENDING)); + sortKeys.add(new RowSorter.SortKey(TunerModel.TUNER_ID, SortOrder.ASCENDING)); + mRowSorter.setSortKeys(sortKeys); - @Override - public Component getTableCellRendererComponent( JTable table, - Object value, boolean isSelected, boolean hasFocus, int row, - int column ) - { - JLabel label = (JLabel)super.getTableCellRendererComponent( table, - value, isSelected, hasFocus, row, column ); - - label.setForeground( Color.BLUE.brighter() ); - - if( column == TunerModel.SPECTRAL_DISPLAY_MAIN ) - { - label.setToolTipText( "Show this tuner in the main spectral display" ); - } - else if( column == TunerModel.SPECTRAL_DISPLAY_NEW ) - { - label.setToolTipText( "Show this tuner in a new spectral display" ); - } - - return label; - } - } + mTunerTable = new JTable(mTunerModel); + mTunerTable.setRowSorter(mRowSorter); + mTunerTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + mTunerTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() + { + @Override + public void valueChanged(ListSelectionEvent event) + { + if(!event.getValueIsAdjusting()) + { + int row = mTunerTable.getSelectedRow(); + int modelRow = mTunerTable.convertRowIndexToModel(row); + + mTunerEditor.setItem(mTunerModel.getTuner(modelRow)); + } + } + }); + + mTunerModel.addListener(new Listener() + { + @Override + public void receive(TunerEvent tunerEvent) + { + switch(tunerEvent.getEvent()) + { + case LOCK_STATE_CHANGE: + int row = mTunerTable.getSelectedRow(); + + if(row >= 0) + { + int modelRow = mTunerTable.convertRowIndexToModel(row); + mTunerEditor.setItem(mTunerModel.getTuner(modelRow)); + } + break; + } + } + }); + + mTunerTable.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent e) + { + int column = mTunerTable.columnAtPoint(e.getPoint()); + + if(column == TunerModel.SPECTRAL_DISPLAY_MAIN) + { + int tableRow = mTunerTable.rowAtPoint(e.getPoint()); + int modelRow = mTunerTable.convertRowIndexToModel(tableRow); + + Tuner tuner = mTunerModel.getTuner(modelRow); + + if(tuner != null) + { + mTunerModel.broadcast(new TunerEvent(tuner, + Event.REQUEST_MAIN_SPECTRAL_DISPLAY)); + } + } + else if(column == TunerModel.SPECTRAL_DISPLAY_NEW) + { + int tableRow = mTunerTable.rowAtPoint(e.getPoint()); + int modelRow = mTunerTable.convertRowIndexToModel(tableRow); + + Tuner tuner = mTunerModel.getTuner(modelRow); + + if(tuner != null) + { + mTunerModel.broadcast(new TunerEvent(tuner, + Event.REQUEST_NEW_SPECTRAL_DISPLAY)); + } + } + } + }); + + TableCellRenderer renderer = new LinkCellRenderer(); + + mTunerTable.getColumnModel().getColumn(5).setCellRenderer(renderer); + mTunerTable.getColumnModel().getColumn(6).setCellRenderer(renderer); + + JScrollPane listScroller = new JScrollPane(mTunerTable); + listScroller.setPreferredSize(new Dimension(400, 20)); + + JScrollPane editorScroller = new JScrollPane(mTunerEditor); + editorScroller.setPreferredSize(new Dimension(400, 80)); + + mSplitPane = new JideSplitPane(); + mSplitPane.setOrientation(JideSplitPane.VERTICAL_SPLIT); + mSplitPane.add(listScroller); + mSplitPane.add(editorScroller); + + add(mSplitPane); + } + + public class LinkCellRenderer extends DefaultTableCellRenderer + { + private static final long serialVersionUID = 1L; + + @Override + public Component getTableCellRendererComponent(JTable table, + Object value, boolean isSelected, boolean hasFocus, int row, + int column) + { + JLabel label = (JLabel)super.getTableCellRendererComponent(table, + value, isSelected, hasFocus, row, column); + + label.setForeground(Color.BLUE.brighter()); + + if(column == TunerModel.SPECTRAL_DISPLAY_MAIN) + { + label.setToolTipText("Show this tuner in the main spectral display"); + } + else if(column == TunerModel.SPECTRAL_DISPLAY_NEW) + { + label.setToolTipText("Show this tuner in a new spectral display"); + } + + return label; + } + } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerController.java index a709bad9..f7a9d022 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerController.java @@ -80,8 +80,7 @@ public class AirspyTunerController extends USBTunerController public static final long FREQUENCY_MAX = 1800000000l; public static final long FREQUENCY_DEFAULT = 101100000; public static final double USABLE_BANDWIDTH_PERCENT = 0.90; - public static final AirspySampleRate DEFAULT_SAMPLE_RATE = - new AirspySampleRate(0, 10000000, "10.00 MHz"); + public static final AirspySampleRate DEFAULT_SAMPLE_RATE = new AirspySampleRate(0, 10000000, "10.00 MHz"); private static final long USB_TIMEOUT_MS = 2000l; //milliseconds private static final byte USB_INTERFACE = (byte) 0x0; @@ -168,7 +167,7 @@ public class AirspyTunerController extends USBTunerController try { - setSampleRate(DEFAULT_SAMPLE_RATE); + setSampleRate(mSampleRates.get(0)); } catch(IllegalArgumentException | LibUsbException | UsbException e) { @@ -292,8 +291,7 @@ public class AirspyTunerController extends USBTunerController } catch(UsbException e) { - throw new SourceException("Couldn't set sample rate [" + - rate.toString() + "]", e); + throw new SourceException("Couldn't set sample rate [" + rate.toString() + "]", e); } try @@ -314,8 +312,7 @@ public class AirspyTunerController extends USBTunerController } catch(Exception e) { - throw new SourceException("Couldn't apply gain settings from " - + "airspy config", e); + throw new SourceException("Couldn't apply gain settings from airspy config", e); } try @@ -389,8 +386,7 @@ public class AirspyTunerController extends USBTunerController * is not supported by the current firmware * @throws UsbException if there was a USB error */ - public void setSampleRate(AirspySampleRate rate) throws - LibUsbException, UsbException, SourceException + public void setSampleRate(AirspySampleRate rate) throws LibUsbException, UsbException, SourceException { if(rate.getRate() != mSampleRate) { @@ -398,8 +394,7 @@ public class AirspyTunerController extends USBTunerController if(result != 1) { - throw new UsbException("Error setting sample rate [" + - rate + "] rate - return value [" + result + "]"); + throw new UsbException("Error setting sample rate [" + rate + "] rate - return value [" + result + "]"); } else { @@ -607,8 +602,7 @@ public class AirspyTunerController extends USBTunerController * Queries the device for available sample rates. Will always provide at * least the default 10 MHz sample rate. */ - private void determineAvailableSampleRates() - throws LibUsbException, UsbException + private void determineAvailableSampleRates() throws LibUsbException, UsbException { mSampleRates.clear(); @@ -629,7 +623,6 @@ public class AirspyTunerController extends USBTunerController for(int x = 0; x < count; x++) { int rate = EndianUtils.readSwappedInteger(rawRates, (x * 4)); - mSampleRates.add(new AirspySampleRate(x, rate, formatSampleRate(rate))); } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerEditor.java index e8ef26c1..51d068f9 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerEditor.java @@ -43,7 +43,6 @@ import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.usb.UsbException; -import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; @@ -55,8 +54,7 @@ public class AirspyTunerEditor extends TunerConfigurationEditor { private static final long serialVersionUID = 1L; - private final static Logger mLog = - LoggerFactory.getLogger(AirspyTunerEditor.class); + private final static Logger mLog = LoggerFactory.getLogger(AirspyTunerEditor.class); private JTextField mConfigurationName; private JButton mTunerInfo; @@ -103,24 +101,6 @@ public class AirspyTunerEditor extends TunerConfigurationEditor return null; } - /** - * Updates the enabled state of the sample rate combo control. - * - * @param enabled state for the sample rate control - */ - @Override - public void setSampleRateControl(boolean enabled) - { - EventQueue.invokeLater(new Runnable() - { - @Override - public void run() - { - mSampleRateCombo.setEnabled(enabled); - } - }); - } - private void init() { setLayout(new MigLayout("fill,wrap 4", "[right][grow,fill][right][grow,fill]", @@ -616,6 +596,21 @@ public class AirspyTunerEditor extends TunerConfigurationEditor return null; } + /** + * Updates the sample rate tooltip according to the tuner controller's lock state. + */ + private void updateSampleRateToolTip() + { + if(mController.isLocked()) + { + mSampleRateCombo.setToolTipText("Sample Rate is locked. Disable decoding channels to unlock."); + } + else + { + mSampleRateCombo.setToolTipText("Select a sample rate for the tuner"); + } + } + /** * Sets all controls to the argument enabled state */ @@ -631,7 +626,13 @@ public class AirspyTunerEditor extends TunerConfigurationEditor mTunerInfo.setEnabled(enabled); } - if(mSampleRateCombo.isEnabled() != enabled) + updateSampleRateToolTip(); + + if(mController.isLocked()) + { + mSampleRateCombo.setEnabled(false); + } + else if(mSampleRateCombo.isEnabled() != enabled) { mSampleRateCombo.setEnabled(enabled); } diff --git a/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfigurationEditor.java b/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfigurationEditor.java index c328c3af..50891f32 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfigurationEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfigurationEditor.java @@ -32,12 +32,4 @@ public abstract class TunerConfigurationEditor extends Editor mProcessors = new ArrayList<>(); + private List mProcessors = new CopyOnWriteArrayList<>(); public FrequencyController(Tunable tunable, long minFrequency, long maxFrequency, double frequencyCorrection) { @@ -95,9 +95,16 @@ public class FrequencyController */ public void setSampleRate(int sampleRate) throws SourceException { - mSampleRate = sampleRate; + if(!mLocked) + { + mSampleRate = sampleRate; - broadcastSampleRateChange(); + broadcastSampleRateChange(); + } + else + { + mLog.warn("Cannot change sample rate while tuner is is LOCKED state."); + } } /** @@ -108,6 +115,17 @@ public class FrequencyController return mSampleRate; } + /** + * Indicates if the specified frequency can be tuned (ie is within min/max frequency) by this controller. + * + * @param frequency to evaluate + * @return true if the frequency falls within the tuning range of this controller + */ + public boolean canTune(long frequency) + { + return getMinimumFrequency() <= frequency && frequency <= getMaximumFrequency(); + } + /** * Get frequency in hertz */ @@ -128,17 +146,6 @@ public class FrequencyController setFrequency(frequency, true); } - /** - * Indicates if the specified frequency can be tuned (ie is within min/max frequency) by this controller. - * - * @param frequency to evaluate - * @return true if the frequency falls within the tuning range of this controller - */ - public boolean canTune(long frequency) - { - return getMinimumFrequency() <= frequency && frequency <= getMaximumFrequency(); - } - /** * Set frequency with optional broadcast of frequency change event. This * method supports changing the frequency correction value without diff --git a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerEditor.java index a2f78262..52f706d0 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerEditor.java @@ -41,7 +41,6 @@ import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.usb.UsbException; -import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; @@ -84,19 +83,6 @@ public class HackRFTunerEditor extends TunerConfigurationEditor return null; } - @Override - public void setSampleRateControl(boolean enabled) - { - EventQueue.invokeLater(new Runnable() - { - @Override - public void run() - { - mComboSampleRate.setEnabled(enabled); - } - }); - } - private void init() { setLayout(new MigLayout("fill,wrap 4", "[right][grow,fill][right][grow,fill]", @@ -297,6 +283,21 @@ public class HackRFTunerEditor extends TunerConfigurationEditor add(mComboVGAGain); } + /** + * Updates the sample rate tooltip according to the tuner controller's lock state. + */ + private void updateSampleRateToolTip() + { + if(mController.isLocked()) + { + mComboSampleRate.setToolTipText("Sample Rate is locked. Disable decoding channels to unlock."); + } + else + { + mComboSampleRate.setToolTipText("Select a sample rate for the tuner"); + } + } + /** * Sets each of the tuner configuration controls to the enabled argument state */ @@ -317,7 +318,13 @@ public class HackRFTunerEditor extends TunerConfigurationEditor mFrequencyCorrection.setEnabled(enabled); } - if(mComboSampleRate.isEnabled() != enabled) + updateSampleRateToolTip(); + + if(mController.isLocked()) + { + mComboSampleRate.setEnabled(false); + } + else if(mComboSampleRate.isEnabled() != enabled) { mComboSampleRate.setEnabled(enabled); } diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerEditor.java index 5bfa9382..b7b2f854 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerEditor.java @@ -45,7 +45,6 @@ import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.usb.UsbException; -import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; @@ -88,19 +87,6 @@ public class E4KTunerEditor extends TunerConfigurationEditor return null; } - @Override - public void setSampleRateControl(boolean enabled) - { - EventQueue.invokeLater(new Runnable() - { - @Override - public void run() - { - mComboSampleRate.setEnabled(enabled); - } - }); - } - private void init() { setLayout(new MigLayout("fill,wrap 4", "[right][grow,fill][right][grow,fill]", @@ -354,6 +340,21 @@ public class E4KTunerEditor extends TunerConfigurationEditor add(mComboEnhanceGain); } + /** + * Updates the sample rate tooltip according to the tuner controller's lock state. + */ + private void updateSampleRateToolTip() + { + if(mController.isLocked()) + { + mComboSampleRate.setToolTipText("Sample Rate is locked. Disable decoding channels to unlock."); + } + else + { + mComboSampleRate.setToolTipText("Select a sample rate for the tuner"); + } + } + /** * Sets each of the tuner configuration controls to the enabled argument state */ @@ -374,7 +375,13 @@ public class E4KTunerEditor extends TunerConfigurationEditor mFrequencyCorrection.setEnabled(enabled); } - if(mComboSampleRate.isEnabled() != enabled) + updateSampleRateToolTip(); + + if(mController.isLocked()) + { + mComboSampleRate.setEnabled(false); + } + else if(mComboSampleRate.isEnabled() != enabled) { mComboSampleRate.setEnabled(enabled); } diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerEditor.java index 1105ffba..acca7f4f 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerEditor.java @@ -45,7 +45,6 @@ import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.usb.UsbException; -import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; @@ -89,19 +88,6 @@ public class R820TTunerEditor extends TunerConfigurationEditor return null; } - @Override - public void setSampleRateControl(boolean enabled) - { - EventQueue.invokeLater(new Runnable() - { - @Override - public void run() - { - mComboSampleRate.setEnabled(enabled); - } - }); - } - private void init() { setLayout(new MigLayout("fill,wrap 4", "[right][grow,fill][right][grow,fill]", @@ -408,6 +394,21 @@ public class R820TTunerEditor extends TunerConfigurationEditor add(mComboVGAGain); } + /** + * Updates the sample rate tooltip according to the tuner controller's lock state. + */ + private void updateSampleRateToolTip() + { + if(mController.isLocked()) + { + mComboSampleRate.setToolTipText("Sample Rate is locked. Disable decoding channels to unlock."); + } + else + { + mComboSampleRate.setToolTipText("Select a sample rate for the tuner"); + } + } + /** * Sets each of the tuner configuration controls to the enabled argument state */ @@ -428,7 +429,13 @@ public class R820TTunerEditor extends TunerConfigurationEditor mFrequencyCorrection.setEnabled(enabled); } - if(mComboSampleRate.isEnabled() != enabled) + updateSampleRateToolTip(); + + if(mController.isLocked()) + { + mComboSampleRate.setEnabled(false); + } + else if(mComboSampleRate.isEnabled() != enabled) { mComboSampleRate.setEnabled(enabled); }