+{
+ /**
+ * Constructs an instance
+ *
+ * @param userPreferences for starting wide-band recorders
+ * @param tunerManager for requesting configuration saves.
+ * @param discoveredTuner that is not started, or that doesn't have a recognized tuner type
+ */
+ public RTL2832UnknownTunerEditor(UserPreferences userPreferences, TunerManager tunerManager,
+ DiscoveredTuner discoveredTuner)
+ {
+ super(userPreferences, tunerManager, discoveredTuner);
+ init();
+ tunerStatusUpdated();
+ }
+
+ private void init()
+ {
+ setLayout(new MigLayout("fill,wrap 3", "[right][grow,fill][fill]",
+ "[][][][][][][][][][][][][][][][grow]"));
+
+ add(new JLabel("Tuner:"));
+ add(getTunerIdLabel(), "wrap");
+
+ add(new JLabel("Status:"));
+ add(getTunerStatusLabel(), "wrap");
+
+ add(getButtonPanel(), "span,align left");
+
+ 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
+ protected void save()
+ {
+ //No-op
+ }
+
+ @Override
+ protected void tunerStatusUpdated()
+ {
+ setLoading(true);
+ getTunerIdLabel().setText(getDiscoveredTuner().getId() + (hasTuner() ? " ID:" + getTuner().getUniqueID() : ""));
+
+ String status = getDiscoveredTuner().getTunerStatus().toString();
+ if(getDiscoveredTuner().hasErrorMessage())
+ {
+ status += " - " + getDiscoveredTuner().getErrorMessage();
+ }
+ getTunerStatusLabel().setText(status);
+ getButtonPanel().updateControls();
+ setLoading(false);
+ }
+
+ @Override
+ public void setTunerLockState(boolean locked)
+ {
+ super.setTunerLockState(locked);
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KEmbeddedTuner.java
similarity index 58%
rename from src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerController.java
rename to src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KEmbeddedTuner.java
index 305ed705..dc235d5c 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerController.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KEmbeddedTuner.java
@@ -21,32 +21,33 @@ package io.github.dsheirer.source.tuner.rtl.e4k;
import io.github.dsheirer.source.SourceException;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.usb4java.Device;
-import org.usb4java.DeviceDescriptor;
-import org.usb4java.DeviceHandle;
import org.usb4java.LibUsb;
import org.usb4java.LibUsbException;
import javax.usb.UsbException;
-import java.util.Arrays;
+import java.util.EnumSet;
-public class E4KTunerController extends RTL2832TunerController
+/**
+ * Elonic E4000 Tuner
+ */
+public class E4KEmbeddedTuner extends EmbeddedTuner
{
- private final static Logger mLog =
- LoggerFactory.getLogger(E4KTunerController.class);
+ private final static Logger mLog = LoggerFactory.getLogger(E4KEmbeddedTuner.class);
- public static final long MIN_FREQUENCY = 52000000;
- public static final long MAX_FREQUENCY = 2200000000l;
+ public static final long MINIMUM_SUPPORTED_FREQUENCY = 52000000;
+ public static final long MAXIMUM_SUPPORTED_FREQUENCY = 2200000000l;
public static final double USABLE_BANDWIDTH_PERCENT = 0.95;
public static final int DC_SPIKE_AVOID_BUFFER = 15000;
- /* The local oscillator is defined by whole (integer) units of the oscillator
- * frequency and fractional units representing 1/65536th of the oscillator
- * frequency, meaning we can only tune the local oscillator in units of
- * 439.453125 hertz. */
+ /**
+ * The local oscillator is defined by whole (integer) units of the oscillator frequency and fractional units
+ * representing 1/65536th of the oscillator frequency, meaning we can only tune the local oscillator in units of
+ * 439.453125 hertz.
+ */
public static final long E4K_PLL_Y = 65536l; /* 16-bit fractional register */
public static final byte MASTER1_RESET = (byte) 0x01;
public static final byte MASTER1_NORM_STBY = (byte) 0x02;
@@ -54,9 +55,7 @@ public class E4KTunerController extends RTL2832TunerController
public static final byte SYNTH1_PLL_LOCK = (byte) 0x01;
public static final byte SYNTH1_BAND_SHIF = (byte) 0x01;
-
public static final byte SYNTH7_3PHASE_EN = (byte) 0x08;
-
public static final byte SYNTH8_VCOCAL_UPD = (byte) 0x04;
public static final byte FILT3_MASK = (byte) 0x20;
@@ -67,7 +66,6 @@ public class E4KTunerController extends RTL2832TunerController
public static final byte IF_CHANNEL_FILTER_MASK = (byte) 0x1F;
public static final byte IF_RC_FILTER_MASK = (byte) 0x0F;
-
public static final byte AGC1_LIN_MODE = (byte) 0x10;
public static final byte AGC1_LNA_UPDATE = (byte) 0x20;
public static final byte AGC1_LNA_G_LOW = (byte) 0x40;
@@ -82,33 +80,14 @@ public class E4KTunerController extends RTL2832TunerController
public static final byte AGC7_MIXER_GAIN_MASK = (byte) 0x01;
public static final byte AGC7_MIX_GAIN_MANUAL = (byte) 0x00;
public static final byte AGC7_MIX_GAIN_AUTO = (byte) 0x01;
- public static final byte AGC7_GAIN_STEP_5DB = (byte) 0x20;
-
- public static final byte AGC8_SENS_LIN_AUTO = (byte) 0x01;
-
- public static final byte AGC11_LNA_GAIN_ENH = (byte) 0x01;
public static final byte ENH_GAIN_MOD_MASK = (byte) 0x07;
public static final byte MIXER_GAIN_MASK = (byte) 0x01;
-
- public static final byte DC1_CAL_REQ = (byte) 0x01;
-
- public static final byte DC5_I_LUT_EN = (byte) 0x01;
- public static final byte DC5_Q_LUT_EN = (byte) 0x02;
public static final byte DC5_RANGE_DETECTOR_ENABLED_MASK = (byte) 0x04; //DC Offset Detector Enabled
public static final byte DC5_RANGE_DETECTOR_ENABLED = (byte) 0x04; //DC Offset Detector Enabled
- public static final byte DC5_RANGE_EN = (byte) 0x08;
- public static final byte DC5_RANGE_DETECTOR_DISABLED_MASK = (byte) 0x03;
- public static final byte DC5_RANGE_DETECTOR_DISABLED = (byte) 0x00;
- public static final byte DC5_TIMEVAR_EN = (byte) 0x10;
-
- public static final byte CLKOUT_DISABLE = (byte) 0x96;
-
- public static final byte CHFCALIB_CMD = (byte) 0x01;
-
- public E4KTunerController(Device device, DeviceDescriptor deviceDescriptor) throws SourceException
+ public E4KEmbeddedTuner(RTL2832TunerController.ControllerAdapter adapter)
{
- super(device, deviceDescriptor, MIN_FREQUENCY, MAX_FREQUENCY, DC_SPIKE_AVOID_BUFFER, USABLE_BANDWIDTH_PERCENT);
+ super(adapter);
}
@Override
@@ -117,21 +96,62 @@ public class E4KTunerController extends RTL2832TunerController
return TunerType.ELONICS_E4000;
}
+ @Override
+ public long getMinimumFrequencySupported()
+ {
+ return MINIMUM_SUPPORTED_FREQUENCY;
+ }
+
+ @Override
+ public long getMaximumFrequencySupported()
+ {
+ return MAXIMUM_SUPPORTED_FREQUENCY;
+ }
+
+ @Override
+ public int getDcSpikeHalfBandwidth()
+ {
+ return DC_SPIKE_AVOID_BUFFER;
+ }
+
+ @Override
+ public double getUsableBandwidthPercent()
+ {
+ return USABLE_BANDWIDTH_PERCENT;
+ }
+
+ @Override
+ public void setSamplingMode(RTL2832TunerController.SampleMode mode) throws LibUsbException
+ {
+ switch(mode)
+ {
+ case QUADRATURE:
+ /* Set intermediate frequency to 0 Hz */
+ getAdapter().setIFFrequency(0);
+
+ /* Enable I/Q ADC Input */
+ getAdapter().writeDemodRegister(RTL2832TunerController.Page.ZERO, (short) 0x08, (short) 0xCD, 1);
+
+ /* Enable zero-IF mode */
+ getAdapter().writeDemodRegister(RTL2832TunerController.Page.ONE, (short) 0xB1, (short) 0x1B, 1);
+
+ /* Set default i/q path */
+ getAdapter().writeDemodRegister(RTL2832TunerController.Page.ZERO, (short) 0x06, (short) 0x80, 1);
+ break;
+ case DIRECT:
+ default:
+ throw new LibUsbException("QUADRATURE mode is the only mode currently supported", LibUsb.ERROR_NOT_SUPPORTED);
+ }
+ }
+
+
@Override
public void apply(TunerConfiguration config) throws SourceException
{
- if(config != null && config instanceof E4KTunerConfiguration)
+ if(config instanceof E4KTunerConfiguration e4kConfig)
{
- E4KTunerConfiguration e4kConfig = (E4KTunerConfiguration) config;
-
try
{
- SampleRate sampleRate = e4kConfig.getSampleRate();
- setSampleRate(sampleRate);
-
- double correction = e4kConfig.getFrequencyCorrection();
- setFrequencyCorrection(correction);
-
E4KGain masterGain = e4kConfig.getMasterGain();
setGain(masterGain, true);
@@ -143,137 +163,18 @@ public class E4KTunerController extends RTL2832TunerController
E4KLNAGain lnaGain = e4kConfig.getLNAGain();
setLNAGain(lnaGain, true);
- E4KEnhanceGain enhanceGain = e4kConfig.getEnhanceGain();
- setEnhanceGain(enhanceGain, true);
- }
-
- try
- {
- setFrequency(e4kConfig.getFrequency());
- }
- catch(SourceException se)
- {
- //Do nothing, we couldn't set the frequency
+ IFGain ifGain = e4kConfig.getIFGain();
+ setIFGain(ifGain, true);
}
}
catch(UsbException e)
{
- throw new SourceException("E4KTunerController - usb error "
- + "while applying tuner config", e);
+ throw new SourceException("Usb error while applying tuner config", e);
}
-
}
else
{
- throw new IllegalArgumentException("E4KTunerController - cannot "
- + "apply tuner configuration of type:[" +
- config.getClass() + "]");
- }
-
- }
-
- public void init() throws SourceException
- {
- mDeviceHandle = new DeviceHandle();
-
- int result = LibUsb.open(mDevice, mDeviceHandle);
-
- if(result != LibUsb.SUCCESS)
- {
- mDeviceHandle = null;
-
- throw new SourceException("libusb couldn't open RTL2832 usb "
- + "device [" + LibUsb.errorName(result) + "]");
- }
-
- claimInterface(mDeviceHandle);
-
- byte[] eeprom = null;
-
- try
- {
- /* Read the contents of the 256-byte EEPROM */
- eeprom = readEEPROM(mDeviceHandle, (short) 0, 256);
- }
- catch(Exception e)
- {
- mLog.error("error while reading the EEPROM device descriptor", e);
- }
-
- try
- {
- mDescriptor = new Descriptor(eeprom);
-
- if(eeprom == null)
- {
- mLog.error("eeprom byte array was null - constructed "
- + "empty descriptor object");
- }
- }
- catch(Exception e)
- {
- mLog.error("error while constructing device descriptor using "
- + "descriptor byte array " +
- (eeprom == null ? "[null]" : Arrays.toString(eeprom)), e);
- }
-
- try
- {
- /* Dummy write to test USB interface */
- writeRegister(mDeviceHandle, Block.USB,
- Address.USB_SYSCTL.getAddress(), (short) 0x09, 1);
-
- initBaseband(mDeviceHandle);
-
- enableI2CRepeater(mDeviceHandle, true);
-
- boolean i2CRepeaterControl = false;
-
- initTuner(i2CRepeaterControl);
-
- enableI2CRepeater(mDeviceHandle, false);
-
- try
- {
- setSampleRate(DEFAULT_SAMPLE_RATE);
- }
- catch(Exception e)
- {
- throw new SourceException("RTL2832 Tuner Controller - couldn't "
- + "set default sample rate", e);
- }
-
- }
- catch(UsbException e)
- {
- e.printStackTrace();
- throw new SourceException("E4K Tuner Controller - error during "
- + "init()", e);
- }
-
- String deviceName = getTunerType().getLabel() + " " + getUniqueID();
-
- mUSBTransferProcessor = new RTL2832USBTransferProcessor(deviceName, mDeviceHandle, mNativeBufferFactory,
- USB_TRANSFER_BUFFER_SIZE_HIGH_SAMPLE_RATE, this);
- }
-
- @Override
- public void dispose()
- {
- if(mDeviceHandle != null)
- {
- mLog.info("Releasing E4000 Tuner");
-
- try
- {
- LibUsb.close(mDeviceHandle);
- }
- catch(Exception e)
- {
- mLog.error("error while closing device handle", e);
- }
-
- mDeviceHandle = null;
+ throw new IllegalArgumentException("Unrecognized tuner config [" + config.getClass() + "]");
}
}
@@ -285,11 +186,11 @@ public class E4KTunerController extends RTL2832TunerController
public void setSampleRateFilters(int bandwidth) throws SourceException
{
/* Determine repeater state so we can restore it when done */
- boolean i2CRepeaterEnabled = isI2CRepeaterEnabled();
+ boolean i2CRepeaterEnabled = getAdapter().isI2CRepeaterEnabled();
if(!i2CRepeaterEnabled)
{
- enableI2CRepeater(mDeviceHandle, true);
+ getAdapter().enableI2CRepeater();
}
boolean controlI2CRepeater = false;
@@ -305,52 +206,46 @@ public class E4KTunerController extends RTL2832TunerController
if(!i2CRepeaterEnabled)
{
- enableI2CRepeater(mDeviceHandle, false);
+ getAdapter().disableI2CRepeater();
}
}
- @Override
public long getTunedFrequency() throws SourceException
{
try
{
/* Determine repeater state so we can restore it when done */
- boolean i2CRepeaterEnabled = isI2CRepeaterEnabled();
+ boolean i2CRepeaterEnabled = getAdapter().isI2CRepeaterEnabled();
if(!i2CRepeaterEnabled)
{
- enableI2CRepeater(mDeviceHandle, true);
+ getAdapter().enableI2CRepeater();
}
boolean controlI2CRepeater = false;
-
byte z = (byte) readE4KRegister(Register.SYNTH3, controlI2CRepeater);
-
int xHigh = readE4KRegister(Register.SYNTH4, controlI2CRepeater);
int xLow = readE4KRegister(Register.SYNTH5, controlI2CRepeater);
-
int x = (Integer.rotateLeft(xHigh, 8)) | xLow;
-
int pllSetting = readE4KRegister(Register.SYNTH7, controlI2CRepeater);
PLL pll = PLL.fromSetting(pllSetting);
/* Return the repeater to its previous state */
if(!i2CRepeaterEnabled)
{
- enableI2CRepeater(mDeviceHandle, false);
+ getAdapter().disableI2CRepeater();
}
return calculateActualFrequency(pll, z, x);
}
catch(LibUsbException e)
{
- throw new SourceException("E4K tuner controller - couldn't get "
- + "tuned frequency", e);
+ throw new SourceException("E4K tuner controller - couldn't get " + "tuned frequency", e);
}
}
@Override
- public void setTunedFrequency(long frequency) throws SourceException
+ public synchronized void setTunedFrequency(long frequency) throws SourceException
{
/* Get the phase locked loop setting */
PLL pll = PLL.fromFrequency(frequency);
@@ -375,61 +270,49 @@ public class E4KTunerController extends RTL2832TunerController
* to rounding errors, 52 mhz becomes 51.999993, so we need to adjust
* x to get 52.000003 mhz ... otherwise the PLL won't lock on the freq
*/
- if(actualFrequency < getMinFrequency())
+ if(actualFrequency < getMinimumFrequencySupported())
{
x++;
actualFrequency = calculateActualFrequency(pll, z, x);
}
- mLock.lock();
+ getAdapter().getLock().lock();
- /* Apply the actual frequency */
try
{
- enableI2CRepeater(mDeviceHandle, true);
-
+ /* Apply the actual frequency */
+ getAdapter().enableI2CRepeater();
boolean controlI2CRepeater = false;
-
/* Write the PLL setting */
writeE4KRegister(Register.SYNTH7, pll.getIndex(), controlI2CRepeater);
-
/* Write z (integral) value */
writeE4KRegister(Register.SYNTH3, z, controlI2CRepeater);
-
/* Write the x (fractional) value high-order byte to synth4 register */
writeE4KRegister(Register.SYNTH4, (byte) (x & 0xFF), controlI2CRepeater);
-
/* Write the x (fractional) value low-order byte to synth5 register */
- writeE4KRegister(Register.SYNTH5,
- (byte) ((Integer.rotateRight(x, 8)) & 0xFF),
- controlI2CRepeater);
-
+ writeE4KRegister(Register.SYNTH5, (byte) ((Integer.rotateRight(x, 8)) & 0xFF), controlI2CRepeater);
/* Set the band for the new frequency */
setBand(actualFrequency, controlI2CRepeater);
-
/* Set the filter */
setRFFilter(actualFrequency, controlI2CRepeater);
-
/* Check for PLL lock */
int lock = readE4KRegister(Register.SYNTH1, controlI2CRepeater);
if(!((lock & 0x1) == 0x1))
{
- throw new SourceException("E4K tuner controller - couldn't "
- + "achieve PLL lock for frequency [" +
- actualFrequency + "] lock value [" + lock + "]");
+ throw new SourceException("E4K tuner - couldn't achieve PLL lock for frequency [" + actualFrequency +
+ "] lock value [" + lock + "]");
}
- enableI2CRepeater(mDeviceHandle, false);
+ getAdapter().disableI2CRepeater();
}
catch(UsbException e)
{
- throw new SourceException("E4K tuner controller - error tuning "
- + "frequency [" + frequency + "]", e);
+ throw new SourceException("E4K tuner controller - error tuning frequency [" + frequency + "]", e);
}
finally
{
- mLock.unlock();
+ getAdapter().getLock().unlock();
}
}
@@ -438,223 +321,190 @@ public class E4KTunerController extends RTL2832TunerController
long whole = pll.getScaledOscillator() * (z & 0xFF);
int fractional = (int) (pll.getScaledOscillator() *
- ((double) x / (double) E4K_PLL_Y));
+ ((double) x / (double) E4K_PLL_Y));
return whole + fractional;
}
- public void initTuner(boolean controlI2CRepeater) throws UsbException
+ protected void initTuner() throws UsbException
{
- if(controlI2CRepeater)
- {
- enableI2CRepeater(mDeviceHandle, true);
- }
+ getAdapter().enableI2CRepeater();
boolean i2CRepeaterControl = false;
/* Perform dummy read */
readE4KRegister(Register.DUMMY, i2CRepeaterControl);
-
- /* Reset everything and clear POR indicator */
- /* NOTE: register value remains 0010 even after we write 0111 to it */
- writeE4KRegister(Register.MASTER1, (byte) (MASTER1_RESET |
- MASTER1_NORM_STBY |
- MASTER1_POR_DET),
- i2CRepeaterControl);
-
+ /* Reset everything and clear POR indicator. NOTE: register value remains 0010 even after we write 0111 to it */
+ writeE4KRegister(Register.MASTER1, (byte) (MASTER1_RESET | MASTER1_NORM_STBY | MASTER1_POR_DET), i2CRepeaterControl);
/* Configure clock input */
writeE4KRegister(Register.CLK_INP, (byte) 0x00, i2CRepeaterControl);
-
/* Disable clock output */
writeE4KRegister(Register.REF_CLK, (byte) 0x00, i2CRepeaterControl);
writeE4KRegister(Register.CLKOUT_PWDN, (byte) 0x96, i2CRepeaterControl);
-
- /* Magic Init */
+ //Make the magic happen ...
magicInit(i2CRepeaterControl);
-// /* Set common mode voltage a bit higher for more margin - 850 mv */
-// writeMaskedE4KRegister( Register.DC7, (byte)0x7,
-// (byte)0x4, i2CRepeaterControl );
-//
-// /* Initialize DC offset lookup tables */
-// generateDCOffsetTables( i2CRepeaterControl );
-//
-// /* Enable time variant DC correction */
-// writeE4KRegister( Register.DCTIME1, (byte)0x01, i2CRepeaterControl );
-// writeE4KRegister( Register.DCTIME2, (byte)0x01, i2CRepeaterControl );
-//
+ /* Initialize DC offset lookup tables */
+ generateDCOffsetTables(i2CRepeaterControl);
+
+ /* Enable time variant DC correction */
+ writeE4KRegister(Register.DCTIME1, (byte) 0x01, i2CRepeaterControl);
+ writeE4KRegister(Register.DCTIME2, (byte) 0x01, i2CRepeaterControl);
+
/* Set LNA Mode */
writeE4KRegister(Register.AGC4, (byte) 0x10, i2CRepeaterControl); //High Threshold
writeE4KRegister(Register.AGC5, (byte) 0x04, i2CRepeaterControl); //Low Threshold
- writeE4KRegister(Register.AGC6, (byte) 0x1A, i2CRepeaterControl); //LNA calibrate + loop rate
-
- //TODO: lna and mixer gain were already set to manual when we generated
- //the DC offset tables. Check the LNA gain setting after we set the
- //LNA mode above, to see if the lna or mixer gain settings have changed
- //and if not, remove the next two steps
-
-// /* Set LNA gain to manual using current auto LNA gain setting */
-// LNAGain lnaGain = getLNAGain( i2CRepeaterControl );
-// setLNAGain( lnaGain, i2CRepeaterControl );
-//
-// /* Set Mixer gain to manual using current auto Mixer gain setting */
-// MixerGain mixerGain = getMixerGain( i2CRepeaterControl );
-// setMixerGain( mixerGain, i2CRepeaterControl );
+ writeE4KRegister(Register.AGC6, (byte) 0x1A, i2CRepeaterControl); //LNA calibrate request + slowest loop rate
//Temp - manual set lna mode to manual
- writeMaskedE4KRegister(Register.AGC1,
- AGC1_MOD_MASK,
- AGCMode.SERIAL.getValue(),
- false);
+ writeMaskedE4KRegister(Register.AGC1, AGC1_MOD_MASK, AGCMode.SERIAL.getValue(), false);
//Temp - set mixer gain to manual
- writeMaskedE4KRegister(Register.AGC7,
- AGC7_MIXER_GAIN_MASK,
- AGC7_MIX_GAIN_MANUAL,
- false);
-
-
-// /* Enable enhance gain */
-// setEnhanceGain( EnhanceGain.GAIN_5, i2CRepeaterControl );
-//
-// /* Enable automatic IF gain mode switching */
-// writeMaskedE4KRegister( Register.AGC8,
-// IF_GAIN_MODE_SWITCHING_MASK,
-// AGC8_SENS_LIN_AUTO,
-// i2CRepeaterControl );
-
+ writeMaskedE4KRegister(Register.AGC7, AGC7_MIXER_GAIN_MASK, AGC7_MIX_GAIN_MANUAL, false);
/* Use automatic gain as a default */
setLNAGain(E4KLNAGain.AUTOMATIC, i2CRepeaterControl);
setMixerGain(E4KMixerGain.AUTOMATIC, i2CRepeaterControl);
- setEnhanceGain(E4KEnhanceGain.AUTOMATIC, i2CRepeaterControl);
+ setEnhanceGain(E4KEnhanceGain.GAIN_5, i2CRepeaterControl); //Setting of 5 is recommended in datasheet
/* Set IF gain stages */
- setIFStage1Gain(IFStage1Gain.GAIN_PLUS6, i2CRepeaterControl);
- setIFStage2Gain(IFStage2Gain.GAIN_PLUS0, i2CRepeaterControl);
- setIFStage3Gain(IFStage3Gain.GAIN_PLUS0, i2CRepeaterControl);
- setIFStage4Gain(IFStage4Gain.GAIN_PLUS0, i2CRepeaterControl);
- setIFStage5Gain(IFStage5Gain.GAIN_PLUS9, i2CRepeaterControl);
- setIFStage6Gain(IFStage6Gain.GAIN_PLUS9, i2CRepeaterControl);
+ setIFGain(IFGain.LINEARITY_8, i2CRepeaterControl);
- /* Set the most narrow filter we can possible use */
+ /* Set the narrowest filter we can possibly use */
setMixerFilter(MixerFilter.BW_1M9, i2CRepeaterControl);
setRCFilter(RCFilter.BW_1M0, i2CRepeaterControl);
setChannelFilter(ChannelFilter.BW_2M15, i2CRepeaterControl);
-
setChannelFilterEnabled(true, i2CRepeaterControl);
-// /* Disable DC detector */
-// setDCRangeDetectorEnabled( false, i2CRepeaterControl );
+ /* Disable DC detector */
+ setDCRangeDetectorEnabled( false, i2CRepeaterControl );
+ setDCOffsetLookupTablesEnabled(false, i2CRepeaterControl);
/* Disable time variant DC correction */
writeMaskedE4KRegister(Register.DC5, (byte) 0x03, (byte) 0, i2CRepeaterControl);
writeMaskedE4KRegister(Register.DCTIME1, (byte) 0x03, (byte) 0, i2CRepeaterControl);
writeMaskedE4KRegister(Register.DCTIME2, (byte) 0x03, (byte) 0, i2CRepeaterControl);
- if(controlI2CRepeater)
- {
- enableI2CRepeater(mDeviceHandle, false);
- }
+ getAdapter().disableI2CRepeater();
}
- @SuppressWarnings("unused")
- private void generateDCOffsetTables(boolean controlI2CRepeater)
- throws UsbException
+ /**
+ * Requests a DC offset calibration for the tuner
+ */
+ private void requestDcOffsetCalibration(boolean controlI2CRepeater) throws LibUsbException
{
- boolean i2CRepeaterControl = false;
+ if(controlI2CRepeater)
+ {
+ getAdapter().enableI2CRepeater();
+ }
+
+ writeMaskedE4KRegister(Register.DC1, (byte) 0x1, (byte) 0x1, false);
if(controlI2CRepeater)
{
- enableI2CRepeater(mDeviceHandle, true);
- }
-
- /* Capture current gain settings to reapply at the end */
- IFStage1Gain stage1 = getIFStage1Gain(i2CRepeaterControl);
- IFStage2Gain stage2 = getIFStage2Gain(i2CRepeaterControl);
- IFStage3Gain stage3 = getIFStage3Gain(i2CRepeaterControl);
- IFStage4Gain stage4 = getIFStage4Gain(i2CRepeaterControl);
- IFStage5Gain stage5 = getIFStage5Gain(i2CRepeaterControl);
- IFStage6Gain stage6 = getIFStage6Gain(i2CRepeaterControl);
-
- /* Set Mixer gain to manual using current auto Mixer gain setting */
- E4KMixerGain mixerGain = getMixerGain(i2CRepeaterControl);
- setMixerGain(mixerGain, i2CRepeaterControl);
-
- /* Set LNA gain to manual using current auto LNA gain setting */
- E4KLNAGain lnaGain = getLNAGain(i2CRepeaterControl);
- setLNAGain(lnaGain, i2CRepeaterControl);
-
- /* Set IF Stage 2 - 6 gains to maximum */
- setIFStage2Gain(IFStage2Gain.GAIN_PLUS9, i2CRepeaterControl);
- setIFStage3Gain(IFStage3Gain.GAIN_PLUS9, i2CRepeaterControl);
- setIFStage4Gain(IFStage4Gain.GAIN_PLUS2B, i2CRepeaterControl);
- setIFStage5Gain(IFStage5Gain.GAIN_PLUS15D, i2CRepeaterControl);
- setIFStage6Gain(IFStage6Gain.GAIN_PLUS15D, i2CRepeaterControl);
-
- /**
- * Iterate all DC gain combinations, apply gain settings, read the
- * DC offset value and apply it to the lookup table entry
- */
- for(DCGainCombination combo : DCGainCombination.values())
- {
- /* Set mixer and stage1 gain values */
- setMixerGain(combo.getMixerGain(), i2CRepeaterControl);
- setIFStage1Gain(combo.getIFStage1Gain(), i2CRepeaterControl);
-
- /* Turn on the DC range detector */
- setDCRangeDetectorEnabled(true, i2CRepeaterControl);
-
- /* Calibrate the DC value */
- writeE4KRegister(Register.DC1, (byte) 0x01, i2CRepeaterControl);
-
- /* Get the I/Q offset and range values */
- byte offsetI = (byte) (readE4KRegister(Register.DC2,
- i2CRepeaterControl) & 0x3F);
- byte offsetQ = (byte) (readE4KRegister(Register.DC3,
- i2CRepeaterControl) & 0x3F);
- byte range = (byte) readE4KRegister(Register.DC4,
- i2CRepeaterControl);
- byte rangeI = (byte) (range & 0x3);
- byte rangeQ = (byte) ((range >> 4) & 0x3);
-
- /* Write the offset and range values to the lookup table */
- writeE4KRegister(combo.getIRegister(),
- (byte) (offsetI | (rangeI << 6)),
- i2CRepeaterControl);
-
- writeE4KRegister(combo.getQRegister(),
- (byte) (offsetQ | (rangeQ << 6)),
- i2CRepeaterControl);
- }
-
- if(controlI2CRepeater)
- {
- enableI2CRepeater(mDeviceHandle, false);
- }
- }
-
- public void setDCRangeDetectorEnabled(boolean enabled,
- boolean controlI2CRepeater) throws UsbException
- {
- if(enabled)
- {
- writeMaskedE4KRegister(Register.DC5,
- DC5_RANGE_DETECTOR_ENABLED_MASK,
- DC5_RANGE_DETECTOR_ENABLED,
- controlI2CRepeater);
- }
- else
- {
- writeMaskedE4KRegister(Register.DC5,
- DC5_RANGE_DETECTOR_DISABLED_MASK,
- DC5_RANGE_DETECTOR_DISABLED,
- controlI2CRepeater);
+ getAdapter().disableI2CRepeater();
}
}
/**
- * Sets the LNA gain within the E4K Tuner
+ * Calibrates the DC offset lookup table values for tuner initialization
+ */
+ private void generateDCOffsetTables(boolean controlI2CRepeater) throws UsbException
+ {
+ if(controlI2CRepeater)
+ {
+ getAdapter().enableI2CRepeater();
+ }
+
+ boolean i2CRepeaterControl = false;
+
+ //Set all IF gain stages (1-6) to maximum values. During calibration we'll change IF stage 1 gain
+ setIFGain(IFGain.LINEARITY_60, i2CRepeaterControl);
+
+ //Enable DC range detector
+ setDCRangeDetectorEnabled(true, i2CRepeaterControl);
+
+ //Enable DC offset lookup tables
+ setDCOffsetLookupTablesEnabled(true, i2CRepeaterControl);
+
+ //Step 0
+ setIFStage1Gain(IFStage1Gain.GAIN_MINUS3, i2CRepeaterControl);
+ setMixerGain(E4KMixerGain.GAIN_4, i2CRepeaterControl);
+ requestDcOffsetCalibration(i2CRepeaterControl);
+ byte i = getDcOffsetI(i2CRepeaterControl);
+ byte q = getDcOffsetQ(i2CRepeaterControl);
+ writeE4KRegister(Register.ILUT0, i, i2CRepeaterControl);
+ writeE4KRegister(Register.QLUT0, q, i2CRepeaterControl);
+
+ //Step 1
+ setMixerGain(E4KMixerGain.GAIN_12, i2CRepeaterControl);
+ requestDcOffsetCalibration(i2CRepeaterControl);
+ i = getDcOffsetI(i2CRepeaterControl);
+ q = getDcOffsetQ(i2CRepeaterControl);
+ writeE4KRegister(Register.ILUT1, i, i2CRepeaterControl);
+ writeE4KRegister(Register.QLUT1, q, i2CRepeaterControl);
+
+ //Step 2
+ setIFStage1Gain(IFStage1Gain.GAIN_PLUS6, i2CRepeaterControl);
+ setMixerGain(E4KMixerGain.GAIN_4, i2CRepeaterControl);
+ requestDcOffsetCalibration(i2CRepeaterControl);
+ i = getDcOffsetI(i2CRepeaterControl);
+ q = getDcOffsetQ(i2CRepeaterControl);
+ writeE4KRegister(Register.ILUT2, i, i2CRepeaterControl);
+ writeE4KRegister(Register.QLUT2, q, i2CRepeaterControl);
+
+ //Step 3
+ setMixerGain(E4KMixerGain.GAIN_12, i2CRepeaterControl);
+ requestDcOffsetCalibration(i2CRepeaterControl);
+ i = getDcOffsetI(i2CRepeaterControl);
+ q = getDcOffsetQ(i2CRepeaterControl);
+ writeE4KRegister(Register.ILUT3, i, i2CRepeaterControl);
+ writeE4KRegister(Register.QLUT3, q, i2CRepeaterControl);
+
+ if(controlI2CRepeater)
+ {
+ getAdapter().disableI2CRepeater();
+ }
+ }
+
+ private byte getDcOffsetI(boolean i2CRepeaterControl)
+ {
+ byte offset = (byte) (readE4KRegister(Register.DC2, i2CRepeaterControl) & 0x3F);
+ byte range = (byte) ((readE4KRegister(Register.DC4, i2CRepeaterControl) & 0x3) << 6);
+ return (byte) (range | offset);
+ }
+
+ private byte getDcOffsetQ(boolean i2CRepeaterControl)
+ {
+ byte offset = (byte) (readE4KRegister(Register.DC3, i2CRepeaterControl) & 0x3F);
+ byte range = (byte) (readE4KRegister(Register.DC4, i2CRepeaterControl) << 2);
+ return (byte) (range | offset);
+ }
+
+ /**
+ * Enables or disables the DC offset lookup tables.
*
+ * @param enabled
+ * @param controlI2CRepeater
+ * @throws LibUsbException
+ */
+ public void setDCOffsetLookupTablesEnabled(boolean enabled, boolean controlI2CRepeater) throws LibUsbException
+ {
+ byte value = enabled ? (byte) 0x3 : (byte) 0x0;
+ writeMaskedE4KRegister(Register.DC5, value, (byte) 0x3, controlI2CRepeater);
+ }
+
+ /**
+ * Enables or disables the DC range detector
+ */
+ public void setDCRangeDetectorEnabled(boolean enabled, boolean controlI2CRepeater) throws LibUsbException
+ {
+ byte value = enabled ? DC5_RANGE_DETECTOR_ENABLED : (byte) 0x0;
+ writeMaskedE4KRegister(Register.DC5, DC5_RANGE_DETECTOR_ENABLED_MASK, value, controlI2CRepeater);
+ }
+
+ /**
+ * Sets the LNA gain within the E4K Tuner
+ *
* Note: requires I2C repeater enabled
*
* @param gain
@@ -662,69 +512,49 @@ public class E4KTunerController extends RTL2832TunerController
*/
public void setLNAGain(E4KLNAGain gain, boolean controlI2CRepeater) throws UsbException
{
- mLock.lock();
+ getAdapter().getLock().lock();
try
{
if(controlI2CRepeater)
{
- enableI2CRepeater(mDeviceHandle, true);
+ getAdapter().enableI2CRepeater();
}
if(gain == E4KLNAGain.AUTOMATIC)
{
- writeMaskedE4KRegister(Register.AGC1,
- AGC1_MOD_MASK,
- AGCMode.IF_SERIAL_LNA_AUTON.getValue(),
- false);
+ writeMaskedE4KRegister(Register.AGC1, AGC1_MOD_MASK, AGCMode.IF_SERIAL_LNA_AUTON.getValue(), false);
}
else
{
- writeMaskedE4KRegister(Register.AGC1,
- AGC1_MOD_MASK,
- AGCMode.SERIAL.getValue(),
- false);
-
-
- writeMaskedE4KRegister(E4KLNAGain.getRegister(),
- E4KLNAGain.getMask(),
- gain.getValue(),
- false);
+ writeMaskedE4KRegister(Register.AGC1, AGC1_MOD_MASK, AGCMode.SERIAL.getValue(), false);
+ writeMaskedE4KRegister(E4KLNAGain.getRegister(), E4KLNAGain.getMask(), gain.getValue(), false);
}
if(controlI2CRepeater)
{
- enableI2CRepeater(mDeviceHandle, false);
+ getAdapter().disableI2CRepeater();
}
}
finally
{
- mLock.unlock();
+ getAdapter().getLock().unlock();
}
}
/**
* Reads LNA gain from E4K tuner
- *
+ *
* Note: requires I2C repeater enabled
*/
public E4KLNAGain getLNAGain(boolean controlI2CRepeater) throws UsbException
{
- mLock.lock();
-
- try
- {
- return E4KLNAGain.fromRegisterValue(readE4KRegister(E4KLNAGain.getRegister(), controlI2CRepeater));
- }
- finally
- {
- mLock.unlock();
- }
+ return E4KLNAGain.fromRegisterValue(readE4KRegister(E4KLNAGain.getRegister(), controlI2CRepeater));
}
/**
* Sets enhanced gain for E4K repeater.
- *
+ *
* Note: requires I2C repeater enabled
*
* @param gain
@@ -732,21 +562,12 @@ public class E4KTunerController extends RTL2832TunerController
*/
public void setEnhanceGain(E4KEnhanceGain gain, boolean controlI2CRepeater) throws UsbException
{
- mLock.lock();
-
- try
- {
- writeMaskedE4KRegister(E4KEnhanceGain.getRegister(), E4KEnhanceGain.getMask(), gain.getValue(), controlI2CRepeater);
- }
- finally
- {
- mLock.unlock();
- }
+ writeMaskedE4KRegister(E4KEnhanceGain.getRegister(), E4KEnhanceGain.getMask(), gain.getValue(), controlI2CRepeater);
}
/**
* Gets the enhanced gain setting in the E4K tuner.
- *
+ *
* Note: requires I2C repeater
*
* @return
@@ -754,271 +575,182 @@ public class E4KTunerController extends RTL2832TunerController
*/
public E4KEnhanceGain getEnhanceGain(boolean controlI2CRepeater) throws UsbException
{
- mLock.lock();
-
- try
- {
- return E4KEnhanceGain.fromRegisterValue(readE4KRegister(E4KEnhanceGain.getRegister(), controlI2CRepeater));
- }
- finally
- {
- mLock.unlock();
- }
+ return E4KEnhanceGain.fromRegisterValue(readE4KRegister(E4KEnhanceGain.getRegister(), controlI2CRepeater));
}
+ /**
+ * Sets the mixer gain
+ *
+ * @param gain to apply
+ * @param controlI2CRepeater set to true to turn on/off repeater within this method or false if already enabled.
+ * @throws UsbException on error
+ */
public void setMixerGain(E4KMixerGain gain, boolean controlI2CRepeater) throws UsbException
{
- mLock.lock();
+ getAdapter().getLock().lock();
try
{
if(controlI2CRepeater)
{
- enableI2CRepeater(mDeviceHandle, true);
+ getAdapter().enableI2CRepeater();
}
- boolean localI2CRepeaterControl = false;
+ boolean repeaterControl = false;
if(gain == E4KMixerGain.AUTOMATIC)
{
- writeMaskedE4KRegister(Register.AGC7,
- AGC7_MIXER_GAIN_MASK,
- AGC7_MIX_GAIN_AUTO,
- localI2CRepeaterControl);
+ writeMaskedE4KRegister(Register.AGC7, AGC7_MIXER_GAIN_MASK, AGC7_MIX_GAIN_AUTO, repeaterControl);
}
else
{
- writeMaskedE4KRegister(Register.AGC7,
- AGC7_MIXER_GAIN_MASK,
- AGC7_MIX_GAIN_MANUAL,
- localI2CRepeaterControl);
-
+ writeMaskedE4KRegister(Register.AGC7, AGC7_MIXER_GAIN_MASK, AGC7_MIX_GAIN_MANUAL, repeaterControl);
/* Set the desired manual gain setting */
- writeMaskedE4KRegister(E4KMixerGain.getRegister(),
- E4KMixerGain.getMask(),
- gain.getValue(),
- localI2CRepeaterControl);
+ writeMaskedE4KRegister(E4KMixerGain.getRegister(), E4KMixerGain.getMask(), gain.getValue(), repeaterControl);
}
if(controlI2CRepeater)
{
- enableI2CRepeater(mDeviceHandle, false);
+ getAdapter().disableI2CRepeater();
}
}
finally
{
- mLock.unlock();
+ getAdapter().getLock().unlock();
}
}
public E4KMixerGain getMixerGain(boolean controlI2CRepeater) throws UsbException
{
- mLock.lock();
+ byte autoOrManual = readMaskedE4KRegister(Register.AGC7, AGC7_MIXER_GAIN_MASK, controlI2CRepeater);
+
+ if(autoOrManual == AGC7_MIX_GAIN_AUTO)
+ {
+ return E4KMixerGain.AUTOMATIC;
+ }
+ else
+ {
+ int register = readE4KRegister(E4KMixerGain.getRegister(), controlI2CRepeater);
+ return E4KMixerGain.fromRegisterValue(register);
+ }
+ }
+
+ /**
+ * Sets IF Gains 1 - 6 using a set of linear gain values defined in the IFGain enumeration
+ *
+ * @param gain to apply
+ * @param controlI2CRepeater set false if I2C repeater is already enabled or true if the I2C repeater should
+ * be turned on and off within this method.
+ * @throws LibUsbException if the write operation doesn't complete successfully
+ */
+ public void setIFGain(IFGain gain, boolean controlI2CRepeater) throws LibUsbException
+ {
+ getAdapter().getLock().lock();
try
{
- byte autoOrManual = readMaskedE4KRegister(Register.AGC7, AGC7_MIXER_GAIN_MASK, controlI2CRepeater);
-
- if(autoOrManual == AGC7_MIX_GAIN_AUTO)
- {
- return E4KMixerGain.AUTOMATIC;
- }
- else
- {
- int register = readE4KRegister(E4KMixerGain.getRegister(), controlI2CRepeater);
- return E4KMixerGain.fromRegisterValue(register);
- }
+ byte linearityMode = gain.isLinearity() ? (byte) 0x00 : (byte) 0x10;
+ writeMaskedE4KRegister(Register.AGC1, gain.getLinearityModeMask(), linearityMode, controlI2CRepeater);
+ writeMaskedE4KRegister(Register.GAIN3, gain.getGain3Mask(), gain.getGain3(), controlI2CRepeater);
+ writeMaskedE4KRegister(Register.GAIN4, gain.getGain4Mask(), gain.getGain4(), controlI2CRepeater);
}
finally
{
- mLock.unlock();
+ getAdapter().getLock().unlock();
}
}
- public void setIFStage1Gain(IFStage1Gain gain, boolean controlI2CRepeater) throws UsbException
+ /**
+ * Sets the IF Stage 1 gain value.
+ */
+ public void setIFStage1Gain(IFStage1Gain gain, boolean controlI2CRepeater)
{
- writeMaskedE4KRegister(IFStage1Gain.getRegister(),
- IFStage1Gain.getMask(),
- gain.getValue(),
- controlI2CRepeater);
+ if(controlI2CRepeater)
+ {
+ getAdapter().enableI2CRepeater();
+ }
+
+ writeMaskedE4KRegister(Register.GAIN3, gain.getValue(), gain.getMask(), false);
+
+ if(controlI2CRepeater)
+ {
+ getAdapter().disableI2CRepeater();
+ }
}
- public IFStage1Gain getIFStage1Gain(boolean controlI2CRepeater)
- throws UsbException
+ public void setMixerFilter(MixerFilter filter, boolean controlI2CRepeater) throws LibUsbException
{
- return IFStage1Gain.fromRegisterValue(
- readE4KRegister(IFStage1Gain.getRegister(), controlI2CRepeater));
+ writeMaskedE4KRegister(MixerFilter.getRegister(), MixerFilter.getMask(), filter.getValue(), controlI2CRepeater);
}
- public void setIFStage2Gain(IFStage2Gain gain,
- boolean controlI2CRepeater) throws UsbException
+ public MixerFilter getMixerFilter(boolean controlI2CRepeater) throws UsbException
{
- writeMaskedE4KRegister(IFStage2Gain.getRegister(),
- IFStage2Gain.getMask(),
- gain.getValue(),
- controlI2CRepeater);
- }
-
- public IFStage2Gain getIFStage2Gain(boolean controlI2CRepeater)
- throws UsbException
- {
- return IFStage2Gain.fromRegisterValue(
- readE4KRegister(IFStage2Gain.getRegister(), controlI2CRepeater));
- }
-
- public void setIFStage3Gain(IFStage3Gain gain,
- boolean controlI2CRepeater) throws UsbException
- {
- writeMaskedE4KRegister(IFStage3Gain.getRegister(),
- IFStage3Gain.getMask(),
- gain.getValue(),
- controlI2CRepeater);
- }
-
- public IFStage3Gain getIFStage3Gain(boolean controlI2CRepeater)
- throws UsbException
- {
- return IFStage3Gain.fromRegisterValue(
- readE4KRegister(IFStage3Gain.getRegister(), controlI2CRepeater));
- }
-
- public void setIFStage4Gain(IFStage4Gain gain,
- boolean controlI2CRepeater) throws UsbException
- {
- writeMaskedE4KRegister(IFStage4Gain.getRegister(),
- IFStage4Gain.getMask(),
- gain.getValue(),
- controlI2CRepeater);
- }
-
- public IFStage4Gain getIFStage4Gain(boolean controlI2CRepeater)
- throws UsbException
- {
- return IFStage4Gain.fromRegisterValue(
- readE4KRegister(IFStage4Gain.getRegister(), controlI2CRepeater));
- }
-
- public void setIFStage5Gain(IFStage5Gain gain,
- boolean controlI2CRepeater) throws UsbException
- {
- writeMaskedE4KRegister(IFStage5Gain.getRegister(),
- IFStage5Gain.getMask(),
- gain.getValue(),
- controlI2CRepeater);
- }
-
- public IFStage5Gain getIFStage5Gain(boolean controlI2CRepeater)
- throws UsbException
- {
- return IFStage5Gain.fromRegisterValue(
- readE4KRegister(IFStage5Gain.getRegister(), controlI2CRepeater));
- }
-
- public void setIFStage6Gain(IFStage6Gain gain,
- boolean controlI2CRepeater) throws UsbException
- {
- writeMaskedE4KRegister(IFStage6Gain.getRegister(),
- IFStage6Gain.getMask(),
- gain.getValue(),
- controlI2CRepeater);
- }
-
- public IFStage6Gain getIFStage6Gain(boolean controlI2CRepeater)
- throws UsbException
- {
- return IFStage6Gain.fromRegisterValue(
- readE4KRegister(IFStage6Gain.getRegister(), controlI2CRepeater));
- }
-
- public void setMixerFilter(MixerFilter filter,
- boolean controlI2CRepeater) throws LibUsbException
- {
- writeMaskedE4KRegister(MixerFilter.getRegister(),
- MixerFilter.getMask(),
- filter.getValue(),
- controlI2CRepeater);
- }
-
- public MixerFilter getMixerFilter(boolean controlI2CRepeater)
- throws UsbException
- {
- int value = readE4KRegister(MixerFilter.getRegister(),
- controlI2CRepeater);
-
+ int value = readE4KRegister(MixerFilter.getRegister(), controlI2CRepeater);
return MixerFilter.fromRegisterValue(value);
}
- public void setRCFilter(RCFilter filter,
- boolean controlI2CRepeater) throws LibUsbException
+ public void setRCFilter(RCFilter filter, boolean controlI2CRepeater) throws LibUsbException
{
- writeMaskedE4KRegister(RCFilter.getRegister(),
- RCFilter.getMask(),
- filter.getValue(),
- controlI2CRepeater);
+ writeMaskedE4KRegister(RCFilter.getRegister(), RCFilter.getMask(), filter.getValue(), controlI2CRepeater);
}
public RCFilter getRCFilter(boolean controlI2CRepeater) throws UsbException
{
int value = readE4KRegister(RCFilter.getRegister(), controlI2CRepeater);
-
return RCFilter.fromRegisterValue(value);
}
- public void setChannelFilter(ChannelFilter filter,
- boolean controlI2CRepeater) throws LibUsbException
+ public void setChannelFilter(ChannelFilter filter, boolean controlI2CRepeater) throws LibUsbException
{
- writeMaskedE4KRegister(ChannelFilter.getRegister(),
- ChannelFilter.getMask(),
- filter.getValue(),
- controlI2CRepeater);
+ writeMaskedE4KRegister(ChannelFilter.getRegister(), ChannelFilter.getMask(), filter.getValue(), controlI2CRepeater);
}
- public ChannelFilter getChannelFilter(boolean controlI2CRepeater)
- throws UsbException
+ public ChannelFilter getChannelFilter(boolean controlI2CRepeater) throws UsbException
{
int value = readE4KRegister(ChannelFilter.getRegister(), controlI2CRepeater);
-
return ChannelFilter.fromRegisterValue(value);
-
}
- public void setChannelFilterEnabled(boolean enabled,
- boolean controlI2CRepeater) throws UsbException
+ public void setChannelFilterEnabled(boolean enabled, boolean controlI2CRepeater) throws UsbException
{
if(enabled)
{
- writeMaskedE4KRegister(Register.FILT3,
- FILT3_MASK,
- FILT3_ENABLE,
- controlI2CRepeater);
+ writeMaskedE4KRegister(Register.FILT3, FILT3_MASK, FILT3_ENABLE, controlI2CRepeater);
}
else
{
- writeMaskedE4KRegister(Register.FILT3,
- FILT3_MASK,
- FILT3_DISABLE,
- controlI2CRepeater);
+ writeMaskedE4KRegister(Register.FILT3, FILT3_MASK, FILT3_DISABLE, controlI2CRepeater);
}
}
+ /**
+ * Enables or disables VCO auto-calibration.
+ */
+ public void setVcoAutoCalibration(boolean enabled, boolean controlI2CRepeater)
+ {
+ byte value = enabled ? (byte) 0x01 : (byte) 0x00;
+ byte mask = (byte) 0x3;
+ writeMaskedE4KRegister(Register.SYNTH8, mask, value, controlI2CRepeater);
+ }
+
public void setBand(long frequency, boolean controlI2CRepeater) throws UsbException
{
if(controlI2CRepeater)
{
- enableI2CRepeater(mDeviceHandle, true);
+ getAdapter().enableI2CRepeater();
}
- Band band = Band.fromFrequency(frequency);
+ FrequencyBand frequencyBand = FrequencyBand.fromFrequency(frequency);
/* Set the bias */
- switch(band)
+ switch(frequencyBand)
{
case UHF:
case VHF2:
case VHF3:
writeE4KRegister(Register.BIAS, (byte) 0x3, false);
break;
- case L:
+ case L_BAND:
default:
writeE4KRegister(Register.BIAS, (byte) 0x0, false);
break;
@@ -1029,56 +761,57 @@ public class E4KTunerController extends RTL2832TunerController
* Workaround - reset register (set value to 0) before writing to it, to
* avoid a gap around 325-350 MHz
*/
- writeMaskedE4KRegister(Register.SYNTH1, Band.getMask(), (byte) 0x0, false);
- writeMaskedE4KRegister(Register.SYNTH1, Band.getMask(), band.getValue(), false);
+ writeMaskedE4KRegister(Register.SYNTH1, FrequencyBand.getMask(), (byte) 0x0, false);
+ writeMaskedE4KRegister(Register.SYNTH1, FrequencyBand.getMask(), frequencyBand.getValue(), false);
if(controlI2CRepeater)
{
- enableI2CRepeater(mDeviceHandle, false);
+ getAdapter().disableI2CRepeater();
}
}
private void setRFFilter(long frequency, boolean controlI2CRepeater) throws UsbException
{
RFFilter filter = RFFilter.fromFrequency(frequency);
-
- writeMaskedE4KRegister(Register.FILT1,
- RFFilter.getMask(),
- filter.getValue(),
- controlI2CRepeater);
+ writeMaskedE4KRegister(Register.FILT1, RFFilter.getMask(), filter.getValue(), controlI2CRepeater);
}
/**
- * Sets the gain combination setting.
- *
- * Note: does not respond to the MANUAL setting. Use the manual setting
- * to configure gui components to expose the individual Mixer, LNA and
- * Enhance gain settings, to allow the user to change those settings
- * individually.
+ * Sets the master gain combination setting.
+ * Note: does not respond to the MANUAL setting. Use the manual setting to configure gui components to expose the
+ * individual Mixer, LNA and Enhance gain settings, to allow the user to change those settings individually.
*
* @param gain - requested gain setting
* @throws UsbException if there are any errors
*/
public void setGain(E4KGain gain, boolean controlI2CRepeater) throws UsbException
{
- if(gain != E4KGain.MANUAL)
+ getAdapter().getLock().lock();
+
+ try
{
- if(controlI2CRepeater)
+ if(gain != E4KGain.MANUAL)
{
- enableI2CRepeater(mDeviceHandle, true);
- }
-
- boolean i2CRepeaterControl = false;
-
- setLNAGain(gain.getLNAGain(), i2CRepeaterControl);
- setMixerGain(gain.getMixerGain(), i2CRepeaterControl);
- setEnhanceGain(gain.getEnhanceGain(), i2CRepeaterControl);
-
- if(controlI2CRepeater)
- {
- enableI2CRepeater(mDeviceHandle, false);
+ if(controlI2CRepeater)
+ {
+ getAdapter().enableI2CRepeater();
+ }
+
+ boolean i2CRepeaterControl = false;
+
+ setLNAGain(gain.getLNAGain(), i2CRepeaterControl);
+ setMixerGain(gain.getMixerGain(), i2CRepeaterControl);
+
+ if(controlI2CRepeater)
+ {
+ getAdapter().disableI2CRepeater();
+ }
}
}
+ finally
+ {
+ getAdapter().getLock().unlock();
+ }
}
/*
@@ -1088,7 +821,7 @@ public class E4KTunerController extends RTL2832TunerController
{
if(controlI2CRepeater)
{
- enableI2CRepeater(mDeviceHandle, true);
+ getAdapter().enableI2CRepeater();
}
writeE4KRegister(Register.MAGIC_1, (byte) 0x01, false);
@@ -1102,63 +835,52 @@ public class E4KTunerController extends RTL2832TunerController
if(controlI2CRepeater)
{
- enableI2CRepeater(mDeviceHandle, false);
+ getAdapter().disableI2CRepeater();
}
}
- private byte readMaskedE4KRegister(Register register,
- byte mask,
- boolean controlI2CRepeater)
- throws UsbException
+ private byte readMaskedE4KRegister(Register register, byte mask, boolean controlI2CRepeater) throws UsbException
{
int temp = readE4KRegister(register, controlI2CRepeater);
return (byte) (temp & mask);
}
- private void writeMaskedE4KRegister(Register register,
- byte mask,
- byte value,
- boolean controlI2CRepeater) throws LibUsbException
+ private void writeMaskedE4KRegister(Register register, byte mask, byte value, boolean controlI2CRepeater) throws LibUsbException
{
int temp = readE4KRegister(register, controlI2CRepeater);
/* If the register is not set to the masked value, then change it */
if((byte) (temp & mask) != value)
{
- writeE4KRegister(register,
- (byte) ((temp & ~mask) | (value & mask)),
- controlI2CRepeater);
-
+ writeE4KRegister(register, (byte) ((temp & ~mask) | (value & mask)), controlI2CRepeater);
readE4KRegister(register, controlI2CRepeater);
}
}
- private int readE4KRegister(Register register,
- boolean controlI2CRepeater) throws LibUsbException
+ private int readE4KRegister(Register register, boolean controlI2CRepeater) throws LibUsbException
{
- return readI2CRegister(mDeviceHandle, Register.I2C_REGISTER.getValue(),
- register.getValue(), controlI2CRepeater);
+ return getAdapter().readI2CRegister(Register.I2C_REGISTER.getValue(), register.getValue(), controlI2CRepeater);
}
- private void writeE4KRegister(Register register,
- byte value,
- boolean controlI2CRepeater) throws LibUsbException
+ private void writeE4KRegister(Register register, byte value, boolean controlI2CRepeater) throws LibUsbException
{
- writeI2CRegister(mDeviceHandle, Register.I2C_REGISTER.getValue(),
- register.getValue(), value, controlI2CRepeater);
+ getAdapter().writeI2CRegister(Register.I2C_REGISTER.getValue(), register.getValue(), value, controlI2CRepeater);
}
- public enum Band
+ /**
+ * Frequency bands enumeration
+ */
+ public enum FrequencyBand
{
- VHF2(0),
- VHF3(2),
- UHF(4),
- L(6);
+ VHF2(0), //64-108 MHz
+ VHF3(2), //170-240 MHz
+ UHF(4), //470-858 MHz
+ L_BAND(6); //1452-1680 MHz
private int mValue;
- private Band(int value)
+ FrequencyBand(int value)
{
mValue = value;
}
@@ -1178,7 +900,7 @@ public class E4KTunerController extends RTL2832TunerController
return toString();
}
- public static Band fromFrequency(long frequency)
+ public static FrequencyBand fromFrequency(long frequency)
{
if(frequency < 140000000) //140 MHz
{
@@ -1194,11 +916,16 @@ public class E4KTunerController extends RTL2832TunerController
}
else
{
- return L;
+ return L_BAND;
}
}
}
+ /**
+ * PLL enumeration for SYNTH7 (0x0D) Register to control the 'R' VCO output divider and 3-phase mixing.
+ *
+ * Note: 3-phase mixing (1-bit) and R index (3-bits) are combined in the index value that is written to the register.
+ */
public enum PLL
{
PLL_72M4(0x0F, 72400000, 48, 600000, true, "72.4 MHz"),
@@ -1212,32 +939,26 @@ public class E4KTunerController extends RTL2832TunerController
PLL_667M0(0x02, 667000000, 6, 4800000, false, "667.0 MHz"),
PLL_1200M0(0x01, 1200000000, 4, 7200000, false, "1200.0 MHz");
- private int mValue;
+ private int mIndex;
private long mFrequency;
private int mMultiplier;
private int mScaledOscillator;
private boolean mRequires3PhaseMixing;
private String mLabel;
- private PLL(int value,
- long frequency,
- int multiplier,
- int scaledOscillator,
- boolean requires3Phase,
- String label)
+ PLL(int index, long frequency, int multiplier, int scaledOscillator, boolean requires3Phase, String label)
{
- mValue = value;
+ mIndex = index;
mFrequency = frequency;
mMultiplier = multiplier;
mScaledOscillator = scaledOscillator;
mRequires3PhaseMixing = requires3Phase;
mLabel = label;
-
}
public byte getIndex()
{
- return (byte) mValue;
+ return (byte) mIndex;
}
public long getFrequency()
@@ -1270,8 +991,9 @@ public class E4KTunerController extends RTL2832TunerController
return mLabel;
}
- /* Returns the PLL setting with the closest frequency that is greater
- * than the frequency argument */
+ /**
+ * Returns the PLL setting with the closest frequency that is greater than the frequency argument
+ */
public static PLL fromFrequency(long frequency)
{
for(PLL pll : values())
@@ -1307,7 +1029,7 @@ public class E4KTunerController extends RTL2832TunerController
* RF filters - UHF Band. Each enum entry defines the center frequency for
* the filter and the applicable frequency minimums and maximums for the
* filter.
- *
+ *
* Note: max frequency overlaps with the next minimum frequency, so valid
* frequencies should be less than the maximum frequency defined for the
* filter.
@@ -1316,50 +1038,55 @@ public class E4KTunerController extends RTL2832TunerController
{
NO_FILTER(0, 0, 0),
- //UHF band Filters
- M360(0, 350000000, 370000000),
- M380(1, 370000000, 392500000),
- M405(2, 392500000, 417500000),
- M425(3, 417500000, 437500000),
- M450(4, 437500000, 462500000),
- M475(5, 462500000, 490000000),
- M505(6, 490000000, 522500000),
- M540(7, 522500000, 557500000),
- M575(8, 557500000, 595000000),
- M615(9, 595000000, 642500000),
- M670(10, 642500000, 695000000),
- M720(11, 695000000, 740000000),
- M760(12, 740000000, 800000000),
- M840(13, 800000000, 865000000),
- M890(14, 865000000, 930000000),
- M970(15, 930000000, 1135000000),
+ //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
+ LP299(8, 86_000_000, 140_000_000), //Values 8 - 15 are all the same
- //L band filters
- M1300(0, 1135000000, 1310000000),
- M1320(1, 1310000000, 1340000000),
- M1360(2, 1340000000, 1385000000),
- M1410(3, 1385000000, 1427500000),
- M1445(4, 1427500000, 1452500000),
- M1460(5, 1452500000, 1475000000),
- M1490(6, 1475000000, 1510000000),
- M1530(7, 1510000000, 1545000000),
- M1560(8, 1545000000, 1575000000),
- M1590(9, 1575000000, 1615000000),
- M1640(10, 1615000000, 1650000000),
- M1660(11, 1650000000, 1670000000),
- M1680(12, 1670000000, 1690000000),
- M1700(13, 1690000000, 1710000000),
- M1720(14, 1710000000, 1735000000),
+ //VHF-III Filters (140.0 - 350.0) Optimal (170-240)
+ LP509(0, 140_000_000, 245_000_000), //Values 0 - 7 are all the same
+ LP656(8, 245_000_000, 350_000_000), //Values 8 - 15 are all the same
- /* Note: max frequency is currently limited by the max integer value
- * and we set the max frequency for this filter to 2147 MHz */
- M1750(15, 1735000000, 2147000000);
+ //UHF Filters (350.0 - 1135) Optimal (470-858)
+ BP360(0, 350000000, 370000000),
+ BP380(1, 370000000, 392500000),
+ BP405(2, 392500000, 417500000),
+ BP425(3, 417500000, 437500000),
+ BP450(4, 437500000, 462500000),
+ BP475(5, 462500000, 490000000),
+ BP505(6, 490000000, 522500000),
+ BP540(7, 522500000, 557500000),
+ BP575(8, 557500000, 595000000),
+ BP615(9, 595000000, 642500000),
+ BP670(10, 642500000, 695000000),
+ BP720(11, 695000000, 740000000),
+ BP760(12, 740000000, 800000000),
+ BP840(13, 800000000, 865000000),
+ BP890(14, 865000000, 930000000),
+ BP970(15, 930000000, 1135000000),
+
+ //L Band Filters (1135.0 - 2147.0) Optimal (1452-1680)
+ BP1300(0, 1135000000, 1310000000),
+ BP1320(1, 1310000000, 1340000000),
+ BP1360(2, 1340000000, 1385000000),
+ BP1410(3, 1385000000, 1427500000),
+ BP1445(4, 1427500000, 1452500000),
+ BP1460(5, 1452500000, 1475000000),
+ BP1490(6, 1475000000, 1510000000),
+ BP1530(7, 1510000000, 1545000000),
+ BP1560(8, 1545000000, 1575000000),
+ BP1590(9, 1575000000, 1615000000),
+ BP1640(10, 1615000000, 1650000000),
+ BP1660(11, 1650000000, 1670000000),
+ BP1680(12, 1670000000, 1690000000),
+ BP1700(13, 1690000000, 1710000000),
+ BP1720(14, 1710000000, 1735000000),
+ BP1750(15, 1735000000, MAXIMUM_SUPPORTED_FREQUENCY);
private int mValue;
private long mMinFrequency;
private long mMaxFrequency;
- private RFFilter(int value, long minFrequency, long maxFrequency)
+ RFFilter(int value, long minFrequency, long maxFrequency)
{
mValue = value;
mMinFrequency = minFrequency;
@@ -1373,7 +1100,7 @@ public class E4KTunerController extends RTL2832TunerController
public static byte getMask()
{
- return (byte) 0xF; //TODO: make this a constant
+ return (byte) 0xF;
}
public byte getValue()
@@ -1398,32 +1125,66 @@ public class E4KTunerController extends RTL2832TunerController
return mMaxFrequency;
}
+ /**
+ * Filter ranges by frequency band
+ */
+ public static EnumSet VHFII_FILTERS = EnumSet.of(LP268, LP299);
+ public static EnumSet VHFIII_FILTERS = EnumSet.of(LP509, LP656);
+ public static EnumSet UHF_FILTERS = EnumSet.range(BP360, BP970);
+ public static EnumSet LBAND_FILTERS = EnumSet.of(BP1300, BP1750);
+
/**
* Selects the appropriate filter for the frequency
*
* @param frequency
* @return selected filter
* @throws IllegalArgumentException if the frequency is outside the
- * max value (2200 MHz)
+ * max value (2200 MHz)
*/
public static RFFilter fromFrequency(long frequency)
{
- if(frequency < 350000000)
+ switch(FrequencyBand.fromFrequency(frequency))
{
- return NO_FILTER;
+ case VHF2:
+ for(RFFilter filter : VHFII_FILTERS)
+ {
+ if(filter.getMinimumFrequency() <= frequency && frequency < filter.getMaximumFrequency())
+ {
+ return filter;
+ }
+ }
+ break;
+ case VHF3:
+ for(RFFilter filter : VHFIII_FILTERS)
+ {
+ if(filter.getMinimumFrequency() <= frequency && frequency < filter.getMaximumFrequency())
+ {
+ return filter;
+ }
+ }
+ break;
+ case UHF:
+ for(RFFilter filter : UHF_FILTERS)
+ {
+ if(filter.getMinimumFrequency() <= frequency && frequency < filter.getMaximumFrequency())
+ {
+ return filter;
+ }
+ }
+ break;
+ case L_BAND:
+ default:
+ for(RFFilter filter : LBAND_FILTERS)
+ {
+ if(filter.getMinimumFrequency() <= frequency && frequency < filter.getMaximumFrequency())
+ {
+ return filter;
+ }
+ }
+ break;
}
- for(RFFilter filter : values())
- {
- if(filter.getMinimumFrequency() <= frequency &&
- frequency < filter.getMaximumFrequency())
- {
- return filter;
- }
- }
-
- throw new IllegalArgumentException("E4KTunerController - "
- + "cannot find RF filter for frequency [" + frequency + "]");
+ return NO_FILTER;
}
}
@@ -1445,11 +1206,7 @@ public class E4KTunerController extends RTL2832TunerController
private int mMaxBandwidth;
private String mLabel;
- private MixerFilter(int value,
- int bandwidth,
- int minimumBandwidth,
- int maximumBandwidth,
- String label)
+ MixerFilter(int value, int bandwidth, int minimumBandwidth, int maximumBandwidth, String label)
{
mValue = value;
mBandwidth = bandwidth;
@@ -1503,8 +1260,7 @@ public class E4KTunerController extends RTL2832TunerController
{
for(MixerFilter filter : values())
{
- if(filter.getMinimumBandwidth() <= bandwidth &&
- bandwidth < filter.getMaximumBandwidth())
+ if(filter.getMinimumBandwidth() <= bandwidth && bandwidth < filter.getMaximumBandwidth())
{
return filter;
}
@@ -1526,8 +1282,7 @@ public class E4KTunerController extends RTL2832TunerController
}
}
- throw new IllegalArgumentException("E4KTunerController - "
- + "unrecognized mixer filter value [" + value + "]");
+ throw new IllegalArgumentException("E4KTunerController - unrecognized mixer filter value [" + value + "]");
}
}
@@ -1556,11 +1311,7 @@ public class E4KTunerController extends RTL2832TunerController
private int mMaxBandwidth;
private String mLabel;
- private RCFilter(int value,
- int bandwidth,
- int minimumBandwidth,
- int maximumBandwidth,
- String label)
+ RCFilter(int value, int bandwidth, int minimumBandwidth, int maximumBandwidth, String label)
{
mValue = value;
mBandwidth = bandwidth;
@@ -1614,8 +1365,7 @@ public class E4KTunerController extends RTL2832TunerController
{
for(RCFilter filter : values())
{
- if(filter.getMinimumBandwidth() <= bandwidth &&
- bandwidth < filter.getMaximumBandwidth())
+ if(filter.getMinimumBandwidth() <= bandwidth && bandwidth < filter.getMaximumBandwidth())
{
return filter;
}
@@ -1637,45 +1387,44 @@ public class E4KTunerController extends RTL2832TunerController
}
}
- throw new IllegalArgumentException("E4KTunerController - "
- + "unrecognized rc filter value [" + value + "]");
+ throw new IllegalArgumentException("E4KTunerController - unrecognized rc filter value [" + value + "]");
}
}
public enum ChannelFilter
{
- BW_5M50(0x00, 5500000, 5400000, 28800000, "5.50 MHz"),
- BW_5M30(0x01, 5300000, 5150000, 5400000, "5.30 MHz"),
- BW_5M00(0x02, 5000000, 4900000, 5150000, "5.00 MHz"),
- BW_4M80(0x03, 4800000, 4700000, 4900000, "4.80 MHz"),
- BW_4M60(0x04, 4600000, 4500000, 4700000, "4.60 MHz"),
- BW_4M40(0x05, 4400000, 4350000, 4500000, "4.40 MHz"),
- BW_4M30(0x06, 4300000, 4200000, 4350000, "4.30 MHz"),
- BW_4M10(0x07, 4100000, 4000000, 4200000, "4.10 MHz"),
- BW_3M90(0x08, 3900000, 3850000, 4000000, "3.90 MHz"),
- BW_3M80(0x09, 3800000, 3750000, 3850000, "3.80 MHz"),
- BW_3M70(0x0A, 3700000, 3650000, 3750000, "3.70 MHz"),
- BW_3M60(0x0B, 3600000, 3500000, 3650000, "3.60 MHz"),
- BW_3M40(0x0C, 3400000, 3350000, 3500000, "3.40 MHz"),
- BW_3M30(0x0D, 3300000, 3250000, 3350000, "3.30 MHz"),
- BW_3M20(0x0E, 3200000, 3150000, 3250000, "3.20 MHz"),
- BW_3M10(0x0F, 3100000, 3050000, 3150000, "3.10 MHz"),
- BW_3M00(0x10, 3000000, 2975000, 3050000, "3.00 MHz"),
- BW_2M95(0x11, 2950000, 2925000, 2975000, "2.95 MHz"),
- BW_2M90(0x12, 2900000, 2850000, 2925000, "2.90 MHz"),
- BW_2M80(0x13, 2800000, 2775000, 2850000, "2.80 MHz"),
- BW_2M75(0x14, 2750000, 2750000, 2775000, "2.75 MHz"),
- BW_2M70(0x15, 2700000, 2650000, 2750000, "2.70 MHz"),
- BW_2M60(0x16, 2600000, 2575000, 2650000, "2.60 MHz"),
- BW_2M55(0x17, 2550000, 2525000, 2575000, "2.55 MHz"),
- BW_2M50(0x18, 2500000, 2475000, 2525000, "2.50 MHz"),
- BW_2M45(0x19, 2450000, 2425000, 2475000, "2.45 MHz"),
- BW_2M40(0x1A, 2400000, 2350000, 2425000, "2.40 MHz"),
- BW_2M30(0x1B, 2300000, 2290000, 2350000, "2.30 MHz"),
- BW_2M28(0x1C, 2280000, 2260000, 2290000, "2.28 MHz"),
- BW_2M24(0x1D, 2240000, 2220000, 2260000, "2.24 MHz"),
- BW_2M20(0x1E, 2200000, 2175000, 2220000, "2.20 MHz"),
- BW_2M15(0x1F, 2150000, 0, 2175000, "2.15 MHz");
+ BW_5M50(0x00, 5500000, 5500000, 28800000, "5.50 MHz"),
+ BW_5M30(0x01, 5300000, 5300000, 5500000, "5.30 MHz"),
+ BW_5M00(0x02, 5000000, 5000000, 5300000, "5.00 MHz"),
+ BW_4M80(0x03, 4800000, 4800000, 5000000, "4.80 MHz"),
+ BW_4M60(0x04, 4600000, 4600000, 4800000, "4.60 MHz"),
+ BW_4M40(0x05, 4400000, 4400000, 4600000, "4.40 MHz"),
+ BW_4M30(0x06, 4300000, 4300000, 4400000, "4.30 MHz"),
+ BW_4M10(0x07, 4100000, 4100000, 4300000, "4.10 MHz"),
+ BW_3M90(0x08, 3900000, 3900000, 4100000, "3.90 MHz"),
+ BW_3M80(0x09, 3800000, 3800000, 3900000, "3.80 MHz"),
+ BW_3M70(0x0A, 3700000, 3700000, 3800000, "3.70 MHz"),
+ BW_3M60(0x0B, 3600000, 3600000, 3700000, "3.60 MHz"),
+ BW_3M40(0x0C, 3400000, 3400000, 3600000, "3.40 MHz"),
+ BW_3M30(0x0D, 3300000, 3300000, 3400000, "3.30 MHz"),
+ BW_3M20(0x0E, 3200000, 3200000, 3300000, "3.20 MHz"),
+ BW_3M10(0x0F, 3100000, 3100000, 3200000, "3.10 MHz"),
+ BW_3M00(0x10, 3000000, 3000000, 3100000, "3.00 MHz"),
+ BW_2M95(0x11, 2950000, 2950000, 3000000, "2.95 MHz"),
+ BW_2M90(0x12, 2900000, 2900000, 2950000, "2.90 MHz"),
+ BW_2M80(0x13, 2800000, 2800000, 2900000, "2.80 MHz"),
+ BW_2M75(0x14, 2750000, 2750000, 2800000, "2.75 MHz"),
+ BW_2M70(0x15, 2700000, 2700000, 2750000, "2.70 MHz"),
+ BW_2M60(0x16, 2600000, 2600000, 2700000, "2.60 MHz"),
+ BW_2M55(0x17, 2550000, 2550000, 2600000, "2.55 MHz"),
+ BW_2M50(0x18, 2500000, 2500000, 2550000, "2.50 MHz"),
+ BW_2M45(0x19, 2450000, 2450000, 2500000, "2.45 MHz"),
+ BW_2M40(0x1A, 2400000, 2400000, 2450000, "2.40 MHz"),
+ BW_2M30(0x1B, 2300000, 2300000, 2400000, "2.30 MHz"),
+ BW_2M28(0x1C, 2280000, 2280000, 2300000, "2.28 MHz"),
+ BW_2M24(0x1D, 2240000, 2240000, 2280000, "2.24 MHz"),
+ BW_2M20(0x1E, 2200000, 2200000, 2240000, "2.20 MHz"),
+ BW_2M15(0x1F, 2150000, 0, 2150000, "2.15 MHz");
private int mValue;
private int mBandwidth;
@@ -1683,11 +1432,7 @@ public class E4KTunerController extends RTL2832TunerController
private int mMaxBandwidth;
private String mLabel;
- private ChannelFilter(int value,
- int bandwidth,
- int minimumBandwidth,
- int maximumBandwidth,
- String label)
+ ChannelFilter(int value, int bandwidth, int minimumBandwidth, int maximumBandwidth, String label)
{
mValue = value;
mBandwidth = bandwidth;
@@ -1741,8 +1486,7 @@ public class E4KTunerController extends RTL2832TunerController
{
for(ChannelFilter filter : values())
{
- if(filter.getMinimumBandwidth() <= bandwidth &&
- bandwidth < filter.getMaximumBandwidth())
+ if(filter.getMinimumBandwidth() <= bandwidth && bandwidth < filter.getMaximumBandwidth())
{
return filter;
}
@@ -1764,8 +1508,7 @@ public class E4KTunerController extends RTL2832TunerController
}
}
- throw new IllegalArgumentException("E4KTunerController - "
- + "unrecognized channel filter value [" + value + "]");
+ throw new IllegalArgumentException("E4KTunerController - unrecognized channel filter value [" + value + "]");
}
}
@@ -1789,7 +1532,7 @@ public class E4KTunerController extends RTL2832TunerController
private int mValue;
private String mLabel;
- private E4KLNAGain(int value, String label)
+ E4KLNAGain(int value, String label)
{
mValue = value;
mLabel = label;
@@ -1832,51 +1575,44 @@ public class E4KTunerController extends RTL2832TunerController
}
}
- throw new IllegalArgumentException("E4KTunerController"
- + " - unrecognized LNA Gain value [" +
- value + "]");
+ throw new IllegalArgumentException("E4KTunerController - unrecognized LNA Gain value [" + value + "]");
}
}
/**
* Defines the default gain settings that are exposed to the user.
- *
+ *
* Manual is an override that keeps each of the settings intact and allows
* the user to change each of them individually
*/
public enum E4KGain
{
- AUTOMATIC("Auto", E4KMixerGain.AUTOMATIC, E4KLNAGain.AUTOMATIC, E4KEnhanceGain.AUTOMATIC),
- MANUAL("Manual", null, null, null),
- MINUS_10("-1.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_MINUS_50, E4KEnhanceGain.AUTOMATIC),
- PLUS_15("1.5 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_MINUS_25, E4KEnhanceGain.AUTOMATIC),
- PLUS_40("4.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_0, E4KEnhanceGain.AUTOMATIC),
- PLUS_65("6.5 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_25, E4KEnhanceGain.AUTOMATIC),
- PLUS_90("9.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_50, E4KEnhanceGain.AUTOMATIC),
- PLUS_115("11.5 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_75, E4KEnhanceGain.AUTOMATIC),
- PLUS_140("14.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_100, E4KEnhanceGain.AUTOMATIC),
- PLUS_165("16.5 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_125, E4KEnhanceGain.AUTOMATIC),
- PLUS_190("19.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_150, E4KEnhanceGain.AUTOMATIC),
- PLUS_215("21.5 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_175, E4KEnhanceGain.AUTOMATIC),
- PLUS_240("24.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_200, E4KEnhanceGain.AUTOMATIC),
- PLUS_290("29.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_250, E4KEnhanceGain.AUTOMATIC),
- PLUS_340("34.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_300, E4KEnhanceGain.AUTOMATIC),
- PLUS_420("42.0 db", E4KMixerGain.GAIN_12, E4KLNAGain.GAIN_PLUS_300, E4KEnhanceGain.AUTOMATIC);
+ AUTOMATIC("Auto", E4KMixerGain.AUTOMATIC, E4KLNAGain.AUTOMATIC),
+ MANUAL("Manual", null, null),
+ MINUS_10("-1.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_MINUS_50),
+ PLUS_15("1.5 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_MINUS_25),
+ PLUS_40("4.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_0),
+ PLUS_65("6.5 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_25),
+ PLUS_90("9.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_50),
+ PLUS_115("11.5 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_75),
+ PLUS_140("14.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_100),
+ PLUS_165("16.5 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_125),
+ PLUS_190("19.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_150),
+ PLUS_215("21.5 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_175),
+ PLUS_240("24.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_200),
+ PLUS_290("29.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_250),
+ PLUS_340("34.0 db", E4KMixerGain.GAIN_4, E4KLNAGain.GAIN_PLUS_300),
+ PLUS_420("42.0 db", E4KMixerGain.GAIN_12, E4KLNAGain.GAIN_PLUS_300);
private String mLabel;
private E4KMixerGain mMixerGain;
private E4KLNAGain mLNAGain;
- private E4KEnhanceGain mEnhanceGain;
- private E4KGain(String label,
- E4KMixerGain mixerGain,
- E4KLNAGain lnaGain,
- E4KEnhanceGain enhanceGain)
+ E4KGain(String label, E4KMixerGain mixerGain, E4KLNAGain lnaGain)
{
mLabel = label;
mMixerGain = mixerGain;
mLNAGain = lnaGain;
- mEnhanceGain = enhanceGain;
}
public String getLabel()
@@ -1898,11 +1634,6 @@ public class E4KTunerController extends RTL2832TunerController
{
return mLNAGain;
}
-
- public E4KEnhanceGain getEnhanceGain()
- {
- return mEnhanceGain;
- }
}
public enum E4KEnhanceGain
@@ -1910,13 +1641,13 @@ public class E4KTunerController extends RTL2832TunerController
AUTOMATIC(0, "Auto"),
GAIN_1(1, "10 db"),
GAIN_3(3, "30 db"),
- GAIN_5(5, "50 db"),
+ GAIN_5(5, "50 db"), //Recommended
GAIN_7(7, "70 db");
private int mValue;
private String mLabel;
- private E4KEnhanceGain(int value, String label)
+ E4KEnhanceGain(int value, String label)
{
mValue = value;
mLabel = label;
@@ -1959,40 +1690,23 @@ public class E4KTunerController extends RTL2832TunerController
}
}
- throw new IllegalArgumentException("E4KTunerController"
- + " - unrecognized Enhance Gain value [" +
- value + "]");
+ throw new IllegalArgumentException("E4KTunerController - unrecognized Enhance Gain value [" + value + "]");
}
}
public enum DCGainCombination
{
- LOOKUP_TABLE_0(Register.QLUT0,
- Register.ILUT0,
- E4KMixerGain.GAIN_4,
- IFStage1Gain.GAIN_MINUS3),
- LOOKUP_TABLE_1(Register.QLUT1,
- Register.ILUT1,
- E4KMixerGain.GAIN_4,
- IFStage1Gain.GAIN_PLUS6),
- LOOKUP_TABLE_2(Register.QLUT2,
- Register.ILUT2,
- E4KMixerGain.GAIN_12,
- IFStage1Gain.GAIN_MINUS3),
- LOOKUP_TABLE_3(Register.QLUT3,
- Register.ILUT3,
- E4KMixerGain.GAIN_12,
- IFStage1Gain.GAIN_PLUS6);
+ LOOKUP_TABLE_0(Register.QLUT0, Register.ILUT0, E4KMixerGain.GAIN_4, IFStage1Gain.GAIN_MINUS3),
+ LOOKUP_TABLE_1(Register.QLUT1, Register.ILUT1, E4KMixerGain.GAIN_4, IFStage1Gain.GAIN_PLUS6),
+ LOOKUP_TABLE_2(Register.QLUT2, Register.ILUT2, E4KMixerGain.GAIN_12, IFStage1Gain.GAIN_MINUS3),
+ LOOKUP_TABLE_3(Register.QLUT3, Register.ILUT3, E4KMixerGain.GAIN_12, IFStage1Gain.GAIN_PLUS6);
private Register mQRegister;
private Register mIRegister;
private E4KMixerGain mMixerGain;
private IFStage1Gain mIFStage1Gain;
- private DCGainCombination(Register qRegister,
- Register iRegister,
- E4KMixerGain mixer,
- IFStage1Gain stage1)
+ DCGainCombination(Register qRegister, Register iRegister, E4KMixerGain mixer, IFStage1Gain stage1)
{
mQRegister = qRegister;
mIRegister = iRegister;
@@ -2031,7 +1745,7 @@ public class E4KTunerController extends RTL2832TunerController
private int mValue;
private String mLabel;
- private E4KMixerGain(int value, String label)
+ E4KMixerGain(int value, String label)
{
mValue = value;
mLabel = label;
@@ -2074,9 +1788,205 @@ public class E4KTunerController extends RTL2832TunerController
}
}
- throw new IllegalArgumentException("E4KTunerController"
- + " - unrecognized Mixer Gain value [" +
- value + "]");
+ throw new IllegalArgumentException("E4KTunerController - unrecognized Mixer Gain value [" + value + "]");
+ }
+ }
+
+ /**
+ * Combines IF Gains 1 - 4 (register 0x16h GAIN3) and IF Gains 5 - 6 (register 0x17h GAIN4) into a contiguous
+ * range if IF gains, per data sheet table page 38, for both Linearity and Sensitivity modes.
+ */
+ public enum IFGain
+ {
+ LINEARITY_6((byte) 0x00, (byte) 0x00, "6"),
+ LINEARITY_7((byte) 0x20, (byte) 0x00, "7"),
+ LINEARITY_8((byte) 0x40, (byte) 0x00, "8"),
+ LINEARITY_9((byte) 0x00, (byte) 0x08, "9"),
+ LINEARITY_10((byte) 0x20, (byte) 0x08, "10"),
+ LINEARITY_11((byte) 0x40, (byte) 0x08, "11"),
+ LINEARITY_12((byte) 0x00, (byte) 0x10, "12"),
+ LINEARITY_13((byte) 0x20, (byte) 0x10, "13"),
+ LINEARITY_14((byte) 0x40, (byte) 0x10, "14"),
+ LINEARITY_15((byte) 0x00, (byte) 0x18, "15"),
+ LINEARITY_16((byte) 0x20, (byte) 0x18, "16"),
+ LINEARITY_17((byte) 0x40, (byte) 0x18, "17"),
+ LINEARITY_18((byte) 0x00, (byte) 0x20, "18"),
+ LINEARITY_19((byte) 0x20, (byte) 0x20, "19"),
+ LINEARITY_20((byte) 0x40, (byte) 0x20, "20"),
+ LINEARITY_21((byte) 0x00, (byte) 0x21, "21"),
+ LINEARITY_22((byte) 0x20, (byte) 0x21, "22"),
+ LINEARITY_23((byte) 0x40, (byte) 0x21, "23"),
+ LINEARITY_24((byte) 0x00, (byte) 0x22, "24"),
+ LINEARITY_25((byte) 0x20, (byte) 0x22, "25"),
+ LINEARITY_26((byte) 0x40, (byte) 0x22, "26"),
+ LINEARITY_27((byte) 0x00, (byte) 0x23, "27"),
+ LINEARITY_28((byte) 0x20, (byte) 0x23, "28"),
+ LINEARITY_29((byte) 0x40, (byte) 0x23, "29"),
+ LINEARITY_30((byte) 0x00, (byte) 0x24, "30"),
+ LINEARITY_31((byte) 0x20, (byte) 0x24, "31"),
+ LINEARITY_32((byte) 0x40, (byte) 0x24, "32"),
+ LINEARITY_33((byte) 0x08, (byte) 0x24, "33"),
+ LINEARITY_34((byte) 0x28, (byte) 0x24, "34"),
+ LINEARITY_35((byte) 0x48, (byte) 0x24, "35"),
+ LINEARITY_36((byte) 0x10, (byte) 0x24, "36"),
+ LINEARITY_37((byte) 0x30, (byte) 0x24, "37"),
+ LINEARITY_38((byte) 0x50, (byte) 0x24, "38"),
+ LINEARITY_39((byte) 0x18, (byte) 0x24, "39"),
+ LINEARITY_40((byte) 0x38, (byte) 0x24, "40"),
+ LINEARITY_41((byte) 0x58, (byte) 0x24, "41"),
+ LINEARITY_42((byte) 0x1A, (byte) 0x24, "42"),
+ LINEARITY_43((byte) 0x3A, (byte) 0x24, "43"),
+ LINEARITY_44((byte) 0x5A, (byte) 0x24, "44"),
+ LINEARITY_45((byte) 0x1C, (byte) 0x24, "45"),
+ LINEARITY_46((byte) 0x3C, (byte) 0x24, "46"),
+ LINEARITY_47((byte) 0x5C, (byte) 0x24, "47"),
+ LINEARITY_48((byte) 0x19, (byte) 0x24, "48"),
+ LINEARITY_49((byte) 0x39, (byte) 0x24, "49"),
+ LINEARITY_50((byte) 0x59, (byte) 0x24, "50"),
+ LINEARITY_51((byte) 0x1B, (byte) 0x24, "51"),
+ LINEARITY_52((byte) 0x3B, (byte) 0x24, "52"),
+ LINEARITY_53((byte) 0x5B, (byte) 0x24, "53"),
+ LINEARITY_54((byte) 0x1D, (byte) 0x24, "54"),
+ LINEARITY_55((byte) 0x3D, (byte) 0x24, "55"),
+ LINEARITY_56((byte) 0x5D, (byte) 0x24, "56"),
+ LINEARITY_57((byte) 0x1F, (byte) 0x24, "57"),
+ LINEARITY_58((byte) 0x3F, (byte) 0x24, "58"),
+ LINEARITY_59((byte) 0x5F, (byte) 0x24, "59"),
+ LINEARITY_60((byte) 0x7F, (byte) 0x24, "60"),
+
+ SENSITIVITY_6((byte) 0x00, (byte) 0x00, "6"),
+ SENSITIVITY_7((byte) 0x20, (byte) 0x00, "7"),
+ SENSITIVITY_8((byte) 0x40, (byte) 0x00, "8"),
+ SENSITIVITY_9((byte) 0x02, (byte) 0x00, "9"),
+ SENSITIVITY_10((byte) 0x22, (byte) 0x00, "10"),
+ SENSITIVITY_11((byte) 0x44, (byte) 0x00, "11"),
+ SENSITIVITY_12((byte) 0x04, (byte) 0x00, "12"),
+ SENSITIVITY_13((byte) 0x24, (byte) 0x00, "13"),
+ SENSITIVITY_14((byte) 0x44, (byte) 0x00, "14"),
+ SENSITIVITY_15((byte) 0x01, (byte) 0x00, "15"),
+ SENSITIVITY_16((byte) 0x21, (byte) 0x00, "16"),
+ SENSITIVITY_17((byte) 0x41, (byte) 0x00, "17"),
+ SENSITIVITY_18((byte) 0x03, (byte) 0x00, "18"),
+ SENSITIVITY_19((byte) 0x23, (byte) 0x00, "19"),
+ SENSITIVITY_20((byte) 0x43, (byte) 0x00, "20"),
+ SENSITIVITY_21((byte) 0x05, (byte) 0x00, "21"),
+ SENSITIVITY_22((byte) 0x25, (byte) 0x00, "22"),
+ SENSITIVITY_23((byte) 0x45, (byte) 0x00, "23"),
+ SENSITIVITY_24((byte) 0x07, (byte) 0x00, "24"),
+ SENSITIVITY_25((byte) 0x27, (byte) 0x00, "25"),
+ SENSITIVITY_26((byte) 0x47, (byte) 0x00, "26"),
+ SENSITIVITY_27((byte) 0x0F, (byte) 0x00, "27"),
+ SENSITIVITY_28((byte) 0x2F, (byte) 0x00, "28"),
+ SENSITIVITY_29((byte) 0x4F, (byte) 0x00, "29"),
+ SENSITIVITY_30((byte) 0x17, (byte) 0x00, "30"),
+ SENSITIVITY_31((byte) 0x37, (byte) 0x00, "31"),
+ SENSITIVITY_32((byte) 0x57, (byte) 0x00, "32"),
+ SENSITIVITY_33((byte) 0x1F, (byte) 0x00, "33"),
+ SENSITIVITY_34((byte) 0x3F, (byte) 0x00, "34"),
+ SENSITIVITY_35((byte) 0x5F, (byte) 0x00, "35"),
+ SENSITIVITY_36((byte) 0x1F, (byte) 0x01, "36"),
+ SENSITIVITY_37((byte) 0x3F, (byte) 0x01, "37"),
+ SENSITIVITY_38((byte) 0x5F, (byte) 0x01, "38"),
+ SENSITIVITY_39((byte) 0x1F, (byte) 0x02, "39"),
+ SENSITIVITY_40((byte) 0x3F, (byte) 0x02, "40"),
+ SENSITIVITY_41((byte) 0x5F, (byte) 0x02, "41"),
+ SENSITIVITY_42((byte) 0x1F, (byte) 0x03, "42"),
+ SENSITIVITY_43((byte) 0x3F, (byte) 0x03, "43"),
+ SENSITIVITY_44((byte) 0x5F, (byte) 0x03, "44"),
+ SENSITIVITY_45((byte) 0x1F, (byte) 0x04, "45"),
+ SENSITIVITY_46((byte) 0x3F, (byte) 0x04, "46"),
+ SENSITIVITY_47((byte) 0x5F, (byte) 0x04, "47"),
+ SENSITIVITY_48((byte) 0x1F, (byte) 0x0C, "48"),
+ SENSITIVITY_49((byte) 0x3F, (byte) 0x0C, "49"),
+ SENSITIVITY_50((byte) 0x5F, (byte) 0x0C, "50"),
+ SENSITIVITY_51((byte) 0x1F, (byte) 0x14, "51"),
+ SENSITIVITY_52((byte) 0x3F, (byte) 0x14, "52"),
+ SENSITIVITY_53((byte) 0x5F, (byte) 0x14, "53"),
+ SENSITIVITY_54((byte) 0x1F, (byte) 0x1C, "54"),
+ SENSITIVITY_55((byte) 0x3F, (byte) 0x1C, "55"),
+ SENSITIVITY_56((byte) 0x5F, (byte) 0x1C, "56"),
+ SENSITIVITY_57((byte) 0x1F, (byte) 0x24, "57"),
+ SENSITIVITY_58((byte) 0x3F, (byte) 0x24, "58"),
+ SENSITIVITY_59((byte) 0x5F, (byte) 0x24, "59"),
+ SENSITIVITY_60((byte) 0x7F, (byte) 0x24, "60");
+
+ private byte mGain3;
+ private byte mGain4;
+ private String mLabel;
+
+ IFGain(byte gain3, byte gain4, String label)
+ {
+ mGain3 = gain3;
+ mGain4 = gain4;
+ mLabel = label;
+ }
+
+ /**
+ * Value to apply to AGC3 register
+ */
+ public byte getGain3()
+ {
+ return mGain3;
+ }
+
+ /**
+ * Value to apply to AGC4 register
+ */
+ public byte getGain4()
+ {
+ return mGain4;
+ }
+
+ /**
+ * Register mask for AGC3
+ */
+ public byte getGain3Mask()
+ {
+ return (byte) 0x7F;
+ }
+
+ /**
+ * Register mask for AGC4
+ */
+ public byte getGain4Mask()
+ {
+ return (byte) 0x3F;
+ }
+
+ /**
+ * Linearity mode mask for AGC1 (0x1A) register
+ */
+ public byte getLinearityModeMask()
+ {
+ return (byte) 0x10;
+ }
+
+ /**
+ * Set of linearity gains
+ */
+ public static EnumSet LINEARITY_GAINS = EnumSet.range(LINEARITY_6, LINEARITY_60);
+
+ /**
+ * Indicates if this is a linearity or sensitivity mode
+ *
+ * @return true if linearity or false if sensitivity mode
+ */
+ public boolean isLinearity()
+ {
+ return LINEARITY_GAINS.contains(this);
+ }
+
+ @Override
+ public String toString()
+ {
+ if(isLinearity())
+ {
+ return "Linearity " + mLabel + " dB";
+ }
+ else
+ {
+ return "Sensitivity " + mLabel + " dB";
+ }
}
}
@@ -2088,7 +1998,7 @@ public class E4KTunerController extends RTL2832TunerController
private int mValue;
private String mLabel;
- private IFStage1Gain(int value, String label)
+ IFStage1Gain(int value, String label)
{
mValue = value;
mLabel = label;
@@ -2099,7 +2009,7 @@ public class E4KTunerController extends RTL2832TunerController
return Register.GAIN3;
}
- public static byte getMask()
+ public byte getMask()
{
return (byte) 0x1;
}
@@ -2118,23 +2028,6 @@ public class E4KTunerController extends RTL2832TunerController
{
return mLabel;
}
-
- public static IFStage1Gain fromRegisterValue(int registerValue)
- {
- int value = registerValue & getMask();
-
- for(IFStage1Gain setting : values())
- {
- if(value == setting.getValue())
- {
- return setting;
- }
- }
-
- throw new IllegalArgumentException("E4KTunerController"
- + " - unrecognized IF Gain Stage 1 value [" +
- value + "]");
- }
}
public enum IFStage2Gain
@@ -2147,7 +2040,7 @@ public class E4KTunerController extends RTL2832TunerController
private int mValue;
private String mLabel;
- private IFStage2Gain(int value, String label)
+ IFStage2Gain(int value, String label)
{
mValue = value;
mLabel = label;
@@ -2190,9 +2083,7 @@ public class E4KTunerController extends RTL2832TunerController
}
}
- throw new IllegalArgumentException("E4KTunerController"
- + " - unrecognized IF Gain Stage 2 value [" +
- value + "]");
+ throw new IllegalArgumentException("E4KTunerController - unrecognized IF Gain Stage 2 value [" + value + "]");
}
}
@@ -2206,7 +2097,7 @@ public class E4KTunerController extends RTL2832TunerController
private int mValue;
private String mLabel;
- private IFStage3Gain(int value, String label)
+ IFStage3Gain(int value, String label)
{
mValue = value;
mLabel = label;
@@ -2249,9 +2140,7 @@ public class E4KTunerController extends RTL2832TunerController
}
}
- throw new IllegalArgumentException("E4KTunerController"
- + " - unrecognized IF Gain Stage 3 value [" +
- value + "]");
+ throw new IllegalArgumentException("E4KTunerController - unrecognized IF Gain Stage 3 value [" + value + "]");
}
}
@@ -2265,7 +2154,7 @@ public class E4KTunerController extends RTL2832TunerController
private int mValue;
private String mLabel;
- private IFStage4Gain(int value, String label)
+ IFStage4Gain(int value, String label)
{
mValue = value;
mLabel = label;
@@ -2308,9 +2197,7 @@ public class E4KTunerController extends RTL2832TunerController
}
}
- throw new IllegalArgumentException("E4KTunerController"
- + " - unrecognized IF Gain Stage 4 value [" +
- value + "]");
+ throw new IllegalArgumentException("E4KTunerController - unrecognized IF Gain Stage 4 value [" + value + "]");
}
}
@@ -2328,7 +2215,7 @@ public class E4KTunerController extends RTL2832TunerController
private int mValue;
private String mLabel;
- private IFStage5Gain(int value, String label)
+ IFStage5Gain(int value, String label)
{
mValue = value;
mLabel = label;
@@ -2371,9 +2258,7 @@ public class E4KTunerController extends RTL2832TunerController
}
}
- throw new IllegalArgumentException("E4KTunerController"
- + " - unrecognized IF Gain Stage 5 value [" +
- value + "]");
+ throw new IllegalArgumentException("E4KTunerController - unrecognized IF Gain Stage 5 value [" + value + "]");
}
}
@@ -2392,7 +2277,7 @@ public class E4KTunerController extends RTL2832TunerController
private int mValue;
private String mLabel;
- private IFStage6Gain(int value, String label)
+ IFStage6Gain(int value, String label)
{
mValue = value;
mLabel = label;
@@ -2435,9 +2320,7 @@ public class E4KTunerController extends RTL2832TunerController
}
}
- throw new IllegalArgumentException("E4KTunerController"
- + " - unrecognized IF Gain Stage 6 value [" +
- value + "]");
+ throw new IllegalArgumentException("E4KTunerController - unrecognized IF Gain Stage 6 value [" + value + "]");
}
}
@@ -2449,7 +2332,7 @@ public class E4KTunerController extends RTL2832TunerController
private String mLabel;
- private IFFilter(String label)
+ IFFilter(String label)
{
mLabel = label;
}
@@ -2476,7 +2359,7 @@ public class E4KTunerController extends RTL2832TunerController
private byte mValue;
- private AGCMode(byte value)
+ AGCMode(byte value)
{
mValue = value;
}
@@ -2563,7 +2446,7 @@ public class E4KTunerController extends RTL2832TunerController
private int mValue;
- private Register(int value)
+ Register(int value)
{
mValue = value;
}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerConfiguration.java
index 85425729..74970eab 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerConfiguration.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerConfiguration.java
@@ -1,39 +1,41 @@
-/*******************************************************************************
- * SDR Trunk
- * Copyright (C) 2014 Dennis Sheirer
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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 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.
+ * 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
- ******************************************************************************/
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
package io.github.dsheirer.source.tuner.rtl.e4k;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.source.tuner.TunerType;
-import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
-import io.github.dsheirer.source.tuner.rtl.RTL2832TunerController;
-import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerController.E4KEnhanceGain;
-import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerController.E4KGain;
-import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerController.E4KLNAGain;
-import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerController.E4KMixerGain;
+import io.github.dsheirer.source.tuner.rtl.RTL2832TunerConfiguration;
+import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KGain;
+import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KLNAGain;
+import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KMixerGain;
+import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.IFGain;
-public class E4KTunerConfiguration extends TunerConfiguration
+/**
+ * RTL-2832 with embedded E4000 tuner configuration
+ */
+public class E4KTunerConfiguration extends RTL2832TunerConfiguration
{
private E4KGain mMasterGain = E4KGain.MANUAL;
private E4KMixerGain mMixerGain = E4KMixerGain.GAIN_4;
private E4KLNAGain mLNAGain = E4KLNAGain.GAIN_PLUS_200;
- private E4KEnhanceGain mEnhanceGain = E4KEnhanceGain.GAIN_3;
- private double mFrequencyCorrection = 0.0d;
- private RTL2832TunerController.SampleRate mSampleRate = RTL2832TunerController.SampleRate.RATE_2_400MHZ;
+ private IFGain mIFGain = IFGain.LINEARITY_8;
/**
* Default constructor for JAXB
@@ -42,18 +44,23 @@ public class E4KTunerConfiguration extends TunerConfiguration
{
}
- public E4KTunerConfiguration(String uniqueID, String name)
- {
- super(uniqueID, name);
- }
-
- @JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
+ @JsonIgnore
@Override
public TunerType getTunerType()
{
return TunerType.ELONICS_E4000;
}
+ /**
+ * Constructs an instance
+ *
+ * @param uniqueID for the tuner
+ */
+ public E4KTunerConfiguration(String uniqueID)
+ {
+ super(uniqueID);
+ }
+
@JacksonXmlProperty(isAttribute = true, localName = "master_gain")
public E4KGain getMasterGain()
{
@@ -87,37 +94,14 @@ public class E4KTunerConfiguration extends TunerConfiguration
mLNAGain = lnaGain;
}
- @JacksonXmlProperty(isAttribute = true, localName = "enhance_gain")
- public E4KEnhanceGain getEnhanceGain()
+ @JacksonXmlProperty(isAttribute = true, localName = "if_gain")
+ public IFGain getIFGain()
{
- return mEnhanceGain;
+ return mIFGain;
}
- public void setEnhanceGain(E4KEnhanceGain enhanceGain)
+ public void setIFGain(IFGain ifGain)
{
- mEnhanceGain = enhanceGain;
+ mIFGain = ifGain;
}
-
- @JacksonXmlProperty(isAttribute = true, localName = "frequency_correction")
- public double getFrequencyCorrection()
- {
- return mFrequencyCorrection;
- }
-
- public void setFrequencyCorrection(double value)
- {
- mFrequencyCorrection = value;
- }
-
- @JacksonXmlProperty(isAttribute = true, localName = "sample_rate")
- public RTL2832TunerController.SampleRate getSampleRate()
- {
- return mSampleRate;
- }
-
- public void setSampleRate(RTL2832TunerController.SampleRate sampleRate)
- {
- mSampleRate = sampleRate;
- }
-
}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerEditor.java
index bcb55c0c..60ee7bc4 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerEditor.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerEditor.java
@@ -1,32 +1,34 @@
-/*******************************************************************************
- * sdr-trunk
- * Copyright (C) 2014-2018 Dennis Sheirer
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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 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.
+ * 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
- *
- ******************************************************************************/
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
package io.github.dsheirer.source.tuner.rtl.e4k;
+import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.source.SourceException;
-import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
-import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEditor;
-import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEvent;
-import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
+import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
+import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.tuner.rtl.RTL2832Tuner;
import io.github.dsheirer.source.tuner.rtl.RTL2832TunerController;
import io.github.dsheirer.source.tuner.rtl.RTL2832TunerController.SampleRate;
-import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerController.E4KEnhanceGain;
-import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerController.E4KGain;
-import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerController.E4KLNAGain;
-import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerController.E4KMixerGain;
+import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KGain;
+import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KLNAGain;
+import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KMixerGain;
+import io.github.dsheirer.source.tuner.ui.TunerEditor;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,51 +39,47 @@ import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
-import javax.swing.JSpinner;
-import javax.swing.JTextField;
-import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
-import javax.swing.SwingConstants;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
import javax.usb.UsbException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.text.DecimalFormat;
-public class E4KTunerEditor extends TunerConfigurationEditor
+/**
+ * E4000 tuner editor
+ */
+public class E4KTunerEditor extends TunerEditor
{
private final static Logger mLog = LoggerFactory.getLogger(E4KTunerEditor.class);
-
private static final long serialVersionUID = 1L;
+ private JButton mTunerInfoButton;
+ private JComboBox mSampleRateCombo;
+ private JComboBox mMasterGainCombo;
+ private JComboBox mMixerGainCombo;
+ private JComboBox mLNAGainCombo;
+ private JComboBox mIfGainCombo;
- private JTextField mConfigurationName;
- private JButton mTunerInfo;
- private JComboBox mComboSampleRate;
- private JSpinner mFrequencyCorrection;
- private JComboBox mComboMasterGain;
- private JComboBox mComboMixerGain;
- private JComboBox mComboLNAGain;
- private JComboBox mComboEnhanceGain;
-
- private E4KTunerController mController;
- private boolean mLoading;
-
- public E4KTunerEditor(TunerConfigurationModel tunerConfigurationModel, RTL2832Tuner tuner)
+ /**
+ * Constructs an instance
+ * @param userPreferences for wide-band recordings
+ * @param tunerManager to save configuration
+ * @param discoveredTuner to control
+ */
+ public E4KTunerEditor(UserPreferences userPreferences, TunerManager tunerManager, DiscoveredTuner discoveredTuner)
{
- super(tunerConfigurationModel);
- mController = (E4KTunerController)tuner.getController();
-
+ super(userPreferences, tunerManager, discoveredTuner);
init();
+ tunerStatusUpdated();
}
- private E4KTunerConfiguration getConfiguration()
+ /**
+ * Access to the E4000 embedded tuner
+ * @return E4000 tuner if there is a tuner, or null otherwise
+ */
+ public E4KEmbeddedTuner getEmbeddedTuner()
{
- if(hasItem())
+ if(hasTuner())
{
- return (E4KTunerConfiguration)getItem();
+ return (E4KEmbeddedTuner)getTuner().getController().getEmbeddedTuner();
}
return null;
@@ -89,336 +87,328 @@ public class E4KTunerEditor extends TunerConfigurationEditor
private void init()
{
- setLayout(new MigLayout("fill,wrap 4", "[right][grow,fill][right][grow,fill]",
- "[][][][][][][][grow]"));
+ setLayout(new MigLayout("fill,wrap 3", "[right][grow,fill][fill]",
+ "[][][][][][][][][][][][][][][][grow]"));
- add(new JLabel("E4000 Tuner Configuration"), "span,align center");
+ add(new JLabel("Tuner:"));
+ add(getTunerIdLabel());
+ add(getTunerInfoButton());
- /**
- * Tuner Configuration Name
- */
- add(new JLabel("Name:"));
- mConfigurationName = new JTextField();
- mConfigurationName.setEnabled(false);
- mConfigurationName.addFocusListener(new FocusListener()
- {
- @Override
- public void focusLost(FocusEvent e)
- {
- save();
- }
+ add(new JLabel("Status:"));
+ add(getTunerStatusLabel(), "wrap");
- @Override
- public void focusGained(FocusEvent e)
- {
- }
- });
+ add(getButtonPanel(), "span,align left");
- add(mConfigurationName, "span 2");
+ add(new JSeparator(), "span,growx,push");
- mTunerInfo = new JButton("Tuner Info");
- mTunerInfo.setEnabled(false);
- mTunerInfo.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- JOptionPane.showMessageDialog(E4KTunerEditor.this, getTunerInfo(),
- "Tuner Info", JOptionPane.INFORMATION_MESSAGE);
- }
- });
- add(mTunerInfo);
+ add(new JLabel("Frequency (MHz):"));
+ add(getFrequencyPanel(), "span 2");
- mComboSampleRate = new JComboBox<>(SampleRate.values());
- mComboSampleRate.setEnabled(false);
- mComboSampleRate.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- SampleRate sampleRate = (SampleRate)mComboSampleRate.getSelectedItem();
-
- try
- {
- mController.setSampleRate(sampleRate);
- save();
- }
- catch(SourceException | LibUsbException eSampleRate)
- {
- JOptionPane.showMessageDialog(E4KTunerEditor.this,
- "E4K Tuner Controller - couldn't apply the sample rate setting [" +
- sampleRate.getLabel() + "] " + eSampleRate.getLocalizedMessage());
-
- mLog.error("E4K Tuner Controller - couldn't apply sample rate setting [" +
- sampleRate.getLabel() + "]", eSampleRate);
- }
- }
- });
add(new JLabel("Sample Rate:"));
- add(mComboSampleRate);
+ add(getSampleRateCombo(), "wrap");
- SpinnerModel model = new SpinnerNumberModel(0.0, //initial value
- -1000.0, //min
- 1000.0, //max
- 0.1); //step
+ add(new JSeparator(), "span,growx,push");
+ add(new JLabel("Mixer/LNA Gain Control"), "wrap");
- mFrequencyCorrection = new JSpinner(model);
- mFrequencyCorrection.setEnabled(false);
-
- JSpinner.NumberEditor editor =
- (JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
-
- DecimalFormat format = editor.getFormat();
- format.setMinimumFractionDigits(1);
- editor.getTextField().setHorizontalAlignment(SwingConstants.CENTER);
-
- mFrequencyCorrection.addChangeListener(new ChangeListener()
- {
- @Override
- public void stateChanged(ChangeEvent e)
- {
- final double value = ((SpinnerNumberModel)mFrequencyCorrection
- .getModel()).getNumber().doubleValue();
-
- try
- {
- mController.setFrequencyCorrection(value);
- save();
- }
- catch(SourceException e1)
- {
- JOptionPane.showMessageDialog(E4KTunerEditor.this, "E4K Tuner Controller - "
- + "couldn't apply frequency correction value: " + value + e1.getLocalizedMessage());
-
- mLog.error("E4K Tuner Controller - couldn't apply frequency correction value:"
- + value, e1);
- }
- }
- });
-
- add(new JLabel("PPM:"));
- add(mFrequencyCorrection);
-
- add(new JSeparator(JSeparator.HORIZONTAL), "span,grow");
- add(new JLabel("Gain"), "wrap");
-
- mComboMasterGain = new JComboBox(E4KGain.values());
- mComboMasterGain.setEnabled(false);
- mComboMasterGain.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent arg0)
- {
- try
- {
- E4KGain gain = (E4KGain)mComboMasterGain.getSelectedItem();
-
- mController.setGain((E4KGain)mComboMasterGain.getSelectedItem(), true);
-
- if(gain == E4KGain.MANUAL)
- {
- mComboMixerGain.setSelectedItem(mController.getMixerGain(true));
- mComboMixerGain.setEnabled(true);
-
- mComboLNAGain.setSelectedItem(mController.getLNAGain(true));
- mComboLNAGain.setEnabled(true);
-
- mComboEnhanceGain.setSelectedItem(mController.getEnhanceGain(true));
- mComboEnhanceGain.setEnabled(true);
- }
- else
- {
- mComboMixerGain.setEnabled(false);
- mComboMixerGain.setSelectedItem(gain.getMixerGain());
-
- mComboLNAGain.setEnabled(false);
- mComboLNAGain.setSelectedItem(gain.getLNAGain());
-
- mComboEnhanceGain.setEnabled(false);
- mComboEnhanceGain.setSelectedItem(gain.getEnhanceGain());
- }
-
- save();
- }
- catch(UsbException e)
- {
- JOptionPane.showMessageDialog(E4KTunerEditor.this, "E4K Tuner Controller - "
- + "couldn't apply the gain setting - " + e.getLocalizedMessage());
-
- mLog.error("E4K Tuner Controller - couldn't apply gain setting", e);
- }
- }
- });
-
- mComboMasterGain.setToolTipText("Select AUTOMATIC for auto "
- + "gain, MANUAL to enable
independent control of "
- + "Mixer, LNA and Enhance gain
"
- + "settings, or one of the individual gain settings for
"
- + "semi-manual gain control");
add(new JLabel("Master:"));
- add(mComboMasterGain);
+ add(getMasterGainCombo(), "wrap");
- mComboMixerGain = new JComboBox(E4KMixerGain.values());
- mComboMixerGain.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent arg0)
- {
- try
- {
- E4KMixerGain mixerGain = (E4KMixerGain)mComboMixerGain.getSelectedItem();
- mController.setMixerGain(mixerGain, true);
- save();
- }
- catch(UsbException e)
- {
- JOptionPane.showMessageDialog(E4KTunerEditor.this, "E4K Tuner Controller - "
- + "couldn't apply the mixer gain setting - " + e.getLocalizedMessage());
-
- mLog.error("E4K Tuner Controller - couldn't apply mixer gain setting", e);
- }
- }
- });
- mComboMixerGain.setToolTipText("Mixer Gain. Set master gain "
- + "to MASTER to enable adjustment");
- mComboMixerGain.setEnabled(false);
add(new JLabel("Mixer:"));
- add(mComboMixerGain);
+ add(getMixerGainCombo(), "wrap");
- mComboLNAGain = new JComboBox(E4KLNAGain.values());
- mComboLNAGain.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent arg0)
- {
- try
- {
- E4KLNAGain lnaGain = (E4KLNAGain)mComboLNAGain.getSelectedItem();
- mController.setLNAGain(lnaGain, true);
- save();
- }
- catch(UsbException e)
- {
- JOptionPane.showMessageDialog(E4KTunerEditor.this, "E4K Tuner Controller - "
- + "couldn't apply the LNA gain setting - " + e.getLocalizedMessage());
-
- mLog.error("E4K Tuner Controller - couldn't apply LNA gain setting - ", e);
- }
- }
- });
- mComboLNAGain.setToolTipText("LNA Gain. Set master gain "
- + "to MANUAL to enable adjustment");
- mComboLNAGain.setEnabled(false);
add(new JLabel("LNA:"));
- add(mComboLNAGain);
+ add(getLNAGainCombo(), "wrap");
- mComboEnhanceGain = new JComboBox(E4KEnhanceGain.values());
- mComboEnhanceGain.addActionListener(new ActionListener()
+ add(new JSeparator(), "span,growx,push");
+
+ add(new JLabel("IF Gain:"));
+ add(getIfGainCombo(), "wrap");
+ }
+
+ @Override
+ protected void tunerStatusUpdated()
+ {
+ setLoading(true);
+
+ if(hasTuner())
{
- @Override
- public void actionPerformed(ActionEvent arg0)
- {
- try
- {
- E4KEnhanceGain enhance = (E4KEnhanceGain)mComboEnhanceGain.getSelectedItem();
- mController.setEnhanceGain(enhance, true);
- save();
- }
- catch(UsbException e)
- {
- JOptionPane.showMessageDialog(E4KTunerEditor.this, "E4K Tuner Controller - "
- + "couldn't apply the enhance gain setting - " + e.getLocalizedMessage());
+ getTunerIdLabel().setText(getTuner().getPreferredName());
+ }
+ else
+ {
+ getTunerIdLabel().setText(getDiscoveredTuner().getId());
+ }
+ getTunerStatusLabel().setText(getDiscoveredTuner().getTunerStatus().toString());
+ getButtonPanel().updateControls();
+ getFrequencyPanel().updateControls();
- mLog.error("E4K Tuner Controller - couldn't apply enhance gain setting", e);
- }
+ if(hasTuner())
+ {
+ getTunerInfoButton().setEnabled(true);
+ getSampleRateCombo().setEnabled(true);
+ getSampleRateCombo().setSelectedItem(getConfiguration().getSampleRate());
+ getMasterGainCombo().setEnabled(true);
+ getIfGainCombo().setEnabled(true);
+ getIfGainCombo().setSelectedItem(getConfiguration().getIFGain());
+
+ E4KGain gain = getConfiguration().getMasterGain();
+ getMasterGainCombo().setEnabled(true);
+ getMasterGainCombo().setSelectedItem(gain);
+
+ if(gain == E4KGain.MANUAL)
+ {
+ getMixerGainCombo().setSelectedItem(getConfiguration().getMixerGain());
+ getMixerGainCombo().setEnabled(true);
+
+ getLNAGainCombo().setSelectedItem(getConfiguration().getLNAGain());
+ getLNAGainCombo().setEnabled(true);
}
- });
- mComboEnhanceGain.setToolTipText("Enhance Gain. Set master gain "
- + "to MANUAL to enable adjustment");
- mComboEnhanceGain.setEnabled(false);
- add(new JLabel("Enhance:"));
- add(mComboEnhanceGain);
+ else
+ {
+ getMixerGainCombo().setEnabled(false);
+ getMixerGainCombo().setSelectedItem(gain.getMixerGain());
+
+ getLNAGainCombo().setEnabled(false);
+ getLNAGainCombo().setSelectedItem(gain.getLNAGain());
+ }
+ }
+ else
+ {
+ getTunerInfoButton().setEnabled(false);
+ getSampleRateCombo().setEnabled(false);
+ getMasterGainCombo().setEnabled(false);
+ getMixerGainCombo().setEnabled(false);
+ getLNAGainCombo().setEnabled(false);
+ getIfGainCombo().setEnabled(false);
+ }
+
+ updateSampleRateToolTip();
+
+ setLoading(false);
+ }
+
+ private JComboBox getIfGainCombo()
+ {
+ if(mIfGainCombo == null)
+ {
+ mIfGainCombo = new JComboBox<>(E4KEmbeddedTuner.IFGain.values());
+ mIfGainCombo.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ if(!isLoading())
+ {
+ try
+ {
+ E4KEmbeddedTuner.IFGain selected = (E4KEmbeddedTuner.IFGain) getIfGainCombo().getSelectedItem();
+ getEmbeddedTuner().setIFGain(selected, true);
+ save();
+ }
+ catch(LibUsbException lue)
+ {
+ JOptionPane.showMessageDialog(E4KTunerEditor.this, "E4000 Tuner Controller - "
+ + "couldn't apply the IF setting - " + lue.getLocalizedMessage());
+ mLog.error("E4000 Tuner Controller - couldn't apply IF gain setting", e);
+ }
+ }
+ }
+ });
+ mIfGainCombo.setToolTipText("Linear IF Gain");
+ mIfGainCombo.setEnabled(true);
+ }
+
+ return mIfGainCombo;
+ }
+
+ private JComboBox getLNAGainCombo()
+ {
+ if(mLNAGainCombo == null)
+ {
+ mLNAGainCombo = new JComboBox<>(E4KLNAGain.values());
+ mLNAGainCombo.addActionListener(arg0 ->
+ {
+ if(!isLoading())
+ {
+ try
+ {
+ E4KLNAGain lnaGain = (E4KLNAGain) mLNAGainCombo.getSelectedItem();
+ getEmbeddedTuner().setLNAGain(lnaGain, true);
+ save();
+ }
+ catch(UsbException e)
+ {
+ JOptionPane.showMessageDialog(E4KTunerEditor.this, "E4000 Tuner Controller - "
+ + "couldn't apply the LNA gain setting - " + e.getLocalizedMessage());
+ mLog.error("E4000 Tuner Controller - couldn't apply LNA gain setting - ", e);
+ }
+ }
+ });
+ mLNAGainCombo.setToolTipText("LNA Gain. Set master gain to MANUAL to enable adjustment");
+ mLNAGainCombo.setEnabled(false);
+ }
+
+ return mLNAGainCombo;
+ }
+
+ private JComboBox getMixerGainCombo()
+ {
+ if(mMixerGainCombo == null)
+ {
+ mMixerGainCombo = new JComboBox<>(E4KMixerGain.values());
+ mMixerGainCombo.addActionListener(arg0 ->
+ {
+ if(!isLoading())
+ {
+ try
+ {
+ E4KMixerGain mixerGain = (E4KMixerGain) mMixerGainCombo.getSelectedItem();
+ getEmbeddedTuner().setMixerGain(mixerGain, true);
+ save();
+ }
+ catch(UsbException e)
+ {
+ JOptionPane.showMessageDialog(E4KTunerEditor.this, "E4000 Tuner Controller - "
+ + "couldn't apply the mixer gain setting - " + e.getLocalizedMessage());
+ mLog.error("E4000 Tuner Controller - couldn't apply mixer gain setting", e);
+ }
+ }
+ });
+ mMixerGainCombo.setToolTipText("Mixer Gain. Set master gain to MASTER to enable adjustment");
+ mMixerGainCombo.setEnabled(false);
+ }
+
+ return mMixerGainCombo;
+ }
+
+ private JComboBox getMasterGainCombo()
+ {
+ if(mMasterGainCombo == null)
+ {
+ mMasterGainCombo = new JComboBox<>(E4KGain.values());
+ mMasterGainCombo.setEnabled(false);
+ mMasterGainCombo.addActionListener(arg0 ->
+ {
+ if(!isLoading())
+ {
+ try
+ {
+ E4KGain gain = (E4KGain) mMasterGainCombo.getSelectedItem();
+ getEmbeddedTuner().setGain((E4KGain) mMasterGainCombo.getSelectedItem(), true);
+ if(gain == E4KGain.MANUAL)
+ {
+ getMixerGainCombo().setSelectedItem(getEmbeddedTuner().getMixerGain(true));
+ getMixerGainCombo().setEnabled(true);
+ getLNAGainCombo().setSelectedItem(getEmbeddedTuner().getLNAGain(true));
+ getLNAGainCombo().setEnabled(true);
+ }
+ else
+ {
+ getMixerGainCombo().setEnabled(false);
+ getMixerGainCombo().setSelectedItem(gain.getMixerGain());
+ getLNAGainCombo().setEnabled(false);
+ getLNAGainCombo().setSelectedItem(gain.getLNAGain());
+ }
+
+ save();
+ }
+ catch(UsbException e)
+ {
+ JOptionPane.showMessageDialog(E4KTunerEditor.this, "E4000 Tuner Controller - "
+ + "couldn't apply the gain setting - " + e.getLocalizedMessage());
+ mLog.error("E4000 Tuner Controller - couldn't apply gain setting", e);
+ }
+ }
+ });
+
+ mMasterGainCombo.setToolTipText("Select AUTOMATIC for auto gain, MANUAL to enable
" +
+ "independent control of Mixer, LNA and Enhance gain
settings, or one of the " +
+ "individual gain settings for
semi-manual gain control");
+ }
+
+ return mMasterGainCombo;
+ }
+
+ private JComboBox getSampleRateCombo()
+ {
+ if(mSampleRateCombo == null)
+ {
+ mSampleRateCombo = new JComboBox<>(SampleRate.values());
+ mSampleRateCombo.setEnabled(false);
+ mSampleRateCombo.addActionListener(e ->
+ {
+ if(!isLoading())
+ {
+ SampleRate sampleRate = (SampleRate) mSampleRateCombo.getSelectedItem();
+
+ try
+ {
+ getTuner().getController().setSampleRate(sampleRate);
+ save();
+ }
+ catch(SourceException | LibUsbException eSampleRate)
+ {
+ JOptionPane.showMessageDialog(E4KTunerEditor.this,
+ "E4000 Tuner Controller - couldn't apply the sample rate setting [" +
+ sampleRate.getLabel() + "] " + eSampleRate.getLocalizedMessage());
+
+ mLog.error("E4000 Tuner Controller - couldn't apply sample rate setting [" +
+ sampleRate.getLabel() + "]", eSampleRate);
+ }
+ }
+ });
+ }
+
+ return mSampleRateCombo;
+ }
+
+ private JButton getTunerInfoButton()
+ {
+ if(mTunerInfoButton == null)
+ {
+ mTunerInfoButton = new JButton("Tuner Info");
+ mTunerInfoButton.setEnabled(false);
+ mTunerInfoButton.addActionListener(e -> JOptionPane.showMessageDialog(E4KTunerEditor.this,
+ getTunerInfo(), "Tuner Info", JOptionPane.INFORMATION_MESSAGE));
+ }
+
+ return mTunerInfoButton;
}
+ /**
+ * Updates the sample rate tooltip according to the tuner controller's lock state.
+ */
/**
* Updates the sample rate tooltip according to the tuner controller's lock state.
*/
private void updateSampleRateToolTip()
{
- if(mController.isLocked())
+ if(hasTuner() && getTuner().getTunerController().isLocked())
{
- mComboSampleRate.setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
+ getSampleRateCombo().setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
+ }
+ else if(hasTuner())
+ {
+ getSampleRateCombo().setToolTipText("Select a sample rate for the tuner");
}
else
{
- mComboSampleRate.setToolTipText("Select a sample rate for the tuner");
+ getSampleRateCombo().setToolTipText("No tuner available");
}
}
@Override
public void setTunerLockState(boolean locked)
{
- mComboSampleRate.setEnabled(!locked);
- }
-
-
- /**
- * Sets each of the tuner configuration controls to the enabled argument state
- */
- private void setControlsEnabled(boolean enabled)
- {
- if(mConfigurationName.isEnabled() != enabled)
- {
- mConfigurationName.setEnabled(enabled);
- }
-
- if(mTunerInfo.isEnabled() != enabled)
- {
- mTunerInfo.setEnabled(enabled);
- }
-
- if(mFrequencyCorrection.isEnabled() != enabled)
- {
- mFrequencyCorrection.setEnabled(enabled);
- }
-
- updateSampleRateToolTip();
-
- if(mController.isLocked())
- {
- mComboSampleRate.setEnabled(false);
- }
- else if(mComboSampleRate.isEnabled() != enabled)
- {
- mComboSampleRate.setEnabled(enabled);
- }
-
- if(mComboMasterGain.isEnabled() != enabled)
- {
- mComboMasterGain.setEnabled(enabled);
- }
-
- if(mComboMixerGain.isEnabled() != enabled)
- {
- mComboMixerGain.setEnabled(enabled);
- }
-
- if(mComboLNAGain.isEnabled() != enabled)
- {
- mComboLNAGain.setEnabled(enabled);
- }
-
- if(mComboEnhanceGain.isEnabled() != enabled)
- {
- mComboEnhanceGain.setEnabled(enabled);
- }
+ super.setTunerLockState(locked);
+ mSampleRateCombo.setEnabled(!locked);
}
private String getTunerInfo()
{
StringBuilder sb = new StringBuilder();
- RTL2832TunerController.Descriptor descriptor = mController.getDescriptor();
+ RTL2832TunerController.Descriptor descriptor = getTuner().getController().getDescriptor();
sb.append("RTL-2832 with E4000 Tuner
");
@@ -461,68 +451,20 @@ public class E4KTunerEditor extends TunerConfigurationEditor
@Override
public void save()
{
- if(hasItem() && !mLoading)
+ if(hasConfiguration() && !isLoading())
{
E4KTunerConfiguration config = getConfiguration();
-
- config.setName(mConfigurationName.getText());
-
- config.setSampleRate((SampleRate)mComboSampleRate.getSelectedItem());
-
- double value = ((SpinnerNumberModel)mFrequencyCorrection
- .getModel()).getNumber().doubleValue();
+ config.setFrequency(getFrequencyControl().getFrequency());
+ double value = ((SpinnerNumberModel)getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue();
config.setFrequencyCorrection(value);
+ config.setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected());
- config.setMasterGain((E4KGain)mComboMasterGain.getSelectedItem());
- config.setMixerGain((E4KMixerGain)mComboMixerGain.getSelectedItem());
- config.setLNAGain((E4KLNAGain)mComboLNAGain.getSelectedItem());
- config.setEnhanceGain((E4KEnhanceGain)mComboEnhanceGain.getSelectedItem());
-
- getTunerConfigurationModel().broadcast(new TunerConfigurationEvent(
- getConfiguration(), TunerConfigurationEvent.Event.CHANGE));
+ config.setSampleRate((SampleRate)getSampleRateCombo().getSelectedItem());
+ config.setMasterGain((E4KGain)getMasterGainCombo().getSelectedItem());
+ config.setMixerGain((E4KMixerGain)getMixerGainCombo().getSelectedItem());
+ config.setLNAGain((E4KLNAGain)getLNAGainCombo().getSelectedItem());
+ config.setIFGain((E4KEmbeddedTuner.IFGain)getIfGainCombo().getSelectedItem());
+ saveConfiguration();
}
-
- }
-
- @Override
- public void setItem(TunerConfiguration tunerConfiguration)
- {
- super.setItem(tunerConfiguration);
-
- //Toggle loading so that we don't fire a change event and schedule a settings file save
- mLoading = true;
-
- if(hasItem())
- {
- E4KTunerConfiguration config = getConfiguration();
-
- if(tunerConfiguration.isAssigned())
- {
- setControlsEnabled(true);
-
- mConfigurationName.setText(config.getName());
- mFrequencyCorrection.setValue(config.getFrequencyCorrection());
- mComboSampleRate.setSelectedItem(config.getSampleRate());
- mComboMasterGain.setSelectedItem(config.getMasterGain());
- mComboMixerGain.setSelectedItem(config.getMixerGain());
- mComboLNAGain.setSelectedItem(config.getLNAGain());
- mComboEnhanceGain.setSelectedItem(config.getEnhanceGain());
-
- //Update enabled state to reflect when frequency and sample rate controls are locked
- mComboSampleRate.setEnabled(!mController.isLocked());
- }
- else
- {
- setControlsEnabled(false);
- mConfigurationName.setText(config.getName());
- }
- }
- else
- {
- setControlsEnabled(false);
- mConfigurationName.setText("");
- }
-
- mLoading = false;
}
}
\ No newline at end of file
diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TEmbeddedTuner.java
similarity index 73%
rename from src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerController.java
rename to src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TEmbeddedTuner.java
index 751a923a..f43b86c1 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerController.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TEmbeddedTuner.java
@@ -1,105 +1,66 @@
-/*******************************************************************************
- * SDR Trunk
- * Copyright (C) 2014-2017 Dennis Sheirer
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
*
- * Java port of librtlsdr
+ * 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.
*
- * Copyright (C) 2013 Mauro Carvalho Chehab
- * Copyright (C) 2013 Steve Markgraf
+ * 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.
*
- * 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
- ******************************************************************************/
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
package io.github.dsheirer.source.tuner.rtl.r820t;
import io.github.dsheirer.source.SourceException;
-import io.github.dsheirer.source.tuner.FrequencyErrorCorrectionManager;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.usb4java.Device;
-import org.usb4java.DeviceDescriptor;
-import org.usb4java.LibUsb;
import org.usb4java.LibUsbException;
import javax.usb.UsbException;
import java.nio.ByteBuffer;
-public class R820TTunerController extends RTL2832TunerController
+public class R820TEmbeddedTuner extends EmbeddedTuner
{
- private final static Logger mLog = LoggerFactory.getLogger(R820TTunerController.class);
-
- public static final long MIN_FREQUENCY = 3180000;
- public static final long MAX_FREQUENCY = 1782030000;
- public static final double USABLE_BANDWIDTH_PERCENT = 0.98;
- public static final int DC_SPIKE_AVOID_BUFFER = 5000;
-
- public static final int R820T_IF_FREQUENCY = 3570000;
- public static final byte VERSION = (byte) 49;
-
- 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};
-
- /* R820T I2C address */
- private byte mI2CAddress = (byte) 0x34;
-
- /* Shadow register is used to keep a cached (in-memory) copy of all
- * registers, so that we don't have to read a full byte from a register in
- * order to apply a masked value and then re-write the full byte. With the
- * shadow register, we can apply the masked value to the cached value, and
- * then just write the masked byte, skipping the need to read the byte
- * first. */
- private int[] mShadowRegister =
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x32, 0x75,
- 0xC0, 0x40, 0xD6, 0x6C, 0xF5, 0x63, 0x75, 0x68,
- 0x6C, 0x83, 0x80, 0x00, 0x0F, 0x00, 0xC0, 0x30,
- 0x48, 0xCC, 0x60, 0x00, 0x54, 0xAE, 0x4A, 0xC0};
-
- public FrequencyErrorCorrectionManager mFrequencyErrorCorrectionManager;
-
- public R820TTunerController(Device device, DeviceDescriptor deviceDescriptor) throws SourceException
- {
- super(device, deviceDescriptor, MIN_FREQUENCY, MAX_FREQUENCY, DC_SPIKE_AVOID_BUFFER,
- USABLE_BANDWIDTH_PERCENT);
-
- mFrequencyErrorCorrectionManager = new FrequencyErrorCorrectionManager(this);
- }
+ private final static Logger mLog = LoggerFactory.getLogger(R820TEmbeddedTuner.class);
+ private static final long MINIMUM_SUPPORTED_FREQUENCY = 3180000;
+ private static final long MAXIMUM_SUPPORTED_FREQUENCY = 1782030000;
+ private static final double USABLE_BANDWIDTH_PERCENT = 0.98;
+ private static final int DC_SPIKE_AVOID_BUFFER = 5000;
+ private static final int R820T_IF_FREQUENCY = 3570000;
+ private static final byte VERSION = (byte) 49;
+ private static final byte I2C_ADDRESS = (byte) 0x34;
+ 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};
/**
- * Manager for applying automatic frequency error PPM adjustments to the tuner controller based on
- * frequency error measurements received from certain downstream decoders (e.g. P25).
- * @return manager
+ * Shadow register is used to keep a cached (in-memory) copy of all registers, so that we don't have to read a
+ * full byte from a register in order to apply a masked value and then re-write the full byte. With the shadow
+ * register, we can apply the masked value to the cached value, and then just write the masked byte, skipping the
+ * need to read the byte first.
*/
- public FrequencyErrorCorrectionManager getFrequencyErrorCorrectionManager()
- {
- return mFrequencyErrorCorrectionManager;
- }
+ private int[] mShadowRegister = {0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x32, 0x75, 0xC0, 0x40, 0xD6, 0x6C, 0xF5, 0x63,
+ 0x75, 0x68, 0x6C, 0x83, 0x80, 0x00, 0x0F, 0x00, 0xC0, 0x30, 0x48, 0xCC, 0x60, 0x00, 0x54, 0xAE, 0x4A, 0xC0};
+
/**
- * Overrides updates for measured frequency error so that the updates can also be applied to the
- * frequency error correction manager for automatic PPM updating.
- * @param measuredFrequencyError in hertz averaged over a 5 second interval.
+ * Constructs an instance
+ * @param adapter for accessing RTL2832USBController interfaces
*/
- @Override
- public void setMeasuredFrequencyError(int measuredFrequencyError)
+ public R820TEmbeddedTuner(RTL2832TunerController.ControllerAdapter adapter)
{
- super.setMeasuredFrequencyError(measuredFrequencyError);
- getFrequencyErrorCorrectionManager().updatePPM(getPPMFrequencyError());
+ super(adapter);
}
@Override
@@ -109,102 +70,92 @@ public class R820TTunerController extends RTL2832TunerController
}
@Override
- public void setSampleRateFilters(int sampleRate) throws LibUsbException
+ public long getMinimumFrequencySupported()
{
- //TODO: why is this being forced as an abstract method on sub classes?
+ return MINIMUM_SUPPORTED_FREQUENCY;
}
+ @Override
+ public long getMaximumFrequencySupported()
+ {
+ return MAXIMUM_SUPPORTED_FREQUENCY;
+ }
+
+ @Override
+ public int getDcSpikeHalfBandwidth()
+ {
+ return DC_SPIKE_AVOID_BUFFER;
+ }
+
+ @Override
+ public double getUsableBandwidthPercent()
+ {
+ return USABLE_BANDWIDTH_PERCENT;
+ }
+
+ @Override
+ public void setSampleRateFilters(int sampleRate) throws SourceException
+ {
+ //No-op
+ }
+
+ /**
+ * Applies the tuner configuration values to this embedded tuner
+ * @param tunerConfig containing settings to apply
+ * @throws SourceException if there is an error
+ */
@Override
public void apply(TunerConfiguration tunerConfig) throws SourceException
{
- if(tunerConfig != null &&
- tunerConfig instanceof R820TTunerConfiguration)
- {
- R820TTunerConfiguration config = (R820TTunerConfiguration) tunerConfig;
+ //Invoke super for frequency, frequency correction and autoPPM
+ if(tunerConfig instanceof R820TTunerConfiguration config)
+ {
try
{
- SampleRate sampleRate = config.getSampleRate();
- setSampleRate(sampleRate);
-
- double correction = config.getFrequencyCorrection();
- setFrequencyCorrection(correction);
-
- getFrequencyErrorCorrectionManager().setEnabled(config.getAutoPPMCorrectionEnabled());
-
R820TGain masterGain = config.getMasterGain();
setGain(masterGain, true);
if(masterGain == R820TGain.MANUAL)
{
- R820TMixerGain mixerGain = config.getMixerGain();
- setMixerGain(mixerGain, true);
-
- R820TLNAGain lnaGain = config.getLNAGain();
- setLNAGain(lnaGain, true);
-
- R820TVGAGain vgaGain = config.getVGAGain();
- setVGAGain(vgaGain, true);
- }
-
- try
- {
- setFrequency(config.getFrequency());
- }
- catch(SourceException se)
- {
- //Do nothing, we couldn't set the frequency
+ setLNAGain(config.getLNAGain(), true);
+ setMixerGain(config.getMixerGain(), true);
+ setVGAGain(config.getVGAGain(), true);
}
}
catch(UsbException e)
{
- throw new SourceException("R820TTunerController - usb error "
- + "while applying tuner config", e);
+ throw new SourceException("R820TTunerController - usb error while applying tuner config", e);
}
}
}
- /**
- * Not implemented.
- */
- @Override
- public long getTunedFrequency() throws SourceException
- {
- return 0;
- }
-
/**
* Sets the center frequency. Setting the frequency is a two-part process
* of setting the multiplexer and then setting the Oscillator (PLL).
*/
@Override
- public void setTunedFrequency(long frequency) throws SourceException
+ public synchronized void setTunedFrequency(long frequency) throws SourceException
{
- mLock.lock();
+ getAdapter().getLock().lock();
try
{
- enableI2CRepeater(mDeviceHandle, true);
-
+ getAdapter().enableI2CRepeater();
boolean controlI2C = false;
-
long offsetFrequency = frequency + R820T_IF_FREQUENCY;
-
setMux(offsetFrequency, controlI2C);
-
setPLL(offsetFrequency, controlI2C);
-
- enableI2CRepeater(mDeviceHandle, false);
+ getAdapter().disableI2CRepeater();
}
catch(UsbException e)
{
- throw new SourceException("R820TTunerController - exception "
- + "while setting frequency [" + frequency + "] - " +
- e.getLocalizedMessage());
+ throw new SourceException("R820TTunerController - exception while setting frequency [" + frequency + "] - " +
+ e.getLocalizedMessage());
}
finally
{
- mLock.unlock();
+ getAdapter().getLock().unlock();
}
}
@@ -212,31 +163,18 @@ public class R820TTunerController extends RTL2832TunerController
* Overrides the same method from the RTL2832 tuner controller to apply
* settings specific to the R820T tuner.
*/
- public void setSamplingMode(SampleMode mode) throws LibUsbException
+ public void setSamplingMode(RTL2832TunerController.SampleMode mode) throws LibUsbException
{
- switch(mode)
+ if(mode == RTL2832TunerController.SampleMode.QUADRATURE)
{
- case QUADRATURE:
- /* Set intermediate frequency to R820T IF frequency */
- setIFFrequency(R820T_IF_FREQUENCY);
+ /* Set intermediate frequency to R820T IF frequency */
+ getAdapter().setIFFrequency(R820T_IF_FREQUENCY);
- /* Enable spectrum inversion */
- writeDemodRegister(mDeviceHandle,
- Page.ONE,
- (short) 0x15,
- (short) 0x01,
- 1);
-
- /* Set default i/q path */
- writeDemodRegister(mDeviceHandle,
- Page.ZERO,
- (short) 0x06,
- (short) 0x80,
- 1);
- break;
- default:
- break;
+ /* Enable spectrum inversion */
+ getAdapter().writeDemodRegister(RTL2832TunerController.Page.ONE, (short) 0x15, (short) 0x01, 1);
+ /* Set default i/q path */
+ getAdapter().writeDemodRegister(RTL2832TunerController.Page.ZERO, (short) 0x06, (short) 0x80, 1);
}
}
@@ -257,8 +195,7 @@ public class R820TTunerController extends RTL2832TunerController
writeR820TRegister(Register.TF_BAND, range.getTFC(), controlI2C);
/* XTAL CAP & Drive */
- writeR820TRegister(Register.PLL_XTAL_CAPACITOR_AND_DRIVE,
- range.getXTALHighCap0P(), controlI2C);
+ writeR820TRegister(Register.PLL_XTAL_CAPACITOR_AND_DRIVE, range.getXTALHighCap0P(), controlI2C);
/* Register 8 - what is it? */
writeR820TRegister(Register.UNKNOWN_REGISTER_8, (byte) 0x00, controlI2C);
@@ -267,86 +204,25 @@ public class R820TTunerController extends RTL2832TunerController
writeR820TRegister(Register.UNKNOWN_REGISTER_9, (byte) 0x00, controlI2C);
}
- /**
- * Initializes the tuner for use.
- */
- public void init() throws SourceException
- {
- /* Initialize the super class to open and claim the usb interface*/
- super.init();
-
- try
- {
- initBaseband(mDeviceHandle);
-
- enableI2CRepeater(mDeviceHandle, true);
-
- boolean i2CRepeaterControl = false;
-
- initTuner(i2CRepeaterControl);
-
- enableI2CRepeater(mDeviceHandle, false);
- }
- catch(UsbException e)
- {
- throw new SourceException("error during init()", e);
- }
- }
-
- @Override
- public void dispose()
- {
- mLog.info("Releasing R820T Tuner");
-
- if(mDeviceHandle != null)
- {
- try
- {
- LibUsb.close(mDeviceHandle);
- }
- catch(Exception e)
- {
- mLog.error("error while closing device handle", e);
- }
-
- mDeviceHandle = null;
- }
- }
-
/**
* Initializes the tuner section.
*/
- public void initTuner(boolean controlI2C) throws UsbException
+ protected void initTuner() throws UsbException
{
/* Disable zero IF mode */
- writeDemodRegister(mDeviceHandle,
- Page.ONE,
- (short) 0xB1,
- (short) 0x1A,
- 1);
+ getAdapter().writeDemodRegister(RTL2832TunerController.Page.ONE, (short) 0xB1, (short) 0x1A, 1);
/* Only enable in-phase ADC input */
- writeDemodRegister(mDeviceHandle,
- Page.ZERO,
- (short) 0x08,
- (short) 0x4D,
- 1);
+ getAdapter().writeDemodRegister(RTL2832TunerController.Page.ZERO, (short) 0x08, (short) 0x4D, 1);
/* Set intermediate frequency to R820T IF frequency (3.57 MHz) */
- setIFFrequency(R820T_IF_FREQUENCY);
+ getAdapter().setIFFrequency(R820T_IF_FREQUENCY);
/* Enable spectrum inversion */
- writeDemodRegister(mDeviceHandle,
- Page.ONE,
- (short) 0x15,
- (short) 0x01,
- 1);
-
- initializeRegisters(controlI2C);
-
- setTVStandard(controlI2C);
-
- systemFrequencySelect(0, controlI2C);
+ getAdapter().writeDemodRegister(RTL2832TunerController.Page.ONE, (short) 0x15, (short) 0x01, 1);
+ initializeRegisters(false);
+ setTVStandard(false);
+ systemFrequencySelect(0, false);
}
/**
@@ -392,8 +268,7 @@ public class R820TTunerController extends RTL2832TunerController
if(!calibrationSuccessful(calibrationCode))
{
- mLog.error("Calibration NOT successful - code: " +
- calibrationCode);
+ mLog.error("Calibration NOT successful - code: " + calibrationCode);
}
}
@@ -453,8 +328,7 @@ public class R820TTunerController extends RTL2832TunerController
/**
* Sets the system IF frequency
*/
- private void systemFrequencySelect(long frequency, boolean controlI2C)
- throws UsbException
+ private void systemFrequencySelect(long frequency, boolean controlI2C) throws UsbException
{
/* LNA top? */
writeR820TRegister(Register.LNA_TOP2, (byte) 0xE5, controlI2C);
@@ -463,9 +337,7 @@ public class R820TTunerController extends RTL2832TunerController
byte cp_cur;
byte div_buf_cur;
- if(frequency == 506000000 ||
- frequency == 666000000 ||
- frequency == 818000000)
+ if(frequency == 506000000 || frequency == 666000000 || frequency == 818000000)
{
mixer_top = (byte) 0x14;
cp_cur = (byte) 0x28;
@@ -479,46 +351,29 @@ public class R820TTunerController extends RTL2832TunerController
}
writeR820TRegister(Register.MIXER_TOP, mixer_top, controlI2C);
-
writeR820TRegister(Register.LNA_VTH_L, (byte) 0x53, controlI2C);
-
writeR820TRegister(Register.MIXER_VTH_L, (byte) 0x75, controlI2C);
-
/* Air-In only for Astrometa */
writeR820TRegister(Register.AIR_CABLE1_INPUT_SELECTOR, (byte) 0x00, controlI2C);
-
writeR820TRegister(Register.CABLE2_INPUT_SELECTOR, (byte) 0x00, controlI2C);
-
writeR820TRegister(Register.CP_CUR, cp_cur, controlI2C);
-
writeR820TRegister(Register.DIVIDER_BUFFER_CURRENT, div_buf_cur, controlI2C);
-
writeR820TRegister(Register.FILTER_CURRENT, (byte) 0x40, controlI2C);
-
/* if( type != TUNER_ANALOG_TV ) ... */
-
writeR820TRegister(Register.LNA_TOP, (byte) 0x00, controlI2C);
-
writeR820TRegister(Register.MIXER_TOP2, (byte) 0x00, controlI2C);
-
writeR820TRegister(Register.PRE_DETECT, (byte) 0x00, controlI2C);
-
writeR820TRegister(Register.AGC_CLOCK, (byte) 0x30, controlI2C);
-
writeR820TRegister(Register.LNA_TOP, (byte) 0x18, controlI2C);
-
writeR820TRegister(Register.MIXER_TOP2, mixer_top, controlI2C);
-
/* LNA discharge current */
writeR820TRegister(Register.LNA_DISCHARGE_CURRENT, (byte) 0x14, controlI2C);
-
/* AGC clock 1 khz, external det1 cap 1u */
writeR820TRegister(Register.AGC_CLOCK, (byte) 0x20, controlI2C);
}
/**
- * Sets the tuner's Phase-Locked-Loop (PLL) oscillator used for frequency
- * (tuning) control
+ * Sets the tuner's Phase-Locked-Loop (PLL) oscillator used for frequency (tuning) control
*
* @param frequency - desired center frequency
* @param controlI2C - control the I2C repeater locally
@@ -528,49 +383,32 @@ public class R820TTunerController extends RTL2832TunerController
{
/* Set reference divider to 0 */
writeR820TRegister(Register.REFERENCE_DIVIDER_2, (byte) 0x00, controlI2C);
-
/* Set PLL autotune to 128kHz */
writeR820TRegister(Register.PLL_AUTOTUNE, (byte) 0x00, controlI2C);
-
/* Set VCO current to 100 */
writeR820TRegister(Register.VCO_CURRENT, (byte) 0x80, controlI2C);
-
/* Set the frequency divider - adjust for vco_fine_tune status */
FrequencyDivider divider = FrequencyDivider.fromFrequency(frequency);
-
int statusRegister4 = getStatusRegister(4, controlI2C);
-
int vco_fine_tune = (statusRegister4 & 0x30) >> 4;
-
int div_num = divider.getDividerNumber(vco_fine_tune);
-
writeR820TRegister(Register.DIVIDER, (byte) (div_num << 5), controlI2C);
-
/* Get the integral number for this divider and frequency */
Integral integral = divider.getIntegral(frequency);
-
writeR820TRegister(Register.PLL, integral.getRegisterValue(), controlI2C);
-
/* Calculate the sigma-delta modulator fractional setting. If it's
* non-zero, power up the sdm and apply the fractional setting,
* otherwise turn it off */
int sdm = divider.getSDM(integral, frequency);
-
if(sdm != 0)
{
- writeR820TRegister(Register.SIGMA_DELTA_MODULATOR_POWER,
- (byte) 0x00, controlI2C);
-
- writeR820TRegister(Register.SIGMA_DELTA_MODULATOR_MSB,
- (byte) ((sdm >> 8) & 0xFF), controlI2C);
-
- writeR820TRegister(Register.SIGMA_DELTA_MODULATOR_LSB,
- (byte) (sdm & 0xFF), controlI2C);
+ writeR820TRegister(Register.SIGMA_DELTA_MODULATOR_POWER, (byte) 0x00, controlI2C);
+ writeR820TRegister(Register.SIGMA_DELTA_MODULATOR_MSB, (byte) ((sdm >> 8) & 0xFF), controlI2C);
+ writeR820TRegister(Register.SIGMA_DELTA_MODULATOR_LSB, (byte) (sdm & 0xFF), controlI2C);
}
else
{
- writeR820TRegister(Register.SIGMA_DELTA_MODULATOR_POWER,
- (byte) 0x08, controlI2C);
+ writeR820TRegister(Register.SIGMA_DELTA_MODULATOR_POWER, (byte) 0x08, controlI2C);
}
/* Check to see if the PLL locked with these divider, integral and sdm
@@ -582,8 +420,7 @@ public class R820TTunerController extends RTL2832TunerController
if(!isPLLLocked(controlI2C))
{
- throw new UsbException("R820T Tuner Controller - couldn't "
- + "achieve PLL lock on frequency [" + frequency + "]");
+ throw new UsbException("R820T Tuner Controller - couldn't achieve PLL lock on frequency [" + frequency + "]");
}
}
@@ -599,7 +436,6 @@ public class R820TTunerController extends RTL2832TunerController
private boolean isPLLLocked(boolean controlI2C) throws UsbException
{
int register = getStatusRegister(2, controlI2C);
-
return (register & 0x40) == 0x40;
}
@@ -614,11 +450,7 @@ public class R820TTunerController extends RTL2832TunerController
{
for(int x = 5; x < mShadowRegister.length; x++)
{
- writeI2CRegister(mDeviceHandle,
- mI2CAddress,
- (byte) x,
- (byte) mShadowRegister[x],
- controlI2C);
+ getAdapter().writeI2CRegister(I2C_ADDRESS, (byte) x, (byte) mShadowRegister[x], controlI2C);
}
}
@@ -628,9 +460,7 @@ public class R820TTunerController extends RTL2832TunerController
private int getStatusRegister(int register, boolean controlI2C) throws UsbException
{
ByteBuffer buffer = ByteBuffer.allocateDirect(5);
-
- read(mDeviceHandle, mI2CAddress, Block.I2C, buffer);
-
+ getAdapter().read(I2C_ADDRESS, RTL2832TunerController.Block.I2C, buffer);
return bitReverse(buffer.get(register) & 0xFF);
}
@@ -639,48 +469,31 @@ public class R820TTunerController extends RTL2832TunerController
*/
private static int bitReverse(int value)
{
- return BIT_REV_LOOKUP_TABLE[value & 0x0F] << 4 |
- BIT_REV_LOOKUP_TABLE[(value & 0xF0) >> 4];
+ return BIT_REV_LOOKUP_TABLE[value & 0x0F] << 4 | BIT_REV_LOOKUP_TABLE[(value & 0xF0) >> 4];
}
/**
* Writes the byte value to the specified register, optionally controlling
* the I2C repeater as needed.
*/
- public void writeR820TRegister(Register register,
- byte value,
- boolean controlI2C) throws UsbException
+ public synchronized void writeR820TRegister(Register register, byte value, boolean controlI2C) throws UsbException
{
if(register.isMasked())
{
int current = mShadowRegister[register.getRegister()];
-
- value = (byte) ((current & ~register.getMask()) |
- (value & register.getMask()));
+ value = (byte) ((current & ~register.getMask()) | (value & register.getMask()));
}
- writeI2CRegister(mDeviceHandle, mI2CAddress,
- (byte) register.getRegister(), value, controlI2C);
-
+ getAdapter().writeI2CRegister(I2C_ADDRESS, (byte) register.getRegister(), value, controlI2C);
mShadowRegister[register.getRegister()] = value;
-
-// Log.info( "R820T writing register " +
-// String.format( "%02X", register.getRegister() ) + " value " +
-// String.format( "%02X", value ) );
}
/**
* Reads the specified register, optionally controlling the I2C repeater
*/
- public int readR820TRegister(Register register, boolean controlI2C)
- throws UsbException
+ public int readR820TRegister(Register register, boolean controlI2C) throws UsbException
{
- int value = readI2CRegister(mDeviceHandle,
- mI2CAddress,
- (byte) register.getRegister(),
- controlI2C);
-
- return value;
+ return getAdapter().readI2CRegister(I2C_ADDRESS, (byte) register.getRegister(), controlI2C);
}
/**
@@ -699,7 +512,7 @@ public class R820TTunerController extends RTL2832TunerController
*/
public void setLNAGain(R820TLNAGain gain, boolean controlI2C) throws UsbException
{
- mLock.lock();
+ getAdapter().getLock().lock();
try
{
@@ -707,7 +520,7 @@ public class R820TTunerController extends RTL2832TunerController
}
finally
{
- mLock.unlock();
+ getAdapter().getLock().unlock();
}
}
@@ -716,7 +529,7 @@ public class R820TTunerController extends RTL2832TunerController
*/
public void setMixerGain(R820TMixerGain gain, boolean controlI2C) throws UsbException
{
- mLock.lock();
+ getAdapter().getLock().lock();
try
{
@@ -724,7 +537,7 @@ public class R820TTunerController extends RTL2832TunerController
}
finally
{
- mLock.unlock();
+ getAdapter().getLock().unlock();
}
}
@@ -733,7 +546,7 @@ public class R820TTunerController extends RTL2832TunerController
*/
public void setVGAGain(R820TVGAGain gain, boolean controlI2C) throws UsbException
{
- mLock.lock();
+ getAdapter().getLock().lock();
try
{
@@ -741,7 +554,7 @@ public class R820TTunerController extends RTL2832TunerController
}
finally
{
- mLock.unlock();
+ getAdapter().getLock().unlock();
}
}
@@ -770,7 +583,7 @@ public class R820TTunerController extends RTL2832TunerController
private String mLabel;
private int mSetting;
- private R820TVGAGain(String label, int setting)
+ R820TVGAGain(String label, int setting)
{
mLabel = label;
mSetting = setting;
@@ -813,7 +626,7 @@ public class R820TTunerController extends RTL2832TunerController
private String mLabel;
private int mSetting;
- private R820TLNAGain(String label, int setting)
+ R820TLNAGain(String label, int setting)
{
mLabel = label;
mSetting = setting;
@@ -859,7 +672,7 @@ public class R820TTunerController extends RTL2832TunerController
private String mLabel;
private int mSetting;
- private R820TMixerGain(String label, int setting)
+ R820TMixerGain(String label, int setting)
{
mLabel = label;
mSetting = setting;
@@ -919,7 +732,7 @@ public class R820TTunerController extends RTL2832TunerController
private R820TLNAGain mLNAGain;
private R820TMixerGain mMixerGain;
- private R820TGain(String label, R820TVGAGain vga, R820TLNAGain lna, R820TMixerGain mixer)
+ R820TGain(String label, R820TVGAGain vga, R820TLNAGain lna, R820TMixerGain mixer)
{
mLabel = label;
mVGAGain = vga;
@@ -1006,7 +819,7 @@ public class R820TTunerController extends RTL2832TunerController
private int mRegister;
private int mMask;
- private Register(int register, int mask)
+ Register(int register, int mask)
{
mRegister = register;
mMask = mask;
@@ -1061,13 +874,8 @@ public class R820TTunerController extends RTL2832TunerController
private int mXtalCap20p;
private int mXtalCap10p;
- private FrequencyRange(long minFrequency,
- long maxFrequency,
- int openDrain,
- int rfMuxPloy,
- int tf_c,
- int xtalCap20p,
- int xtalCap10p)
+ FrequencyRange(long minFrequency, long maxFrequency, int openDrain, int rfMuxPloy, int tf_c, int xtalCap20p,
+ int xtalCap10p)
{
mMinFrequency = minFrequency;
mMaxFrequency = maxFrequency;
@@ -1078,11 +886,19 @@ public class R820TTunerController extends RTL2832TunerController
mXtalCap10p = xtalCap10p;
}
+ /**
+ * Indicates if the frequency is contained by the frequency range of this band
+ */
public boolean contains(long frequency)
{
return mMinFrequency <= frequency && frequency <= mMaxFrequency;
}
+ /**
+ * Finds the correct frequency range that contains the frequency
+ * @param frequency to lookup
+ * @return frequency range
+ */
public static FrequencyRange getRangeForFrequency(long frequency)
{
for(FrequencyRange range : values())
@@ -1175,12 +991,8 @@ public class R820TTunerController extends RTL2832TunerController
private int mIntegralValue;
private static final int mVCOPowerReference = 2;
- private FrequencyDivider(int dividerNumber,
- int mixerDivider,
- long minimumFrequency,
- long maximumFrequency,
- int registerSetting,
- int integralValue)
+ FrequencyDivider(int dividerNumber, int mixerDivider, long minimumFrequency, long maximumFrequency,
+ int registerSetting, int integralValue)
{
mDividerNumber = dividerNumber;
mMixerDivider = mixerDivider;
@@ -1230,8 +1042,7 @@ public class R820TTunerController extends RTL2832TunerController
public boolean contains(long frequency)
{
- return mMinimumFrequency <= frequency &&
- frequency <= mMaximumFrequency;
+ return mMinimumFrequency <= frequency && frequency <= mMaximumFrequency;
}
/**
@@ -1269,27 +1080,22 @@ public class R820TTunerController extends RTL2832TunerController
return Integral.fromValue(integral);
}
- throw new IllegalArgumentException("PLL frequency [" + frequency +
- "] is not valid for this frequency divider " + this.toString());
+ throw new IllegalArgumentException("PLL frequency [" + frequency + "] is not valid for this frequency " +
+ "divider " + this);
}
/**
- * Calculates the 16-bit value of the sigma-delta modulator setting
- * which represents the fractional portion of the requested frequency
- * that is left over after subtracting the divider minimum frequency
- * and the integral frequency units. That residual value is divided
- * by the integral unit value to derive a 16-bit fractional value,
- * returned as an integer
+ * Calculates the 16-bit value of the sigma-delta modulator setting which represents the fractional portion of
+ * the requested frequency that is left over after subtracting the divider minimum frequency and the integral
+ * frequency units. That residual value is divided by the integral unit value to derive a 16-bit fractional
+ * value, returned as an integer
*/
public int getSDM(Integral integral, long frequency)
{
if(contains(frequency))
{
- int delta = (int) (frequency - mMinimumFrequency -
- (integral.getNumber() * mIntegralValue));
-
+ int delta = (int) (frequency - mMinimumFrequency - (integral.getNumber() * mIntegralValue));
double fractional = (double) delta / (double) mIntegralValue;
-
//Left shift the double value 16 bits and truncate to an integer
return (int) (fractional * 0x10000) & 0xFFFF;
}
@@ -1348,7 +1154,7 @@ public class R820TTunerController extends RTL2832TunerController
private int mNumber;
private int mRegister;
- private Integral(int number, int register)
+ Integral(int number, int register)
{
mNumber = number;
mRegister = register;
@@ -1371,8 +1177,7 @@ public class R820TTunerController extends RTL2832TunerController
return Integral.values()[value];
}
- throw new IllegalArgumentException("PLL integral value [" + value +
- "] must be in the range 0 - 31");
+ throw new IllegalArgumentException("PLL integral value [" + value + "] must be in the range 0 - 31");
}
}
}
\ No newline at end of file
diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerConfiguration.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerConfiguration.java
index 1c1ad8d4..cdeb67b7 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerConfiguration.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerConfiguration.java
@@ -1,36 +1,37 @@
-/*******************************************************************************
- * SDR Trunk
- * Copyright (C) 2014 Dennis Sheirer
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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 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.
+ * 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
- ******************************************************************************/
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
package io.github.dsheirer.source.tuner.rtl.r820t;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.source.tuner.TunerType;
-import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
-import io.github.dsheirer.source.tuner.rtl.RTL2832TunerController;
+import io.github.dsheirer.source.tuner.rtl.RTL2832TunerConfiguration;
-public class R820TTunerConfiguration extends TunerConfiguration
+/**
+ * RTL-2832 with embedded R820T tuner configuration
+ */
+public class R820TTunerConfiguration extends RTL2832TunerConfiguration
{
- private R820TTunerController.R820TGain mMasterGain = R820TTunerController.R820TGain.GAIN_327;
- private R820TTunerController.R820TMixerGain mMixerGain = R820TTunerController.R820TMixerGain.GAIN_105;
- private R820TTunerController.R820TLNAGain mLNAGain = R820TTunerController.R820TLNAGain.GAIN_222;
- private R820TTunerController.R820TVGAGain mVGAGain = R820TTunerController.R820TVGAGain.GAIN_210;
- private double mFrequencyCorrection = 0.0d;
- private RTL2832TunerController.SampleRate mSampleRate = RTL2832TunerController.SampleRate.RATE_2_400MHZ;
- private boolean mAutoPPMCorrection = true;
+ private R820TEmbeddedTuner.R820TGain mMasterGain = R820TEmbeddedTuner.R820TGain.GAIN_327;
+ private R820TEmbeddedTuner.R820TMixerGain mMixerGain = R820TEmbeddedTuner.R820TMixerGain.GAIN_105;
+ private R820TEmbeddedTuner.R820TLNAGain mLNAGain = R820TEmbeddedTuner.R820TLNAGain.GAIN_222;
+ private R820TEmbeddedTuner.R820TVGAGain mVGAGain = R820TEmbeddedTuner.R820TVGAGain.GAIN_210;
/**
* Default constructor for JAXB
@@ -39,100 +40,64 @@ public class R820TTunerConfiguration extends TunerConfiguration
{
}
- public R820TTunerConfiguration(String uniqueID, String name)
- {
- super(uniqueID, name);
- }
-
- @JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
+ @JsonIgnore
@Override
public TunerType getTunerType()
{
return TunerType.RAFAELMICRO_R820T;
}
+ /**
+ * Constructs an instance
+ *
+ * @param uniqueID for the tuner
+ */
+ public R820TTunerConfiguration(String uniqueID)
+ {
+ super(uniqueID);
+ }
+
@JacksonXmlProperty(isAttribute = true, localName = "master_gain")
- public R820TTunerController.R820TGain getMasterGain()
+ public R820TEmbeddedTuner.R820TGain getMasterGain()
{
return mMasterGain;
}
- public void setMasterGain(R820TTunerController.R820TGain gain)
+ public void setMasterGain(R820TEmbeddedTuner.R820TGain gain)
{
mMasterGain = gain;
}
@JacksonXmlProperty(isAttribute = true, localName = "mixer_gain")
- public R820TTunerController.R820TMixerGain getMixerGain()
+ public R820TEmbeddedTuner.R820TMixerGain getMixerGain()
{
return mMixerGain;
}
- public void setMixerGain(R820TTunerController.R820TMixerGain mixerGain)
+ public void setMixerGain(R820TEmbeddedTuner.R820TMixerGain mixerGain)
{
mMixerGain = mixerGain;
}
@JacksonXmlProperty(isAttribute = true, localName = "lna_gain")
- public R820TTunerController.R820TLNAGain getLNAGain()
+ public R820TEmbeddedTuner.R820TLNAGain getLNAGain()
{
return mLNAGain;
}
- public void setLNAGain(R820TTunerController.R820TLNAGain lnaGain)
+ public void setLNAGain(R820TEmbeddedTuner.R820TLNAGain lnaGain)
{
mLNAGain = lnaGain;
}
@JacksonXmlProperty(isAttribute = true, localName = "vga_gain")
- public R820TTunerController.R820TVGAGain getVGAGain()
+ public R820TEmbeddedTuner.R820TVGAGain getVGAGain()
{
return mVGAGain;
}
- public void setVGAGain(R820TTunerController.R820TVGAGain vgaGain)
+ public void setVGAGain(R820TEmbeddedTuner.R820TVGAGain vgaGain)
{
mVGAGain = vgaGain;
}
-
- @JacksonXmlProperty(isAttribute = true, localName = "frequency_correction")
- public double getFrequencyCorrection()
- {
- return mFrequencyCorrection;
- }
-
- public void setFrequencyCorrection(double value)
- {
- mFrequencyCorrection = value;
- }
-
- @JacksonXmlProperty(isAttribute = true, localName = "sample_rate")
- public RTL2832TunerController.SampleRate getSampleRate()
- {
- return mSampleRate;
- }
-
- public void setSampleRate(RTL2832TunerController.SampleRate sampleRate)
- {
- mSampleRate = sampleRate;
- }
-
- /**
- * Indicates if automatic correction of PPM from measured frequency error is enabled/disabled.
- * @return true if auto-correction is enabled.
- */
- @JacksonXmlProperty(isAttribute = true, localName = "auto_ppm_correction_enabled")
- public boolean getAutoPPMCorrectionEnabled()
- {
- return mAutoPPMCorrection;
- }
-
- /**
- * Sets the enabled state for auto-correction of PPM from measured frequency error values.
- * @param enabled
- */
- public void setAutoPPMCorrectionEnabled(boolean enabled)
- {
- mAutoPPMCorrection = enabled;
- }
}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerEditor.java
index 47620750..5589c510 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerEditor.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerEditor.java
@@ -1,90 +1,82 @@
-/*******************************************************************************
- * sdr-trunk
- * Copyright (C) 2014-2018 Dennis Sheirer
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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 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.
+ * 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
- *
- ******************************************************************************/
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * ****************************************************************************
+ */
package io.github.dsheirer.source.tuner.rtl.r820t;
+import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.source.SourceException;
-import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
-import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEditor;
-import io.github.dsheirer.source.tuner.configuration.TunerConfigurationEvent;
-import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
+import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
+import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.tuner.rtl.RTL2832Tuner;
import io.github.dsheirer.source.tuner.rtl.RTL2832TunerController;
import io.github.dsheirer.source.tuner.rtl.RTL2832TunerController.SampleRate;
-import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerController.R820TGain;
-import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerController.R820TLNAGain;
-import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerController.R820TMixerGain;
-import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerController.R820TVGAGain;
+import io.github.dsheirer.source.tuner.rtl.r820t.R820TEmbeddedTuner.R820TGain;
+import io.github.dsheirer.source.tuner.rtl.r820t.R820TEmbeddedTuner.R820TLNAGain;
+import io.github.dsheirer.source.tuner.rtl.r820t.R820TEmbeddedTuner.R820TMixerGain;
+import io.github.dsheirer.source.tuner.rtl.r820t.R820TEmbeddedTuner.R820TVGAGain;
+import io.github.dsheirer.source.tuner.ui.TunerEditor;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.usb4java.LibUsbException;
import javax.swing.JButton;
-import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
-import javax.swing.JSpinner;
-import javax.swing.JTextField;
-import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
-import javax.swing.SwingConstants;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
import javax.usb.UsbException;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.text.DecimalFormat;
-public class R820TTunerEditor extends TunerConfigurationEditor
+public class R820TTunerEditor extends TunerEditor
{
private final static Logger mLog = LoggerFactory.getLogger(R820TTunerEditor.class);
-
private static final long serialVersionUID = 1L;
private static final R820TGain DEFAULT_GAIN = R820TGain.GAIN_279;
+ private JButton mTunerInfoButton;
+ private JComboBox mSampleRateCombo;
+ private JComboBox mMasterGainCombo;
+ private JComboBox mMixerGainCombo;
+ private JComboBox mLNAGainCombo;
+ private JComboBox mVGAGainCombo;
- private R820TTunerController mController;
-
- private JTextField mConfigurationName;
- private JButton mTunerInfo;
- private JComboBox mComboSampleRate;
- private JSpinner mFrequencyCorrection;
- private JCheckBox mAutoPPMEnabled;
- private JComboBox mComboMasterGain;
- private JComboBox mComboMixerGain;
- private JComboBox mComboLNAGain;
- private JComboBox mComboVGAGain;
- private boolean mLoading;
-
- public R820TTunerEditor(TunerConfigurationModel tunerConfigurationModel, RTL2832Tuner tuner)
+ /**
+ * Constructs an instance
+ * @param userPreferences for wide-band recordings
+ * @param tunerManager for saving configurations
+ * @param discoveredTuner to edit
+ */
+ public R820TTunerEditor(UserPreferences userPreferences, TunerManager tunerManager, DiscoveredTuner discoveredTuner)
{
- super(tunerConfigurationModel);
- mController = (R820TTunerController)tuner.getController();
-
+ super(userPreferences, tunerManager, discoveredTuner);
init();
+ tunerStatusUpdated();
}
- private R820TTunerConfiguration getConfiguration()
+ /**
+ * Access the R820T embedded tuner
+ * @return R820T tuner if there is a tuner, or null otherwise
+ */
+ private R820TEmbeddedTuner getEmbeddedTuner()
{
- if(hasItem())
+ if(hasTuner())
{
- return (R820TTunerConfiguration)getItem();
+ return (R820TEmbeddedTuner)getTuner().getController().getEmbeddedTuner();
}
return null;
@@ -92,324 +84,331 @@ public class R820TTunerEditor extends TunerConfigurationEditor
private void init()
{
- setLayout(new MigLayout("fill,wrap 4", "[right][grow,fill][right][grow,fill]",
- "[][][][][][][][grow]"));
+ setLayout(new MigLayout("fill,wrap 3", "[right][grow,fill][fill]",
+ "[][][][][][][][][][][][][][][][grow]"));
- add(new JLabel("R820T Tuner Configuration"), "span,align center");
+ add(new JLabel("Tuner:"));
+ add(getTunerIdLabel());
+ add(getTunerInfoButton());
- mConfigurationName = new JTextField();
- mConfigurationName.setEnabled(false);
- mConfigurationName.addFocusListener(new FocusListener()
- {
- @Override
- public void focusLost(FocusEvent e)
- {
- save();
- }
+ add(new JLabel("Status:"));
+ add(getTunerStatusLabel(), "wrap");
- @Override
- public void focusGained(FocusEvent e)
- {
- }
- });
+ add(getButtonPanel(), "span,align left");
- add(new JLabel("Name:"));
- add(mConfigurationName, "span 2");
+ add(new JSeparator(), "span,growx,push");
- mTunerInfo = new JButton("Tuner Info");
- mTunerInfo.setEnabled(false);
- mTunerInfo.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- JOptionPane.showMessageDialog(R820TTunerEditor.this, getTunerInfo(),
- "Tuner Info", JOptionPane.INFORMATION_MESSAGE);
- }
- });
- add(mTunerInfo);
+ add(new JLabel("Frequency (MHz):"));
+ add(getFrequencyPanel(), "wrap");
- mComboSampleRate = new JComboBox<>(SampleRate.values());
- mComboSampleRate.setEnabled(false);
- mComboSampleRate.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- SampleRate sampleRate =
- (SampleRate)mComboSampleRate.getSelectedItem();
- try
- {
-
- mController.setSampleRate(sampleRate);
- save();
- }
- catch(SourceException | LibUsbException eSampleRate)
- {
- JOptionPane.showMessageDialog(
- R820TTunerEditor.this,
- "R820T Tuner Controller - couldn't apply the sample "
- + "rate setting [" + sampleRate.getLabel() + "] " +
- eSampleRate.getLocalizedMessage());
-
- mLog.error("R820T Tuner Controller - couldn't apply sample "
- + "rate setting [" + sampleRate.getLabel() + "]",
- eSampleRate);
- }
- }
- });
add(new JLabel("Sample Rate:"));
- add(mComboSampleRate);
+ add(getSampleRateCombo(), "wrap");
- /**
- * Frequency Correction
- */
- SpinnerModel model =
- new SpinnerNumberModel(0.0, //initial value
- -1000.0, //min
- 1000.0, //max
- 0.1); //step
+ add(new JSeparator(), "span,growx,push");
+ add(new JLabel("Gain Control"), "wrap");
- mFrequencyCorrection = new JSpinner(model);
- mFrequencyCorrection.setEnabled(false);
-
- JSpinner.NumberEditor editor =
- (JSpinner.NumberEditor)mFrequencyCorrection.getEditor();
-
- DecimalFormat format = editor.getFormat();
- format.setMinimumFractionDigits(1);
- editor.getTextField().setHorizontalAlignment(SwingConstants.CENTER);
-
- mFrequencyCorrection.addChangeListener(new ChangeListener()
- {
- @Override
- public void stateChanged(ChangeEvent e)
- {
- final double value = ((SpinnerNumberModel)mFrequencyCorrection
- .getModel()).getNumber().doubleValue();
-
- try
- {
- mController.setFrequencyCorrection(value);
- }
- catch(SourceException e1)
- {
- mLog.error("Error setting frequency correction value", e1);
- }
-
- save();
- }
- });
-
- add(new JLabel("PPM:"));
- add(mFrequencyCorrection);
-
- add(new JLabel("")); //Space filler
- add(new JLabel("")); //Space filler
- add(new JLabel("")); //Space filler
- mAutoPPMEnabled = new JCheckBox("PPM Auto-Correction");
- mAutoPPMEnabled.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- boolean enabled = mAutoPPMEnabled.isSelected();
- mController.getFrequencyErrorCorrectionManager().setEnabled(enabled);
- save();
- }
- });
- add(mAutoPPMEnabled);
-
- add(new JSeparator(JSeparator.HORIZONTAL), "span,grow");
-
- /**
- * Gain Controls
- */
- add(new JLabel("Gain"), "wrap");
-
- /* Master Gain Control */
- mComboMasterGain = new JComboBox(R820TGain.values());
- mComboMasterGain.setEnabled(false);
- mComboMasterGain.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent arg0)
- {
- try
- {
- R820TGain gain = (R820TGain)mComboMasterGain.getSelectedItem();
-
- mController.setGain((R820TGain)mComboMasterGain.getSelectedItem(), true);
-
- if(gain == R820TGain.MANUAL)
- {
- mComboMixerGain.setSelectedItem(gain.getMixerGain());
- mComboMixerGain.setEnabled(true);
-
- mComboLNAGain.setSelectedItem(gain.getLNAGain());
- mComboLNAGain.setEnabled(true);
-
- mComboVGAGain.setSelectedItem(gain.getVGAGain());
- mComboVGAGain.setEnabled(true);
- }
- else
- {
- mComboMixerGain.setEnabled(false);
- mComboMixerGain.setSelectedItem(gain.getMixerGain());
-
- mComboLNAGain.setEnabled(false);
- mComboLNAGain.setSelectedItem(gain.getLNAGain());
-
- mComboVGAGain.setEnabled(false);
- mComboVGAGain.setSelectedItem(gain.getVGAGain());
- }
-
- save();
- }
- catch(UsbException e)
- {
- JOptionPane.showMessageDialog(
- R820TTunerEditor.this,
- "R820T Tuner Controller - couldn't apply the gain "
- + "setting - " + e.getLocalizedMessage());
-
- mLog.error("R820T Tuner Controller - couldn't apply "
- + "gain setting - ", e);
- }
- }
- });
- mComboMasterGain.setToolTipText("Select AUTOMATIC for auto "
- + "gain, MANUAL to enable
independent control of "
- + "Mixer, LNA and Enhance gain
"
- + "settings, or one of the individual gain settings for
"
- + "semi-manual gain control");
add(new JLabel("Master:"));
- add(mComboMasterGain);
-
- /* Mixer Gain Control */
- mComboMixerGain = new JComboBox(R820TMixerGain.values());
- mComboMixerGain.setEnabled(false);
- mComboMixerGain.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent arg0)
- {
- try
- {
- R820TMixerGain mixerGain =
- (R820TMixerGain)mComboMixerGain.getSelectedItem();
-
- if(mixerGain == null)
- {
- mixerGain = DEFAULT_GAIN.getMixerGain();
- }
-
- if(mComboMixerGain.isEnabled())
- {
- mController.setMixerGain(mixerGain, true);
- }
-
- save();
- }
- catch(UsbException e)
- {
- JOptionPane.showMessageDialog(R820TTunerEditor.this,
- "R820T Tuner Controller - couldn't apply the mixer "
- + "gain setting - " + e.getLocalizedMessage());
-
- mLog.error("R820T Tuner Controller - couldn't apply mixer "
- + "gain setting - ", e);
- }
- }
- });
- mComboMixerGain.setToolTipText("Mixer Gain. Set master gain "
- + "to MANUAL to enable adjustment");
+ add(getMasterGainCombo(), "wrap");
add(new JLabel("Mixer:"));
- add(mComboMixerGain);
-
- /* LNA Gain Control */
- mComboLNAGain = new JComboBox(R820TLNAGain.values());
- mComboLNAGain.setEnabled(false);
- mComboLNAGain.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent arg0)
- {
- try
- {
- R820TLNAGain lnaGain =
- (R820TLNAGain)mComboLNAGain.getSelectedItem();
-
- if(lnaGain == null)
- {
- lnaGain = DEFAULT_GAIN.getLNAGain();
- }
-
- if(mComboLNAGain.isEnabled())
- {
- mController.setLNAGain(lnaGain, true);
- }
-
- save();
- }
- catch(UsbException e)
- {
- JOptionPane.showMessageDialog(R820TTunerEditor.this,
- "R820T Tuner Controller - couldn't apply the LNA "
- + "gain setting - " + e.getLocalizedMessage());
-
- mLog.error("R820T Tuner Controller - couldn't apply LNA "
- + "gain setting - ", e);
- }
- }
- });
- mComboLNAGain.setToolTipText("LNA Gain. Set master gain "
- + "to MANUAL to enable adjustment");
+ add(getMixerGainCombo(), "wrap");
add(new JLabel("LNA:"));
- add(mComboLNAGain);
+ add(getLNAGainCombo(), "wrap");
- /* VGA Gain Control */
- mComboVGAGain = new JComboBox(R820TVGAGain.values());
- mComboVGAGain.setEnabled(false);
- mComboVGAGain.addActionListener(new ActionListener()
+ add(new JLabel("VGA:"));
+ add(getVGAGainCombo(), "wrap");
+ }
+
+ @Override
+ protected void tunerStatusUpdated()
+ {
+ setLoading(true);
+
+ if(hasTuner())
{
- @Override
- public void actionPerformed(ActionEvent arg0)
+ getTunerIdLabel().setText(getTuner().getPreferredName());
+ }
+ else
+ {
+ getTunerIdLabel().setText(getDiscoveredTuner().getId());
+ }
+
+ String status = getDiscoveredTuner().getTunerStatus().toString();
+ if(getDiscoveredTuner().hasErrorMessage())
+ {
+ status += " - " + getDiscoveredTuner().getErrorMessage();
+ }
+ getTunerStatusLabel().setText(status);
+ getButtonPanel().updateControls();
+ getFrequencyPanel().updateControls();
+
+ if(hasTuner())
+ {
+ getTunerInfoButton().setEnabled(true);
+ getSampleRateCombo().setEnabled(true);
+ getSampleRateCombo().setSelectedItem(getConfiguration().getSampleRate());
+ getMasterGainCombo().setEnabled(true);
+ R820TGain gain = getConfiguration().getMasterGain();
+ getMasterGainCombo().setEnabled(true);
+ getMasterGainCombo().setSelectedItem(gain);
+
+ if(gain == R820TGain.MANUAL)
+ {
+ getMixerGainCombo().setSelectedItem(getConfiguration().getMixerGain());
+ getMixerGainCombo().setEnabled(true);
+
+ getLNAGainCombo().setSelectedItem(getConfiguration().getLNAGain());
+ getLNAGainCombo().setEnabled(true);
+
+ getVGAGainCombo().setSelectedItem(getConfiguration().getVGAGain());
+ getVGAGainCombo().setEnabled(true);
+ }
+ else
+ {
+ getMixerGainCombo().setEnabled(false);
+ getMixerGainCombo().setSelectedItem(gain.getMixerGain());
+
+ getLNAGainCombo().setEnabled(false);
+ getLNAGainCombo().setSelectedItem(gain.getLNAGain());
+
+ getVGAGainCombo().setEnabled(false);
+ getVGAGainCombo().setSelectedItem(gain.getVGAGain());
+ }
+ }
+ else
+ {
+ getTunerInfoButton().setEnabled(false);
+ getSampleRateCombo().setEnabled(false);
+ getMasterGainCombo().setEnabled(false);
+ getMixerGainCombo().setEnabled(false);
+ getLNAGainCombo().setEnabled(false);
+ getVGAGainCombo().setEnabled(false);
+ }
+
+ updateSampleRateToolTip();
+
+ setLoading(false);
+ }
+
+ /**
+ * Hyperlink button that provides tuner information
+ */
+ private JButton getTunerInfoButton()
+ {
+ if(mTunerInfoButton == null)
+ {
+ mTunerInfoButton = new JButton("Info");
+ mTunerInfoButton.setEnabled(false);
+ mTunerInfoButton.addActionListener(e -> JOptionPane.showMessageDialog(R820TTunerEditor.this,
+ getTunerInfo(), "Tuner Info", JOptionPane.INFORMATION_MESSAGE));
+ }
+
+ return mTunerInfoButton;
+ }
+
+ private JComboBox getVGAGainCombo()
+ {
+ if(mVGAGainCombo == null)
+ {
+ mVGAGainCombo = new JComboBox<>(R820TVGAGain.values());
+ mVGAGainCombo.setEnabled(false);
+ mVGAGainCombo.addActionListener(arg0 ->
{
try
{
- R820TVGAGain vgaGain =
- (R820TVGAGain)mComboVGAGain.getSelectedItem();
+ R820TVGAGain vgaGain = (R820TVGAGain) mVGAGainCombo.getSelectedItem();
if(vgaGain == null)
{
vgaGain = DEFAULT_GAIN.getVGAGain();
}
- if(mComboVGAGain.isEnabled())
+ if(mVGAGainCombo.isEnabled())
{
- mController.setVGAGain(vgaGain, true);
+ getEmbeddedTuner().setVGAGain(vgaGain, true);
}
save();
}
catch(UsbException e)
{
- JOptionPane.showMessageDialog(R820TTunerEditor.this,
- "R820T Tuner Controller - couldn't apply the VGA "
- + "gain setting - " + e.getLocalizedMessage());
-
- mLog.error("R820T Tuner Controller - couldn't apply VGA "
- + "gain setting", e);
+ JOptionPane.showMessageDialog(R820TTunerEditor.this, "R820T Tuner Controller - " +
+ "couldn't apply the VGA gain setting - " + e.getLocalizedMessage());
+ mLog.error("R820T Tuner Controller - couldn't apply VGA gain setting", e);
}
- }
- });
- mComboVGAGain.setToolTipText("VGA Gain. Set master gain "
- + "to MANUAL to enable adjustment");
- add(new JLabel("VGA:"));
- add(mComboVGAGain);
+ });
+ mVGAGainCombo.setToolTipText("VGA Gain. Set master gain to MANUAL to enable adjustment");
+ }
+
+ return mVGAGainCombo;
+ }
+
+ private JComboBox getLNAGainCombo()
+ {
+ if(mLNAGainCombo == null)
+ {
+ mLNAGainCombo = new JComboBox<>(R820TLNAGain.values());
+ mLNAGainCombo.setEnabled(false);
+ mLNAGainCombo.addActionListener(arg0 ->
+ {
+ try
+ {
+ R820TLNAGain lnaGain = (R820TLNAGain) mLNAGainCombo.getSelectedItem();
+
+ if(lnaGain == null)
+ {
+ lnaGain = DEFAULT_GAIN.getLNAGain();
+ }
+
+ if(mLNAGainCombo.isEnabled())
+ {
+ getEmbeddedTuner().setLNAGain(lnaGain, true);
+ }
+
+ save();
+ }
+ catch(UsbException e)
+ {
+ JOptionPane.showMessageDialog(R820TTunerEditor.this, "R820T Tuner Controller - " +
+ "couldn't apply the LNA gain setting - " + e.getLocalizedMessage());
+ mLog.error("R820T Tuner Controller - couldn't apply LNA " + "gain setting - ", e);
+ }
+ });
+ mLNAGainCombo.setToolTipText("LNA Gain. Set master gain to MANUAL to enable adjustment");
+ }
+
+ return mLNAGainCombo;
+ }
+
+ private JComboBox getSampleRateCombo()
+ {
+ if(mSampleRateCombo == null)
+ {
+ mSampleRateCombo = new JComboBox<>(SampleRate.values());
+ mSampleRateCombo.setEnabled(false);
+ mSampleRateCombo.addActionListener(e ->
+ {
+ if(!isLoading())
+ {
+ SampleRate sampleRate = (SampleRate) mSampleRateCombo.getSelectedItem();
+
+ try
+ {
+ getTuner().getController().setSampleRate(sampleRate);
+ save();
+ }
+ catch(SourceException | LibUsbException eSampleRate)
+ {
+ JOptionPane.showMessageDialog(R820TTunerEditor.this,
+ "R820T Tuner Controller - couldn't apply the sample rate setting [" +
+ sampleRate.getLabel() + "] " + eSampleRate.getLocalizedMessage());
+
+ mLog.error("R820T Tuner Controller - couldn't apply sample rate setting [" + sampleRate.getLabel() +
+ "]", eSampleRate);
+ }
+ }
+ });
+ }
+
+ return mSampleRateCombo;
+ }
+
+ private JComboBox getMixerGainCombo()
+ {
+ if(mMixerGainCombo == null)
+ {
+ mMixerGainCombo = new JComboBox<>(R820TMixerGain.values());
+ mMixerGainCombo.setEnabled(false);
+ mMixerGainCombo.addActionListener(arg0 ->
+ {
+ if(!isLoading())
+ {
+ try
+ {
+ R820TMixerGain mixerGain = (R820TMixerGain) mMixerGainCombo.getSelectedItem();
+
+ if(mixerGain == null)
+ {
+ mixerGain = DEFAULT_GAIN.getMixerGain();
+ }
+
+ if(mMixerGainCombo.isEnabled())
+ {
+ getEmbeddedTuner().setMixerGain(mixerGain, true);
+ }
+
+ save();
+ }
+ catch(UsbException e)
+ {
+ JOptionPane.showMessageDialog(R820TTunerEditor.this, "R820T Tuner Controller - " +
+ "couldn't apply the mixer gain setting - " + e.getLocalizedMessage());
+
+ mLog.error("R820T Tuner Controller - couldn't apply mixer gain setting - ", e);
+ }
+ }
+ });
+ mMixerGainCombo.setToolTipText("Mixer Gain. Set master gain to MANUAL to enable adjustment");
+ }
+
+ return mMixerGainCombo;
+ }
+
+ private JComboBox getMasterGainCombo()
+ {
+ if(mMasterGainCombo == null)
+ {
+ mMasterGainCombo = new JComboBox<>(R820TGain.values());
+ mMasterGainCombo.setEnabled(false);
+ mMasterGainCombo.addActionListener(arg0 ->
+ {
+ if(!isLoading())
+ {
+ try
+ {
+ R820TGain gain = (R820TGain)getMasterGainCombo().getSelectedItem();
+ getEmbeddedTuner().setGain((R820TGain)getMasterGainCombo().getSelectedItem(), true);
+
+ if(gain == R820TGain.MANUAL)
+ {
+ getMixerGainCombo().setSelectedItem(gain.getMixerGain());
+ getMixerGainCombo().setEnabled(true);
+
+ getLNAGainCombo().setSelectedItem(gain.getLNAGain());
+ getLNAGainCombo().setEnabled(true);
+
+ getVGAGainCombo().setSelectedItem(gain.getVGAGain());
+ getVGAGainCombo().setEnabled(true);
+ }
+ else
+ {
+ getMixerGainCombo().setEnabled(false);
+ getMixerGainCombo().setSelectedItem(gain.getMixerGain());
+
+ getLNAGainCombo().setEnabled(false);
+ getLNAGainCombo().setSelectedItem(gain.getLNAGain());
+
+ getVGAGainCombo().setEnabled(false);
+ getVGAGainCombo().setSelectedItem(gain.getVGAGain());
+ }
+
+ save();
+ }
+ catch(UsbException e)
+ {
+ JOptionPane.showMessageDialog(R820TTunerEditor.this, "R820T Tuner Controller - " +
+ "couldn't apply the gain setting - " + e.getLocalizedMessage());
+ mLog.error("R820T Tuner Controller - couldn't apply gain setting - ", e);
+ }
+ }
+ });
+ mMasterGainCombo.setToolTipText("Select AUTOMATIC for auto gain, MANUAL to enable
" +
+ "independent control of Mixer, LNA and Enhance gain
settings, or one of the " +
+ "individual gain settings for
semi-manual gain control");
+ }
+
+ return mMasterGainCombo;
}
/**
@@ -417,85 +416,31 @@ public class R820TTunerEditor extends TunerConfigurationEditor
*/
private void updateSampleRateToolTip()
{
- if(mController.isLocked())
+ if(hasTuner() && getTuner().getTunerController().isLocked())
{
- mComboSampleRate.setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
+ getSampleRateCombo().setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
+ }
+ else if(hasTuner())
+ {
+ getSampleRateCombo().setToolTipText("Select a sample rate for the tuner");
}
else
{
- mComboSampleRate.setToolTipText("Select a sample rate for the tuner");
+ getSampleRateCombo().setToolTipText("No tuner available");
}
}
@Override
public void setTunerLockState(boolean locked)
{
- mComboSampleRate.setEnabled(!locked);
- }
-
- /**
- * Sets each of the tuner configuration controls to the enabled argument state
- */
- private void setControlsEnabled(boolean enabled)
- {
- if(mConfigurationName.isEnabled() != enabled)
- {
- mConfigurationName.setEnabled(enabled);
- }
-
- if(mTunerInfo.isEnabled() != enabled)
- {
- mTunerInfo.setEnabled(enabled);
- }
-
- if(mFrequencyCorrection.isEnabled() != enabled)
- {
- mFrequencyCorrection.setEnabled(enabled);
- }
-
- if(mAutoPPMEnabled.isEnabled() != enabled)
- {
- mAutoPPMEnabled.setEnabled(enabled);
- }
-
- updateSampleRateToolTip();
-
- if(mController.isLocked())
- {
- mComboSampleRate.setEnabled(false);
- }
- else if(mComboSampleRate.isEnabled() != enabled)
- {
- mComboSampleRate.setEnabled(enabled);
- }
-
- if(mComboMasterGain.isEnabled() != enabled)
- {
- mComboMasterGain.setEnabled(enabled);
- }
-
- if(mComboMixerGain.isEnabled() != enabled)
- {
- mComboMixerGain.setEnabled(enabled);
- }
-
- if(mComboLNAGain.isEnabled() != enabled)
- {
- mComboLNAGain.setEnabled(enabled);
- }
-
- if(mComboVGAGain.isEnabled() != enabled)
- {
- mComboVGAGain.setEnabled(enabled);
- }
+ super.setTunerLockState(locked);
+ mSampleRateCombo.setEnabled(!locked);
}
private String getTunerInfo()
{
StringBuilder sb = new StringBuilder();
-
- RTL2832TunerController.Descriptor descriptor = mController.getDescriptor();
-
+ RTL2832TunerController.Descriptor descriptor = getTuner().getController().getDescriptor();
sb.append("RTL-2832 with R820T Tuner
");
if(descriptor == null)
@@ -537,76 +482,25 @@ public class R820TTunerEditor extends TunerConfigurationEditor
@Override
public void save()
{
- if(hasItem() && !mLoading)
+ if(hasConfiguration() && !isLoading())
{
R820TTunerConfiguration config = getConfiguration();
- config.setName(mConfigurationName.getText());
-
- double value = ((SpinnerNumberModel)mFrequencyCorrection
- .getModel()).getNumber().doubleValue();
+ config.setFrequency(getFrequencyControl().getFrequency());
+ double value = ((SpinnerNumberModel)getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue();
config.setFrequencyCorrection(value);
+ config.setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected());
- config.setAutoPPMCorrectionEnabled(mAutoPPMEnabled.isSelected());
-
- config.setSampleRate((SampleRate)mComboSampleRate.getSelectedItem());
-
- R820TGain gain = (R820TGain)mComboMasterGain.getSelectedItem();
+ config.setSampleRate((SampleRate)getSampleRateCombo().getSelectedItem());
+ R820TGain gain = (R820TGain)getMasterGainCombo().getSelectedItem();
config.setMasterGain(gain);
-
- R820TMixerGain mixerGain = (R820TMixerGain)mComboMixerGain.getSelectedItem();
+ R820TMixerGain mixerGain = (R820TMixerGain)getMixerGainCombo().getSelectedItem();
config.setMixerGain(mixerGain);
-
- R820TLNAGain lnaGain = (R820TLNAGain)mComboLNAGain.getSelectedItem();
+ R820TLNAGain lnaGain = (R820TLNAGain)getLNAGainCombo().getSelectedItem();
config.setLNAGain(lnaGain);
-
- R820TVGAGain vgaGain = (R820TVGAGain)mComboVGAGain.getSelectedItem();
+ R820TVGAGain vgaGain = (R820TVGAGain)getVGAGainCombo().getSelectedItem();
config.setVGAGain(vgaGain);
-
- getTunerConfigurationModel().broadcast(
- new TunerConfigurationEvent(getConfiguration(), TunerConfigurationEvent.Event.CHANGE));
+ saveConfiguration();
}
}
-
- @Override
- public void setItem(TunerConfiguration tunerConfiguration)
- {
- super.setItem(tunerConfiguration);
-
- //Toggle loading so that we don't fire a change event and schedule a settings file save
- mLoading = true;
-
- if(hasItem())
- {
- R820TTunerConfiguration config = getConfiguration();
-
- if(tunerConfiguration.isAssigned())
- {
- setControlsEnabled(true);
- mConfigurationName.setText(config.getName());
- mFrequencyCorrection.setValue(config.getFrequencyCorrection());
- mAutoPPMEnabled.setSelected(config.getAutoPPMCorrectionEnabled());
- mComboSampleRate.setSelectedItem(config.getSampleRate());
- mComboMasterGain.setSelectedItem(config.getMasterGain());
- mComboMixerGain.setSelectedItem(config.getMixerGain());
- mComboLNAGain.setSelectedItem(config.getLNAGain());
- mComboVGAGain.setSelectedItem(config.getVGAGain());
-
- //Update enabled state to reflect when frequency and sample rate controls are locked
- mComboSampleRate.setEnabled(!mController.isLocked());
- }
- else
- {
- setControlsEnabled(false);
- mConfigurationName.setText(config.getName());
- }
- }
- else
- {
- setControlsEnabled(false);
- mConfigurationName.setText("");
- }
-
- mLoading = false;
- }
}
\ No newline at end of file
diff --git a/src/main/java/io/github/dsheirer/source/tuner/test/TestTuner.java b/src/main/java/io/github/dsheirer/source/tuner/test/TestTuner.java
index 93d215a3..631c78fc 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/test/TestTuner.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/test/TestTuner.java
@@ -1,27 +1,24 @@
/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
*
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 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
- * * *****************************************************************************
+ * 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.source.tuner.test;
-import io.github.dsheirer.preference.UserPreferences;
+import io.github.dsheirer.source.tuner.ITunerErrorListener;
import io.github.dsheirer.source.tuner.Tuner;
import io.github.dsheirer.source.tuner.TunerClass;
import io.github.dsheirer.source.tuner.TunerType;
@@ -38,9 +35,9 @@ public class TestTuner extends Tuner
private static int mInstanceCounter = 1;
private final int mInstanceID = mInstanceCounter++;
- public TestTuner(UserPreferences userPreferences)
+ public TestTuner(ITunerErrorListener tunerErrorListener)
{
- super("Test Tuner", new TestTunerController(), userPreferences);
+ super(new TestTunerController(), tunerErrorListener);
}
/**
@@ -51,10 +48,16 @@ public class TestTuner extends Tuner
return (TestTunerController)super.getTunerController();
}
+ @Override
+ public String getPreferredName()
+ {
+ return "Test Tuner-" + mInstanceID;
+ }
+
@Override
public String getUniqueID()
{
- return getName() + "-" + mInstanceID;
+ return getPreferredName();
}
@Override
@@ -66,7 +69,7 @@ public class TestTuner extends Tuner
@Override
public TunerType getTunerType()
{
- return TunerClass.TEST_TUNER.getTunerType();
+ return TunerType.TEST;
}
@Override
diff --git a/src/main/java/io/github/dsheirer/source/tuner/test/TestTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/test/TestTunerController.java
index a3cd4da4..c1830d50 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/test/TestTunerController.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/test/TestTunerController.java
@@ -21,7 +21,9 @@ package io.github.dsheirer.source.tuner.test;
import io.github.dsheirer.buffer.INativeBuffer;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.source.SourceException;
+import io.github.dsheirer.source.tuner.LoggingTunerErrorListener;
import io.github.dsheirer.source.tuner.TunerController;
+import io.github.dsheirer.source.tuner.TunerType;
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -47,7 +49,12 @@ public class TestTunerController extends TunerController
*/
public TestTunerController()
{
- super(MINIMUM_FREQUENCY, MAXIMUM_FREQUENCY, DC_NOISE_BANDWIDTH, USABLE_BANDWIDTH_PERCENTAGE);
+ super(new LoggingTunerErrorListener());
+
+ setMinimumFrequency(MINIMUM_FREQUENCY);
+ setMaximumFrequency(MAXIMUM_FREQUENCY);
+ setMiddleUnusableHalfBandwidth(DC_NOISE_BANDWIDTH);
+ setUsableBandwidthPercentage(USABLE_BANDWIDTH_PERCENTAGE);
int sweepRate = 0; //Hz per interval
// long initialToneFrequency = SAMPLE_RATE / 2 + 100;
@@ -72,9 +79,21 @@ public class TestTunerController extends TunerController
}
@Override
- public void dispose()
+ public void start() throws SourceException
{
- //no-op
+ //No-op
+ }
+
+ @Override
+ public void stop()
+ {
+ //No-op
+ }
+
+ @Override
+ public TunerType getTunerType()
+ {
+ return TunerType.TEST;
}
@Override
diff --git a/src/main/java/io/github/dsheirer/source/tuner/ui/DiscoveredTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/ui/DiscoveredTunerEditor.java
new file mode 100644
index 00000000..a3f6efb6
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/source/tuner/ui/DiscoveredTunerEditor.java
@@ -0,0 +1,128 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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.source.tuner.ui;
+
+import io.github.dsheirer.gui.editor.Editor;
+import io.github.dsheirer.preference.UserPreferences;
+import io.github.dsheirer.source.tuner.configuration.TunerConfigurationFactory;
+import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
+import io.github.dsheirer.source.tuner.manager.IDiscoveredTunerStatusListener;
+import io.github.dsheirer.source.tuner.manager.TunerManager;
+import io.github.dsheirer.source.tuner.manager.TunerStatus;
+import net.miginfocom.swing.MigLayout;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+
+/**
+ * Editor for Discovered Tuners that displays custom tuner editor for the selected discovered tuner
+ */
+public class DiscoveredTunerEditor extends Editor implements IDiscoveredTunerStatusListener
+{
+ private static final long serialVersionUID = 1L;
+ private static final Logger mLog = LoggerFactory.getLogger(DiscoveredTunerEditor.class);
+ private UserPreferences mUserPreferences;
+ private TunerManager mTunerManager;
+ private JPanel mEmptyEditor = new EmptyTunerEditor();
+ private JPanel mEditor = mEmptyEditor;
+ private JScrollPane mEditorScroller;
+
+ /**
+ * Constructs an instance
+ * @param userPreferences to use for starting wideband recordings sourced by a tuner
+ * @param tunerManager for creating tuner editors
+ */
+ public DiscoveredTunerEditor(UserPreferences userPreferences, TunerManager tunerManager)
+ {
+ mUserPreferences = userPreferences;
+ mTunerManager = tunerManager;
+ init();
+ }
+
+ /**
+ * Updates the lock state of the tuner editor so that lockable controls are updated
+ * @param locked true if the tuner is locked and the controls should be locked.
+ */
+ public void setTunerLockState(boolean locked)
+ {
+ if(mEditor instanceof TunerEditor tunerEditor)
+ {
+ tunerEditor.setTunerLockState(locked);
+ }
+ }
+
+ public void init()
+ {
+ setLayout(new MigLayout("insets 0 0 0 0", "[grow,fill]", "[grow,fill]"));
+ mEditorScroller = new JScrollPane(mEditor);
+ add(mEditorScroller);
+ }
+
+ @Override
+ public void save()
+ {
+ //Unused
+ }
+
+ @Override
+ public void setItem(DiscoveredTuner tuner)
+ {
+ if(hasItem())
+ {
+ getItem().removeTunerStatusListener(this);
+ }
+
+ //Cleanup previously selected tuner
+ if(hasItem() && mEditor instanceof TunerEditor tunerEditor)
+ {
+ tunerEditor.dispose();
+ }
+
+ super.setItem(tuner);
+
+ if(hasItem())
+ {
+ mEditor = TunerConfigurationFactory.getEditor(mUserPreferences, getItem(), mTunerManager);
+ getItem().addTunerStatusListener(this);
+ }
+ else
+ {
+ mEditor = mEmptyEditor;
+ }
+
+ remove(mEditorScroller);
+ mEditorScroller = new JScrollPane(mEditor);
+ add(mEditorScroller);
+ revalidate();
+ repaint();
+ }
+
+ @Override
+ public void tunerStatusUpdated(DiscoveredTuner discoveredTuner, TunerStatus previous, TunerStatus current)
+ {
+ //If this is the currently displayed tuner, set it again to re-render the editor
+ if(hasItem() && getItem().equals(discoveredTuner))
+ {
+ setItem(discoveredTuner);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/dsheirer/source/tuner/ui/DiscoveredTunerModel.java b/src/main/java/io/github/dsheirer/source/tuner/ui/DiscoveredTunerModel.java
new file mode 100644
index 00000000..32592427
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/source/tuner/ui/DiscoveredTunerModel.java
@@ -0,0 +1,500 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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.source.tuner.ui;
+
+import io.github.dsheirer.sample.Listener;
+import io.github.dsheirer.source.tuner.Tuner;
+import io.github.dsheirer.source.tuner.TunerEvent;
+import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
+import io.github.dsheirer.source.tuner.manager.DiscoveredUSBTuner;
+import io.github.dsheirer.source.tuner.manager.IDiscoveredTunerStatusListener;
+import io.github.dsheirer.source.tuner.manager.TunerStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.table.AbstractTableModel;
+import java.awt.EventQueue;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Model for discovered tuners
+ */
+public class DiscoveredTunerModel extends AbstractTableModel implements Listener,
+ IDiscoveredTunerStatusListener
+{
+ private static final long serialVersionUID = 1L;
+ private static final Logger mLog = LoggerFactory.getLogger(DiscoveredTunerModel.class);
+
+ //Model columns
+ public static final int COLUMN_TUNER_STATUS = 0;
+ public static final int COLUMN_TUNER_CLASS = 1;
+ public static final int COLUMN_TUNER_TYPE = 2;
+ public static final int COLUMN_FREQUENCY = 3;
+ public static final int COLUMN_CHANNEL_COUNT = 4;
+ private static final String MHZ = " MHz";
+ private static final String[] COLUMN_HEADERS = {"Status","Class", "Type", "Frequency", "Channels"};
+
+ private List mDiscoveredTuners = new CopyOnWriteArrayList<>();
+ private List> mTunerEventListeners = new ArrayList<>();
+ private DecimalFormat mFrequencyFormat = new DecimalFormat("0.00000");
+ private Lock mLock = new ReentrantLock();
+
+
+ /**
+ * Constructs an instance
+ */
+ public DiscoveredTunerModel()
+ {
+ }
+
+ /**
+ * List of currently enabled and available tuners
+ */
+ public List getAvailableTuners()
+ {
+ return mDiscoveredTuners.stream().filter(discoveredTuner -> discoveredTuner.hasTuner()).toList();
+ }
+
+ /**
+ * Find the discovered tuner that matches the instantiated tuner
+ * @param tuner to match
+ * @return matching discovered tuner
+ */
+ private DiscoveredTuner getDiscoveredTuner(Tuner tuner)
+ {
+ DiscoveredTuner match = null;
+
+ mLock.lock();
+
+ try
+ {
+ for(DiscoveredTuner discoveredTuner: mDiscoveredTuners)
+ {
+ if(discoveredTuner.hasTuner() && discoveredTuner.getTuner().equals(tuner))
+ {
+ match = discoveredTuner;
+ break;
+ }
+ }
+ }
+ finally
+ {
+ mLock.unlock();
+ }
+
+ return match;
+ }
+
+ /**
+ * Access the discovered tuner at the specified row index
+ * @param index to lookup
+ * @return discovered tuner or null
+ */
+ public DiscoveredTuner getDiscoveredTuner(int index)
+ {
+ mLock.lock();
+
+ try
+ {
+ if(index < mDiscoveredTuners.size())
+ {
+ return mDiscoveredTuners.get(index);
+ }
+ }
+ finally
+ {
+ mLock.unlock();
+ }
+
+ return null;
+ }
+
+ /**
+ * Adds the Tuner to this model
+ */
+ public void addDiscoveredTuner(DiscoveredTuner discoveredTuner)
+ {
+ mLock.lock();
+
+ try
+ {
+ if(!mDiscoveredTuners.contains(discoveredTuner))
+ {
+ mDiscoveredTuners.add(discoveredTuner);
+ int index = mDiscoveredTuners.indexOf(discoveredTuner);
+ EventQueue.invokeLater(() -> fireTableRowsInserted(index, index));
+ if(discoveredTuner.hasTuner())
+ {
+ discoveredTuner.getTuner().addTunerEventListener(this);
+ }
+ discoveredTuner.addTunerStatusListener(this);
+ }
+ }
+ finally
+ {
+ mLock.unlock();
+ }
+ }
+
+ /**
+ * Stops and removes all discovered tuners, in preparation for shutdown.
+ */
+ public void releaseDiscoveredTuners()
+ {
+ mLock.lock();
+
+ try
+ {
+ List discoveredTuners = new ArrayList<>(mDiscoveredTuners);
+
+ for(DiscoveredTuner discoveredTuner: discoveredTuners)
+ {
+ if(discoveredTuner.hasTuner())
+ {
+ discoveredTuner.getTuner().removeTunerEventListener(this);
+ }
+
+ removeDiscoveredTuner(discoveredTuner);
+ }
+ }
+ finally
+ {
+ mLock.unlock();
+ }
+ }
+
+ /**
+ * Removes the Tuner from this model
+ */
+ public void removeDiscoveredTuner(DiscoveredTuner discoveredTuner)
+ {
+ mLock.lock();
+
+ try
+ {
+ if(mDiscoveredTuners.contains(discoveredTuner))
+ {
+ int index = mDiscoveredTuners.indexOf(discoveredTuner);
+ mDiscoveredTuners.remove(discoveredTuner);
+ EventQueue.invokeLater(() -> fireTableRowsDeleted(index, index));
+ discoveredTuner.stop();
+ }
+ }
+ finally
+ {
+ mLock.unlock();
+ }
+ }
+
+ /**
+ * Indicates if the discovered tuner is still being managed by this tuner model and hasn't been removed.
+ */
+ public boolean hasTuner(DiscoveredTuner discoveredTuner)
+ {
+ return mDiscoveredTuners.contains(discoveredTuner);
+ }
+
+ /**
+ * Indicates if this model currently has the discovered tuner that is plugged into the specified bus and port.
+ * @param bus number
+ * @param port number
+ * @return true if it already has the discovered device
+ */
+ public boolean hasUsbTuner(int bus, int port)
+ {
+ boolean hasDevice;
+ mLock.lock();
+
+ try
+ {
+ hasDevice = mDiscoveredTuners.stream()
+ .filter(tuner -> tuner instanceof DiscoveredUSBTuner usbTuner && usbTuner.isAt(bus, port))
+ .findFirst()
+ .isPresent();
+ }
+ finally
+ {
+ mLock.unlock();
+ }
+
+ return hasDevice;
+ }
+
+ /**
+ * Removes the USB tuner at bus and port number
+ * @param bus usb
+ * @param port usb
+ */
+ public void removeUsbTuner(int bus, int port)
+ {
+ mLock.lock();
+
+ try
+ {
+ DiscoveredTuner discoveredTuner = mDiscoveredTuners.stream()
+ .filter(tuner -> tuner instanceof DiscoveredUSBTuner usbTuner &&
+ usbTuner.isAt(bus, port)).findFirst().get();
+
+ if(discoveredTuner != null)
+ {
+ removeDiscoveredTuner(discoveredTuner);
+ }
+ }
+ finally
+ {
+ mLock.unlock();
+ }
+ }
+
+ /**
+ * Adds a tuner event listener
+ */
+ public void addListener(Listener listener)
+ {
+ mTunerEventListeners.add(listener);
+ }
+
+ /**
+ * Removes a tuner event listener
+ */
+ public void removeListener(Listener listener)
+ {
+ mTunerEventListeners.remove(listener);
+ }
+
+ public void broadcast(TunerEvent event)
+ {
+ for(Listener listener : mTunerEventListeners)
+ {
+ listener.receive(event);
+ }
+ }
+
+ /**
+ * Requests to display the first tuner in this model. Invoke this method
+ * after all listeners have registered and tuners have been added to this
+ * model, in order to inform the primary display to use the first tuner.
+ */
+ public void requestFirstTunerDisplay()
+ {
+//TODO: move this out of the model ... is not part of the scope of this model
+// SystemProperties properties = SystemProperties.getInstance();
+// boolean enabled = properties.get(SpectralDisplayPanel.SPECTRAL_DISPLAY_ENABLED, true);
+//
+// if(enabled && mDiscoveredTuners.size() > 0)
+// {
+// //Hack: the airspy tuner would lockup aperiodically and refuse to produce
+// //transfer buffers ... delaying registering for buffers for 500 ms seems
+// //to allow the airspy to stabilize before we start asking for samples.
+// ThreadPool.SCHEDULED.schedule(new Runnable()
+// {
+// @Override
+// public void run()
+// {
+// broadcast(new TunerEvent(mDiscoveredTuners.get(0), Event.REQUEST_MAIN_SPECTRAL_DISPLAY));
+// }
+// }, 500, TimeUnit.MILLISECONDS);
+// }
+// else
+// {
+// broadcast(new TunerEvent(null, Event.CLEAR_MAIN_SPECTRAL_DISPLAY));
+// }
+ }
+
+ @Override
+ public void tunerStatusUpdated(DiscoveredTuner discoveredTuner, TunerStatus previous, TunerStatus current)
+ {
+ if(current == TunerStatus.ENABLED && discoveredTuner.hasTuner())
+ {
+ discoveredTuner.getTuner().addTunerEventListener(this);
+ }
+
+ int row = mDiscoveredTuners.indexOf(discoveredTuner);
+ EventQueue.invokeLater(() -> fireTableRowsUpdated(row, row));
+ }
+
+ @Override
+ public void receive(TunerEvent event)
+ {
+ if(event.hasTuner())
+ {
+ mLock.lock();
+
+ try
+ {
+ DiscoveredTuner matching = getDiscoveredTuner(event.getTuner());
+ int index = mDiscoveredTuners.indexOf(matching);
+
+ if(index >= 0)
+ {
+ switch(event.getEvent())
+ {
+ case UPDATE_CHANNEL_COUNT:
+ EventQueue.invokeLater(() -> fireTableCellUpdated(index, COLUMN_CHANNEL_COUNT));
+ break;
+ case UPDATE_FREQUENCY:
+ EventQueue.invokeLater(() -> fireTableCellUpdated(index, COLUMN_FREQUENCY));
+ break;
+ case NOTIFICATION_ERROR_STATE:
+ EventQueue.invokeLater(() -> fireTableRowsUpdated(index, index));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ finally
+ {
+ mLock.unlock();
+ }
+ }
+ else
+ {
+ mLog.error("Got a tuner event without a tuner - " + event);
+ }
+
+ broadcast(event);
+ }
+
+ @Override
+ public int getRowCount()
+ {
+ return mDiscoveredTuners.size();
+ }
+
+ @Override
+ public int getColumnCount()
+ {
+ return COLUMN_HEADERS.length;
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex)
+ {
+ if(rowIndex < mDiscoveredTuners.size())
+ {
+ DiscoveredTuner discoveredTuner = mDiscoveredTuners.get(rowIndex);
+
+ switch(columnIndex)
+ {
+ case COLUMN_TUNER_STATUS:
+ return discoveredTuner.getTunerStatus();
+ case COLUMN_TUNER_CLASS:
+ return discoveredTuner.getTunerClass().toString();
+ case COLUMN_TUNER_TYPE:
+ if(discoveredTuner.hasTuner())
+ {
+ return discoveredTuner.getTuner().getTunerType().getLabel();
+ }
+ else
+ {
+ return "";
+ }
+// case COLUMN_TUNER_ID:
+// if(discoveredTuner.hasTuner())
+// {
+// return discoveredTuner.getTuner().getUniqueID();
+// }
+// else
+// {
+// return discoveredTuner.getId();
+// }
+// case COLUMN_SAMPLE_RATE:
+// if(discoveredTuner.hasTuner())
+// {
+// double sampleRate = discoveredTuner.getTuner().getTunerController().getSampleRate();
+// return mSampleRateFormat.format(sampleRate / 1E6D) + MHZ;
+// }
+// else
+// {
+// return "";
+// }
+ case COLUMN_FREQUENCY:
+ if(discoveredTuner.hasTuner())
+ {
+ long frequency = discoveredTuner.getTuner().getTunerController().getFrequency();
+ return mFrequencyFormat.format(frequency / 1E6D) + MHZ;
+ }
+ else
+ {
+ return "";
+ }
+ case COLUMN_CHANNEL_COUNT:
+ if(discoveredTuner.hasTuner())
+ {
+ int channelCount = discoveredTuner.getTuner().getChannelSourceManager().getTunerChannelCount();
+ return channelCount + " (" + (discoveredTuner.getTuner().getTunerController().isLocked() ? "LOCKED)" : "UNLOCKED)");
+ }
+ else
+ {
+ return "";
+ }
+// case COLUMN_FREQUENCY_ERROR:
+// if(discoveredTuner.hasTuner())
+// {
+// double ppm = discoveredTuner.getTuner().getTunerController().getFrequencyCorrection();
+// return mFrequencyErrorPPMFormat.format(ppm);
+// }
+// else
+// {
+// return "";
+// }
+// case COLUMN_MEASURED_FREQUENCY_ERROR:
+// if(discoveredTuner.hasTuner())
+// {
+// if(discoveredTuner.getTuner().getTunerController().hasMeasuredFrequencyError())
+// {
+// StringBuilder sb = new StringBuilder();
+// sb.append(discoveredTuner.getTuner().getTunerController().getMeasuredFrequencyError());
+// sb.append("Hz (");
+// sb.append(mFrequencyErrorPPMFormat.format(discoveredTuner.getTuner().getTunerController().getPPMFrequencyError()));
+// sb.append("ppm)");
+// return sb.toString();
+// }
+// }
+// return "";
+// case COLUMN_ERROR_OR_SPECTRAL_DISPLAY_NEW:
+// if(discoveredTuner.hasErrorMessage())
+// {
+// return discoveredTuner.getErrorMessage();
+// }
+// else if(discoveredTuner.hasTuner())
+// {
+// return "New";
+// }
+// return "";
+ default:
+ break;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public String getColumnName(int columnIndex)
+ {
+ return COLUMN_HEADERS[columnIndex];
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/dsheirer/source/tuner/ui/EmptyTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/ui/EmptyTunerEditor.java
new file mode 100644
index 00000000..98a5e556
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/source/tuner/ui/EmptyTunerEditor.java
@@ -0,0 +1,42 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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.source.tuner.ui;
+
+import net.miginfocom.swing.MigLayout;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+/**
+ * Empty tuner editor panel
+ */
+public class EmptyTunerEditor extends JPanel
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs an instance
+ */
+ public EmptyTunerEditor()
+ {
+ setLayout(new MigLayout("insets 0 0 0 0", "[center,grow]", "[center,grow]"));
+ add(new JLabel("No tuner selected"), "wrap");
+ }
+}
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
new file mode 100644
index 00000000..3a85ad31
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/source/tuner/ui/TunerEditor.java
@@ -0,0 +1,707 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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.source.tuner.ui;
+
+import io.github.dsheirer.gui.control.JFrequencyControl;
+import io.github.dsheirer.preference.UserPreferences;
+import io.github.dsheirer.record.wave.IRecordingStatusListener;
+import io.github.dsheirer.sample.Listener;
+import io.github.dsheirer.source.ISourceEventProcessor;
+import io.github.dsheirer.source.SourceEvent;
+import io.github.dsheirer.source.SourceException;
+import io.github.dsheirer.source.tuner.Tuner;
+import io.github.dsheirer.source.tuner.TunerEvent;
+import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
+import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
+import io.github.dsheirer.source.tuner.manager.IDiscoveredTunerStatusListener;
+import io.github.dsheirer.source.tuner.manager.TunerManager;
+import io.github.dsheirer.source.tuner.manager.TunerStatus;
+import io.github.dsheirer.util.SwingUtils;
+import net.miginfocom.swing.MigLayout;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.JToggleButton;
+import javax.swing.SpinnerModel;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SwingConstants;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.EventQueue;
+import java.text.CharacterIterator;
+import java.text.DecimalFormat;
+import java.text.StringCharacterIterator;
+
+/**
+ * Base tuner configuration editor.
+ */
+public abstract class TunerEditor extends JPanel
+ implements IDiscoveredTunerStatusListener, Listener
+{
+ private Logger mLog = LoggerFactory.getLogger(TunerEditor.class);
+ private static final String BUTTON_STATUS_ENABLE = "Enable";
+ private static final String BUTTON_STATUS_DISABLE = "Disable";
+ private static final String BUTTON_STATUS_RESET = "Reset Error";
+ private static final long serialVersionUID = 1L;
+ private UserPreferences mUserPreferences;
+ private TunerManager mTunerManager;
+ private DiscoveredTuner mDiscoveredTuner;
+ private C mTunerConfiguration;
+ private FrequencyAndCorrectionChangeListener mFrequencyAndCorrectionChangeListener = new FrequencyAndCorrectionChangeListener();
+ private JFrequencyControl mFrequencyControl;
+ private JSpinner mFrequencyCorrectionSpinner;
+ private JButton mChangeStatusButton;
+ private JButton mViewSpectrumButton;
+ private JButton mNewSpectrumButton;
+ private JToggleButton mRecordButton;
+ private ButtonPanel mButtonsPanel;
+ private FrequencyPanel mFrequencyPanel;
+ private JLabel mTunerIdLabel;
+ private JCheckBox mAutoPPMCheckBox;
+ private JLabel mMeasuredPPMLabel;
+ private JLabel mRecordingStatusLabel;
+ private JLabel mTunerStatusLabel;
+ private JLabel mTunerLockedStatusLabel;
+ private boolean mLoading = false;
+
+ /**
+ * Constructs an instance
+ * @param tunerManager for requesting configuration saves.
+ */
+ public TunerEditor(UserPreferences userPreferences, TunerManager tunerManager, DiscoveredTuner discoveredTuner)
+ {
+ mUserPreferences = userPreferences;
+ mTunerManager = tunerManager;
+ mDiscoveredTuner = discoveredTuner;
+
+ if(mDiscoveredTuner != null && mDiscoveredTuner.hasTunerConfiguration())
+ {
+ mTunerConfiguration = (C)mDiscoveredTuner.getTunerConfiguration();
+ }
+
+ if(mDiscoveredTuner != null)
+ {
+ mDiscoveredTuner.addTunerStatusListener(this);
+
+ if(mDiscoveredTuner.hasTuner())
+ {
+ mDiscoveredTuner.getTuner().addTunerEventListener(this);
+ }
+ }
+ }
+
+ /**
+ * Indicates if the controls are currently being loaded with values.
+ */
+ protected boolean isLoading()
+ {
+ return mLoading;
+ }
+
+ /**
+ * Changes the loading status
+ */
+ protected void setLoading(boolean loading)
+ {
+ mLoading = loading;
+ }
+
+ /**
+ * Measured PPM value received from any decoders that may be running.
+ */
+ protected JLabel getMeasuredPPMLabel()
+ {
+ if(mMeasuredPPMLabel == null)
+ {
+ mMeasuredPPMLabel = new JLabel("");
+ mMeasuredPPMLabel.setToolTipText("Displays the measured frequency error and PPM when provided by compatible channel decoders");
+ }
+
+ return mMeasuredPPMLabel;
+ }
+
+ /**
+ * Tuner locked status label that can be turned on/off depending on tuner lock state.
+ */
+ protected JLabel getTunerLockedStatusLabel()
+ {
+ if(mTunerLockedStatusLabel == null)
+ {
+ mTunerLockedStatusLabel = new JLabel("Channel(s) active - frequency and sample rate controls are locked");
+ mTunerLockedStatusLabel.setToolTipText("Indicates that the tuner is providing channel(s) and you can't " +
+ "change the tuner frequency or sample rate");
+ mTunerLockedStatusLabel.setVisible(false);
+ }
+
+ return mTunerLockedStatusLabel;
+ }
+
+ /**
+ * Tuner status label
+ */
+ protected JLabel getTunerStatusLabel()
+ {
+ if(mTunerStatusLabel == null)
+ {
+ mTunerStatusLabel = new JLabel(" ");
+ }
+
+ return mTunerStatusLabel;
+ }
+
+
+ /**
+ * Label to display current file size for a wide-band recording
+ */
+ protected JLabel getRecordingStatusLabel()
+ {
+ if(mRecordingStatusLabel == null)
+ {
+ mRecordingStatusLabel = new JLabel(" ");
+ mRecordingStatusLabel.setToolTipText("Shows the status of the latest baseband recording when active");
+ mRecordingStatusLabel.setVisible(false);
+ }
+
+ return mRecordingStatusLabel;
+ }
+
+ /**
+ * Check box for enable/disable automatic PPM adjustment from decoder(s) frequency error feedback.
+ */
+ protected JCheckBox getAutoPPMCheckBox()
+ {
+ if(mAutoPPMCheckBox == null)
+ {
+ mAutoPPMCheckBox = new JCheckBox("Enable decoder(s) to auto-adjust PPM");
+ mAutoPPMCheckBox.setToolTipText("Allow decoders to measure channel frequency error and correct tuner PPM");
+ mAutoPPMCheckBox.addActionListener(e ->
+ {
+ if(!isLoading())
+ {
+ Tuner tuner = getTuner();
+ if(tuner != null)
+ {
+ boolean enabled = getAutoPPMCheckBox().isSelected();
+ getTuner().getTunerController().getFrequencyErrorCorrectionManager().setEnabled(enabled);
+ save();
+ }
+ }
+ });
+ }
+
+ return mAutoPPMCheckBox;
+ }
+
+ /**
+ * Label for displaying the tuner ID
+ */
+ protected JLabel getTunerIdLabel()
+ {
+ if(mTunerIdLabel == null)
+ {
+ mTunerIdLabel = new JLabel(" ");
+ }
+
+ return mTunerIdLabel;
+ }
+
+ protected FrequencyPanel getFrequencyPanel()
+ {
+ if(mFrequencyPanel == null)
+ {
+ mFrequencyPanel = new FrequencyPanel();
+ mFrequencyPanel.setToolTipText("Tuner frequency and PPM controls");
+ }
+
+ return mFrequencyPanel;
+ }
+
+ protected JSpinner getFrequencyCorrectionSpinner()
+ {
+ if(mFrequencyCorrectionSpinner == null)
+ {
+ SpinnerModel model = new SpinnerNumberModel(0.0, -1000.0, 1000.0, 0.1);
+ mFrequencyCorrectionSpinner = new JSpinner(model);
+ mFrequencyCorrectionSpinner.setToolTipText("Adjust the PPM value to compensate for tuner frequency error");
+ mFrequencyCorrectionSpinner.setEnabled(false);
+ JSpinner.NumberEditor editor = (JSpinner.NumberEditor) mFrequencyCorrectionSpinner.getEditor();
+ DecimalFormat format = editor.getFormat();
+ format.setMinimumFractionDigits(1);
+ editor.getTextField().setHorizontalAlignment(SwingConstants.CENTER);
+ mFrequencyCorrectionSpinner.addChangeListener(mFrequencyAndCorrectionChangeListener);
+ }
+
+ return mFrequencyCorrectionSpinner;
+ }
+
+ protected ButtonPanel getButtonPanel()
+ {
+ if(mButtonsPanel == null)
+ {
+ mButtonsPanel = new ButtonPanel();
+ mButtonsPanel.setToolTipText("Button controls for the selected tuner");
+ }
+
+ return mButtonsPanel;
+ }
+
+ protected JFrequencyControl getFrequencyControl()
+ {
+ if(mFrequencyControl == null)
+ {
+ mFrequencyControl = new JFrequencyControl();
+ }
+
+ return mFrequencyControl;
+ }
+
+ /**
+ * Button requesting to show tuner in new spectral display
+ */
+ protected JButton getNewSpectrumButton()
+ {
+ if(mNewSpectrumButton == null)
+ {
+ mNewSpectrumButton = new JButton("New Spectrum Display");
+ mNewSpectrumButton.setToolTipText("Show this tuner in a new (separate) spectral display window");
+ mNewSpectrumButton.addActionListener(e ->
+ {
+ Tuner tuner = getTuner();
+
+ if(tuner != null)
+ {
+ mTunerManager.getDiscoveredTunerModel().broadcast(new TunerEvent(tuner,
+ TunerEvent.Event.REQUEST_NEW_SPECTRAL_DISPLAY));
+ }
+ });
+ }
+
+ return mNewSpectrumButton;
+ }
+
+ /**
+ * Button requesting to show tuner in main spectral display
+ */
+ protected JButton getViewSpectrumButton()
+ {
+ if(mViewSpectrumButton == null)
+ {
+ mViewSpectrumButton = new JButton("View Spectrum");
+ mViewSpectrumButton.setToolTipText("Show this tuner in the spectral display");
+ mViewSpectrumButton.addActionListener(e ->
+ {
+ Tuner tuner = getTuner();
+
+ if(tuner != null)
+ {
+ mTunerManager.getDiscoveredTunerModel().broadcast(new TunerEvent(tuner,
+ TunerEvent.Event.REQUEST_MAIN_SPECTRAL_DISPLAY));
+ }
+ });
+ }
+
+ return mViewSpectrumButton;
+ }
+
+ /**
+ * Button to change enable, disable, or error restart status.
+ */
+ protected JButton getChangeStatusButton()
+ {
+ if(mChangeStatusButton == null)
+ {
+ mChangeStatusButton = new JButton(BUTTON_STATUS_ENABLE);
+ mChangeStatusButton.setToolTipText("Enable or disable the tuner for use by sdrtrunk, or attempt to reset a tuner error");
+ mChangeStatusButton.addActionListener(e ->
+ {
+ switch(getChangeStatusButton().getText())
+ {
+ case BUTTON_STATUS_DISABLE:
+ mLog.info("Disabling " + getDiscoveredTuner().getTunerClass() + " tuner");
+ getDiscoveredTuner().setEnabled(false);
+ break;
+ case BUTTON_STATUS_ENABLE:
+ mLog.info("Enabling " + getDiscoveredTuner().getTunerClass() + " tuner");
+ getDiscoveredTuner().setEnabled(true);
+ break;
+ case BUTTON_STATUS_RESET:
+ mLog.info("Resetting " + getDiscoveredTuner().getTunerClass() + " tuner");
+ getDiscoveredTuner().reset();
+ break;
+ default:
+ mLog.info("None matched");
+ }
+ });
+ }
+
+ return mChangeStatusButton;
+ }
+
+ /**
+ * Turns off the recorder, if it's currently recording.
+ */
+ protected void turnOffRecorder()
+ {
+ if(getRecordButton().isSelected())
+ {
+ getRecordButton().setSelected(false);
+ }
+ }
+
+ /**
+ * Records the tuner's wide-band sample stream.
+ */
+ protected JToggleButton getRecordButton()
+ {
+ if(mRecordButton == null)
+ {
+ mRecordButton = new JToggleButton("Record");
+ mRecordButton.setToolTipText("Create a baseband recording for this tuner");
+ mRecordButton.setEnabled(false);
+ mRecordButton.addActionListener(e ->
+ {
+ if(hasTuner())
+ {
+ if(getRecordButton().isSelected())
+ {
+ getRecordingStatusLabel().setVisible(true);
+ getRecordingStatusLabel().setText(" ");
+ getTuner().getTunerController().startRecorder(mUserPreferences, new RecordingStatusListener(),
+ getDiscoveredTuner().getTunerClass().name());
+ }
+ else
+ {
+ getTuner().getTunerController().stopRecorder();
+ }
+ }
+ });
+ }
+
+ return mRecordButton;
+ }
+
+ protected abstract void save();
+
+ /**
+ * Access the tuner configuration
+ */
+ protected C getConfiguration()
+ {
+ return mTunerConfiguration;
+ }
+
+ /**
+ * Indicates if this editor has a tuner configuration
+ */
+ protected boolean hasConfiguration()
+ {
+ return mTunerConfiguration != null;
+ }
+
+ /**
+ * Discovered tuner for this editor
+ */
+ protected DiscoveredTuner getDiscoveredTuner()
+ {
+ return mDiscoveredTuner;
+ }
+
+ /**
+ * Notification that the status of the discovered tuner has changed and that the editor implementation must
+ * refresh the UI controls with the current tuner state.
+ */
+ protected abstract void tunerStatusUpdated();
+
+ /**
+ * Implements the tuner status listener interface to send notification to editor implementations that the
+ * status of the discovered tuner has changed.
+ * @param discoveredTuner that has a status change.
+ * @param previous tuner status
+ * @param current tuner status
+ */
+ @Override
+ public void tunerStatusUpdated(DiscoveredTuner discoveredTuner, TunerStatus previous, TunerStatus current)
+ {
+ SwingUtils.run(() -> tunerStatusUpdated());
+
+ if(current == TunerStatus.ENABLED)
+ {
+ if(hasTuner())
+ {
+ getTuner().addTunerEventListener(this);
+ }
+ }
+ }
+
+ @Override
+ public void receive(TunerEvent tunerEvent)
+ {
+ if(tunerEvent.getEvent().equals(TunerEvent.Event.UPDATE_MEASURED_FREQUENCY_ERROR))
+ {
+ SwingUtils.run(() -> getFrequencyPanel().updateFrequencyError());
+ }
+ }
+
+ /**
+ * Prepare this editor for disposal
+ */
+ public void dispose()
+ {
+ if(mDiscoveredTuner != null)
+ {
+ mDiscoveredTuner.removeTunerStatusListener(this);
+
+ if(mDiscoveredTuner.hasTuner())
+ {
+ mDiscoveredTuner.getTuner().removeTunerEventListener(this);
+ }
+ }
+
+ turnOffRecorder();
+ }
+
+ /**
+ * Indicates if the discovered tuner has a usable tuner
+ */
+ public boolean hasTuner()
+ {
+ return mDiscoveredTuner != null && mDiscoveredTuner.hasTuner();
+ }
+
+ /**
+ * Access the usable tuner from the discovered tuner
+ * Note: use hasTuner() to check before invoking this method.
+ * @return tuner or null.
+ */
+ public T getTuner()
+ {
+ if(hasTuner())
+ {
+ return (T)mDiscoveredTuner.getTuner();
+ }
+
+ return null;
+ }
+
+ /**
+ * Request to save the state of this configuration.
+ */
+ protected void saveConfiguration()
+ {
+ mTunerManager.saveConfigurations();
+ }
+
+ /**
+ * Sets the lock state for the tuner so that the frequency and sample rate controls can be enabled/disabled.
+ *
+ * @param locked true if the tuner is locked.
+ */
+ public void setTunerLockState(boolean locked)
+ {
+ getFrequencyPanel().updateControls();
+ }
+
+ /**
+ * Tuner buttons panel
+ */
+ public class ButtonPanel extends JPanel
+ {
+ /**
+ * Constructs an instance
+ */
+ public ButtonPanel()
+ {
+ setLayout(new MigLayout("insets 0,fill", "[][][][][grow,fill]", ""));
+ add(getChangeStatusButton());
+ add(getRecordButton());
+ add(getViewSpectrumButton());
+ add(getNewSpectrumButton(), "wrap");
+// add(new JLabel(""), "wrap"); //Spacer to allow recording status label to grow and not affect buttons
+ add(getRecordingStatusLabel(), "span");
+ }
+
+ /**
+ * Updates the state and text of the buttons based on the tuner status.
+ */
+ public void updateControls()
+ {
+ TunerStatus tunerStatus = getDiscoveredTuner().getTunerStatus();
+
+ getRecordButton().setEnabled(tunerStatus.isAvailable() && getDiscoveredTuner().hasTuner());
+ getRecordingStatusLabel().setText(" ");
+ getViewSpectrumButton().setEnabled(tunerStatus.isAvailable() && getDiscoveredTuner().hasTuner());
+ getNewSpectrumButton().setEnabled(tunerStatus.isAvailable() && getDiscoveredTuner().hasTuner());
+
+ switch(tunerStatus)
+ {
+ case ENABLED:
+ getChangeStatusButton().setText(BUTTON_STATUS_DISABLE);
+ break;
+ case DISABLED:
+ getChangeStatusButton().setText(BUTTON_STATUS_ENABLE);
+ break;
+ case ERROR:
+ getChangeStatusButton().setText(BUTTON_STATUS_RESET);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Sub panel that displays frequency control, ppm spinner and control, and tuner locked status label.
+ */
+ public class FrequencyPanel extends JPanel
+ {
+ public FrequencyPanel()
+ {
+ setLayout(new MigLayout("insets 0,fill", "[][][][][grow,fill]", ""));
+ add(getFrequencyControl(), "spany 2");
+ add(new JLabel("PPM:"));
+ add(getFrequencyCorrectionSpinner());
+ add(getMeasuredPPMLabel(), "wrap");
+ add(getAutoPPMCheckBox(), "span");
+ add(getTunerLockedStatusLabel(), "span");
+ }
+
+ /**
+ * Update the state of the frequency panel controls
+ */
+ public void updateControls()
+ {
+ getFrequencyControl().clearListeners();
+ getFrequencyControl().addListener(mFrequencyAndCorrectionChangeListener);
+ getFrequencyControl().setEnabled(hasTuner() && !getTuner().getTunerController().isLocked());
+ getTunerLockedStatusLabel().setVisible(hasTuner() && getTuner().getTunerController().isLocked());
+ getFrequencyCorrectionSpinner().setEnabled(hasTuner());
+ getAutoPPMCheckBox().setEnabled(hasTuner());
+
+ Tuner tuner = getTuner();
+
+ if(tuner != null)
+ {
+ getFrequencyControl().setFrequency(tuner.getTunerController().getFrequency(), false);
+ getFrequencyCorrectionSpinner().setValue(tuner.getTunerController().getFrequencyCorrection());
+ getAutoPPMCheckBox().setSelected(tuner.getTunerController().getFrequencyErrorCorrectionManager().isEnabled());
+ getFrequencyControl().addListener(getTuner().getTunerController());
+ getTuner().getTunerController().addListener(getFrequencyControl());
+ getMeasuredPPMLabel().setText(tuner.getTunerController().getMeasuredErrorStatus());
+ }
+ else
+ {
+ getFrequencyControl().setFrequency(0, false);
+ getFrequencyCorrectionSpinner().setValue(0);
+ getAutoPPMCheckBox().setSelected(false);
+ getMeasuredPPMLabel().setText("");
+ }
+ }
+
+ /**
+ * Updates the measured frequency error label
+ */
+ public void updateFrequencyError()
+ {
+ SwingUtils.run(() ->
+ {
+ if(hasTuner())
+ {
+ getMeasuredPPMLabel().setText(getTuner().getTunerController().getMeasuredErrorStatus());
+ }
+ else
+ {
+ getMeasuredPPMLabel().setText("");
+ }
+ });
+ }
+ }
+
+ /**
+ * Implements status listener to receive updates for wide-band recordings
+ */
+ public class RecordingStatusListener implements IRecordingStatusListener
+ {
+ private DecimalFormat mSizeFormat = new DecimalFormat("0.0");
+
+ @Override
+ public void update(int fileCount, String file, long size)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Recording Size: ").append(humanReadableByteCount(size));
+ sb.append(" File #").append(fileCount).append(": ").append(file);
+ final String status = sb.toString();
+ EventQueue.invokeLater(() -> getRecordingStatusLabel().setText(status));
+ }
+
+ public static String humanReadableByteCount(long bytes) {
+ long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
+ if (absB < 1024) {
+ return bytes + " B";
+ }
+ long value = absB;
+ CharacterIterator ci = new StringCharacterIterator("KMGTPE");
+ for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) {
+ value >>= 10;
+ ci.next();
+ }
+ value *= Long.signum(bytes);
+ return String.format("%.1f %cB", value / 1024.0, ci.current());
+ }
+ }
+
+ /**
+ * Monitors the frequency correction spinner for changed value.
+ */
+ private class FrequencyAndCorrectionChangeListener implements ChangeListener, ISourceEventProcessor
+ {
+ //This monitors the frequency correction spinner, applies the changes to the tuner, and saves configuration.
+ @Override
+ public void stateChanged(ChangeEvent e)
+ {
+ final double value = ((SpinnerNumberModel) getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue();
+
+ if(hasTuner() && !isLoading())
+ {
+ try
+ {
+ getTuner().getTunerController().setFrequencyCorrection(value);
+ }
+ catch(SourceException e1)
+ {
+ mLog.error("Error setting frequency correction value", e1);
+ }
+
+ save();
+ }
+ }
+
+ //This monitors the frequency control and saves configuration.
+ @Override
+ public void process(SourceEvent event) throws SourceException
+ {
+ if(hasTuner() && !isLoading())
+ {
+ save();
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/ui/TunerSpectralDisplayManager.java b/src/main/java/io/github/dsheirer/source/tuner/ui/TunerSpectralDisplayManager.java
new file mode 100644
index 00000000..b90b373c
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/source/tuner/ui/TunerSpectralDisplayManager.java
@@ -0,0 +1,102 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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.source.tuner.ui;
+
+import io.github.dsheirer.playlist.PlaylistManager;
+import io.github.dsheirer.sample.Listener;
+import io.github.dsheirer.settings.SettingsManager;
+import io.github.dsheirer.source.tuner.Tuner;
+import io.github.dsheirer.source.tuner.TunerEvent;
+import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
+import io.github.dsheirer.spectrum.SpectralDisplayPanel;
+import io.github.dsheirer.spectrum.SpectrumFrame;
+import io.github.dsheirer.util.SwingUtils;
+import io.github.dsheirer.util.ThreadPool;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public class TunerSpectralDisplayManager implements Listener
+{
+ private SpectralDisplayPanel mSpectralDisplayPanel;
+ private PlaylistManager mPlaylistManager;
+ private SettingsManager mSettingsManager;
+ private DiscoveredTunerModel mDiscoveredTunerModel;
+
+ public TunerSpectralDisplayManager(SpectralDisplayPanel panel, PlaylistManager playlistManager,
+ SettingsManager settingsManager, DiscoveredTunerModel discoveredTunerModel)
+ {
+ mSpectralDisplayPanel = panel;
+ mPlaylistManager = playlistManager;
+ mSettingsManager = settingsManager;
+ mDiscoveredTunerModel = discoveredTunerModel;
+ }
+
+ /**
+ * Shows the first available tuner from the discovered tuner model
+ */
+ public Tuner showFirstTuner()
+ {
+ List availableTuners = mDiscoveredTunerModel.getAvailableTuners();
+
+ for(DiscoveredTuner discoveredTuner: availableTuners)
+ {
+ if(discoveredTuner.hasTuner())
+ {
+ mSpectralDisplayPanel.showTuner(discoveredTuner.getTuner());
+ return discoveredTuner.getTuner();
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public void receive(TunerEvent event)
+ {
+ switch(event.getEvent())
+ {
+ case REQUEST_CLEAR_MAIN_SPECTRAL_DISPLAY:
+ SwingUtils.run(() -> mSpectralDisplayPanel.clearTuner());
+ break;
+ case REQUEST_MAIN_SPECTRAL_DISPLAY:
+ SwingUtils.run(() -> mSpectralDisplayPanel.showTuner(event.getTuner()));
+ break;
+ case REQUEST_NEW_SPECTRAL_DISPLAY:
+ final SpectrumFrame frame = new SpectrumFrame(mPlaylistManager, mSettingsManager, mDiscoveredTunerModel, event.getTuner());
+ SwingUtils.run(() -> frame.setVisible(true));
+ break;
+ case NOTIFICATION_ERROR_STATE:
+ case NOTIFICATION_SHUTTING_DOWN:
+ if(event.getTuner().equals(mSpectralDisplayPanel.getTuner()))
+ {
+ SwingUtils.run(() ->
+ {
+ mSpectralDisplayPanel.clearTuner();
+ ThreadPool.SCHEDULED.schedule(() -> SwingUtils.run(() ->
+ {
+ showFirstTuner();
+ }), 1, TimeUnit.SECONDS);
+ });
+ }
+ default:
+ break;
+ }
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/ui/TunerViewPanel.java b/src/main/java/io/github/dsheirer/source/tuner/ui/TunerViewPanel.java
new file mode 100644
index 00000000..9242b968
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/source/tuner/ui/TunerViewPanel.java
@@ -0,0 +1,210 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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.source.tuner.ui;
+
+import com.jidesoft.swing.JideSplitPane;
+import io.github.dsheirer.preference.UserPreferences;
+import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
+import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
+import io.github.dsheirer.source.tuner.manager.TunerManager;
+import io.github.dsheirer.source.tuner.manager.TunerStatus;
+import net.miginfocom.swing.MigLayout;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.RowSorter;
+import javax.swing.SortOrder;
+import javax.swing.event.TableModelEvent;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableRowSorter;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Panel containing a discovered tuners table and a tuner editor for a selected tuner.
+ */
+public class TunerViewPanel extends JPanel
+{
+ private static final long serialVersionUID = 1L;
+ private final static Logger mLog = LoggerFactory.getLogger(TunerViewPanel.class);
+ private static final String TABLE_PREFERENCE_KEY = "tuner.view.panel";
+
+ private DiscoveredTunerModel mDiscoveredTunerModel;
+ private JTable mTunerTable;
+ private JTableColumnWidthMonitor mColumnWidthMonitor;
+ private TableRowSorter mRowSorter;
+ private JideSplitPane mSplitPane;
+ private DiscoveredTunerEditor mDiscoveredTunerEditor;
+ private UserPreferences mUserPreferences;
+
+ /**
+ * Constructs an instance
+ * @param tunerManager for tuners
+ * @param userPreferences for making recordings in the tuner editor
+ */
+ public TunerViewPanel(TunerManager tunerManager, UserPreferences userPreferences)
+ {
+ mDiscoveredTunerModel = tunerManager.getDiscoveredTunerModel();
+ mDiscoveredTunerEditor = new DiscoveredTunerEditor(userPreferences, tunerManager);
+ mUserPreferences = userPreferences;
+ init();
+ }
+
+ private void init()
+ {
+ setLayout(new MigLayout("insets 0 0 0 0", "[fill,grow]", "[fill,grow]"));
+
+ mRowSorter = new TableRowSorter<>(mDiscoveredTunerModel);
+ List sortKeys = new ArrayList<>();
+ sortKeys.add(new RowSorter.SortKey(DiscoveredTunerModel.COLUMN_TUNER_TYPE, SortOrder.ASCENDING));
+ mRowSorter.setSortKeys(sortKeys);
+
+ mTunerTable = new JTable(mDiscoveredTunerModel);
+ mTunerTable.setRowSorter(mRowSorter);
+ mTunerTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ mTunerTable.getSelectionModel().addListSelectionListener(event ->
+ {
+ if(!event.getValueIsAdjusting())
+ {
+ int row = mTunerTable.getSelectedRow();
+
+ if(row >= 0)
+ {
+ int modelRow = mTunerTable.convertRowIndexToModel(row);
+ mDiscoveredTunerEditor.setItem(mDiscoveredTunerModel.getDiscoveredTuner(modelRow));
+ }
+ }
+ });
+
+ //Monitor for tuner removal events so we can update the editor when our selected tuner is removed
+ mDiscoveredTunerModel.addTableModelListener(e ->
+ {
+ //Detect when status is for the currently selected tuner
+ if(e.getType() == TableModelEvent.DELETE &&
+ mDiscoveredTunerEditor.hasItem() &&
+ !mDiscoveredTunerModel.hasTuner(mDiscoveredTunerEditor.getItem()))
+ {
+ mDiscoveredTunerEditor.setItem(null);
+ }
+ });
+
+ mDiscoveredTunerModel.addListener(tunerEvent ->
+ {
+ switch(tunerEvent.getEvent())
+ {
+ case UPDATE_LOCK_STATE:
+ if(tunerEvent.getTuner() != null)
+ {
+ int row = mTunerTable.getSelectedRow();
+
+ if(row >= 0)
+ {
+ int modelRow = mTunerTable.convertRowIndexToModel(row);
+ DiscoveredTuner selectedTuner = mDiscoveredTunerModel.getDiscoveredTuner(modelRow);
+
+ if(selectedTuner != null && selectedTuner.hasTuner() && tunerEvent.getTuner() == selectedTuner.getTuner())
+ {
+ mDiscoveredTunerEditor.setTunerLockState(selectedTuner.getTuner().getTunerController().isLocked());
+ }
+ }
+ }
+ break;
+ }
+ });
+
+
+ TableCellRenderer errorCellRenderer = new TunerStatusCellRenderer();
+ mTunerTable.getColumnModel().getColumn(DiscoveredTunerModel.COLUMN_TUNER_STATUS).setCellRenderer(errorCellRenderer);
+
+ mColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mTunerTable, TABLE_PREFERENCE_KEY);
+ JScrollPane tunerTableScroller = new JScrollPane(mTunerTable);
+
+ JPanel tunerTablePanel = new JPanel();
+ tunerTablePanel.setLayout(new MigLayout("insets 0 0 0 0", "[fill,grow][]", "[fill,grow][]"));
+ tunerTablePanel.add(tunerTableScroller, "span");
+
+ tunerTablePanel.add(new JLabel("")); //Empty spacer
+
+// JButton addRecordingTunerButton = new JButton("Add Recording Tuner");
+// addRecordingTunerButton.addActionListener(e ->
+// {
+// AddRecordingTunerDialog dialog = new AddRecordingTunerDialog(mUserPreferences, mDiscoveredTunerModel);
+// dialog.setLocationRelativeTo(TunerViewPanel.this);
+// EventQueue.invokeLater(() -> dialog.setVisible(true));
+// });
+//
+// tunerTablePanel.add(addRecordingTunerButton);
+
+ tunerTablePanel.setPreferredSize(new Dimension(200,200));
+ JScrollPane editorScroller = new JScrollPane(mDiscoveredTunerEditor);
+ editorScroller.setPreferredSize(new Dimension(200, 200));
+
+ mSplitPane = new JideSplitPane();
+ mSplitPane.setOrientation(JideSplitPane.HORIZONTAL_SPLIT);
+ mSplitPane.add(tunerTablePanel);
+ mSplitPane.add(editorScroller);
+
+ add(mSplitPane);
+ }
+
+ /**
+ * Custom cell renderer for the TunerStatus enumeration column
+ */
+ public class TunerStatusCellRenderer extends DefaultTableCellRenderer
+ {
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
+ int row, int column)
+ {
+ Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+
+ if(value instanceof TunerStatus tunerStatus)
+ {
+ if(tunerStatus == TunerStatus.ERROR)
+ {
+ component.setForeground(Color.RED);
+ }
+ else if(tunerStatus == TunerStatus.DISABLED)
+ {
+ component.setForeground(Color.DARK_GRAY);
+ }
+ else
+ {
+ component.setForeground(table.getForeground());
+ }
+ }
+ else
+ {
+ component.setForeground(table.getForeground());
+ }
+
+ return component;
+ }
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/usb/USBMasterProcessor.java b/src/main/java/io/github/dsheirer/source/tuner/usb/USBMasterProcessor.java
deleted file mode 100644
index 067e15d4..00000000
--- a/src/main/java/io/github/dsheirer/source/tuner/usb/USBMasterProcessor.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.source.tuner.usb;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.usb4java.LibUsb;
-
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Scheduled runnable for the primary LibUsb processing thread. Each USB device's transfer processor
- * registers with this processor to support auto-start/stop of this event processing thread.
- */
-public class USBMasterProcessor
-{
- private final static Logger mLog = LoggerFactory.getLogger(USBMasterProcessor.class);
-
- private static final long USB_TIMEOUT_MS = 2000l; //milliseconds
-
- private List mRegisteredProcessors = new CopyOnWriteArrayList<>();
- private AtomicBoolean mRunning = new AtomicBoolean();
- private Processor mProcessor = new Processor();
- private Thread mProcessorThread;
-
- /**
- * Registers the transfer processor so that LibUSB timeout processing will auto-start.
- * @param processor to register
- */
- public void registerTransferProcessor(USBTransferProcessor processor)
- {
- if(!mRegisteredProcessors.contains(processor))
- {
- mRegisteredProcessors.add(processor);
- }
-
- start();
- }
-
- /**
- * Unregisters the transfer processor so that LibUSB timeout processing will auto-stop once all processors have
- * been unregistered.
- *
- * @param processor to unregister
- */
- public void unregisterTransferProcessor(USBTransferProcessor processor)
- {
- mRegisteredProcessors.remove(processor);
-
- if(mRegisteredProcessors.isEmpty())
- {
- stop();
- }
- }
-
- /**
- * Starts processing of LibUSB timeout events
- */
- private void start()
- {
- if(mRunning.compareAndSet(false, true))
- {
- mLog.info("Starting USB master processor thread");
- if(mProcessorThread == null)
- {
- mProcessor.reset();
- mProcessorThread = new Thread(mProcessor);
- mProcessorThread.setName("sdrtrunk USB event processor");
- mProcessorThread.setPriority(Thread.MAX_PRIORITY);
- mProcessorThread.start();
- }
- }
- }
-
- /**
- * Stops processing of LibUSB timeout events
- */
- private void stop()
- {
- if(mRunning.compareAndSet(true, false))
- {
- mLog.info("Stopping USB master processor thread");
- if(mProcessorThread != null)
- {
- mProcessor.stop();
- mProcessorThread.interrupt();
-
- try
- {
- mProcessorThread.join(1000);
- }
- catch(InterruptedException ie)
- {
- //No action
- }
-
- mProcessorThread = null;
- }
- }
- }
-
- /**
- * Stops the libusb timeout processor and prepares for shutdown.
- */
- public void shutdown()
- {
- stop();
- }
-
- /**
- * Runnable to invoke LibUSB timeout handler. All downstream completed transfer processing will occur on this
- * thread instance.
- */
- class Processor implements Runnable
- {
- private boolean mRunning = true;
-
- /**
- * Sets stop flag to signal to stop processing
- */
- public void stop()
- {
- mRunning = false;
- }
-
- /**
- * Resets this processor so that it can be reused.
- */
- public void reset()
- {
- mRunning = true;
- }
-
- @Override
- public void run()
- {
- while(mRunning)
- {
- try
- {
- LibUsb.handleEvents(null);
- }
- catch(Throwable throwable)
- {
- mLog.error("Error while processing LibUSB timeout events", throwable);
- }
- }
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/usb/USBTransferProcessor.java b/src/main/java/io/github/dsheirer/source/tuner/usb/USBTransferProcessor.java
deleted file mode 100644
index 972ab226..00000000
--- a/src/main/java/io/github/dsheirer/source/tuner/usb/USBTransferProcessor.java
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * *****************************************************************************
- * Copyright (C) 2014-2022 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.source.tuner.usb;
-
-import io.github.dsheirer.buffer.INativeBuffer;
-import io.github.dsheirer.buffer.INativeBufferFactory;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.source.tuner.ITunerErrorListener;
-import io.github.dsheirer.source.tuner.TunerManager;
-import io.github.dsheirer.util.ThreadPool;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.usb4java.DeviceHandle;
-import org.usb4java.LibUsb;
-import org.usb4java.LibUsbException;
-import org.usb4java.Transfer;
-import org.usb4java.TransferCallback;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.LinkedTransferQueue;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class USBTransferProcessor implements TransferCallback
-{
- private final static Logger mLog = LoggerFactory.getLogger(USBTransferProcessor.class);
-
- private static final byte USB_BULK_TRANSFER_ENDPOINT = (byte) 0x81;
- private static final long USB_TIMEOUT_MS = 2000l; //milliseconds
-
- //Number of native byte buffers to allocate for transferring data from the USB device
- private static final int TRANSFER_BUFFER_POOL_SIZE = 40;
-
- private LinkedTransferQueue mAvailableTransfers = new LinkedTransferQueue<>();
- private LinkedTransferQueue mInProgressTransfers = new LinkedTransferQueue<>();
- private LinkedTransferQueue