mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-09 15:17:24 -05:00
#2600 LimeSDR support
This commit is contained in:
@@ -129,6 +129,7 @@ dependencies {
|
||||
implementation 'io.github.dsheirer:jbladerf:2.6.0' //bladeRF tuners - GitHub release, see settings.gradle
|
||||
implementation 'io.github.dsheirer:jhackrf:2026.01.3' //HackRF tuners - GitHub release, see settings.gradle
|
||||
implementation 'io.github.dsheirer:jhydrasdr:1.1.4' //HydraSDR tuners - GitHub release, see settings.gradle
|
||||
implementation 'io.github.dsheirer:jlimesdr:25.1.0.1' //LimeSDR tuners - GitHub release, see settings.gradle
|
||||
implementation 'io.github.dsheirer:jrtl:1.4.0.1' //RTL-SDR tuners - GitHub release, see settings.gradle
|
||||
implementation 'io.github.dsheirer:jsdrplay:3.15.3' //SDRplay RSP tuners - GitHub release, see settings.gradle
|
||||
implementation 'io.github.dsheirer:radio-reference-api:18.0.0'
|
||||
|
||||
@@ -49,6 +49,14 @@ dependencyResolutionManagement {
|
||||
content { includeModule 'io.github.dsheirer', 'jhydrasdr' }
|
||||
}
|
||||
|
||||
//jLimeSDR is published as a GitHub release, with the native libraries for all platforms in the jar
|
||||
ivy {
|
||||
url = 'https://github.com/DSheirer/jLimeSDR/releases/download'
|
||||
patternLayout { artifact 'v[revision]/[artifact]-[revision].[ext]' }
|
||||
metadataSources { artifact() }
|
||||
content { includeModule 'io.github.dsheirer', 'jlimesdr' }
|
||||
}
|
||||
|
||||
//jsdrplay is published as a GitHub release. The jar does not contain the SDRplay API native library, which
|
||||
//users install separately from sdrplay.com
|
||||
ivy {
|
||||
|
||||
@@ -32,6 +32,7 @@ public enum TunerClass
|
||||
FUNCUBE_DONGLE_PRO_PLUS("Funcube Dongle Pro+" ),
|
||||
HACKRF("HackRF" ),
|
||||
HYDRASDR("HydraSDR"),
|
||||
LIMESDR("LimeSDR"),
|
||||
RTL2832("RTL-2832"),
|
||||
RSP("RSP"),
|
||||
TEST_TUNER("Test"),
|
||||
@@ -56,7 +57,7 @@ public enum TunerClass
|
||||
}
|
||||
|
||||
public static final EnumSet<TunerClass> SUPPORTED_USB_TUNERS = EnumSet.of(AIRSPY, AIRSPY_HF, BLADERF, HACKRF,
|
||||
HYDRASDR, RTL2832, FUNCUBE_DONGLE_PRO, FUNCUBE_DONGLE_PRO_PLUS);
|
||||
HYDRASDR, LIMESDR, RTL2832, FUNCUBE_DONGLE_PRO, FUNCUBE_DONGLE_PRO_PLUS);
|
||||
|
||||
public static final EnumSet<TunerClass> FUNCUBE_TUNERS = EnumSet.of(FUNCUBE_DONGLE_PRO, FUNCUBE_DONGLE_PRO_PLUS);
|
||||
|
||||
@@ -146,6 +147,9 @@ public enum TunerClass
|
||||
return BLADERF;
|
||||
case 0x38AF0001: //HYDRASDR RFONE (official VID 38af, PID 0001)
|
||||
return HYDRASDR;
|
||||
case 0x1D506108: //LIMESDR-USB
|
||||
case 0x0403601F: //LIMESDR MINI (FTDI FT601)
|
||||
return LIMESDR;
|
||||
case 0x1D5060A1:
|
||||
return AIRSPY;
|
||||
case 0x03EB800C:
|
||||
|
||||
@@ -54,6 +54,10 @@ import io.github.dsheirer.source.tuner.hydrasdr.HydraSdrTuner;
|
||||
import io.github.dsheirer.source.tuner.hydrasdr.HydraSdrTunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.hydrasdr.HydraSdrTunerController;
|
||||
import io.github.dsheirer.source.tuner.hydrasdr.HydraSdrTunerEditor;
|
||||
import io.github.dsheirer.source.tuner.limesdr.LimeSdrTuner;
|
||||
import io.github.dsheirer.source.tuner.limesdr.LimeSdrTunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.limesdr.LimeSdrTunerController;
|
||||
import io.github.dsheirer.source.tuner.limesdr.LimeSdrTunerEditor;
|
||||
import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
|
||||
import io.github.dsheirer.source.tuner.manager.TunerManager;
|
||||
import io.github.dsheirer.source.tuner.recording.RecordingTunerConfiguration;
|
||||
@@ -313,6 +317,8 @@ public class TunerFactory
|
||||
return new HackRFTuner(new HackRFTunerController(bus, portAddress, tunerErrorListener), tunerErrorListener, channelizerType);
|
||||
case HYDRASDR:
|
||||
return new HydraSdrTuner(new HydraSdrTunerController(bus, portAddress, tunerErrorListener), tunerErrorListener, channelizerType);
|
||||
case LIMESDR:
|
||||
return new LimeSdrTuner(new LimeSdrTunerController(bus, portAddress, tunerErrorListener), tunerErrorListener, channelizerType);
|
||||
case RTL2832:
|
||||
return new RTL2832Tuner(new RTL2832TunerController(bus, portAddress, tunerErrorListener), tunerErrorListener, channelizerType);
|
||||
default:
|
||||
@@ -352,6 +358,8 @@ public class TunerFactory
|
||||
return new HackRFTunerConfiguration(uniqueID);
|
||||
case HYDRASDR_R828D:
|
||||
return new HydraSdrTunerConfiguration(uniqueID);
|
||||
case LIMESDR:
|
||||
return new LimeSdrTunerConfiguration(uniqueID);
|
||||
case RAFAELMICRO_R820T:
|
||||
return new R820TTunerConfiguration(uniqueID);
|
||||
case RAFAELMICRO_R828D:
|
||||
@@ -399,6 +407,8 @@ public class TunerFactory
|
||||
return new HackRFTunerEditor(userPreferences, tunerManager, discoveredTuner);
|
||||
case HYDRASDR:
|
||||
return new HydraSdrTunerEditor(userPreferences, tunerManager, discoveredTuner);
|
||||
case LIMESDR:
|
||||
return new LimeSdrTunerEditor(userPreferences, tunerManager, discoveredTuner);
|
||||
case RSP:
|
||||
if(discoveredTuner instanceof DiscoveredRspTuner discoveredRspTuner)
|
||||
{
|
||||
|
||||
@@ -39,6 +39,7 @@ public enum TunerType
|
||||
HACKRF_JAWBREAKER("Jawbreaker"),
|
||||
HACKRF_RAD1O("RAD1O"),
|
||||
HYDRASDR_R828D("R828D"),
|
||||
LIMESDR("LimeSDR"),
|
||||
RAFAELMICRO_R820T("R820T"),
|
||||
RAFAELMICRO_R828D("R828D"),
|
||||
RSP_1("RSP1"),
|
||||
@@ -76,7 +77,7 @@ public enum TunerType
|
||||
* Supported USB tuner types
|
||||
*/
|
||||
public static final EnumSet<TunerType> SUPPORTED_USB_TUNERS = EnumSet.of(AIRSPY_R820T, BLADERF, ELONICS_E4000, FITIPOWER_FC0012,
|
||||
HACKRF_JAWBREAKER, HACKRF_RAD1O, HACKRF_ONE, HACKRF_PRO, HYDRASDR_R828D, RAFAELMICRO_R820T);
|
||||
HACKRF_JAWBREAKER, HACKRF_RAD1O, HACKRF_ONE, HACKRF_PRO, HYDRASDR_R828D, LIMESDR, RAFAELMICRO_R820T);
|
||||
|
||||
/**
|
||||
* Supported sound card tuner types
|
||||
|
||||
@@ -31,6 +31,7 @@ import io.github.dsheirer.source.tuner.fcd.proV1.FCD1TunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.fcd.proplusV2.FCD2TunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.hackrf.HackRFTunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.hydrasdr.HydraSdrTunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.limesdr.LimeSdrTunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.recording.RecordingTunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerConfiguration;
|
||||
import io.github.dsheirer.source.tuner.rtl.fc0012.FC0012TunerConfiguration;
|
||||
@@ -56,6 +57,7 @@ import io.github.dsheirer.source.tuner.sdrplay.RspTunerConfiguration;
|
||||
@JsonSubTypes.Type(value = FCD2TunerConfiguration.class, name = "fcd2TunerConfiguration"),
|
||||
@JsonSubTypes.Type(value = HackRFTunerConfiguration.class, name = "hackRFTunerConfiguration"),
|
||||
@JsonSubTypes.Type(value = HydraSdrTunerConfiguration.class, name = "hydraSdrTunerConfiguration"),
|
||||
@JsonSubTypes.Type(value = LimeSdrTunerConfiguration.class, name = "limeSdrTunerConfiguration"),
|
||||
@JsonSubTypes.Type(value = RecordingTunerConfiguration.class, name = "recordingTunerConfiguration"),
|
||||
@JsonSubTypes.Type(value = R820TTunerConfiguration.class, name = "r820TTunerConfiguration"),
|
||||
@JsonSubTypes.Type(value = R828DTunerConfiguration.class, name = "r828DTunerConfiguration"),
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2026 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.source.tuner.limesdr;
|
||||
|
||||
/**
|
||||
* LimeSDR device details for display.
|
||||
* @param serial board serial number, 16 hex digits
|
||||
* @param board name, such as LimeSDR-USB or LimeSDR-Mini
|
||||
* @param firmware version
|
||||
* @param hardware version
|
||||
* @param gateware (FPGA) version
|
||||
* @param connection USB link, such as USB3.0
|
||||
* @param library version of LimeSuiteNG
|
||||
*/
|
||||
public record LimeSdrDeviceInformation(String serial, String board, String firmware, String hardware, String gateware,
|
||||
String connection, String library)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2026 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.source.tuner.limesdr;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* LimeSDR sample rates offered to the user. The LMS7002M supports any rate in its range, so these are rates that divide
|
||||
* evenly into polyphase channelizer channels.
|
||||
*/
|
||||
public enum LimeSdrSampleRate
|
||||
{
|
||||
RATE_1_25(1_250_000, "1.25 MHz"),
|
||||
RATE_2_5(2_500_000, "2.50 MHz"),
|
||||
RATE_5_0(5_000_000, "5.00 MHz"),
|
||||
RATE_7_5(7_500_000, "7.50 MHz"),
|
||||
RATE_10_0(10_000_000, "10.00 MHz"),
|
||||
RATE_12_5(12_500_000, "12.50 MHz"),
|
||||
RATE_15_0(15_000_000, "15.00 MHz"),
|
||||
RATE_20_0(20_000_000, "20.00 MHz"),
|
||||
RATE_25_0(25_000_000, "25.00 MHz"),
|
||||
RATE_30_0(30_000_000, "30.00 MHz"),
|
||||
RATE_30_72(30_720_000, "30.72 MHz"),
|
||||
RATE_40_0(40_000_000, "40.00 MHz"),
|
||||
RATE_50_0(50_000_000, "50.00 MHz"),
|
||||
RATE_60_0(60_000_000, "60.00 MHz"),
|
||||
RATE_61_44(61_440_000, "61.44 MHz");
|
||||
|
||||
public static final LimeSdrSampleRate DEFAULT = RATE_10_0;
|
||||
private final int mRate;
|
||||
private final String mLabel;
|
||||
|
||||
LimeSdrSampleRate(int rate, String label)
|
||||
{
|
||||
mRate = rate;
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample rate in Hertz
|
||||
*/
|
||||
public int getRate()
|
||||
{
|
||||
return mRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample rates within the device range, which is the lower of what the board and its USB connection support.
|
||||
* @param minimumRate in Hertz
|
||||
* @param maximumRate in Hertz
|
||||
* @return rates, lowest to highest
|
||||
*/
|
||||
public static List<LimeSdrSampleRate> getRates(double minimumRate, double maximumRate)
|
||||
{
|
||||
List<LimeSdrSampleRate> rates = new ArrayList<>();
|
||||
|
||||
for(LimeSdrSampleRate rate : values())
|
||||
{
|
||||
if(rate.getRate() >= minimumRate && rate.getRate() <= maximumRate)
|
||||
{
|
||||
rates.add(rate);
|
||||
}
|
||||
}
|
||||
|
||||
return rates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the highest rate from the list that doesn't exceed the requested rate.
|
||||
* @param rates to search, lowest to highest
|
||||
* @param requested rate in Hertz
|
||||
* @return closest rate, or the lowest rate when the requested rate is below all of them.
|
||||
*/
|
||||
public static LimeSdrSampleRate getClosest(List<LimeSdrSampleRate> rates, int requested)
|
||||
{
|
||||
LimeSdrSampleRate closest = rates.getFirst();
|
||||
|
||||
for(LimeSdrSampleRate rate : rates)
|
||||
{
|
||||
if(rate.getRate() <= requested)
|
||||
{
|
||||
closest = rate;
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2026 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.source.tuner.limesdr;
|
||||
|
||||
import io.github.dsheirer.preference.source.ChannelizerType;
|
||||
import io.github.dsheirer.source.tuner.ITunerErrorListener;
|
||||
import io.github.dsheirer.source.tuner.Tuner;
|
||||
import io.github.dsheirer.source.tuner.TunerClass;
|
||||
|
||||
/**
|
||||
* LimeSDR tuner
|
||||
*/
|
||||
public class LimeSdrTuner extends Tuner
|
||||
{
|
||||
//The USB link carries 12-bit I and Q samples, packed into 3 bytes
|
||||
private static final int LINK_BITS_PER_SAMPLE = 24;
|
||||
private static final double SAMPLE_SIZE_12_BIT = 12.0;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param controller for the LimeSDR
|
||||
* @param tunerErrorListener to listen for errors from this tuner
|
||||
* @param channelizerType for the channelizer
|
||||
*/
|
||||
public LimeSdrTuner(LimeSdrTunerController controller, ITunerErrorListener tunerErrorListener,
|
||||
ChannelizerType channelizerType)
|
||||
{
|
||||
super(controller, tunerErrorListener, channelizerType);
|
||||
}
|
||||
|
||||
/**
|
||||
* LimeSDR tuner controller
|
||||
*/
|
||||
public LimeSdrTunerController getController()
|
||||
{
|
||||
return (LimeSdrTunerController)getTunerController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferredName()
|
||||
{
|
||||
LimeSdrDeviceInformation info = getController().getDeviceInfo();
|
||||
return (info != null ? info.board() : "LimeSDR") + " " + getUniqueID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueID()
|
||||
{
|
||||
return getController().getDeviceInfo().serial();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TunerClass getTunerClass()
|
||||
{
|
||||
return TunerClass.LIMESDR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSampleSize()
|
||||
{
|
||||
return SAMPLE_SIZE_12_BIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaximumUSBBitsPerSecond()
|
||||
{
|
||||
return LimeSdrSampleRate.RATE_61_44.getRate() * LINK_BITS_PER_SAMPLE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2026 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.source.tuner.limesdr;
|
||||
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
|
||||
/**
|
||||
* LimeSDR tuner configuration
|
||||
*/
|
||||
public class LimeSdrTunerConfiguration extends TunerConfiguration
|
||||
{
|
||||
private int mSampleRate = LimeSdrSampleRate.DEFAULT.getRate();
|
||||
private int mGain = LimeSdrTunerController.GAIN_DEFAULT;
|
||||
private String mAntenna = LimeSdrTunerController.ANTENNA_DEFAULT;
|
||||
|
||||
/**
|
||||
* Default constructor for Jackson
|
||||
*/
|
||||
public LimeSdrTunerConfiguration()
|
||||
{
|
||||
super(LimeSdrTunerController.MINIMUM_TUNABLE_FREQUENCY_HZ, LimeSdrTunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param uniqueID for the tuner
|
||||
*/
|
||||
public LimeSdrTunerConfiguration(String uniqueID)
|
||||
{
|
||||
super(uniqueID);
|
||||
}
|
||||
|
||||
@Override
|
||||
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
||||
public TunerType getTunerType()
|
||||
{
|
||||
return TunerType.LIMESDR;
|
||||
}
|
||||
|
||||
@JacksonXmlProperty(isAttribute = true, localName = "sample_rate")
|
||||
public int getSampleRate()
|
||||
{
|
||||
return mSampleRate;
|
||||
}
|
||||
|
||||
public void setSampleRate(int sampleRate)
|
||||
{
|
||||
mSampleRate = sampleRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combined receive gain in dB, 0 to 73.
|
||||
*/
|
||||
@JacksonXmlProperty(isAttribute = true, localName = "gain")
|
||||
public int getGain()
|
||||
{
|
||||
return mGain;
|
||||
}
|
||||
|
||||
public void setGain(int gain)
|
||||
{
|
||||
mGain = gain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive antenna port name, such as LNAW.
|
||||
*/
|
||||
@JacksonXmlProperty(isAttribute = true, localName = "antenna")
|
||||
public String getAntenna()
|
||||
{
|
||||
return mAntenna;
|
||||
}
|
||||
|
||||
public void setAntenna(String antenna)
|
||||
{
|
||||
mAntenna = antenna;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2026 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.source.tuner.limesdr;
|
||||
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
|
||||
import io.github.dsheirer.source.tuner.manager.TunerManager;
|
||||
import io.github.dsheirer.source.tuner.manager.TunerStatus;
|
||||
import io.github.dsheirer.source.tuner.ui.TunerEditor;
|
||||
import java.io.Serial;
|
||||
import java.util.List;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
|
||||
/**
|
||||
* LimeSDR tuner editor
|
||||
*/
|
||||
public class LimeSdrTunerEditor extends TunerEditor<LimeSdrTuner, LimeSdrTunerConfiguration>
|
||||
{
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger mLog = LoggerFactory.getLogger(LimeSdrTunerEditor.class);
|
||||
private JButton mTunerInfoButton;
|
||||
private JComboBox<LimeSdrSampleRate> mSampleRateCombo;
|
||||
private JComboBox<String> mAntennaCombo;
|
||||
private JSlider mGainSlider;
|
||||
private JLabel mGainValueLabel;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param userPreferences for wide-band recordings
|
||||
* @param tunerManager for saving tuner configuration
|
||||
* @param discoveredTuner for the optionally usable LimeSDR tuner and controller
|
||||
*/
|
||||
public LimeSdrTunerEditor(UserPreferences userPreferences, TunerManager tunerManager, DiscoveredTuner discoveredTuner)
|
||||
{
|
||||
super(userPreferences, tunerManager, discoveredTuner);
|
||||
init();
|
||||
tunerStatusUpdated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMinimumTunableFrequency()
|
||||
{
|
||||
return hasTuner() ? getTuner().getController().getMinimumTunableFrequency() :
|
||||
LimeSdrTunerController.MINIMUM_TUNABLE_FREQUENCY_HZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaximumTunableFrequency()
|
||||
{
|
||||
return hasTuner() ? getTuner().getController().getMaximumTunableFrequency() :
|
||||
LimeSdrTunerController.MAXIMUM_TUNABLE_FREQUENCY_HZ;
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout(new MigLayout("fill,wrap 3", "[right][grow,fill][fill]", "[][][][][][][][][][][grow]"));
|
||||
|
||||
add(new JLabel("Tuner:"));
|
||||
add(getTunerIdLabel());
|
||||
add(getTunerInfoButton());
|
||||
|
||||
add(new JLabel("Status:"));
|
||||
add(getTunerStatusLabel(), "wrap");
|
||||
|
||||
add(getButtonPanel(), "span,align left");
|
||||
|
||||
add(new JSeparator(), "span,growx");
|
||||
|
||||
add(new JLabel("Frequency (MHz):"));
|
||||
add(getFrequencyPanel(), "wrap");
|
||||
|
||||
add(new JLabel("Sample Rate:"));
|
||||
add(getSampleRateCombo(), "wrap");
|
||||
|
||||
add(new JLabel("Antenna:"));
|
||||
add(getAntennaCombo(), "wrap");
|
||||
|
||||
add(new JSeparator(), "span,growx");
|
||||
|
||||
add(new JLabel("Gain:"));
|
||||
add(getGainSlider());
|
||||
add(getGainValueLabel());
|
||||
|
||||
//Empty row that takes all extra vertical space so that the controls stay stacked at the top of the editor.
|
||||
add(new JLabel(), "span,pushy");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tunerStatusUpdated()
|
||||
{
|
||||
setLoading(true);
|
||||
|
||||
boolean started = hasStartedTuner();
|
||||
getTunerIdLabel().setText(started ? getTuner().getPreferredName() : getDiscoveredTuner().getId());
|
||||
|
||||
String status = getDiscoveredTuner().getTunerStatus().toString();
|
||||
if(getDiscoveredTuner().hasErrorMessage())
|
||||
{
|
||||
status += " - " + getDiscoveredTuner().getErrorMessage();
|
||||
}
|
||||
getTunerStatusLabel().setText(status);
|
||||
getButtonPanel().updateControls();
|
||||
getFrequencyPanel().updateControls();
|
||||
getTunerInfoButton().setEnabled(started);
|
||||
|
||||
if(started)
|
||||
{
|
||||
LimeSdrTunerController controller = getTuner().getController();
|
||||
List<LimeSdrSampleRate> rates = controller.getSampleRates();
|
||||
getSampleRateCombo().setModel(new DefaultComboBoxModel<>(rates.toArray(new LimeSdrSampleRate[0])));
|
||||
getSampleRateCombo().setSelectedItem(controller.getLimeSdrSampleRate());
|
||||
getSampleRateCombo().setEnabled(!controller.isLockedSampleRate());
|
||||
|
||||
List<String> antennas = controller.getAntennas();
|
||||
getAntennaCombo().setModel(new DefaultComboBoxModel<>(antennas.toArray(new String[0])));
|
||||
getAntennaCombo().setSelectedItem(controller.getAntenna());
|
||||
getAntennaCombo().setEnabled(true);
|
||||
|
||||
getGainSlider().setValue(controller.getGain());
|
||||
getGainSlider().setEnabled(true);
|
||||
getGainValueLabel().setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
getSampleRateCombo().setModel(new DefaultComboBoxModel<>());
|
||||
getSampleRateCombo().setEnabled(false);
|
||||
getAntennaCombo().setModel(new DefaultComboBoxModel<>());
|
||||
getAntennaCombo().setEnabled(false);
|
||||
getGainSlider().setEnabled(false);
|
||||
getGainValueLabel().setEnabled(false);
|
||||
}
|
||||
|
||||
updateGainLabel();
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the tuner has finished starting, since a status update can arrive while it's starting or restarting.
|
||||
*/
|
||||
private boolean hasStartedTuner()
|
||||
{
|
||||
return hasTuner() && getTuner().getController().getAntenna() != null;
|
||||
}
|
||||
|
||||
private void updateGainLabel()
|
||||
{
|
||||
getGainValueLabel().setText(getGainSlider().getValue() + " dB");
|
||||
}
|
||||
|
||||
/**
|
||||
* Button that provides tuner information
|
||||
*/
|
||||
private JButton getTunerInfoButton()
|
||||
{
|
||||
if(mTunerInfoButton == null)
|
||||
{
|
||||
mTunerInfoButton = new JButton("Info");
|
||||
mTunerInfoButton.setEnabled(false);
|
||||
mTunerInfoButton.addActionListener(_ -> JOptionPane.showMessageDialog(LimeSdrTunerEditor.this,
|
||||
getTunerInfo(), "Tuner Info", JOptionPane.INFORMATION_MESSAGE));
|
||||
}
|
||||
|
||||
return mTunerInfoButton;
|
||||
}
|
||||
|
||||
private JComboBox<LimeSdrSampleRate> getSampleRateCombo()
|
||||
{
|
||||
if(mSampleRateCombo == null)
|
||||
{
|
||||
mSampleRateCombo = new JComboBox<>();
|
||||
mSampleRateCombo.setEnabled(false);
|
||||
mSampleRateCombo.addActionListener(_ ->
|
||||
{
|
||||
if(hasTuner() && !isLoading())
|
||||
{
|
||||
LimeSdrSampleRate rate = (LimeSdrSampleRate)mSampleRateCombo.getSelectedItem();
|
||||
|
||||
try
|
||||
{
|
||||
getTuner().getController().setSampleRate(rate);
|
||||
|
||||
//Adjust the min/max values for the sample rate.
|
||||
adjustForSampleRate(rate.getRate());
|
||||
|
||||
save();
|
||||
}
|
||||
catch(Exception e1)
|
||||
{
|
||||
mLog.error("Error setting LimeSDR sample rate", e1);
|
||||
JOptionPane.showMessageDialog(LimeSdrTunerEditor.this, "Couldn't set sample rate to " + rate);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return mSampleRateCombo;
|
||||
}
|
||||
|
||||
private JComboBox<String> getAntennaCombo()
|
||||
{
|
||||
if(mAntennaCombo == null)
|
||||
{
|
||||
mAntennaCombo = new JComboBox<>();
|
||||
mAntennaCombo.setEnabled(false);
|
||||
mAntennaCombo.setToolTipText("Receive port: LNAW wideband (default), LNAL low band, LNAH high band");
|
||||
mAntennaCombo.addActionListener(_ ->
|
||||
{
|
||||
if(hasTuner() && !isLoading())
|
||||
{
|
||||
String antenna = (String)mAntennaCombo.getSelectedItem();
|
||||
|
||||
try
|
||||
{
|
||||
getTuner().getController().setAntenna(antenna);
|
||||
save();
|
||||
}
|
||||
catch(Exception e1)
|
||||
{
|
||||
mLog.error("Error setting LimeSDR antenna", e1);
|
||||
JOptionPane.showMessageDialog(mAntennaCombo, "Couldn't set antenna to " + antenna);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return mAntennaCombo;
|
||||
}
|
||||
|
||||
private JSlider getGainSlider()
|
||||
{
|
||||
if(mGainSlider == null)
|
||||
{
|
||||
mGainSlider = new JSlider(JSlider.HORIZONTAL, LimeSdrTunerController.GAIN_MINIMUM,
|
||||
LimeSdrTunerController.GAIN_MAXIMUM, LimeSdrTunerController.GAIN_DEFAULT);
|
||||
mGainSlider.setEnabled(false);
|
||||
mGainSlider.setMajorTickSpacing(5);
|
||||
mGainSlider.setPaintTicks(true);
|
||||
mGainSlider.addChangeListener(_ ->
|
||||
{
|
||||
int gain = mGainSlider.getValue();
|
||||
|
||||
if(hasTuner() && !isLoading())
|
||||
{
|
||||
try
|
||||
{
|
||||
getTuner().getController().setGain(gain);
|
||||
save();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("Couldn't set LimeSDR gain to:" + gain, e);
|
||||
JOptionPane.showMessageDialog(mGainSlider, "Couldn't set gain value to " + gain);
|
||||
}
|
||||
}
|
||||
|
||||
updateGainLabel();
|
||||
});
|
||||
}
|
||||
|
||||
return mGainSlider;
|
||||
}
|
||||
|
||||
private JLabel getGainValueLabel()
|
||||
{
|
||||
if(mGainValueLabel == null)
|
||||
{
|
||||
mGainValueLabel = new JLabel("0 dB");
|
||||
mGainValueLabel.setEnabled(false);
|
||||
}
|
||||
|
||||
return mGainValueLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
if(hasConfiguration() && !isLoading())
|
||||
{
|
||||
getConfiguration().setFrequency(getFrequencyControl().getFrequency());
|
||||
getConfiguration().setMinimumFrequency(getMinimumFrequencyTextField().getFrequency());
|
||||
getConfiguration().setMaximumFrequency(getMaximumFrequencyTextField().getFrequency());
|
||||
double value = ((SpinnerNumberModel)getFrequencyCorrectionSpinner().getModel()).getNumber().doubleValue();
|
||||
getConfiguration().setFrequencyCorrection(value);
|
||||
getConfiguration().setAutoPPMCorrectionEnabled(getAutoPPMCheckBox().isSelected());
|
||||
|
||||
if(getSampleRateCombo().getSelectedItem() instanceof LimeSdrSampleRate rate)
|
||||
{
|
||||
getConfiguration().setSampleRate(rate.getRate());
|
||||
}
|
||||
|
||||
if(getAntennaCombo().getSelectedItem() instanceof String antenna)
|
||||
{
|
||||
getConfiguration().setAntenna(antenna);
|
||||
}
|
||||
|
||||
getConfiguration().setGain(getGainSlider().getValue());
|
||||
saveConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTunerLockState(boolean locked)
|
||||
{
|
||||
getFrequencyPanel().updateControls();
|
||||
getSampleRateCombo().setEnabled(!locked);
|
||||
getSampleRateCombo().setToolTipText(locked ? "Sample Rate is locked. Disable decoding channels to unlock." :
|
||||
"Select a sample rate for the tuner");
|
||||
}
|
||||
|
||||
private String getTunerInfo()
|
||||
{
|
||||
if(getDiscoveredTuner().getTunerStatus() == TunerStatus.ERROR)
|
||||
{
|
||||
return getDiscoveredTuner().getErrorMessage();
|
||||
}
|
||||
|
||||
if(hasTuner())
|
||||
{
|
||||
LimeSdrDeviceInformation info = getTuner().getController().getDeviceInfo();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<html><h3>LimeSDR Tuner</h3>");
|
||||
sb.append("<b>Board: </b>").append(info.board()).append("<br>");
|
||||
sb.append("<b>Serial: </b>").append(info.serial()).append("<br>");
|
||||
sb.append("<b>Hardware: </b>").append(info.hardware()).append("<br>");
|
||||
sb.append("<b>Firmware: </b>").append(info.firmware()).append("<br>");
|
||||
sb.append("<b>Gateware: </b>").append(info.gateware()).append("<br>");
|
||||
sb.append("<b>Connection: </b>").append(info.connection()).append("<br>");
|
||||
sb.append("<b>LimeSuiteNG: </b>").append(info.library()).append("<br>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
7
src/main/resources/65-limesdr.rules
Normal file
7
src/main/resources/65-limesdr.rules
Normal file
@@ -0,0 +1,7 @@
|
||||
# LimeSDR udev rules
|
||||
# Grants access to the logged-in user (uaccess) and to the plugdev group.
|
||||
|
||||
# LimeSDR-USB
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="1d50", ATTR{idProduct}=="6108", MODE="0660", GROUP="plugdev", TAG+="uaccess"
|
||||
# LimeSDR Mini and LimeSDR Mini 2.0
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="601f", MODE="0660", GROUP="plugdev", TAG+="uaccess"
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2026 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.source.tuner.limesdr;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.github.dsheirer.dsp.filter.channelizer.ComplexPolyphaseChannelizerM2;
|
||||
import io.github.dsheirer.limesdr.DeviceEntry;
|
||||
import io.github.dsheirer.limesdr.LogLevel;
|
||||
import io.github.dsheirer.limesdr.Range;
|
||||
import io.github.dsheirer.limesdr.StreamConfig;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.TunerClass;
|
||||
import io.github.dsheirer.source.tuner.TunerFactory;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Tests for the parts of the LimeSDR tuner that don't require a device.
|
||||
*/
|
||||
class LimeSdrTunerTest
|
||||
{
|
||||
private static final DeviceEntry USB_A = DeviceEntry.parse("LimeSDR-USB, media=USB3.0, addr=1d50:6108, serial=0009060B00462008");
|
||||
private static final DeviceEntry USB_B = DeviceEntry.parse("LimeSDR-USB, media=USB3.0, addr=1d50:6108, serial=0009060B00471B22");
|
||||
private static final DeviceEntry MINI = DeviceEntry.parse("LimeSDR-Mini, media=USB3.0, addr=0403:601f, serial=1D3AC9A5C7B4D2");
|
||||
|
||||
@Test
|
||||
void lookupFindsEachUsbProduct()
|
||||
{
|
||||
assertEquals(TunerClass.LIMESDR, TunerClass.lookup((short)0x1D50, (short)0x6108));
|
||||
assertEquals(TunerClass.LIMESDR, TunerClass.lookup((short)0x0403, (short)0x601F));
|
||||
assertTrue(TunerClass.LIMESDR.isSupportedUsbTuner());
|
||||
assertTrue(TunerType.LIMESDR.isSupportedUsbTuner());
|
||||
}
|
||||
|
||||
@Test
|
||||
void scalesSamplesAndRemovesHalfBitOffset()
|
||||
{
|
||||
short[] samples = {2047, -2048, -1, 0};
|
||||
|
||||
assertArrayEquals(new float[]{2047.5f / 2048, -2047.5f / 2048, -0.5f / 2048, 0.5f / 2048},
|
||||
LimeSdrTunerController.scale(samples));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sampleRatesAreLimitedByTheDevice()
|
||||
{
|
||||
//LimeSDR-USB on USB 3.0
|
||||
assertEquals(List.of(LimeSdrSampleRate.values()), LimeSdrSampleRate.getRates(100_000, 61_440_000));
|
||||
//LimeSDR Mini
|
||||
assertEquals(LimeSdrSampleRate.RATE_30_72, LimeSdrSampleRate.getRates(100_000, 30_720_000).getLast());
|
||||
}
|
||||
|
||||
@Test
|
||||
void usb2LimitsTheSampleRate()
|
||||
{
|
||||
Range range = new Range(100_000, 61_440_000, 0);
|
||||
|
||||
assertEquals(61_440_000, LimeSdrTunerController.getMaximumSampleRate(range, "USB3.0"));
|
||||
double usb2 = LimeSdrTunerController.getMaximumSampleRate(range, "USB2.0");
|
||||
assertEquals(LimeSdrSampleRate.RATE_10_0, LimeSdrSampleRate.getRates(range.min(), usb2).getLast());
|
||||
}
|
||||
|
||||
@Test
|
||||
void savedRateAboveTheDeviceMaximumIsReduced()
|
||||
{
|
||||
List<LimeSdrSampleRate> rates = LimeSdrSampleRate.getRates(100_000, 30_720_000);
|
||||
|
||||
assertEquals(LimeSdrSampleRate.RATE_30_72, LimeSdrSampleRate.getClosest(rates, LimeSdrSampleRate.RATE_61_44.getRate()));
|
||||
assertEquals(LimeSdrSampleRate.RATE_1_25, LimeSdrSampleRate.getClosest(rates, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sampleRatesDivideIntoPolyphaseChannels()
|
||||
{
|
||||
for(LimeSdrSampleRate rate : LimeSdrSampleRate.values())
|
||||
{
|
||||
int channelCount = ComplexPolyphaseChannelizerM2.getChannelCount(rate.getRate());
|
||||
assertEquals(0, channelCount % 2, rate.toString());
|
||||
assertTrue((double)rate.getRate() / channelCount >= 25_000.0, rate.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void maximumUsbRateDoesNotOverflow()
|
||||
{
|
||||
assertTrue(LimeSdrSampleRate.RATE_61_44.getRate() * 24L <= Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void antennaListExcludesNoneAndLoopbackPorts()
|
||||
{
|
||||
List<String> ports = List.of("None", "LNAH", "LNAL", "LNAW", "LB1", "LB2");
|
||||
List<String> antennas = LimeSdrTunerController.getSelectableAntennas(ports);
|
||||
|
||||
assertEquals(List.of("LNAH", "LNAL", "LNAW"), antennas);
|
||||
assertEquals("LNAW", LimeSdrTunerController.getDefaultAntenna(antennas));
|
||||
assertEquals("LNAH", LimeSdrTunerController.getDefaultAntenna(List.of("LNAH")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deviceIsFoundBySerialNumber() throws SourceException
|
||||
{
|
||||
LimeSdrTunerController.UsbIdentity identity = new LimeSdrTunerController.UsbIdentity(0x1D50, 0x6108,
|
||||
"0009060B00471B22");
|
||||
|
||||
assertEquals(USB_B, LimeSdrTunerController.findDevice(identity, List.of(MINI, USB_A, USB_B)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deviceWithoutSerialIsFoundWhenItIsTheOnlyOneOfItsKind() throws SourceException
|
||||
{
|
||||
LimeSdrTunerController.UsbIdentity mini = new LimeSdrTunerController.UsbIdentity(0x0403, 0x601F, null);
|
||||
LimeSdrTunerController.UsbIdentity usb = new LimeSdrTunerController.UsbIdentity(0x1D50, 0x6108, null);
|
||||
|
||||
assertEquals(MINI, LimeSdrTunerController.findDevice(mini, List.of(USB_A, MINI)));
|
||||
assertThrows(SourceException.class, () -> LimeSdrTunerController.findDevice(usb, List.of(USB_A, USB_B, MINI)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deviceThatLimeSuiteCantSeeIsAnError()
|
||||
{
|
||||
LimeSdrTunerController.UsbIdentity identity = new LimeSdrTunerController.UsbIdentity(0x1D50, 0x6108,
|
||||
"0009060B00462008");
|
||||
|
||||
assertThrows(SourceException.class, () -> LimeSdrTunerController.findDevice(identity, List.of(MINI)));
|
||||
assertThrows(SourceException.class, () -> LimeSdrTunerController.findDevice(identity, List.of(USB_B)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configurationSurvivesSerialization() throws Exception
|
||||
{
|
||||
LimeSdrTunerConfiguration configuration = new LimeSdrTunerConfiguration("test");
|
||||
configuration.setSampleRate(LimeSdrSampleRate.RATE_5_0.getRate());
|
||||
configuration.setGain(55);
|
||||
configuration.setAntenna("LNAH");
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
String json = mapper.writeValueAsString(configuration);
|
||||
TunerConfiguration restored = mapper.readValue(json, TunerConfiguration.class);
|
||||
|
||||
LimeSdrTunerConfiguration limeSdr = assertInstanceOf(LimeSdrTunerConfiguration.class, restored);
|
||||
assertEquals(TunerType.LIMESDR, limeSdr.getTunerType());
|
||||
assertEquals(LimeSdrSampleRate.RATE_5_0.getRate(), limeSdr.getSampleRate());
|
||||
assertEquals(55, limeSdr.getGain());
|
||||
assertEquals("LNAH", limeSdr.getAntenna());
|
||||
assertEquals("test", limeSdr.getUniqueID());
|
||||
}
|
||||
|
||||
@Test
|
||||
void factoryCreatesTheConfiguration()
|
||||
{
|
||||
assertInstanceOf(LimeSdrTunerConfiguration.class, TunerFactory.getTunerConfiguration(TunerType.LIMESDR, "id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void fifoHoldsAQuarterSecondOfSamples()
|
||||
{
|
||||
assertEquals(StreamConfig.DEFAULT_FIFO_SIZE, LimeSdrTunerController.getFifoSize(LimeSdrSampleRate.RATE_1_25));
|
||||
assertEquals(10_000_000, LimeSdrTunerController.getFifoSize(LimeSdrSampleRate.RATE_40_0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void debugMessagesAreDiscarded()
|
||||
{
|
||||
LimeSdrTunerController.log(LogLevel.DEBUG, "Loss: pkt:4622555 exp: 000000017a863dc0, got: 000000017a864860");
|
||||
LimeSdrTunerController.log(LogLevel.VERBOSE, "Set Rx LO frequency (450100180 Hz)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void droppedSamplesAreFoundFromTimestampGaps()
|
||||
{
|
||||
assertEquals(0, LimeSdrTunerController.getTimestampGap(-1, 5_000_000));
|
||||
assertEquals(0, LimeSdrTunerController.getTimestampGap(65536, 65536));
|
||||
assertEquals(718_080, LimeSdrTunerController.getTimestampGap(32_309_248, 33_027_328));
|
||||
assertEquals(0, LimeSdrTunerController.getTimestampGap(32_309_248, 0));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user