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 00000000..e986f693
--- /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 9d522e1d..1e013e23 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 7e00f853..cd5bbf77 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 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
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 00000000..94171233
--- /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 bc30a29a..fcaebaa9 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 class InvalidFrequencyException extends SourceException
{
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 46c8dde4..88816da9 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 abstract class TunerController implements Tunable, ISourceEventProcessor,
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 abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
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 05248028..2aac26c4 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 7c74f998..0faa1171 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 class AirspyTunerController extends USBTunerController
@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 class AirspyTunerController extends USBTunerController
}
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 d1f72188..ed32e804 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 class AirspyTunerEditor extends TunerEditor 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 class FrequencyController
*/
public void setMinimumFrequency(long minimum)
{
- mMaximumFrequency = minimum;
+ mMinimumFrequency = minimum;
}
/**
@@ -252,15 +251,12 @@ public class FrequencyController
}
/**
- * 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 a9e328e5..9213577c 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 3d20b81a..55e3313d 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 388ff63c..4190e677 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 class HackRFTunerEditor extends TunerEditor 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 abstract class RspTunerController extends TunerCon
//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 6921d37b..d70f1393 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 @@ public abstract class RspTunerEditor extends Tu
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 ea3a5093..b8278f9b 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 class Rsp1TunerEditor extends RspTunerEditor
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 @@ public class Rsp1TunerEditor extends RspTunerEditor
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 4650c13a..6cdeb1d5 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 class Rsp1aTunerEditor extends RspTunerEditor
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 @@ public class Rsp1aTunerEditor extends RspTunerEditor
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 5150db63..86d8f449 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 class Rsp1bTunerEditor extends RspTunerEditor
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 @@ public class Rsp1bTunerEditor extends RspTunerEditor
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 2b483df0..b5f383a0 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 class Rsp2TunerEditor extends RspTunerEditor
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 @@ public class Rsp2TunerEditor extends RspTunerEditor
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 a4a75701..8d1d4aa1 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 class RspDuoTuner1Editor extends RspTunerEditor
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 @@ public class RspDxTunerEditor extends RspTunerEditor
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 d0d11e65..a09f1436 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.spectrum.SpectralDisplayPanel;
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 org.slf4j.LoggerFactory;
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 abstract class TunerEditor
}
}
+ /**
+ * 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 @@ public abstract class TunerEditor
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 abstract class TunerEditor
{
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 abstract class TunerEditor
{
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 abstract class TunerEditor
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());