diff --git a/src/main/java/io/github/dsheirer/gui/control/FrequencyTextField.java b/src/main/java/io/github/dsheirer/gui/control/FrequencyTextField.java new file mode 100644 index 000000000..e986f6932 --- /dev/null +++ b/src/main/java/io/github/dsheirer/gui/control/FrequencyTextField.java @@ -0,0 +1,192 @@ +/* + * ***************************************************************************** + * Copyright (C) 2014-2024 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 + * **************************************************************************** + */ + +package io.github.dsheirer.gui.control; + +import java.awt.EventQueue; +import net.miginfocom.swing.MigLayout; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.swing.JFrame; +import javax.swing.JTextField; +import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.DocumentFilter; +import javax.swing.text.PlainDocument; + +/** + * Swing text field control for entering frequency (MHz) values. + */ +public class FrequencyTextField extends JTextField +{ + private static final Logger LOGGER = LoggerFactory.getLogger(FrequencyTextField.class); + private static final String REGEX = "[1-9][0-9]{0,3}(\\.[0-9]{0,6})?"; + private double mMinimum; + private double mMaximum; + + /** + * Constructs an instance + * + * @param minimum allowable frequency value in Hertz + * @param maximum allowable frequency value in Hertz + * @param current frequency value in Hertz + */ + public FrequencyTextField(long minimum, long maximum, long current) + { + super(8); + mMinimum = minimum / 1E6d; + mMaximum = maximum / 1E6d; + + PlainDocument document = (PlainDocument)this.getDocument(); + document.setDocumentFilter(new FrequencyFilter()); + setFrequency(current); + } + + /** + * Current frequency value + * @return frequency in Hertz + */ + public long getFrequency() + { + String value = getText(); + + if(value == null || value.isEmpty()) + { + return 0; + } + + try + { + return (long)(Double.parseDouble(getText()) * 1E6d); + } + catch(Exception e) + { + LOGGER.error("Unable to parse frequency value from text [" + value + "] " + e.getLocalizedMessage()); + } + + return 0; + } + + /** + * Sets the current frequency value + * @param frequency in Hertz + */ + public void setFrequency(long frequency) + { + double frequencyMHz = frequency / 1E6d; + + if(isValid(String.valueOf(frequencyMHz))) + { + setText(String.valueOf(frequencyMHz)); + } + else + { + LOGGER.warn("Can't set frequency [" + frequency + "Hz / " + frequencyMHz + "MHz] with current minimum [" + mMinimum + "MHz] and maximum [" + mMaximum + "MHz] limits"); + } + } + + /** + * Indicates if the value is a valid double value that is between the minimum and maximum extents. + * @param value to test + * @return true if it is valid. + */ + private boolean isValid(String value) + { + if(value == null || value.isEmpty()) + { + return true; + } + + if(value.matches(REGEX)) + { + try + { + double frequency = Double.parseDouble(value); + return mMinimum <= frequency && frequency <= mMaximum; + } + catch(NumberFormatException e) + { + return false; + } + } + + return false; + } + + /** + * Input filter for user entered values. + */ + class FrequencyFilter extends DocumentFilter + { + @Override + public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException + { + Document doc = fb.getDocument(); + StringBuilder sb = new StringBuilder(); + sb.append(doc.getText(0, doc.getLength())); + sb.insert(offset, string); + + if(isValid(sb.toString())) + { + super.insertString(fb, offset, string, attr); + } + } + + @Override + public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException + { + Document doc = fb.getDocument(); + StringBuilder sb = new StringBuilder(); + sb.append(doc.getText(0, doc.getLength())); + sb.replace(offset, offset + length, text); + + if(isValid(sb.toString())) + { + super.replace(fb, offset, length, text, attrs); + } + } + + @Override + public void remove(FilterBypass fb, int offset, int length) throws BadLocationException + { + Document doc = fb.getDocument(); + StringBuilder sb = new StringBuilder(); + sb.append(doc.getText(0, doc.getLength())); + sb.delete(offset, offset + length); + + if(isValid(sb.toString())) + { + super.remove(fb, offset, length); + } + } + } + + public static void main(String[] args) + { + JFrame frame = new JFrame("Frequency Control Test"); + frame.setSize(300, 200); + FrequencyTextField ftf = new FrequencyTextField(20, 2_000_000_000, 101_100_000); + frame.setLayout(new MigLayout()); + frame.add(ftf); + + EventQueue.invokeLater(() -> frame.setVisible(true)); + } +} diff --git a/src/main/java/io/github/dsheirer/gui/control/IntegerFormatter.java b/src/main/java/io/github/dsheirer/gui/control/IntegerFormatter.java index 9d522e1dc..1e013e23b 100644 --- a/src/main/java/io/github/dsheirer/gui/control/IntegerFormatter.java +++ b/src/main/java/io/github/dsheirer/gui/control/IntegerFormatter.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2020 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -19,20 +19,18 @@ package io.github.dsheirer.gui.control; -import io.github.dsheirer.gui.playlist.alias.AliasItemEditor; +import java.util.function.UnaryOperator; import javafx.scene.control.TextFormatter; import javafx.util.converter.IntegerStringConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.function.UnaryOperator; - /** * Text formatter for integer values that constrains values to specified minimum and maximum valid values. */ public class IntegerFormatter extends TextFormatter { - private static final Logger mLog = LoggerFactory.getLogger(AliasItemEditor.class); + private static final Logger mLog = LoggerFactory.getLogger(IntegerFormatter.class); /** * Constructs an instance 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 7e00f8531..cd5bbf770 100644 --- a/src/main/java/io/github/dsheirer/gui/control/JFrequencyControl.java +++ b/src/main/java/io/github/dsheirer/gui/control/JFrequencyControl.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -434,8 +434,7 @@ private void set(long amount, boolean fireChangeEvent) if(se instanceof InvalidFrequencyException ife) { - JOptionPane.showMessageDialog(this, "Frequency [" + ife.getInvalidFrequency() + - "] exceeds the frequency limit [" + ife.getValidFrequency() + "] for this tuner."); + JOptionPane.showMessageDialog(this, ife.getMessage() + " for this tuner."); } } } diff --git a/src/main/java/io/github/dsheirer/gui/control/LongFormatter.java b/src/main/java/io/github/dsheirer/gui/control/LongFormatter.java new file mode 100644 index 000000000..94171233a --- /dev/null +++ b/src/main/java/io/github/dsheirer/gui/control/LongFormatter.java @@ -0,0 +1,111 @@ +/* + * ***************************************************************************** + * Copyright (C) 2014-2024 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 + * **************************************************************************** + */ + +package io.github.dsheirer.gui.control; + +import java.util.function.UnaryOperator; +import javafx.scene.control.TextFormatter; +import javafx.util.converter.LongStringConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Text formatter for long values that constrains values to specified minimum and maximum valid values. + */ +public class LongFormatter extends TextFormatter +{ + private static final Logger mLog = LoggerFactory.getLogger(LongFormatter.class); + + /** + * Constructs an instance + * @param minimum allowed value + * @param maximum allowed value + */ + public LongFormatter(int minimum, int maximum) + { + super(new LongStringConverter(), null, new LongFilter(minimum, maximum)); + } + + /** + * Formatted text change filter that only allows hexadecimal characters where the converted decimal value + * is also constrained within minimum and maximum valid values. + */ + public static class LongFilter implements UnaryOperator + { + private String DECIMAL_REGEX = "\\-?[0-9].*"; + private int mMinimum; + private int mMaximum; + + /** + * Constructs an instance + * @param minimum value + * @param maximum value + */ + public LongFilter(int minimum, int maximum) + { + mMinimum = minimum; + mMaximum = maximum; + } + + /** + * Indicates if the value argument is parsable as an integer, or is empty or null. + */ + private boolean isValid(String value) + { + if(value == null || value.isEmpty()) + { + return true; + } + + try + { + long parsed = Long.parseLong(value); + return mMinimum <= parsed && parsed <= mMaximum; + } + catch(Exception e) + { + //no-op + } + + return false; + } + + @Override + public Change apply(Change change) + { + //Only validate if the user added text to the control. Otherwise, allow it to go through + if(change.getText() != null) + { + String updatedText = change.getControlNewText(); + + if(updatedText == null || updatedText.isEmpty()) + { + return change; + } + + if(!updatedText.matches(DECIMAL_REGEX) || !isValid(updatedText)) + { + return null; + } + } + + return change; + } + } +} diff --git a/src/main/java/io/github/dsheirer/source/InvalidFrequencyException.java b/src/main/java/io/github/dsheirer/source/InvalidFrequencyException.java index bc30a29a3..fcaebaa9e 100644 --- a/src/main/java/io/github/dsheirer/source/InvalidFrequencyException.java +++ b/src/main/java/io/github/dsheirer/source/InvalidFrequencyException.java @@ -1,6 +1,6 @@ -/******************************************************************************* - * sdrtrunk - * Copyright (C) 2014-2016 Dennis Sheirer +/* + * ***************************************************************************** + * Copyright (C) 2014-2024 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 @@ -14,8 +14,8 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see - * - ******************************************************************************/ + * **************************************************************************** + */ package io.github.dsheirer.source; public class InvalidFrequencyException extends SourceException @@ -54,11 +54,4 @@ public long getValidFrequency() { return mValidFrequency; } - - @Override - public String getMessage() - { - return super.getMessage() + " Invalid Frequency: " + getInvalidFrequency() + - " - current valid frequency:" + getValidFrequency(); - } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerController.java b/src/main/java/io/github/dsheirer/source/tuner/TunerController.java index 46c8dde4c..88816da9a 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerController.java @@ -74,6 +74,17 @@ public TunerController(ITunerErrorListener tunerErrorListener) mFrequencyErrorCorrectionManager = new FrequencyErrorCorrectionManager(this); } + /** + * Updates the frequency controller with the new minimum and maximum values. + * @param minimum frequency Hertz + * @param maximum frequency Hertz + */ + public void setFrequencyExtents(long minimum, long maximum) + { + mFrequencyController.setMinimumFrequency(minimum); + mFrequencyController.setMaximumFrequency(maximum); + } + /** * 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 @@ -175,7 +186,31 @@ public Listener getSourceEventListener() */ public void apply(TunerConfiguration config) throws SourceException { - setFrequency(config.getFrequency()); + //Set the frequency from the config. If the config frequency generates an error, try setting the default + //frequency before we give up on the tuner as having an error. + try + { + setFrequency(config.getFrequency()); + } + catch(Exception e) + { + mLog.warn("Unable to restore previous frequency [" + config.getFrequency() + "] trying default frequency"); + if(config.getFrequency() != TunerConfiguration.DEFAULT_FREQUENCY) + { + setFrequency(TunerConfiguration.DEFAULT_FREQUENCY); + //If we're successful to here, update the config with the default frequency. + config.setFrequency(TunerConfiguration.DEFAULT_FREQUENCY); + } + } + + if(config.getMinimumFrequency() > 0) + { + setMinimumFrequency(config.getMinimumFrequency()); + } + if(config.getMaximumFrequency() > 0) + { + setMaximumFrequency(config.getMaximumFrequency()); + } setFrequencyCorrection(config.getFrequencyCorrection()); getFrequencyErrorCorrectionManager().setEnabled(config.getAutoPPMCorrectionEnabled()); } diff --git a/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerConfiguration.java index 052480287..2aac26c45 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerConfiguration.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -38,6 +38,7 @@ public class AirspyTunerConfiguration extends TunerConfiguration */ public AirspyTunerConfiguration() { + super(AirspyTunerController.MINIMUM_TUNABLE_FREQUENCY_HZ, AirspyTunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ); } @Override 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 7c74f9980..0faa1171a 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 @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -59,8 +59,8 @@ public class AirspyTunerController extends USBTunerController public static final int IF_GAIN_MIN = 0; public static final int IF_GAIN_MAX = 15; public static final int IF_GAIN_DEFAULT = 9; - public static final long FREQUENCY_MIN = 24000000l; - public static final long FREQUENCY_MAX = 1800000000l; + public static final long MINIMUM_TUNABLE_FREQUENCY_HZ = 24000000l; + public static final long MAXIMUM_TUNABLE_FREQUENCY_HZ = 1800000000l; public static final long FREQUENCY_DEFAULT = 101100000; public static final double USABLE_BANDWIDTH_PERCENT = 0.90; private static final long USB_TIMEOUT_MS = 2000l; //milliseconds @@ -82,7 +82,7 @@ public class AirspyTunerController extends USBTunerController */ public AirspyTunerController(int bus, String portAddress, ITunerErrorListener tunerErrorListener) { - super(bus, portAddress, FREQUENCY_MIN, FREQUENCY_MAX, 0, USABLE_BANDWIDTH_PERCENT, tunerErrorListener); + super(bus, portAddress, MINIMUM_TUNABLE_FREQUENCY_HZ, MAXIMUM_TUNABLE_FREQUENCY_HZ, 0, USABLE_BANDWIDTH_PERCENT, tunerErrorListener); } @Override @@ -233,7 +233,7 @@ public long getTunedFrequency() throws SourceException @Override public synchronized void setTunedFrequency(long frequency) throws SourceException { - if(FREQUENCY_MIN <= frequency && frequency <= FREQUENCY_MAX) + if(MINIMUM_TUNABLE_FREQUENCY_HZ <= frequency && frequency <= MAXIMUM_TUNABLE_FREQUENCY_HZ) { ByteBuffer buffer = ByteBuffer.allocateDirect(4); buffer.order(ByteOrder.LITTLE_ENDIAN); @@ -252,7 +252,7 @@ public synchronized void setTunedFrequency(long frequency) throws SourceExceptio } else { - throw new SourceException("Frequency [" + frequency + "] outside " + "of tunable range " + FREQUENCY_MIN + "-" + FREQUENCY_MAX); + throw new SourceException("Frequency [" + frequency + "] outside " + "of tunable range " + MINIMUM_TUNABLE_FREQUENCY_HZ + "-" + MAXIMUM_TUNABLE_FREQUENCY_HZ); } } 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 d1f721882..ed32e804e 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 @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -80,6 +80,18 @@ public AirspyTunerEditor(UserPreferences userPreferences, TunerManager tunerMana tunerStatusUpdated(); } + @Override + public long getMinimumTunableFrequency() + { + return AirspyTunerController.MINIMUM_TUNABLE_FREQUENCY_HZ; + } + + @Override + public long getMaximumTunableFrequency() + { + return AirspyTunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ; + } + @Override protected void tunerStatusUpdated() { @@ -472,6 +484,10 @@ public void actionPerformed(ActionEvent e) try { getTuner().getController().setSampleRate(rate); + + //Adjust the min/max values for the sample rate. + adjustForSampleRate(rate.getRate()); + save(); } catch(Exception e1) @@ -578,6 +594,8 @@ public void save() if(hasConfiguration() && !isLoading()) { getConfiguration().setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); getConfiguration().setFrequencyCorrection(value); getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); diff --git a/src/main/java/io/github/dsheirer/source/tuner/airspy/hf/AirspyHfTunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/airspy/hf/AirspyHfTunerConfiguration.java index eb77bdf38..e98f115c6 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/airspy/hf/AirspyHfTunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/airspy/hf/AirspyHfTunerConfiguration.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -38,6 +38,7 @@ public class AirspyHfTunerConfiguration extends TunerConfiguration */ public AirspyHfTunerConfiguration() { + super(AirspyHfTunerController.MINIMUM_TUNABLE_FREQUENCY_HZ, AirspyHfTunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ); } /** diff --git a/src/main/java/io/github/dsheirer/source/tuner/airspy/hf/AirspyHfTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/airspy/hf/AirspyHfTunerController.java index 3fbfcb791..5b380d374 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/airspy/hf/AirspyHfTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/airspy/hf/AirspyHfTunerController.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -46,8 +46,8 @@ public class AirspyHfTunerController extends USBTunerController private static final AirspyHfSampleRate DEFAULT_SAMPLE_RATE = new AirspyHfSampleRate(0, 768_000, false); private static final long IF_SHIFT_LIF = 0; private static final long IF_SHIFT_ZIF = 5_000; - private static final long MINIMUM_FREQUENCY_HZ = 500_000; - private static final long MAXIMUM_FREQUENCY_HZ = 260_000_000; + public static final long MINIMUM_TUNABLE_FREQUENCY_HZ = 500_000; + public static final long MAXIMUM_TUNABLE_FREQUENCY_HZ = 260_000_000; private static final byte REQUEST_TYPE_IN = LibUsb.ENDPOINT_IN | LibUsb.REQUEST_TYPE_VENDOR | LibUsb.RECIPIENT_DEVICE; private static final byte REQUEST_TYPE_OUT = LibUsb.ENDPOINT_OUT | LibUsb.REQUEST_TYPE_VENDOR | LibUsb.RECIPIENT_DEVICE; private static final int BUFFER_SAMPLE_COUNT = 1024; @@ -75,8 +75,8 @@ public class AirspyHfTunerController extends USBTunerController public AirspyHfTunerController(int bus, String portAddress, ITunerErrorListener tunerErrorListener) { super(bus, portAddress, tunerErrorListener); - setMinimumFrequency(MINIMUM_FREQUENCY_HZ); - setMaximumFrequency(MAXIMUM_FREQUENCY_HZ); + setMinimumFrequency(MINIMUM_TUNABLE_FREQUENCY_HZ); + setMaximumFrequency(MAXIMUM_TUNABLE_FREQUENCY_HZ); setUsableBandwidthPercentage(.9); //90% usable after filter rolloff setMiddleUnusableHalfBandwidth(3000); } diff --git a/src/main/java/io/github/dsheirer/source/tuner/airspy/hf/AirspyHfTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/airspy/hf/AirspyHfTunerEditor.java index 14155350f..850215c07 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/airspy/hf/AirspyHfTunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/airspy/hf/AirspyHfTunerEditor.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -62,6 +62,18 @@ public AirspyHfTunerEditor(UserPreferences userPreferences, TunerManager tunerMa tunerStatusUpdated(); } + @Override + public long getMinimumTunableFrequency() + { + return AirspyHfTunerController.MINIMUM_TUNABLE_FREQUENCY_HZ; + } + + @Override + public long getMaximumTunableFrequency() + { + return AirspyHfTunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ; + } + private void init() { setLayout(new MigLayout("fill,wrap 3", "[right][grow,fill][fill]", @@ -102,6 +114,8 @@ protected void save() if(hasConfiguration() && !isLoading()) { getConfiguration().setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); getConfiguration().setFrequencyCorrection(value); getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); @@ -216,6 +230,10 @@ private JComboBox getSampleRateCombo() try { getTuner().getController().setSampleRate(sampleRate); + + //Adjust the min/max values for the sample rate. + adjustForSampleRate(sampleRate.getSampleRate()); + save(); } catch(SourceException se) diff --git a/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfiguration.java index f2fb8fd59..160c5cf6e 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/configuration/TunerConfiguration.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -56,16 +56,21 @@ @JacksonXmlRootElement(localName = "tuner_configuration") public abstract class TunerConfiguration { + public static final long DEFAULT_FREQUENCY = 101_100_000; private String mUniqueID; - private long mFrequency = 101100000; + private long mFrequency = DEFAULT_FREQUENCY; + private long mMinimumFrequency; + private long mMaximumFrequency; private double mFrequencyCorrection = 0.0d; private boolean mAutoPPMCorrection = true; /** * Default constructor to support Jackson */ - public TunerConfiguration() + public TunerConfiguration(long minimumFrequency, long maximumFrequency) { + mMinimumFrequency = minimumFrequency; + mMaximumFrequency = maximumFrequency; } /** @@ -123,7 +128,7 @@ public void setFrequencyCorrection(double value) /** * Indicates if automatic correction of PPM from measured frequency error is enabled/disabled. * - * @return true if auto-correction is enabled. + * @return true if autocorrection is enabled. */ @JacksonXmlProperty(isAttribute = true, localName = "auto_ppm_correction_enabled") public boolean getAutoPPMCorrectionEnabled() @@ -140,4 +145,42 @@ public void setAutoPPMCorrectionEnabled(boolean enabled) { mAutoPPMCorrection = enabled; } + + /** + * Minimum tunable frequency. + * @return minimum frequency + */ + @JacksonXmlProperty(isAttribute = true, localName = "min_frequency") + public long getMinimumFrequency() + { + return mMinimumFrequency; + } + + /** + * Sets the minimum tunable frequency + * @param minimumFrequency to set + */ + public void setMinimumFrequency(long minimumFrequency) + { + mMinimumFrequency = minimumFrequency; + } + + /** + * Maximum tunable frequency. + * @return maximum frequency + */ + @JacksonXmlProperty(isAttribute = true, localName = "max_frequency") + public long getMaximumFrequency() + { + return mMaximumFrequency; + } + + /** + * Sets the maximum tunable frequency + * @param maximumFrequency to set + */ + public void setMaximumFrequency(long maximumFrequency) + { + mMaximumFrequency = maximumFrequency; + } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/fcd/proV1/FCD1TunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/fcd/proV1/FCD1TunerConfiguration.java index b6afe8e9b..73927d042 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/fcd/proV1/FCD1TunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/fcd/proV1/FCD1TunerConfiguration.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -41,6 +41,7 @@ public class FCD1TunerConfiguration extends TunerConfiguration */ public FCD1TunerConfiguration() { + super(FCD1TunerController.MINIMUM_TUNABLE_FREQUENCY_HZ, FCD1TunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ); } public FCD1TunerConfiguration(String uniqueID) diff --git a/src/main/java/io/github/dsheirer/source/tuner/fcd/proV1/FCD1TunerController.java b/src/main/java/io/github/dsheirer/source/tuner/fcd/proV1/FCD1TunerController.java index 49bde78e9..c5238c24e 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/fcd/proV1/FCD1TunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/fcd/proV1/FCD1TunerController.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -26,14 +26,14 @@ import io.github.dsheirer.source.tuner.configuration.TunerConfiguration; import io.github.dsheirer.source.tuner.fcd.FCDCommand; import io.github.dsheirer.source.tuner.fcd.FCDTunerController; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.sound.sampled.TargetDataLine; import javax.usb.UsbClaimException; import javax.usb.UsbException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; /** * Funcube Dongle Pro tuner controller. Combines USB HID control with Audio Mixer data streaming interface. @@ -41,8 +41,8 @@ public class FCD1TunerController extends FCDTunerController { private final static Logger mLog = LoggerFactory.getLogger(FCD1TunerController.class); - public static final int MINIMUM_TUNABLE_FREQUENCY = 64000000; - public static final int MAXIMUM_TUNABLE_FREQUENCY = 1700000000; + public static final int MINIMUM_TUNABLE_FREQUENCY_HZ = 64000000; + public static final int MAXIMUM_TUNABLE_FREQUENCY_HZ = 1700000000; public static final int SAMPLE_RATE = 96000; private double mDCCorrectionInPhase = 0.0; private double mDCCorrectionQuadrature = 0.0; @@ -61,8 +61,8 @@ public class FCD1TunerController extends FCDTunerController */ public FCD1TunerController(TargetDataLine mixerTDL, int bus, String portAddress, ITunerErrorListener tunerErrorListener) { - super(MixerTunerType.FUNCUBE_DONGLE_PRO, mixerTDL, bus, portAddress, MINIMUM_TUNABLE_FREQUENCY, - MAXIMUM_TUNABLE_FREQUENCY, tunerErrorListener); + super(MixerTunerType.FUNCUBE_DONGLE_PRO, mixerTDL, bus, portAddress, MINIMUM_TUNABLE_FREQUENCY_HZ, + MAXIMUM_TUNABLE_FREQUENCY_HZ, tunerErrorListener); } protected void deviceStart() throws SourceException diff --git a/src/main/java/io/github/dsheirer/source/tuner/fcd/proV1/FCD1TunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/fcd/proV1/FCD1TunerEditor.java index 81da4b684..8b480b5a8 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/fcd/proV1/FCD1TunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/fcd/proV1/FCD1TunerEditor.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -80,6 +80,18 @@ private FCD1TunerController getController() return null; } + @Override + public long getMinimumTunableFrequency() + { + return FCD1TunerController.MINIMUM_TUNABLE_FREQUENCY_HZ; + } + + @Override + public long getMaximumTunableFrequency() + { + return FCD1TunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ; + } + @Override protected void tunerStatusUpdated() { @@ -366,6 +378,8 @@ public void save() if(hasConfiguration() && !isLoading()) { getConfiguration().setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); getConfiguration().setFrequencyCorrection(value); getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); diff --git a/src/main/java/io/github/dsheirer/source/tuner/fcd/proplusV2/FCD2TunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/fcd/proplusV2/FCD2TunerConfiguration.java index 5e237ef05..70c0ad703 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/fcd/proplusV2/FCD2TunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/fcd/proplusV2/FCD2TunerConfiguration.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -33,6 +33,7 @@ public class FCD2TunerConfiguration extends TunerConfiguration */ public FCD2TunerConfiguration() { + super(FCD2TunerController.MINIMUM_TUNABLE_FREQUENCY_HZ, FCD2TunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ); } @JsonIgnore diff --git a/src/main/java/io/github/dsheirer/source/tuner/fcd/proplusV2/FCD2TunerController.java b/src/main/java/io/github/dsheirer/source/tuner/fcd/proplusV2/FCD2TunerController.java index 2a705fc9a..1fe2bfa1c 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/fcd/proplusV2/FCD2TunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/fcd/proplusV2/FCD2TunerController.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -26,12 +26,12 @@ import io.github.dsheirer.source.tuner.configuration.TunerConfiguration; import io.github.dsheirer.source.tuner.fcd.FCDCommand; import io.github.dsheirer.source.tuner.fcd.FCDTunerController; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.sound.sampled.TargetDataLine; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; /** * Funcube Dongle Pro Plus tuner controller. Combines USB HID control with Audio Mixer for data streaming. @@ -40,8 +40,8 @@ public class FCD2TunerController extends FCDTunerController { private final static Logger mLog = LoggerFactory.getLogger(FCD2TunerController.class); - public static final int MINIMUM_TUNABLE_FREQUENCY = 150000; - public static final int MAXIMUM_TUNABLE_FREQUENCY = 2050000000; + public static final int MINIMUM_TUNABLE_FREQUENCY_HZ = 150000; + public static final int MAXIMUM_TUNABLE_FREQUENCY_HZ = 2050000000; public static final int SAMPLE_RATE = 192000; /** @@ -53,8 +53,8 @@ public class FCD2TunerController extends FCDTunerController */ public FCD2TunerController(TargetDataLine mixerTDL, int bus, String portAddress, ITunerErrorListener tunerErrorListener) { - super(MixerTunerType.FUNCUBE_DONGLE_PRO_PLUS, mixerTDL, bus, portAddress, MINIMUM_TUNABLE_FREQUENCY, - MAXIMUM_TUNABLE_FREQUENCY, tunerErrorListener); + super(MixerTunerType.FUNCUBE_DONGLE_PRO_PLUS, mixerTDL, bus, portAddress, MINIMUM_TUNABLE_FREQUENCY_HZ, + MAXIMUM_TUNABLE_FREQUENCY_HZ, tunerErrorListener); } protected void deviceStart() throws SourceException diff --git a/src/main/java/io/github/dsheirer/source/tuner/fcd/proplusV2/FCD2TunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/fcd/proplusV2/FCD2TunerEditor.java index 39709aa4e..d5616ab18 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/fcd/proplusV2/FCD2TunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/fcd/proplusV2/FCD2TunerEditor.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -69,6 +69,18 @@ private FCD2TunerController getController() return null; } + @Override + public long getMinimumTunableFrequency() + { + return FCD2TunerController.MINIMUM_TUNABLE_FREQUENCY_HZ; + } + + @Override + public long getMaximumTunableFrequency() + { + return FCD2TunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ; + } + @Override protected void tunerStatusUpdated() { @@ -236,6 +248,8 @@ public void save() if(hasConfiguration() && !isLoading()) { getConfiguration().setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); getConfiguration().setFrequencyCorrection(value); getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); diff --git a/src/main/java/io/github/dsheirer/source/tuner/frequency/FrequencyController.java b/src/main/java/io/github/dsheirer/source/tuner/frequency/FrequencyController.java index 80ef95615..ca539d140 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/frequency/FrequencyController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/frequency/FrequencyController.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -182,21 +182,20 @@ public void setFrequency(long frequency) throws SourceException */ private void setFrequency(long frequency, boolean broadcastChange) throws SourceException { - long tunedFrequency = getTunedFrequency(frequency); - - if(tunedFrequency < mMinimumFrequency) + if(frequency < mMinimumFrequency) { - throw new InvalidFrequencyException("Requested frequency not valid", frequency, mMinimumFrequency); + throw new InvalidFrequencyException("Frequency [" + frequency + "] is below the minimum [" + + mMinimumFrequency + "]", frequency, mMinimumFrequency); } - if(tunedFrequency > mMaximumFrequency) + if(frequency > mMaximumFrequency) { - throw new InvalidFrequencyException("Requested frequency not valid", frequency, mMaximumFrequency); + throw new InvalidFrequencyException("Frequency [" + frequency + "] is above the maximum [" + + mMaximumFrequency + "]", frequency, mMaximumFrequency); } mFrequency = frequency; - - mTunedFrequency = tunedFrequency; + mTunedFrequency = getTunedFrequency(frequency); if(mTunable != null) { @@ -230,7 +229,7 @@ public long getMinimumFrequency() */ public void setMinimumFrequency(long minimum) { - mMaximumFrequency = minimum; + mMinimumFrequency = minimum; } /** @@ -252,15 +251,12 @@ public void setMaximumFrequency(long maximum) } /** - * Calculate the tuned frequency by adding frequency correction to the - * corrected frequency. - * + * Calculate the tuned frequency by adding frequency correction to the corrected frequency. * @param correctedFrequency */ private long getTunedFrequency(long correctedFrequency) { - return (long)((double)correctedFrequency / - (1.0 + (mFrequencyCorrection / 1000000.0))); + return (long)((double)correctedFrequency / (1.0 + (mFrequencyCorrection / 1000000.0))); } /** diff --git a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerConfiguration.java index a9e328e53..9213577cf 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerConfiguration.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2024 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,6 +39,7 @@ public class HackRFTunerConfiguration extends TunerConfiguration */ public HackRFTunerConfiguration() { + super(HackRFTunerController.MINIMUM_TUNABLE_FREQUENCY_HZ, HackRFTunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ); } public HackRFTunerConfiguration(String uniqueID) diff --git a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerController.java index 3d20b81a6..55e3313d8 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerController.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -47,8 +47,8 @@ public class HackRFTunerController extends USBTunerController public static final byte REQUEST_TYPE_IN = (byte)(LibUsb.ENDPOINT_IN | LibUsb.REQUEST_TYPE_VENDOR | LibUsb.RECIPIENT_DEVICE); public static final byte REQUEST_TYPE_OUT = (byte)(LibUsb.ENDPOINT_OUT | LibUsb.REQUEST_TYPE_VENDOR | LibUsb.RECIPIENT_DEVICE); - public static final long MINIMUM_TUNABLE_FREQUENCY = 10000000l; - public static final long MAXIMUM_TUNABLE_FREQUENCY = 6000000000l; + public static final long MINIMUM_TUNABLE_FREQUENCY_HZ = 10000000l; + public static final long MAXIMUM_TUNABLE_FREQUENCY_HZ = 6000000000l; public static final long DEFAULT_FREQUENCY = 101100000; public static final double USABLE_BANDWIDTH = 0.90; public static final int DC_HALF_BANDWIDTH = 5000; @@ -64,7 +64,7 @@ public class HackRFTunerController extends USBTunerController */ public HackRFTunerController(int bus, String portAddress, ITunerErrorListener tunerErrorListener) { - super(bus, portAddress, MINIMUM_TUNABLE_FREQUENCY, MAXIMUM_TUNABLE_FREQUENCY, DC_HALF_BANDWIDTH, USABLE_BANDWIDTH, + super(bus, portAddress, MINIMUM_TUNABLE_FREQUENCY_HZ, MAXIMUM_TUNABLE_FREQUENCY_HZ, DC_HALF_BANDWIDTH, USABLE_BANDWIDTH, tunerErrorListener); } 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 388ff63c7..4190e677c 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 @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -65,6 +65,18 @@ public HackRFTunerEditor(UserPreferences userPreferences, TunerManager tunerMana tunerStatusUpdated(); } + @Override + public long getMinimumTunableFrequency() + { + return HackRFTunerController.MINIMUM_TUNABLE_FREQUENCY_HZ; + } + + @Override + public long getMaximumTunableFrequency() + { + return HackRFTunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ; + } + private void init() { setLayout(new MigLayout("fill,wrap 3", "[right][grow,fill][fill]", @@ -258,6 +270,8 @@ private JComboBox getSampleRateCombo() try { getTuner().getController().setSampleRate(sampleRate); + //Adjust the min/max values for the sample rate. + adjustForSampleRate(sampleRate.getRate()); save(); } catch(SourceException | UsbException e2) @@ -400,6 +414,8 @@ public void save() if(hasConfiguration() && !isLoading()) { getConfiguration().setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); getConfiguration().setFrequencyCorrection(value); getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); diff --git a/src/main/java/io/github/dsheirer/source/tuner/manager/DiscoveredTuner.java b/src/main/java/io/github/dsheirer/source/tuner/manager/DiscoveredTuner.java index 1cade643e..d7e2bc883 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/manager/DiscoveredTuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/manager/DiscoveredTuner.java @@ -215,7 +215,7 @@ public void setTunerConfiguration(TunerConfiguration tunerConfiguration) catch(SourceException se) { mLog.error("Error applying tuner configuration [" + mTunerConfiguration.getClass() + - "] to discovered tuner [" + getId() + "}"); + "] to discovered tuner [" + getId() + "}", se); } } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerConfiguration.java index a90cb7f09..aaa4f646e 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerConfiguration.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2024 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,6 +39,7 @@ public class RecordingTunerConfiguration extends TunerConfiguration */ public RecordingTunerConfiguration() { + super(0, Long.MAX_VALUE); } /** @@ -47,6 +48,7 @@ public RecordingTunerConfiguration() */ public RecordingTunerConfiguration(String uniqueId) { + this(); setUniqueID(uniqueId); } diff --git a/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerEditor.java index daabf2652..5d0a588d4 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTunerEditor.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -57,6 +57,18 @@ public void setTunerLockState(boolean locked) getFrequencyPanel().updateControls(); } + @Override + public long getMinimumTunableFrequency() + { + return 0; + } + + @Override + public long getMaximumTunableFrequency() + { + return Long.MAX_VALUE; + } + @Override protected void tunerStatusUpdated() { @@ -125,6 +137,8 @@ public void save() { RecordingTunerConfiguration config = getConfiguration(); config.setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); saveConfiguration(); } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832TunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832TunerConfiguration.java index 587f2064c..e115553e6 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832TunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832TunerConfiguration.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -46,9 +46,12 @@ public abstract class RTL2832TunerConfiguration extends TunerConfiguration /** * Default constructor to support Jackson + * @param minimumFrequency tunable + * @param maximumFrequency tunable */ - public RTL2832TunerConfiguration() + public RTL2832TunerConfiguration(long minimumFrequency, long maximumFrequency) { + super(minimumFrequency, maximumFrequency); } public RTL2832TunerConfiguration(String uniqueID) diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832UnknownTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832UnknownTunerEditor.java index c706c3b66..219958bc2 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832UnknownTunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832UnknownTunerEditor.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -22,6 +22,7 @@ import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.source.tuner.manager.DiscoveredTuner; import io.github.dsheirer.source.tuner.manager.TunerManager; +import io.github.dsheirer.source.tuner.rtl.r8x.R8xEmbeddedTuner; import io.github.dsheirer.source.tuner.ui.TunerEditor; import net.miginfocom.swing.MigLayout; @@ -63,13 +64,20 @@ private void init() add(new JSeparator(), "span,growx,push"); -// add(new JLabel("Frequency (MHz):")); -// add(getFrequencyPanel(), "wrap"); -// -// add(new JLabel("Sample Rate:")); -//// add(getSampleRateCombo(), "wrap"); -// -// add(new JSeparator(), "span,growx,push"); + } + + @Override + public long getMinimumTunableFrequency() + { + //Bogus value. + return R8xEmbeddedTuner.MINIMUM_TUNABLE_FREQUENCY_HZ; + } + + @Override + public long getMaximumTunableFrequency() + { + //Bogus value. + return R8xEmbeddedTuner.MAXIMUM_TUNABLE_FREQUENCY_HZ; } @Override diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KEmbeddedTuner.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KEmbeddedTuner.java index dc235d5c4..5ad54178e 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KEmbeddedTuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KEmbeddedTuner.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -23,13 +23,13 @@ import io.github.dsheirer.source.tuner.configuration.TunerConfiguration; import io.github.dsheirer.source.tuner.rtl.EmbeddedTuner; import io.github.dsheirer.source.tuner.rtl.RTL2832TunerController; +import java.util.EnumSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.usb4java.LibUsb; import org.usb4java.LibUsbException; import javax.usb.UsbException; -import java.util.EnumSet; /** * Elonic E4000 Tuner @@ -38,8 +38,8 @@ public class E4KEmbeddedTuner extends EmbeddedTuner { private final static Logger mLog = LoggerFactory.getLogger(E4KEmbeddedTuner.class); - public static final long MINIMUM_SUPPORTED_FREQUENCY = 52000000; - public static final long MAXIMUM_SUPPORTED_FREQUENCY = 2200000000l; + public static final long MINIMUM_TUNABLE_FREQUENCY_HZ = 52000000; + public static final long MAXIMUM_TUNABLE_FREQUENCY_HZ = 2200000000l; public static final double USABLE_BANDWIDTH_PERCENT = 0.95; public static final int DC_SPIKE_AVOID_BUFFER = 15000; @@ -99,13 +99,13 @@ public TunerType getTunerType() @Override public long getMinimumFrequencySupported() { - return MINIMUM_SUPPORTED_FREQUENCY; + return MINIMUM_TUNABLE_FREQUENCY_HZ; } @Override public long getMaximumFrequencySupported() { - return MAXIMUM_SUPPORTED_FREQUENCY; + return MAXIMUM_TUNABLE_FREQUENCY_HZ; } @Override @@ -1039,7 +1039,7 @@ public enum RFFilter NO_FILTER(0, 0, 0), //VHF-II Filters (0.0 - 140.0) Optimal (64-108) - LP268(0, MINIMUM_SUPPORTED_FREQUENCY, 86_000_000), //Values 0 - 7 are all the same + LP268(0, MINIMUM_TUNABLE_FREQUENCY_HZ, 86_000_000), //Values 0 - 7 are all the same LP299(8, 86_000_000, 140_000_000), //Values 8 - 15 are all the same //VHF-III Filters (140.0 - 350.0) Optimal (170-240) @@ -1080,7 +1080,7 @@ public enum RFFilter BP1680(12, 1670000000, 1690000000), BP1700(13, 1690000000, 1710000000), BP1720(14, 1710000000, 1735000000), - BP1750(15, 1735000000, MAXIMUM_SUPPORTED_FREQUENCY); + BP1750(15, 1735000000, MAXIMUM_TUNABLE_FREQUENCY_HZ); private int mValue; private long mMinFrequency; diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerConfiguration.java index 74970eab8..0df9dedbf 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerConfiguration.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -42,6 +42,7 @@ public class E4KTunerConfiguration extends RTL2832TunerConfiguration */ public E4KTunerConfiguration() { + super(E4KEmbeddedTuner.MINIMUM_TUNABLE_FREQUENCY_HZ, E4KEmbeddedTuner.MAXIMUM_TUNABLE_FREQUENCY_HZ); } @JsonIgnore 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 f08528439..35fdb9db6 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 @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -73,6 +73,18 @@ public E4KTunerEditor(UserPreferences userPreferences, TunerManager tunerManager tunerStatusUpdated(); } + @Override + public long getMinimumTunableFrequency() + { + return E4KEmbeddedTuner.MINIMUM_TUNABLE_FREQUENCY_HZ; + } + + @Override + public long getMaximumTunableFrequency() + { + return E4KEmbeddedTuner.MAXIMUM_TUNABLE_FREQUENCY_HZ; + } + /** * Access to the E4000 embedded tuner * @return E4000 tuner if there is a tuner, or null otherwise @@ -373,6 +385,8 @@ private JComboBox getSampleRateCombo() try { getTuner().getController().setSampleRate(sampleRate); + //Adjust the min/max values for the sample rate. + adjustForSampleRate(sampleRate.getRate()); save(); } catch(SourceException | LibUsbException eSampleRate) @@ -485,6 +499,8 @@ public void save() { E4KTunerConfiguration config = getConfiguration(); config.setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel)getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); config.setFrequencyCorrection(value); config.setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/fc0013/FC0013EmbeddedTuner.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/fc0013/FC0013EmbeddedTuner.java index 7afd57cb4..fcc2abfc6 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/fc0013/FC0013EmbeddedTuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/fc0013/FC0013EmbeddedTuner.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -61,8 +61,8 @@ public class FC0013EmbeddedTuner extends EmbeddedTuner { private final static Logger mLog = LoggerFactory.getLogger(FC0013EmbeddedTuner.class); private DecimalFormat FREQUENCY_FORMAT = new DecimalFormat("0.000000"); - private static final long MINIMUM_SUPPORTED_FREQUENCY = 13_500_000; - private static final long MAXIMUM_SUPPORTED_FREQUENCY = 1_907_999_890l; + public static final long MINIMUM_TUNABLE_FREQUENCY_HZ = 13_500_000; + public static final long MAXIMUM_TUNABLE_FREQUENCY_HZ = 1_907_999_890l; private static final double USABLE_BANDWIDTH_PERCENT = 0.95; private static final int DC_SPIKE_AVOID_BUFFER = 15000; //Hardware I2C address @@ -74,7 +74,7 @@ public class FC0013EmbeddedTuner extends EmbeddedTuner private static byte[] REGISTERS = {(byte) 0x00, (byte) 0x09, (byte) 0x16, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x02, (byte) 0x2A, (byte) 0xFF, (byte) 0x6E, (byte) 0xB8, (byte) 0x82, (byte) 0xFE, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x50, (byte) 0x01}; - private long mTunedFrequency = MINIMUM_SUPPORTED_FREQUENCY; + private long mTunedFrequency = MINIMUM_TUNABLE_FREQUENCY_HZ; /** * Constructs an instance @@ -95,13 +95,13 @@ public TunerType getTunerType() @Override public long getMinimumFrequencySupported() { - return MINIMUM_SUPPORTED_FREQUENCY; + return MINIMUM_TUNABLE_FREQUENCY_HZ; } @Override public long getMaximumFrequencySupported() { - return MAXIMUM_SUPPORTED_FREQUENCY; + return MAXIMUM_TUNABLE_FREQUENCY_HZ; } @Override diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/fc0013/FC0013TunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/fc0013/FC0013TunerConfiguration.java index b08b0609f..c30eabfab 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/fc0013/FC0013TunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/fc0013/FC0013TunerConfiguration.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -36,6 +36,7 @@ public class FC0013TunerConfiguration extends RTL2832TunerConfiguration */ public FC0013TunerConfiguration() { + super(FC0013EmbeddedTuner.MINIMUM_TUNABLE_FREQUENCY_HZ, FC0013EmbeddedTuner.MAXIMUM_TUNABLE_FREQUENCY_HZ); } @JsonIgnore diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/fc0013/FC0013TunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/fc0013/FC0013TunerEditor.java index 187f0f657..1dd0f4886 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/fc0013/FC0013TunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/fc0013/FC0013TunerEditor.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -68,6 +68,18 @@ public FC0013TunerEditor(UserPreferences userPreferences, TunerManager tunerMana tunerStatusUpdated(); } + @Override + public long getMinimumTunableFrequency() + { + return FC0013EmbeddedTuner.MINIMUM_TUNABLE_FREQUENCY_HZ; + } + + @Override + public long getMaximumTunableFrequency() + { + return FC0013EmbeddedTuner.MAXIMUM_TUNABLE_FREQUENCY_HZ; + } + /** * Access the FC0013 embedded tuner * @return tuner if there is a tuner, or null otherwise @@ -263,6 +275,8 @@ private JComboBox getSampleRateCombo() try { getTuner().getController().setSampleRate(sampleRate); + //Adjust the min/max values for the sample rate. + adjustForSampleRate(sampleRate.getRate()); save(); } catch(SourceException | LibUsbException eSampleRate) @@ -390,6 +404,8 @@ public void save() FC0013TunerConfiguration config = getConfiguration(); config.setBiasT(getTuner().getController().isBiasT()); config.setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel)getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); config.setFrequencyCorrection(value); config.setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/r8x/R8xEmbeddedTuner.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/r8x/R8xEmbeddedTuner.java index 2ff44cf73..ccdd0b0bd 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/r8x/R8xEmbeddedTuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/r8x/R8xEmbeddedTuner.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -38,8 +38,8 @@ public abstract class R8xEmbeddedTuner extends EmbeddedTuner public static final byte[] BIT_REV_LOOKUP_TABLE = {(byte) 0x0, (byte) 0x8, (byte) 0x4, (byte) 0xC, (byte) 0x2, (byte) 0xA, (byte) 0x6, (byte) 0xE, (byte) 0x1, (byte) 0x9, (byte) 0x5, (byte) 0xD, (byte) 0x3, (byte) 0xB, (byte) 0x7, (byte) 0xF}; - private static final long MINIMUM_SUPPORTED_FREQUENCY = 3180000; - private static final long MAXIMUM_SUPPORTED_FREQUENCY = 1782030000; + public static final long MINIMUM_TUNABLE_FREQUENCY_HZ = 3180000; + public static final long MAXIMUM_TUNABLE_FREQUENCY_HZ = 1782030000; private static final double USABLE_BANDWIDTH_PERCENT = 0.98; private static final int DC_SPIKE_AVOID_BUFFER = 5000; private static final byte VERSION = (byte) 49; @@ -147,13 +147,13 @@ private static int bitReverse(int value) @Override public long getMinimumFrequencySupported() { - return MINIMUM_SUPPORTED_FREQUENCY; + return MINIMUM_TUNABLE_FREQUENCY_HZ; } @Override public long getMaximumFrequencySupported() { - return MAXIMUM_SUPPORTED_FREQUENCY; + return MAXIMUM_TUNABLE_FREQUENCY_HZ; } @Override diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/r8x/R8xTunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/r8x/R8xTunerConfiguration.java index 43ab8b7f9..a81ae8657 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/r8x/R8xTunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/r8x/R8xTunerConfiguration.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -36,6 +36,7 @@ public abstract class R8xTunerConfiguration extends RTL2832TunerConfiguration */ public R8xTunerConfiguration() { + super(R8xEmbeddedTuner.MINIMUM_TUNABLE_FREQUENCY_HZ, R8xEmbeddedTuner.MAXIMUM_TUNABLE_FREQUENCY_HZ); } /** diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/r8x/R8xTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/r8x/R8xTunerEditor.java index 4c48e3ddd..db3713fcb 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/r8x/R8xTunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/r8x/R8xTunerEditor.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -69,6 +69,18 @@ public R8xTunerEditor(UserPreferences userPreferences, TunerManager tunerManager tunerStatusUpdated(); } + @Override + public long getMinimumTunableFrequency() + { + return R8xEmbeddedTuner.MINIMUM_TUNABLE_FREQUENCY_HZ; + } + + @Override + public long getMaximumTunableFrequency() + { + return R8xEmbeddedTuner.MAXIMUM_TUNABLE_FREQUENCY_HZ; + } + /** * Access the R8xxx embedded tuner * @return R8xxx tuner if there is a tuner, or null otherwise @@ -329,6 +341,8 @@ private JComboBox getSampleRateCombo() try { getTuner().getController().setSampleRate(sampleRate); + //Adjust the min/max values for the sample rate. + adjustForSampleRate(sampleRate.getRate()); save(); } catch(SourceException | LibUsbException eSampleRate) @@ -521,6 +535,8 @@ public void save() R8xTunerConfiguration config = getConfiguration(); config.setBiasT(getTuner().getController().isBiasT()); config.setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel)getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); config.setFrequencyCorrection(value); config.setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerConfiguration.java index eb5e4070a..28769c3e5 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerConfiguration.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerConfiguration.java @@ -60,6 +60,7 @@ public abstract class RspTunerConfiguration extends TunerConfiguration */ public RspTunerConfiguration() { + super(RspTunerController.MINIMUM_TUNABLE_FREQUENCY_HZ, RspTunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ); } /** diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerController.java index 79e5ec9eb..db11c8fff 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerController.java @@ -45,8 +45,8 @@ public abstract class RspTunerController extends TunerCon implements IDeviceEventListener, IStreamListener { private static final Logger mLog = LoggerFactory.getLogger(RspTunerController.class); - protected static final long MINIMUM_FREQUENCY = 100_000; - protected static final long MAXIMUM_FREQUENCY = 2_000_000_000; + protected static final long MINIMUM_TUNABLE_FREQUENCY_HZ = 100_000; + protected static final long MAXIMUM_TUNABLE_FREQUENCY_HZ = 2_000_000_000; protected static final int MIDDLE_UNUSABLE_BANDWIDTH = 0; private I mControlRsp; private RspNativeBufferFactory mNativeBufferFactory = new RspNativeBufferFactory(RspSampleRate.RATE_8_000); @@ -66,8 +66,8 @@ public RspTunerController(I controlRsp, ITunerErrorListener tunerErrorListener) //Register this controller to receive device events and sample streams when startStream() is invoked. mControlRsp.resister(this, this); - setMinimumFrequency(MINIMUM_FREQUENCY); - setMaximumFrequency(MAXIMUM_FREQUENCY); + setMinimumFrequency(MINIMUM_TUNABLE_FREQUENCY_HZ); + setMaximumFrequency(MAXIMUM_TUNABLE_FREQUENCY_HZ); setMiddleUnusableHalfBandwidth(MIDDLE_UNUSABLE_BANDWIDTH); setUsableBandwidthPercentage(1.0); //Initial value } diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerEditor.java index 6921d37b1..d70f1393a 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerEditor.java @@ -73,6 +73,18 @@ private RspTunerController getTunerController() return (RspTunerController) getTuner().getTunerController(); } + @Override + public long getMinimumTunableFrequency() + { + return RspTunerController.MINIMUM_TUNABLE_FREQUENCY_HZ; + } + + @Override + public long getMaximumTunableFrequency() + { + return RspTunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ; + } + /** * Gain controls panel * @return gain panel diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1/Rsp1TunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1/Rsp1TunerEditor.java index ea3a5093a..b8278f9bf 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1/Rsp1TunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1/Rsp1TunerEditor.java @@ -156,6 +156,8 @@ public void save() if(hasConfiguration() && !isLoading()) { getConfiguration().setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); getConfiguration().setFrequencyCorrection(value); getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); @@ -186,6 +188,8 @@ private JComboBox getSampleRateCombo() try { getTunerController().setSampleRate(selected); + //Adjust the min/max values for the sample rate. + adjustForSampleRate((int)selected.getSampleRate()); save(); } catch(SDRPlayException se) diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1a/Rsp1aTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1a/Rsp1aTunerEditor.java index 4650c13a2..6cdeb1d5e 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1a/Rsp1aTunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1a/Rsp1aTunerEditor.java @@ -197,6 +197,8 @@ public void save() if(hasConfiguration() && !isLoading()) { getConfiguration().setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); getConfiguration().setFrequencyCorrection(value); getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); @@ -230,6 +232,8 @@ private JComboBox getSampleRateCombo() try { getTunerController().setSampleRate(selected); + //Adjust the min/max values for the sample rate. + adjustForSampleRate((int)selected.getSampleRate()); save(); } catch(SDRPlayException se) diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1b/Rsp1bTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1b/Rsp1bTunerEditor.java index 5150db63e..86d8f4494 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1b/Rsp1bTunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1b/Rsp1bTunerEditor.java @@ -196,6 +196,8 @@ public void save() if(hasConfiguration() && !isLoading()) { getConfiguration().setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); getConfiguration().setFrequencyCorrection(value); getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); @@ -229,6 +231,8 @@ private JComboBox getSampleRateCombo() try { getTunerController().setSampleRate(selected); + //Adjust the min/max values for the sample rate. + adjustForSampleRate((int)selected.getSampleRate()); save(); } catch(SDRPlayException se) diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp2/Rsp2TunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp2/Rsp2TunerEditor.java index 2b483df0c..b5f383a0a 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp2/Rsp2TunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp2/Rsp2TunerEditor.java @@ -211,6 +211,8 @@ public void save() if(hasConfiguration() && !isLoading()) { getConfiguration().setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); getConfiguration().setFrequencyCorrection(value); getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); @@ -244,6 +246,8 @@ private JComboBox getSampleRateCombo() try { getTunerController().setSampleRate(selected); + //Adjust the min/max values for the sample rate. + adjustForSampleRate((int)selected.getSampleRate()); save(); } catch(SDRPlayException se) diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/RspDuoTuner1Editor.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/RspDuoTuner1Editor.java index a4a757015..8d1d4aa11 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/RspDuoTuner1Editor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/RspDuoTuner1Editor.java @@ -239,6 +239,8 @@ public void save() if(hasConfiguration() && !isLoading()) { getConfiguration().setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); getConfiguration().setFrequencyCorrection(value); getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); @@ -296,6 +298,8 @@ private JComboBox getSampleRateCombo() try { getTunerController().setSampleRate(selected); + //Adjust the min/max values for the sample rate. + adjustForSampleRate((int)selected.getSampleRate()); save(); } catch(SDRPlayException se) diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/RspDuoTuner2Editor.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/RspDuoTuner2Editor.java index f6dc89ad3..9f1106ad2 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/RspDuoTuner2Editor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/RspDuoTuner2Editor.java @@ -246,6 +246,8 @@ public void save() if(hasConfiguration() && !isLoading()) { getConfiguration().setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); getConfiguration().setFrequencyCorrection(value); getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); @@ -308,6 +310,8 @@ private JComboBox getSampleRateCombo() try { getTunerController().setSampleRate(selected); + //Adjust the min/max values for the sample rate. + adjustForSampleRate((int)selected.getSampleRate()); save(); } catch(SDRPlayException se) diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDx/RspDxTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDx/RspDxTunerEditor.java index f36d725c1..c61e3a85c 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDx/RspDxTunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDx/RspDxTunerEditor.java @@ -230,6 +230,8 @@ public void save() if(hasConfiguration() && !isLoading()) { getConfiguration().setFrequency(getFrequencyControl().getFrequency()); + getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency()); + getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency()); double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue(); getConfiguration().setFrequencyCorrection(value); getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected()); @@ -265,6 +267,8 @@ private JComboBox getSampleRateCombo() try { getTunerController().setSampleRate(selected); + //Adjust the min/max values for the sample rate. + adjustForSampleRate((int)selected.getSampleRate()); save(); } catch(SDRPlayException se) diff --git a/src/main/java/io/github/dsheirer/source/tuner/ui/TunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/ui/TunerEditor.java index d0d11e654..a09f14367 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/ui/TunerEditor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/ui/TunerEditor.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2023 Dennis Sheirer + * Copyright (C) 2014-2024 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 @@ -18,6 +18,7 @@ */ package io.github.dsheirer.source.tuner.ui; +import io.github.dsheirer.gui.control.FrequencyTextField; import io.github.dsheirer.gui.control.JFrequencyControl; import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.properties.SystemProperties; @@ -37,6 +38,8 @@ import io.github.dsheirer.util.SwingUtils; import io.github.dsheirer.util.ThreadPool; import java.awt.EventQueue; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; import java.text.CharacterIterator; import java.text.DecimalFormat; import java.text.StringCharacterIterator; @@ -47,6 +50,7 @@ import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JLabel; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.JToggleButton; @@ -63,6 +67,8 @@ public abstract class TunerEditor implements IDiscoveredTunerStatusListener, Listener { private Logger mLog = LoggerFactory.getLogger(TunerEditor.class); + private static final long DEFAULT_MINIMUM_FREQUENCY = 1_000_000; + private static final long DEFAULT_MAXIMUM_FREQUENCY = 9_999_999_999l; private static final String BUTTON_STATUS_ENABLE = "Enable"; private static final String BUTTON_STATUS_DISABLE = "Disable"; private static final long serialVersionUID = 1L; @@ -86,6 +92,9 @@ public abstract class TunerEditor private JLabel mRecordingStatusLabel; private JLabel mTunerStatusLabel; private JLabel mTunerLockedStatusLabel; + private FrequencyTextField mMinimumFrequencyTextField; + private FrequencyTextField mMaximumFrequencyTextField; + private JButton mResetFrequenciesButton; private boolean mLoading = false; /** @@ -119,6 +128,32 @@ public TunerEditor(UserPreferences userPreferences, TunerManager tunerManager, D } } + /** + * Minimum tunable frequency supported by the tuner. + * @return minimum frequency hertz + */ + public abstract long getMinimumTunableFrequency(); + + /** + * Maximum tunable frequency supported by the tuner. + * @return maximum frequency hertz + */ + public abstract long getMaximumTunableFrequency(); + + /** + * Current sample rate for the tuner. + * @return sample rate in hertz. + */ + public int getCurrentSampleRate() + { + if(hasTuner()) + { + return (int)getTuner().getTunerController().getSampleRate(); + } + + return 0; + } + /**r * Indicates if the controls are currently being loaded with values. */ @@ -284,6 +319,235 @@ protected JFrequencyControl getFrequencyControl() return mFrequencyControl; } + /** + * Minimum frequency value text field + */ + protected FrequencyTextField getMinimumFrequencyTextField() + { + if(mMinimumFrequencyTextField == null) + { + mMinimumFrequencyTextField = new FrequencyTextField(DEFAULT_MINIMUM_FREQUENCY, DEFAULT_MAXIMUM_FREQUENCY, + getMinimumTunableFrequency()); + mMinimumFrequencyTextField.setToolTipText("Sets or changes the minimum frequency value that this tuner will support."); + mMinimumFrequencyTextField.addFocusListener(new FocusListener() + { + private long mExistingFrequency; + + @Override + public void focusGained(FocusEvent e) + { + mExistingFrequency = getMinimumFrequencyTextField().getFrequency(); + } + + @Override + public void focusLost(FocusEvent e) + { + if(!isLoading()) + { + setLoading(true); + + long minimum = getMinimumFrequencyTextField().getFrequency(); + long maximum = getMaximumFrequencyTextField().getFrequency(); + + if(minimum < getMinimumTunableFrequency()) + { + JOptionPane.showMessageDialog(TunerEditor.this, "Frequency value [" + + getMinimumFrequencyTextField().getText() + "] is below the supported frequency range for this tuner", + "Invalid Frequency", JOptionPane.ERROR_MESSAGE); + getMinimumFrequencyTextField().setFrequency(mExistingFrequency); + return; + } + + if((minimum + getCurrentSampleRate()) > maximum) + { + long newMaximum = minimum + getCurrentSampleRate(); + + if(newMaximum <= getMaximumTunableFrequency()) + { + maximum = newMaximum; + getMaximumFrequencyTextField().setFrequency(maximum); + } + else + { + JOptionPane.showMessageDialog(TunerEditor.this, "Frequency value [" + + getMinimumFrequencyTextField().getText() + "] is invalid for current sample rate " + + "and maximum supported frequency for this tuner", "Invalid Frequency", + JOptionPane.ERROR_MESSAGE); + getMinimumFrequencyTextField().setFrequency(mExistingFrequency); + return; + } + } + + if(hasTuner()) + { + getTuner().getTunerController().setFrequencyExtents(minimum, maximum); + } + + adjustFrequencyControl(minimum, maximum); + setLoading(false); + save(); + } + } + }); + } + + return mMinimumFrequencyTextField; + } + + /** + * Adjusts the frequency control to be within the min-max range. + * @param minimum frequency value. + * @param maximum frequency value. + */ + private void adjustFrequencyControl(long minimum, long maximum) + { + if(hasTuner()) + { + try + { + if(getFrequencyControl().getFrequency() < minimum) + { + getTuner().getTunerController().setFrequency(minimum); + } + else if(getFrequencyControl().getFrequency() > maximum) + { + getTuner().getTunerController().setFrequency(maximum); + } + } + catch(SourceException se) + { + mLog.error("Error adjusting frequency", se); + } + } + } + + /** + * Adjusts the minimum and maximum frequency values to ensure the gap is wide enough for the sample rate. + * @param sampleRate to adjust for. + */ + protected void adjustForSampleRate(int sampleRate) + { + long minimum = getMinimumFrequencyTextField().getFrequency(); + long maximum = getMaximumFrequencyTextField().getFrequency(); + + if(maximum - minimum < sampleRate) + { + long newMaximum = minimum + sampleRate; + + if(newMaximum <= getMaximumTunableFrequency()) + { + getMaximumFrequencyTextField().setFrequency(newMaximum); + } + else + { + long newMinimum = maximum - sampleRate; + + if(newMinimum >= getMinimumTunableFrequency()) + { + getMinimumFrequencyTextField().setFrequency(newMinimum); + } + else + { + JOptionPane.showMessageDialog(TunerEditor.this, "Unable to adjust tuner's " + + "minimum and maximum frequency values to accommodate new sample rate [" + sampleRate + "]", + "Frequency Error", JOptionPane.ERROR_MESSAGE); + } + } + } + } + + /** + * Maximum frequency value text field + */ + protected FrequencyTextField getMaximumFrequencyTextField() + { + if(mMaximumFrequencyTextField == null) + { + mMaximumFrequencyTextField = new FrequencyTextField(DEFAULT_MINIMUM_FREQUENCY, DEFAULT_MAXIMUM_FREQUENCY, + getMaximumTunableFrequency()); + mMaximumFrequencyTextField.setToolTipText("Sets or changes the maximum frequency value that this tuner will support."); + mMaximumFrequencyTextField.addFocusListener(new FocusListener() + { + private long mExistingFrequency; + + @Override + public void focusGained(FocusEvent e) + { + mExistingFrequency = getMaximumFrequencyTextField().getFrequency(); + } + + @Override + public void focusLost(FocusEvent e) + { + if(!isLoading()) + { + + setLoading(true); + long minimum = getMinimumFrequencyTextField().getFrequency(); + long maximum = getMaximumFrequencyTextField().getFrequency(); + + if(maximum > getMaximumTunableFrequency()) + { + JOptionPane.showMessageDialog(TunerEditor.this, "Frequency value [" + + getMaximumFrequencyTextField().getText() + "] is above the supported frequency " + + "range for this tuner", "Invalid Frequency", JOptionPane.ERROR_MESSAGE); + getMaximumFrequencyTextField().setFrequency(mExistingFrequency); + return; + } + + if((maximum - getCurrentSampleRate()) < minimum) + { + long newMinimum = maximum - getCurrentSampleRate(); + + if(newMinimum >= getMinimumTunableFrequency()) + { + minimum = newMinimum; + getMinimumFrequencyTextField().setFrequency(minimum); + } + else + { + JOptionPane.showMessageDialog(TunerEditor.this, "Frequency value [" + + getMaximumFrequencyTextField().getText() + "] is invalid for current sample rate " + + "and minimum supported frequency for this tuner", "Invalid Frequency", + JOptionPane.ERROR_MESSAGE); + getMaximumFrequencyTextField().setFrequency(mExistingFrequency); + return; + } + } + + if(hasTuner()) + { + getTuner().getTunerController().setFrequencyExtents(minimum, maximum); + } + + adjustFrequencyControl(minimum, maximum); + setLoading(false); + save(); + } + } + }); + } + + return mMaximumFrequencyTextField; + } + + /** + * Resets the minimum and maximum frequency values. + */ + protected JButton getResetFrequenciesButton() + { + if(mResetFrequenciesButton == null) + { + mResetFrequenciesButton = new JButton("Reset"); + mResetFrequenciesButton.addActionListener(e -> { + getMinimumFrequencyTextField().setFrequency(getMinimumTunableFrequency()); + getMaximumFrequencyTextField().setFrequency(getMaximumTunableFrequency()); + }); + } + + return mResetFrequenciesButton; + } + /** * Button requesting to show tuner in new spectral display */ @@ -603,12 +867,22 @@ public class FrequencyPanel extends JPanel { public FrequencyPanel() { - setLayout(new MigLayout("insets 0,fill", "[][][][][grow,fill]", "")); + setLayout(new MigLayout("insets 0,fill", "[][][][grow,fill]", "")); add(getFrequencyControl(), "spany 2"); add(new JLabel("PPM:")); add(getFrequencyCorrectionSpinner()); add(getMeasuredPPMLabel(), "wrap"); add(getAutoPPMCheckBox(), "span"); + + JPanel minMaxPanel = new JPanel(); + minMaxPanel.setLayout(new MigLayout("insets 0", "[][][][][][grow,fill]", "")); + minMaxPanel.add(new JLabel("Minimum:")); + minMaxPanel.add(getMinimumFrequencyTextField()); + minMaxPanel.add(new JLabel("Maximum:")); + minMaxPanel.add(getMaximumFrequencyTextField()); + minMaxPanel.add(getResetFrequenciesButton()); + add(minMaxPanel, "span"); + add(getTunerLockedStatusLabel(), "span"); } @@ -619,7 +893,11 @@ public void updateControls() { getFrequencyControl().clearListeners(); getFrequencyControl().addListener(mFrequencyAndCorrectionChangeListener); - getFrequencyControl().setEnabled(hasTuner() && !getTuner().getTunerController().isLockedSampleRate()); + boolean hasTunerUnlocked = hasTuner() && !getTuner().getTunerController().isLockedSampleRate(); + getFrequencyControl().setEnabled(hasTunerUnlocked); + getMinimumFrequencyTextField().setEnabled(hasTunerUnlocked); + getMaximumFrequencyTextField().setEnabled(hasTunerUnlocked); + getResetFrequenciesButton().setEnabled(hasTunerUnlocked); getTunerLockedStatusLabel().setVisible(hasTuner() && getTuner().getTunerController().isLockedSampleRate()); getFrequencyCorrectionSpinner().setEnabled(hasTuner()); getAutoPPMCheckBox().setEnabled(hasTuner()); @@ -629,6 +907,8 @@ public void updateControls() if(tuner != null) { getFrequencyControl().setFrequency(tuner.getTunerController().getFrequency(), false); + getMinimumFrequencyTextField().setFrequency(tuner.getTunerController().getMinimumFrequency()); + getMaximumFrequencyTextField().setFrequency(tuner.getTunerController().getMaximumFrequency()); getFrequencyCorrectionSpinner().setValue(tuner.getTunerController().getFrequencyCorrection()); getAutoPPMCheckBox().setSelected(tuner.getTunerController().getFrequencyErrorCorrectionManager().isEnabled()); getFrequencyControl().addListener(getTuner().getTunerController());