#172 Allow users to adjust tuner min/max frequency ranges so that they can ensure tuners stay put and support channels in a predicatable manner. (#1850)

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
Denny Sheirer
2024-02-11 17:08:43 -05:00
committed by GitHub
parent 2c32096ec9
commit 73275aa8ae
48 changed files with 975 additions and 124 deletions

View File

@@ -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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
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));
}
}

View File

@@ -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<Integer>
{
private static final Logger mLog = LoggerFactory.getLogger(AliasItemEditor.class);
private static final Logger mLog = LoggerFactory.getLogger(IntegerFormatter.class);
/**
* Constructs an instance

View File

@@ -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.");
}
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
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<Long>
{
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<Change>
{
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;
}
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>
*
******************************************************************************/
* ****************************************************************************
*/
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();
}
}

View File

@@ -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());
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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<AirspyTuner, AirspyTunerConfi
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 class AirspyTunerEditor extends TunerEditor<AirspyTuner, AirspyTunerConfi
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 class AirspyTunerEditor extends TunerEditor<AirspyTuner, AirspyTunerConfi
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());

View File

@@ -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);
}
/**

View File

@@ -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);
}

View File

@@ -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 class AirspyHfTunerEditor extends TunerEditor<AirspyHfTuner,AirspyHfTuner
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 @@ public class AirspyHfTunerEditor extends TunerEditor<AirspyHfTuner,AirspyHfTuner
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 @@ public class AirspyHfTunerEditor extends TunerEditor<AirspyHfTuner,AirspyHfTuner
try
{
getTuner().getController().setSampleRate(sampleRate);
//Adjust the min/max values for the sample rate.
adjustForSampleRate(sampleRate.getSampleRate());
save();
}
catch(SourceException se)

View File

@@ -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 @@ import io.github.dsheirer.source.tuner.sdrplay.RspTunerConfiguration;
@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 abstract class TunerConfiguration
/**
* 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 abstract class TunerConfiguration
{
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;
}
}

View File

@@ -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)

View File

@@ -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.TunerType;
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 @@ import java.nio.ByteOrder;
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

View File

@@ -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 FCD1TunerEditor extends TunerEditor<FCDTuner,FCD1TunerConfiguration
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 class FCD1TunerEditor extends TunerEditor<FCDTuner,FCD1TunerConfiguration
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());

View File

@@ -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

View File

@@ -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.TunerType;
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

View File

@@ -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 class FCD2TunerEditor extends TunerEditor<FCDTuner, FCD2TunerConfiguratio
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 class FCD2TunerEditor extends TunerEditor<FCDTuner, FCD2TunerConfiguratio
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());

View File

@@ -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 class FrequencyController
*/
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 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)));
}
/**

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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<HackRFTuner,HackRFTunerConfig
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 @@ public class HackRFTunerEditor extends TunerEditor<HackRFTuner,HackRFTunerConfig
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 class HackRFTunerEditor extends TunerEditor<HackRFTuner,HackRFTunerConfig
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());

View File

@@ -215,7 +215,7 @@ public abstract class DiscoveredTuner implements ITunerErrorListener
catch(SourceException se)
{
mLog.error("Error applying tuner configuration [" + mTunerConfiguration.getClass() +
"] to discovered tuner [" + getId() + "}");
"] to discovered tuner [" + getId() + "}", se);
}
}
}

View File

@@ -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 class RecordingTunerConfiguration extends TunerConfiguration
*/
public RecordingTunerConfiguration(String uniqueId)
{
this();
setUniqueID(uniqueId);
}

View File

@@ -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 class RecordingTunerEditor extends TunerEditor<RecordingTuner,RecordingTu
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 class RecordingTunerEditor extends TunerEditor<RecordingTuner,RecordingTu
{
RecordingTunerConfiguration config = getConfiguration();
config.setFrequency(getFrequencyControl().getFrequency());
getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency());
getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency());
saveConfiguration();
}
}

View File

@@ -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)

View File

@@ -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 @@ package io.github.dsheirer.source.tuner.rtl;
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 @@ public class RTL2832UnknownTunerEditor extends TunerEditor<RTL2832Tuner, RTL2832
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

View File

@@ -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.TunerType;
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 class E4KEmbeddedTuner extends EmbeddedTuner
@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 class E4KEmbeddedTuner extends EmbeddedTuner
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 class E4KEmbeddedTuner extends EmbeddedTuner
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;

View File

@@ -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

View File

@@ -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 class E4KTunerEditor extends TunerEditor<RTL2832Tuner, E4KTunerConfigurat
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 @@ public class E4KTunerEditor extends TunerEditor<RTL2832Tuner, E4KTunerConfigurat
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 class E4KTunerEditor extends TunerEditor<RTL2832Tuner, E4KTunerConfigurat
{
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());

View File

@@ -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 class FC0013EmbeddedTuner extends EmbeddedTuner
@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

View File

@@ -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

View File

@@ -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 class FC0013TunerEditor extends TunerEditor<RTL2832Tuner, FC0013TunerConf
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 @@ public class FC0013TunerEditor extends TunerEditor<RTL2832Tuner, FC0013TunerConf
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 class FC0013TunerEditor extends TunerEditor<RTL2832Tuner, FC0013TunerConf
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());

View File

@@ -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 @@ public abstract class R8xEmbeddedTuner extends EmbeddedTuner
@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

View File

@@ -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);
}
/**

View File

@@ -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 class R8xTunerEditor extends TunerEditor<RTL2832Tuner, R8xTunerConfigurat
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 @@ public class R8xTunerEditor extends TunerEditor<RTL2832Tuner, R8xTunerConfigurat
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 class R8xTunerEditor extends TunerEditor<RTL2832Tuner, R8xTunerConfigurat
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());

View File

@@ -60,6 +60,7 @@ public abstract class RspTunerConfiguration extends TunerConfiguration
*/
public RspTunerConfiguration()
{
super(RspTunerController.MINIMUM_TUNABLE_FREQUENCY_HZ, RspTunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ);
}
/**

View File

@@ -45,8 +45,8 @@ public abstract class RspTunerController<I extends IControlRsp> 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<I extends IControlRsp> 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
}

View File

@@ -73,6 +73,18 @@ public abstract class RspTunerEditor<C extends RspTunerConfiguration> 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

View File

@@ -156,6 +156,8 @@ public class Rsp1TunerEditor extends RspTunerEditor<Rsp1TunerConfiguration>
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<Rsp1TunerConfiguration>
try
{
getTunerController().setSampleRate(selected);
//Adjust the min/max values for the sample rate.
adjustForSampleRate((int)selected.getSampleRate());
save();
}
catch(SDRPlayException se)

View File

@@ -197,6 +197,8 @@ public class Rsp1aTunerEditor extends RspTunerEditor<Rsp1aTunerConfiguration>
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<Rsp1aTunerConfiguration>
try
{
getTunerController().setSampleRate(selected);
//Adjust the min/max values for the sample rate.
adjustForSampleRate((int)selected.getSampleRate());
save();
}
catch(SDRPlayException se)

View File

@@ -196,6 +196,8 @@ public class Rsp1bTunerEditor extends RspTunerEditor<Rsp1bTunerConfiguration>
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<Rsp1bTunerConfiguration>
try
{
getTunerController().setSampleRate(selected);
//Adjust the min/max values for the sample rate.
adjustForSampleRate((int)selected.getSampleRate());
save();
}
catch(SDRPlayException se)

View File

@@ -211,6 +211,8 @@ public class Rsp2TunerEditor extends RspTunerEditor<Rsp2TunerConfiguration>
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<Rsp2TunerConfiguration>
try
{
getTunerController().setSampleRate(selected);
//Adjust the min/max values for the sample rate.
adjustForSampleRate((int)selected.getSampleRate());
save();
}
catch(SDRPlayException se)

View File

@@ -239,6 +239,8 @@ public class RspDuoTuner1Editor extends RspTunerEditor<RspDuoTuner1Configuration
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 @@ public class RspDuoTuner1Editor extends RspTunerEditor<RspDuoTuner1Configuration
try
{
getTunerController().setSampleRate(selected);
//Adjust the min/max values for the sample rate.
adjustForSampleRate((int)selected.getSampleRate());
save();
}
catch(SDRPlayException se)

View File

@@ -246,6 +246,8 @@ public class RspDuoTuner2Editor extends RspTunerEditor<RspDuoTuner2Configuration
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 @@ public class RspDuoTuner2Editor extends RspTunerEditor<RspDuoTuner2Configuration
try
{
getTunerController().setSampleRate(selected);
//Adjust the min/max values for the sample rate.
adjustForSampleRate((int)selected.getSampleRate());
save();
}
catch(SDRPlayException se)

View File

@@ -230,6 +230,8 @@ public class RspDxTunerEditor extends RspTunerEditor<RspDxTunerConfiguration>
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<RspDxTunerConfiguration>
try
{
getTunerController().setSampleRate(selected);
//Adjust the min/max values for the sample rate.
adjustForSampleRate((int)selected.getSampleRate());
save();
}
catch(SDRPlayException se)

View File

@@ -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<T extends Tuner,C extends TunerConfiguration>
implements IDiscoveredTunerStatusListener, Listener<TunerEvent>
{
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<T extends Tuner,C extends TunerConfiguration>
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<T extends Tuner,C extends TunerConfiguration>
}
}
/**
* 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<T extends Tuner,C extends TunerConfiguration>
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<T extends Tuner,C extends TunerConfiguration>
{
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<T extends Tuner,C extends TunerConfiguration>
{
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<T extends Tuner,C extends TunerConfiguration>
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());