#52 SDRPlay RSP tuner support. (#1453)

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
Denny Sheirer
2023-02-19 08:21:54 -05:00
committed by GitHub
parent 9abf64c6ab
commit 75347f9d0a
336 changed files with 31841 additions and 264 deletions

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* 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;
@@ -29,4 +26,9 @@ public interface ITunerErrorListener
* @param errorMessage to set
*/
void setErrorMessage(String errorMessage);
/**
* Indicates that the tuner has been removed from the system.
*/
void tunerRemoved();
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 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
@@ -34,4 +34,10 @@ public class LoggingTunerErrorListener implements ITunerErrorListener
{
mLog.error("Tuner Error: " + errorMessage);
}
@Override
public void tunerRemoved()
{
mLog.warn("Tuner removal detected");
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 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
@@ -149,6 +149,20 @@ public abstract class Tuner implements ISourceEventProcessor, ITunerErrorListene
}
}
/**
* Process tuner removal error from tuner controller and propagate to an external listener.
*/
@Override
public void tunerRemoved()
{
stop();
if(mTunerErrorListener != null)
{
mTunerErrorListener.tunerRemoved();
}
}
/**
* Sets the channel source manager
* @param manager to use

View File

@@ -30,6 +30,7 @@ public enum TunerClass
FUNCUBE_DONGLE_PRO_PLUS("Funcube Dongle Pro+" ),
HACKRF("HackRF" ),
RTL2832("RTL-2832"),
RSP("RSP"),
TEST_TUNER("Test"),
RECORDING_TUNER("Recording"),
UNKNOWN("Unknown" );

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -46,7 +46,11 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
INativeBufferProvider, Listener<INativeBuffer>, ITunerErrorListener
{
private final static Logger mLog = LoggerFactory.getLogger(TunerController.class);
//Protects access to the native buffer broadcaster for adding, removing or checking for listener count.
protected ReentrantLock mBufferListenerLock = new ReentrantLock();
protected Broadcaster<INativeBuffer> mNativeBufferBroadcaster = new Broadcaster();
protected FrequencyController mFrequencyController;
private int mMiddleUnusableHalfBandwidth;
private int mMeasuredFrequencyError;
@@ -129,6 +133,19 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
}
}
/**
* Indicates that the tuner has been removed from the system and requests the listener to process the cleanup.
*/
@Override
public void tunerRemoved()
{
//Request parent tuner process the shutdown and cleanup
if(mTunerErrorListener != null)
{
mTunerErrorListener.tunerRemoved();
}
}
/**
* Number of samples contained in each complex buffer provided by this tuner.
*
@@ -572,7 +589,16 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
@Override
public void addBufferListener(Listener<INativeBuffer> listener)
{
mNativeBufferBroadcaster.addListener(listener);
mBufferListenerLock.lock();
try
{
mNativeBufferBroadcaster.addListener(listener);
}
finally
{
mBufferListenerLock.unlock();
}
}
/**
@@ -581,7 +607,16 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
@Override
public void removeBufferListener(Listener<INativeBuffer> listener)
{
mNativeBufferBroadcaster.removeListener(listener);
mBufferListenerLock.lock();
try
{
mNativeBufferBroadcaster.removeListener(listener);
}
finally
{
mBufferListenerLock.unlock();
}
}
/**
@@ -590,7 +625,20 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
@Override
public boolean hasBufferListeners()
{
return mNativeBufferBroadcaster.hasListeners();
boolean hasListeners;
mBufferListenerLock.lock();
try
{
hasListeners = mNativeBufferBroadcaster.hasListeners();
}
finally
{
mBufferListenerLock.unlock();
}
return hasListeners;
}
/**
@@ -598,6 +646,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
*/
protected void broadcast(INativeBuffer complexSamples)
{
//Note: unprotected access to the broadcaster ... the broadcaster uses thread-save internal list
mNativeBufferBroadcaster.broadcast(complexSamples);
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 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
@@ -54,6 +54,24 @@ public class TunerEvent
return mTuner != null;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Tuner Event [").append(getEvent().name()).append("] for tuner [");
if(hasTuner())
{
sb.append(getTuner());
}
else
{
sb.append("No Tuner");
}
sb.append("]");
return sb.toString();
}
/**
* Event type
*/
@@ -75,6 +93,7 @@ public class TunerEvent
NOTIFICATION_SHUTTING_DOWN,
REQUEST_CLEAR_MAIN_SPECTRAL_DISPLAY,
REQUEST_ENABLE_RSP_SLAVE_DEVICE,
REQUEST_MAIN_SPECTRAL_DISPLAY,
REQUEST_NEW_SPECTRAL_DISPLAY;
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
package io.github.dsheirer.source.tuner;
import io.github.dsheirer.gui.preference.tuner.RspDuoSelectionMode;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.preference.source.ChannelizerType;
import io.github.dsheirer.source.SourceException;
@@ -53,7 +54,60 @@ import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerEditor;
import io.github.dsheirer.source.tuner.rtl.r820t.R820TEmbeddedTuner;
import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerConfiguration;
import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerEditor;
import io.github.dsheirer.source.tuner.sdrplay.DiscoveredRspTuner;
import io.github.dsheirer.source.tuner.sdrplay.RspTuner;
import io.github.dsheirer.source.tuner.sdrplay.api.DeviceSelectionMode;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.device.Device;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceInfo;
import io.github.dsheirer.source.tuner.sdrplay.api.device.Rsp1Device;
import io.github.dsheirer.source.tuner.sdrplay.api.device.Rsp1aDevice;
import io.github.dsheirer.source.tuner.sdrplay.api.device.Rsp2Device;
import io.github.dsheirer.source.tuner.sdrplay.api.device.RspDuoDevice;
import io.github.dsheirer.source.tuner.sdrplay.api.device.RspDxDevice;
import io.github.dsheirer.source.tuner.sdrplay.rsp1.ControlRsp1;
import io.github.dsheirer.source.tuner.sdrplay.rsp1.DiscoveredRsp1Tuner;
import io.github.dsheirer.source.tuner.sdrplay.rsp1.IControlRsp1;
import io.github.dsheirer.source.tuner.sdrplay.rsp1.Rsp1TunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.rsp1.Rsp1TunerController;
import io.github.dsheirer.source.tuner.sdrplay.rsp1.Rsp1TunerEditor;
import io.github.dsheirer.source.tuner.sdrplay.rsp1a.ControlRsp1a;
import io.github.dsheirer.source.tuner.sdrplay.rsp1a.DiscoveredRsp1aTuner;
import io.github.dsheirer.source.tuner.sdrplay.rsp1a.IControlRsp1a;
import io.github.dsheirer.source.tuner.sdrplay.rsp1a.Rsp1aTunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.rsp1a.Rsp1aTunerController;
import io.github.dsheirer.source.tuner.sdrplay.rsp1a.Rsp1aTunerEditor;
import io.github.dsheirer.source.tuner.sdrplay.rsp2.ControlRsp2;
import io.github.dsheirer.source.tuner.sdrplay.rsp2.DiscoveredRsp2Tuner;
import io.github.dsheirer.source.tuner.sdrplay.rsp2.IControlRsp2;
import io.github.dsheirer.source.tuner.sdrplay.rsp2.Rsp2TunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.rsp2.Rsp2TunerController;
import io.github.dsheirer.source.tuner.sdrplay.rsp2.Rsp2TunerEditor;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.ControlRspDuoTuner1Master;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.ControlRspDuoTuner1Single;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.ControlRspDuoTuner2Single;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.ControlRspDuoTuner2Slave;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.DiscoveredRspDuoTuner1;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.DiscoveredRspDuoTuner2;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.IControlRspDuoTuner1;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.IControlRspDuoTuner2;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.MasterSlaveBridge;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.RspDuoTuner1Configuration;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.RspDuoTuner1Controller;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.RspDuoTuner1Editor;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.RspDuoTuner2Configuration;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.RspDuoTuner2Controller;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.RspDuoTuner2Editor;
import io.github.dsheirer.source.tuner.sdrplay.rspDx.ControlRspDx;
import io.github.dsheirer.source.tuner.sdrplay.rspDx.DiscoveredRspDxTuner;
import io.github.dsheirer.source.tuner.sdrplay.rspDx.IControlRspDx;
import io.github.dsheirer.source.tuner.sdrplay.rspDx.RspDxTunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.rspDx.RspDxTunerController;
import io.github.dsheirer.source.tuner.sdrplay.rspDx.RspDxTunerEditor;
import io.github.dsheirer.source.tuner.ui.TunerEditor;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -66,6 +120,182 @@ public class TunerFactory
{
private static final Logger mLog = LoggerFactory.getLogger(TunerFactory.class);
/**
* Creates one or two (e.g. RSPduo) Discovered RSP tuner instances for the RSP device.
* @param deviceInfo describing the RSP device
* @param channelizerType to use with the device
* @param selectionMode to specify how to configure an RSPduo dual-tuner device.
* @return zero or more discovered RSP tuners.
*/
public static List<DiscoveredRspTuner> getRspTuners(DeviceInfo deviceInfo, ChannelizerType channelizerType, RspDuoSelectionMode selectionMode)
{
List<DiscoveredRspTuner> tuners = new ArrayList<>();
switch(deviceInfo.getDeviceType())
{
case RSP1:
tuners.add(new DiscoveredRsp1Tuner(deviceInfo, channelizerType));
break;
case RSP1A:
tuners.add(new DiscoveredRsp1aTuner(deviceInfo, channelizerType));
break;
case RSP2:
tuners.add(new DiscoveredRsp2Tuner(deviceInfo, channelizerType));
break;
case RSPdx:
tuners.add(new DiscoveredRspDxTuner(deviceInfo, channelizerType));
break;
case RSPduo:
switch(selectionMode)
{
case SINGLE_1:
deviceInfo.setDeviceSelectionMode(DeviceSelectionMode.SINGLE_TUNER_1);
tuners.add(new DiscoveredRspDuoTuner1(deviceInfo, channelizerType));
break;
case SINGLE_2:
deviceInfo.setDeviceSelectionMode(DeviceSelectionMode.SINGLE_TUNER_2);
tuners.add(new DiscoveredRspDuoTuner2(deviceInfo, channelizerType));
break;
case DUAL:
MasterSlaveBridge bridge = new MasterSlaveBridge();
deviceInfo.setDeviceSelectionMode(DeviceSelectionMode.MASTER_TUNER_1);
tuners.add(new DiscoveredRspDuoTuner1(deviceInfo, channelizerType, bridge));
DeviceInfo deviceInfoTuner2 = deviceInfo.clone();
deviceInfoTuner2.setDeviceSelectionMode(DeviceSelectionMode.SLAVE_TUNER_2);
tuners.add(new DiscoveredRspDuoTuner2(deviceInfoTuner2, channelizerType, bridge));
break;
}
break;
}
return tuners;
}
/**
* Locates the matching RSP device described by the device info object and creates an RSP tuner instance.
* @param deviceInfo to match
* @param channelizerType for the tuner
* @param tunerErrorListener to monitor the tuner's status
* @return constructed RSP tuner instance
* @throws SDRPlayException if the device is not available or is not supported
*/
public static RspTuner getRspTuner(DeviceInfo deviceInfo, ChannelizerType channelizerType,
ITunerErrorListener tunerErrorListener) throws SDRPlayException
{
//API instance is retained across the lifecycle of the constructed device, so we only close it if we don't get
//a device from it.
SDRplay api = new SDRplay();
if(api.isAvailable())
{
Device device = api.getDevice(deviceInfo);
switch(device.getDeviceType())
{
case RSP1:
if(device instanceof Rsp1Device rsp1Device)
{
IControlRsp1 controlRsp1 = new ControlRsp1(rsp1Device);
Rsp1TunerController rsp1TunerController = new Rsp1TunerController(controlRsp1, tunerErrorListener);
return new RspTuner(rsp1TunerController, tunerErrorListener, channelizerType);
}
break;
case RSP1A:
if(device instanceof Rsp1aDevice rsp1aDevice)
{
IControlRsp1a controlRsp1a = new ControlRsp1a(rsp1aDevice);
Rsp1aTunerController rsp1aTunerController = new Rsp1aTunerController(controlRsp1a, tunerErrorListener);
return new RspTuner(rsp1aTunerController, tunerErrorListener, channelizerType);
}
break;
case RSP2:
if(device instanceof Rsp2Device rsp2Device)
{
IControlRsp2 controlRsp2 = new ControlRsp2(rsp2Device);
Rsp2TunerController rsp2TunerController = new Rsp2TunerController(controlRsp2, tunerErrorListener);
return new RspTuner(rsp2TunerController, tunerErrorListener, channelizerType);
}
break;
case RSPdx:
if(device instanceof RspDxDevice rspDxDevice)
{
IControlRspDx controlRspDx = new ControlRspDx(rspDxDevice);
RspDxTunerController rspDxTunerController = new RspDxTunerController(controlRspDx, tunerErrorListener);
return new RspTuner(rspDxTunerController, tunerErrorListener, channelizerType);
}
break;
case RSPduo:
if(device instanceof RspDuoDevice rspDuoDevice)
{
switch(deviceInfo.getDeviceSelectionMode())
{
case SINGLE_TUNER_1:
IControlRspDuoTuner1 controlRspDuoTuner1 = new ControlRspDuoTuner1Single(rspDuoDevice);
RspDuoTuner1Controller rspDuoTuner1Controller = new RspDuoTuner1Controller(controlRspDuoTuner1, tunerErrorListener);
return new RspTuner(rspDuoTuner1Controller, tunerErrorListener, channelizerType);
case SINGLE_TUNER_2:
IControlRspDuoTuner2 controlRspDuoTuner2 = new ControlRspDuoTuner2Single(rspDuoDevice);
RspDuoTuner2Controller rspDuoTuner2Controller = new RspDuoTuner2Controller(controlRspDuoTuner2, tunerErrorListener);
return new RspTuner(rspDuoTuner2Controller, tunerErrorListener, channelizerType);
default:
throw new SDRPlayException("This method only supports RSPduo single tuner configurations");
}
}
break;
case default:
mLog.warn("Unrecognized SDRplay RSP Device Type: " + device.getDeviceType() + " SER#: " + device.getSerialNumber());
break;
}
}
throw new SDRPlayException("Unable to obtain RSP tuner");
}
/**
* Locates the matching RSP device described by the device info object and creates an RSP tuner instance.
* @param deviceInfo to match
* @param channelizerType for the tuner
* @param tunerErrorListener to monitor the tuner's status
* @param bridge to link master/slave instances together
* @return constructed RSP tuner instance
* @throws SDRPlayException if the device is not available or is not supported
*/
public static RspTuner getRspDuoTuner(DeviceInfo deviceInfo, ChannelizerType channelizerType,
ITunerErrorListener tunerErrorListener, MasterSlaveBridge bridge) throws SDRPlayException
{
SDRplay api = new SDRplay();
if(api.isAvailable())
{
Device device = api.getDevice(deviceInfo);
switch(device.getDeviceType())
{
case RSPduo:
if(device instanceof RspDuoDevice rspDuoDevice)
{
switch(deviceInfo.getDeviceSelectionMode())
{
case MASTER_TUNER_1:
IControlRspDuoTuner1 controlRspDuoTuner1 = new ControlRspDuoTuner1Master(rspDuoDevice, bridge);
RspDuoTuner1Controller rspDuoTuner1Controller = new RspDuoTuner1Controller(controlRspDuoTuner1, tunerErrorListener);
return new RspTuner(rspDuoTuner1Controller, tunerErrorListener, channelizerType);
case SLAVE_TUNER_2:
IControlRspDuoTuner2 controlRspDuoTuner2 = new ControlRspDuoTuner2Slave(rspDuoDevice, bridge);
RspDuoTuner2Controller rspDuoTuner2Controller = new RspDuoTuner2Controller(controlRspDuoTuner2, tunerErrorListener);
return new RspTuner(rspDuoTuner2Controller, tunerErrorListener, channelizerType);
default:
throw new SDRPlayException("This method only supports RSPduo single tuner configurations");
}
}
break;
}
}
throw new SDRPlayException("Unable to obtain RSPduo tuner");
}
/**
* Create a USB tuner
* @param tunerClass to instantiate
@@ -148,6 +378,18 @@ public class TunerFactory
return new R820TTunerConfiguration(uniqueID);
case RECORDING:
return RecordingTunerConfiguration.create();
case RSP_1:
return new Rsp1TunerConfiguration(uniqueID);
case RSP_1A:
return new Rsp1aTunerConfiguration(uniqueID);
case RSP_2:
return new Rsp2TunerConfiguration(uniqueID);
case RSP_DUO_1:
return new RspDuoTuner1Configuration(uniqueID);
case RSP_DUO_2:
return new RspDuoTuner2Configuration(uniqueID);
case RSP_DX:
return new RspDxTunerConfiguration(uniqueID);
default:
throw new IllegalArgumentException("Unrecognized tuner type [" + type.name() + "]");
}
@@ -169,6 +411,42 @@ public class TunerFactory
return new FCD2TunerEditor(userPreferences, tunerManager, discoveredTuner);
case HACKRF:
return new HackRFTunerEditor(userPreferences, tunerManager, discoveredTuner);
case RSP:
if(discoveredTuner instanceof DiscoveredRspTuner discoveredRspTuner)
{
switch(discoveredRspTuner.getDeviceType())
{
case RSP1:
return new Rsp1TunerEditor(userPreferences, tunerManager, discoveredRspTuner);
case RSP1A:
return new Rsp1aTunerEditor(userPreferences, tunerManager, discoveredRspTuner);
case RSP2:
return new Rsp2TunerEditor(userPreferences, tunerManager, discoveredRspTuner);
case RSPdx:
return new RspDxTunerEditor(userPreferences, tunerManager, discoveredRspTuner);
case RSPduo:
if(discoveredRspTuner instanceof DiscoveredRspDuoTuner1 duoTuner1)
{
return new RspDuoTuner1Editor(userPreferences, tunerManager, duoTuner1);
}
else if(discoveredRspTuner instanceof DiscoveredRspDuoTuner2 duoTuner2)
{
return new RspDuoTuner2Editor(userPreferences, tunerManager, duoTuner2);
}
else
{
throw new IllegalArgumentException("Unrecognized RSPduo device type:" +
discoveredRspTuner.getClass());
}
case UNKNOWN:
throw new IllegalArgumentException("Unrecognized RSP device type: " +
discoveredRspTuner.getDeviceType());
}
}
throw new IllegalArgumentException("Unrecognized discovered RSP tuner class: " +
discoveredTuner.getClass());
case RECORDING_TUNER:
return new RecordingTunerEditor(userPreferences, tunerManager, discoveredTuner);
case RTL2832:
if(discoveredTuner.hasTuner())
{
@@ -181,8 +459,6 @@ public class TunerFactory
}
}
return new RTL2832UnknownTunerEditor(userPreferences, tunerManager, discoveredTuner);
case RECORDING_TUNER:
return new RecordingTunerEditor(userPreferences, tunerManager, discoveredTuner);
case TEST_TUNER:
case UNKNOWN:
default:

View File

@@ -37,6 +37,13 @@ public enum TunerType
HACKRF_RAD1O("RAD1O"),
RAFAELMICRO_R820T("R820T"),
RAFAELMICRO_R828D("R828D"),
RSP_1("RSP1"),
RSP_1A("RSP1A"),
RSP_2("RSP2"),
RSP_DUO_1("RSPduo Tuner 1"),
RSP_DUO_2("RSPduo Tuner 2"),
RSP_DX("RSPdx"),
TEST("Test"),
RECORDING("Recording"),
UNKNOWN("Unknown");

View File

@@ -31,6 +31,7 @@ import io.github.dsheirer.source.tuner.hackrf.HackRFTunerConfiguration;
import io.github.dsheirer.source.tuner.recording.RecordingTunerConfiguration;
import io.github.dsheirer.source.tuner.rtl.e4k.E4KTunerConfiguration;
import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.RspTunerConfiguration;
/**
* Abstract class to hold a configuration for a specific type of tuner
@@ -44,6 +45,7 @@ import io.github.dsheirer.source.tuner.rtl.r820t.R820TTunerConfiguration;
@JsonSubTypes.Type(value = HackRFTunerConfiguration.class, name = "hackRFTunerConfiguration"),
@JsonSubTypes.Type(value = RecordingTunerConfiguration.class, name = "recordingTunerConfiguration"),
@JsonSubTypes.Type(value = R820TTunerConfiguration.class, name = "r820TTunerConfiguration"),
@JsonSubTypes.Type(value = RspTunerConfiguration.class, name = "rspTunerConfiguration"),
})
@JacksonXmlRootElement(localName = "tuner_configuration")
public abstract class TunerConfiguration

View File

@@ -147,6 +147,12 @@ public class TunerConfigurationManager implements IDiscoveredTunerStatusListener
}
}
/**
* Monitors discovered tuner enabled status and applies configurations or updates disable state of tuners.
* @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)
{
@@ -157,6 +163,23 @@ public class TunerConfigurationManager implements IDiscoveredTunerStatusListener
else if(current == TunerStatus.ENABLED)
{
removeDisabledTuner(discoveredTuner);
if(discoveredTuner.hasTuner())
{
TunerType tunerType = discoveredTuner.getTuner().getTunerType();
if(tunerType != TunerType.RECORDING)
{
TunerConfiguration tunerConfiguration = getTunerConfiguration(tunerType, discoveredTuner.getId());
if(tunerConfiguration != null)
{
discoveredTuner.setTunerConfiguration(tunerConfiguration);
saveConfigurations();
}
}
}
}
}

View File

@@ -219,7 +219,10 @@ public abstract class DiscoveredTuner implements ITunerErrorListener
*/
public void addTunerStatusListener(IDiscoveredTunerStatusListener listener)
{
mListeners.add(listener);
if(!mListeners.contains(listener))
{
mListeners.add(listener);
}
}
/**
@@ -257,6 +260,12 @@ public abstract class DiscoveredTuner implements ITunerErrorListener
setTunerStatus(TunerStatus.ERROR);
}
@Override
public void tunerRemoved()
{
setTunerStatus(TunerStatus.REMOVED);
}
/**
* Indicates if this tuner has an error message.
*/

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
package io.github.dsheirer.source.tuner.manager;
import io.github.dsheirer.gui.preference.tuner.RspDuoSelectionMode;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.preference.source.ChannelizerType;
import io.github.dsheirer.source.Source;
@@ -28,6 +29,7 @@ import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.mixer.MixerManager;
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.channel.ChannelSpecification;
import io.github.dsheirer.source.tuner.channel.MultiFrequencyTunerChannelSource;
@@ -36,6 +38,11 @@ import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationManager;
import io.github.dsheirer.source.tuner.recording.RecordingTunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.DiscoveredRspTuner;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceInfo;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.DiscoveredRspDuoTuner1;
import io.github.dsheirer.source.tuner.ui.DiscoveredTunerModel;
import io.github.dsheirer.util.ThreadPool;
import java.nio.ByteBuffer;
@@ -63,14 +70,13 @@ import org.usb4java.LibUsb;
public class TunerManager implements IDiscoveredTunerStatusListener
{
private static final Logger mLog = LoggerFactory.getLogger(TunerManager.class);
private static final int MAXIMUM_USB_2_DATA_RATE = 480000000;
private UserPreferences mUserPreferences;
private DiscoveredTunerModel mDiscoveredTunerModel = new DiscoveredTunerModel();
private TunerConfigurationManager mTunerConfigurationManager;
private HotplugEventSupport mHotplugEventSupport = new HotplugEventSupport();
private Context mLibUsbApplicationContext = new Context();
private boolean mLibUsbInitialized = false;
private SDRplay mSDRplay;
/**
* Constructs an instance
@@ -142,6 +148,13 @@ public class TunerManager implements IDiscoveredTunerStatusListener
//Stop all tuners
mDiscoveredTunerModel.releaseDiscoveredTuners();
//Shutdown SDRplay API instance
if(mSDRplay != null)
{
mSDRplay.close();
mSDRplay = null;
}
//Shutdown LibUsb
if(mLibUsbInitialized)
{
@@ -238,37 +251,7 @@ public class TunerManager implements IDiscoveredTunerStatusListener
{
if(!mDiscoveredTunerModel.hasUsbTuner(discoveredUSBTuner.getBus(), discoveredUSBTuner.getPortAddress()))
{
discoveredUSBTuner.addTunerStatusListener(this);
//Set the tuner to disabled if the user has previously blacklisted the tuner
if(mTunerConfigurationManager.isDisabled(discoveredUSBTuner))
{
discoveredUSBTuner.setEnabled(false);
mLog.info("Tuner: " + discoveredUSBTuner + " - Added / Disabled");
}
else
{
mLog.info("Tuner: " + discoveredUSBTuner + " - Added / Starting ...");
//Attempt to start the discovered tuner and determine the tuner type
discoveredUSBTuner.start();
if(discoveredUSBTuner.hasTuner())
{
TunerType tunerType = discoveredUSBTuner.getTuner().getTunerType();
TunerConfiguration tunerConfiguration = mTunerConfigurationManager
.getTunerConfiguration(tunerType, discoveredUSBTuner.getId());
if(tunerConfiguration != null)
{
mLog.info("Tuner: " + discoveredUSBTuner + " - Applying Tuner Configuration");
discoveredUSBTuner.setTunerConfiguration(tunerConfiguration);
mTunerConfigurationManager.saveConfigurations();
}
}
}
mDiscoveredTunerModel.addDiscoveredTuner(discoveredUSBTuner);
startAndConfigureTuner(discoveredUSBTuner);
}
}
@@ -282,12 +265,77 @@ public class TunerManager implements IDiscoveredTunerStatusListener
return mDiscoveredTunerModel.removeUsbTuner(bus, portAddress);
}
/**
* Starts, configures and adds the tuner to the tuner model.
* @param discoveredTuner to add and configure
*/
private void startAndConfigureTuner(DiscoveredTuner discoveredTuner)
{
discoveredTuner.addTunerStatusListener(this);
//Set the tuner to disabled if the user has previously blacklisted the tuner
if(mTunerConfigurationManager.isDisabled(discoveredTuner))
{
discoveredTuner.setEnabled(false);
mLog.info("Tuner: " + discoveredTuner + " - Added / Disabled");
}
else
{
mLog.info("Tuner: " + discoveredTuner + " - Added / Starting ...");
//Attempt to start the discovered tuner and determine the tuner type
tunerStatusUpdated(discoveredTuner, TunerStatus.DISABLED, TunerStatus.ENABLED);
}
mDiscoveredTunerModel.addDiscoveredTuner(discoveredTuner);
}
/**
* Discover SDRPlay RSP tuners
*/
private void discoverSdrPlayTuners()
{
//placeholder ...
ChannelizerType channelizerType = mUserPreferences.getTunerPreference().getChannelizerType();
RspDuoSelectionMode duoSelectionMode = mUserPreferences.getTunerPreference().getRspDuoTunerMode();
//Note: we have to keep this first API instance open while we use any RSP tuners, otherwise the additional API
//instance(s) used by the individual tuners become unresponsive. Note sure why.
mSDRplay = new SDRplay();
if(mSDRplay.isAvailable())
{
try
{
List<DeviceInfo> deviceInfos = mSDRplay.getDeviceInfos();
mLog.info("Discovered [" + deviceInfos.size() + "] RSP devices from SDRplay API");
if(deviceInfos.isEmpty())
{
mSDRplay.close();
mSDRplay = null;
return;
}
for(DeviceInfo deviceInfo: deviceInfos)
{
List<DiscoveredRspTuner> tuners = TunerFactory.getRspTuners(deviceInfo, channelizerType, duoSelectionMode);
for(DiscoveredRspTuner tuner: tuners)
{
startAndConfigureTuner(tuner);
}
}
}
catch(SDRPlayException se)
{
mLog.info("Unable to get list of devices from SDRplay API");
}
}
else
{
mSDRplay.close();
mSDRplay = null;
}
}
/**
@@ -329,29 +377,43 @@ public class TunerManager implements IDiscoveredTunerStatusListener
@Override
public void tunerStatusUpdated(DiscoveredTuner discoveredTuner, TunerStatus previous, TunerStatus current)
{
mTunerConfigurationManager.tunerStatusUpdated(discoveredTuner, previous, current);
if(previous != TunerStatus.ENABLED && current == TunerStatus.ENABLED)
if(current == TunerStatus.ENABLED)
{
discoveredTuner.start();
}
if(discoveredTuner.hasTuner())
//Special handling for RSPduo to auto-update enabled state for slave device when configured for master/slave operation
if(discoveredTuner instanceof DiscoveredRspDuoTuner1 rspDuoTuner1 && rspDuoTuner1.getDeviceInfo().getDeviceSelectionMode().isMasterMode())
{
String id = rspDuoTuner1.getId();
id = id.replace(DiscoveredRspDuoTuner1.RSP_DUO_ID_PREFIX + "1", DiscoveredRspDuoTuner1.RSP_DUO_ID_PREFIX + "2");
DiscoveredTuner rspDuoTuner2 = getDiscoveredTunerModel().getDiscoveredTuner(id);
if(rspDuoTuner2 != null)
{
TunerType tunerType = discoveredTuner.getTuner().getTunerType();
//Don't fetch or create a configuration for recording tuners
if(tunerType != TunerType.RECORDING)
if(previous == TunerStatus.ENABLED && current == TunerStatus.DISABLED)
{
TunerConfiguration tunerConfiguration = mTunerConfigurationManager
.getTunerConfiguration(tunerType, discoveredTuner.getId());
if(tunerConfiguration != null)
{
discoveredTuner.setTunerConfiguration(tunerConfiguration);
mTunerConfigurationManager.saveConfigurations();
}
rspDuoTuner2.setEnabled(false);
}
else if(previous == TunerStatus.DISABLED && current == TunerStatus.ENABLED)
{
rspDuoTuner2.setEnabled(true);
rspDuoTuner2.start();
}
}
//Notify tuner configuration manager to apply tuner configurations & update disabled tuner states
mTunerConfigurationManager.tunerStatusUpdated(rspDuoTuner1, previous, current);
if(rspDuoTuner2 != null)
{
mTunerConfigurationManager.tunerStatusUpdated(rspDuoTuner2, previous, current);
}
}
else
{
//Notify tuner configuration manager to apply tuner configuration
mTunerConfigurationManager.tunerStatusUpdated(discoveredTuner, previous, current);
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 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
@@ -34,6 +34,12 @@ public enum TunerStatus
*/
DISABLED("Disabled"),
/**
* Indicates that the tuner has been removed from the system.
*/
REMOVED("Removed"),
/**
* A tuner that has an error state and is unusable
*/

View File

@@ -0,0 +1,371 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay;
import io.github.dsheirer.source.tuner.sdrplay.api.DeviceSelectionMode;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.Status;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IDeviceEventListener;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IStreamListener;
import io.github.dsheirer.source.tuner.sdrplay.api.device.Device;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.AgcMode;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.GainReduction;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.IfMode;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.LoMode;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Base RSP control implementation
*/
public abstract class ControlRsp<T extends Device> implements IControlRsp
{
private static final Logger mLog = LoggerFactory.getLogger(ControlRsp.class);
private T mDevice;
protected RspSampleRate mSampleRate = RspSampleRate.RATE_8_000;
protected int mGain;
private IDeviceEventListener mDeviceEventListener;
private IStreamListener mStreamListener;
//Streaming control lock and boolean status indicator. Access to the boolean indicator is protected by the lock.
protected ReentrantLock mStreamingLock = new ReentrantLock();
protected boolean mStreaming = false;
/**
* Constructs an instance
* @param device for the device, obtained from the API
*/
public ControlRsp(T device)
{
mDevice = device;
}
@Override
public TunerSelect getTunerSelect()
{
return TunerSelect.TUNER_1;
}
@Override
public void start() throws SDRPlayException
{
if(hasDevice())
{
getDevice().select();
//Enable automatic DC and I/Q correction
getDevice().getCompositeParameters().getControlAParameters().getDcOffset().setDC(true);
getDevice().getCompositeParameters().getControlAParameters().getDcOffset().setIQ(true);
//Setup IF, LO, and AGC Mode
getDevice().getCompositeParameters().getControlAParameters().getAgc().setAgcMode(AgcMode.DISABLE);
getDevice().setIfMode(IfMode.IF_ZERO);
getDevice().setLoMode(LoMode.AUTO);
}
else
{
throw new SDRPlayException("Unable to start - device is null");
}
}
@Override
public void stop() throws SDRPlayException
{
if(hasDevice())
{
stopStream();
getDevice().release();
clearDevice();
}
}
@Override
public void startStream()
{
mStreamingLock.lock();
try
{
if(hasDevice())
{
if(!mStreaming)
{
getDevice().initStreamA(getDeviceEventListener(), getStreamListener());
mStreaming = true;
}
}
else
{
mLog.error("Unable to start RSP device sample stream - device not started");
}
}
catch(SDRPlayException se)
{
if(se.getStatus() == Status.FAIL)
{
mLog.error("Unable to start RSP streaming - device may have been unplugged - removing.");
if(mDeviceEventListener != null)
{
mDeviceEventListener.processDeviceRemoval(getTunerSelect());
}
}
else
{
mLog.error("Unable to initialize/start streaming for RSP device", se);
}
}
finally
{
mStreamingLock.unlock();
}
}
@Override
public void stopStream()
{
mStreamingLock.lock();
try
{
if(hasDevice() && mStreaming)
{
getDevice().uninitialize();
}
}
catch(SDRPlayException se)
{
mLog.error("Unable to uninitialize/stop streaming for RSP device");
}
finally
{
mStreaming = false;
mStreamingLock.unlock();
}
}
@Override
public DeviceSelectionMode getDeviceSelectionMode()
{
//Default device selection mode for all tuners except the RSPduo
return DeviceSelectionMode.SINGLE_TUNER_1;
}
/**
* Device descriptor for this device
*/
public T getDevice()
{
return mDevice;
}
/**
* RSP device was unplugged from USB bus. Clear the device and do not attempt any further interaction with the
* device via the API.
*/
@Override
public void deviceRemoved()
{
clearDevice();
mStreamingLock.lock();
try
{
mStreaming = false;
}
finally
{
mStreamingLock.unlock();
}
}
/**
* Clears/nullifies the device. This should be invoked after stopping the device to prevent reuse.
*/
public void clearDevice()
{
mDevice = null;
}
/**
* Indicates if this control has a non-null device.
* @return true if non-null device.
*/
public boolean hasDevice()
{
return getDevice() != null;
}
/**
* Sets the sample rate
* @param sampleRate enumeration value.
* @throws SDRPlayException
*/
@Override
public void setSampleRate(RspSampleRate sampleRate) throws SDRPlayException
{
if(hasDevice())
{
mSampleRate = sampleRate;
getDevice().getTuner().setBandwidth(sampleRate.getBandwidth());
getDevice().getCompositeParameters().getDeviceParameters().getSamplingFrequency()
.setSampleRate(sampleRate.getSampleRate());
getDevice().update(getTunerSelect(), UpdateReason.DEVICE_SAMPLE_RATE);
getDevice().getCompositeParameters().getControlAParameters().getDecimation().setWideBandSignal(true);
getDevice().setDecimation(sampleRate.getDecimation());
}
else
{
throw new SDRPlayException("RSP tuner has not been started - can't apply sample rate");
}
}
/**
* Sets the gain index
* @param gain index value (0 - 28)
* @throws SDRPlayException
*/
@Override
public void setGain(int gain) throws SDRPlayException
{
validateGain(gain);
if(gain != mGain)
{
mGain = gain;
getDevice().getTuner().setGain(mGain);
}
}
@Override
public void acknowledgePowerOverload(TunerSelect tunerSelect) throws SDRPlayException
{
if(hasDevice())
{
getDevice().acknowledgePowerOverload(tunerSelect);
}
else
{
throw new SDRPlayException("Device is not initialized");
}
}
@Override
public long getTunedFrequency() throws SDRPlayException
{
if(hasDevice())
{
return getDevice().getTuner().getFrequency();
}
else
{
throw new SDRPlayException("Device is not initialized");
}
}
@Override
public void setTunedFrequency(long frequency) throws SDRPlayException
{
if(hasDevice())
{
getDevice().getTuner().setFrequency(frequency);
}
else
{
throw new SDRPlayException("Device is not initialized");
}
}
/**
* Current sample rate setting
*/
@Override
public RspSampleRate getSampleRateEnumeration()
{
return mSampleRate;
}
/**
* Current sample rate
*/
@Override
public double getCurrentSampleRate()
{
return getSampleRateEnumeration().getEffectiveSampleRate();
}
/**
* Current gain index
* @return gain index
*/
@Override
public int getGain()
{
return mGain;
}
/**
* Verifies that the requested gain index setting is within the range of valid gain values.
* @param gain to validate
* @throws SDRPlayException if the gain index value is outside the range of valid values.
*/
protected void validateGain(int gain) throws SDRPlayException
{
if(gain < GainReduction.MIN_GAIN_INDEX || gain > GainReduction.MAX_GAIN_INDEX)
{
throw new SDRPlayException("Invalid gain index value [" + gain + "]. Valid range is " +
GainReduction.MIN_GAIN_INDEX + " - " + GainReduction.MAX_GAIN_INDEX);
}
}
/**
* Registers listeners to receive device events and sample streams.
* @param deviceEventListener to receive device events
* @param streamListener to receive sample stream and related parameters.
*/
@Override
public void resister(IDeviceEventListener deviceEventListener, IStreamListener streamListener)
{
mDeviceEventListener = deviceEventListener;
mStreamListener = streamListener;
}
/**
* Registered device event listener
* @return device event listener or null if a listener has not been registered.
*/
protected IDeviceEventListener getDeviceEventListener()
{
return mDeviceEventListener;
}
/**
* Registered stream listener
* @return stream listener or null if a listener has not been registered.
*/
protected IStreamListener getStreamListener()
{
return mStreamListener;
}
}

View File

@@ -0,0 +1,122 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay;
import io.github.dsheirer.preference.source.ChannelizerType;
import io.github.dsheirer.source.tuner.TunerClass;
import io.github.dsheirer.source.tuner.TunerFactory;
import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceInfo;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceType;
/**
* Discovered SDRplay RSP tuner
*/
public abstract class DiscoveredRspTuner<R extends IControlRsp> extends DiscoveredTuner
{
private final DeviceInfo mDeviceInfo;
private final ChannelizerType mChannelizerType;
/**
* Constructs an instance
* @param deviceInfo to select the device from the API
*/
public DiscoveredRspTuner(DeviceInfo deviceInfo, ChannelizerType channelizerType)
{
mDeviceInfo = deviceInfo;
mChannelizerType = channelizerType;
}
/**
* Information about the discovered RSP device
* @return device info
*/
public DeviceInfo getDeviceInfo()
{
return mDeviceInfo;
}
/**
* Channelizer type to use for the tuner
*/
protected ChannelizerType getChannelizerType()
{
return mChannelizerType;
}
@Override
public TunerClass getTunerClass()
{
return TunerClass.RSP;
}
/**
* Type of RSP tuner device
*/
public DeviceType getDeviceType()
{
return mDeviceInfo.getDeviceType();
}
/**
* Constructs and starts the tuner
*/
@Override
public void start()
{
if(isAvailable() && !hasTuner())
{
try
{
mTuner = TunerFactory.getRspTuner(getDeviceInfo(), getChannelizerType(), this);
}
catch(Exception se)
{
setErrorMessage("Tuner unavailable [" + getId() + "]");
mTuner = null;
}
if(hasTuner())
{
try
{
mTuner.start();
}
catch(Exception se)
{
setErrorMessage("Error starting tuner [" + getId() + "]");
mTuner = null;
}
}
}
}
@Override
public String getId()
{
return getDeviceType().name() + " SER#" + getDeviceInfo().getSerialNumber();
}
@Override
public String toString()
{
return getId();
}
}

View File

@@ -0,0 +1,128 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay;
import io.github.dsheirer.source.tuner.sdrplay.api.DeviceSelectionMode;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IDeviceEventListener;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IStreamListener;
import io.github.dsheirer.source.tuner.sdrplay.api.device.Device;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
/**
* Control interface for base RSP device
*/
public interface IControlRsp
{
DeviceSelectionMode getDeviceSelectionMode();
/**
* Device descriptor for this RSP
* @return device descriptor
*/
Device getDevice();
/**
* Process an RSP device removal. Device memory resources should be nullified and the software should not attempt
* any further interaction with the device via the API.
*/
void deviceRemoved();
/**
* Selected tuner for this RSP.
* @return selected tuner.
*/
TunerSelect getTunerSelect();
/**
* Starts the device
*/
void start() throws SDRPlayException;
/**
* Stops the device
*/
void stop() throws SDRPlayException;
/**
* Registers listeners to receive device events and streaming samples when startStream() is invoked.
* @param deviceEventListener to receive device events
* @param streamListener to receive sample stream and related parameters.
*/
void resister(IDeviceEventListener deviceEventListener, IStreamListener streamListener);
/**
* Starts the sample stream and delivers the samples to the registered listener.
*/
void startStream();
/**
* Stops the sample stream.
*/
void stopStream();
/**
* Callback to acknowledge a power overload event.
* @param tunerSelect identifies the tuner where the power overload is happening.
*/
void acknowledgePowerOverload(TunerSelect tunerSelect) throws SDRPlayException;
/**
* Current center tune frequency
* @return frequency in Hertz
*/
long getTunedFrequency() throws SDRPlayException;
/**
* Sets the center tune frequency
* @param frequency in Hertz
*/
void setTunedFrequency(long frequency) throws SDRPlayException;
/**
* Current sample rate enumeration value
* @return sample rate enumeration.
*/
RspSampleRate getSampleRateEnumeration();
/**
* Sets the sample rate.
* @param rspSampleRate enumeration value.
*/
void setSampleRate(RspSampleRate rspSampleRate) throws SDRPlayException;
/**
* Current sample rate value.
* @return sample rate in Hertz
*/
double getCurrentSampleRate();
/**
* Sets the gain index value.
* @param gain index value (0 - 28)
*/
void setGain(int gain) throws SDRPlayException;
/**
* Current gain index value
* @return gain index value (0 - 28)
*/
int getGain();
}

View File

@@ -0,0 +1,141 @@
/*
* *****************************************************************************
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay;
import io.github.dsheirer.buffer.AbstractNativeBuffer;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
import java.util.Iterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Native buffer implementation for RSP tuner I/Q sample buffers.
*
* Note: in testing with API v3.07, the daemon returns 2016 samples in each of the I and Q arrays.
*/
public class RspNativeBuffer extends AbstractNativeBuffer
{
private static final Logger mLog = LoggerFactory.getLogger(RspNativeBuffer.class);
private static final float SAMPLE_TO_FLOAT = 1.0f / 32768.0f;
private short[] mISamples;
private short[] mQSamples;
/**
* Constructs an instance
* @param i samples array
* @param q samples array
* @param timestamp for the first sample
* @param samplesPerMillisecond used to calculate sub-buffer fragment timestamp offsets from the start of this buffer.
*/
public RspNativeBuffer(short[] i, short[] q, long timestamp, float samplesPerMillisecond)
{
super(timestamp, samplesPerMillisecond);
mISamples = i;
mQSamples = q;
}
/**
* Iterator over samples that produces complex sample buffers.
*/
@Override
public Iterator<ComplexSamples> iterator()
{
return new SampleIterator();
}
/**
* Iterator over samples that produces interleaved complex sample buffers
*/
@Override
public Iterator<InterleavedComplexSamples> iteratorInterleaved()
{
return new InterleavedSampleIterator();
}
@Override
public int sampleCount()
{
return mISamples.length * 2;
}
/**
* Iterator providing (non-interleaved) complex sample buffers
*/
private class SampleIterator implements Iterator<ComplexSamples>
{
private int mSamplePointer;
@Override
public boolean hasNext()
{
return mSamplePointer < mISamples.length;
}
@Override
public ComplexSamples next()
{
float[] i = new float[mISamples.length];
float[] q = new float[mISamples.length];
for(int x = 0; x < mISamples.length; x++)
{
i[x] = mISamples[x] * SAMPLE_TO_FLOAT;
q[x] = mQSamples[x] * SAMPLE_TO_FLOAT;
}
mSamplePointer += mISamples.length;
return new ComplexSamples(i, q, getTimestamp());
}
}
/**
* Interator providing interleaved sample buffers.
*/
private class InterleavedSampleIterator implements Iterator<InterleavedComplexSamples>
{
private int mSamplePointer;
@Override
public boolean hasNext()
{
return mSamplePointer < mISamples.length;
}
@Override
public InterleavedComplexSamples next()
{
float[] samples = new float[mISamples.length * 2];
int index = 0;
for(int x = 0; x < mISamples.length; x++)
{
samples[index++] = mISamples[x] * SAMPLE_TO_FLOAT;
samples[index++] = mQSamples[x] * SAMPLE_TO_FLOAT;
}
mSamplePointer += mISamples.length;
return new InterleavedComplexSamples(samples, getTimestamp());
}
}
}

View File

@@ -0,0 +1,184 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay;
import io.github.dsheirer.source.tuner.sdrplay.api.device.Decimate;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Bandwidth;
import java.util.EnumSet;
/**
* RSP device Sample Rate, Bandwidth and Decimation enumeration
*
* Note: final effective sample rate must be greater than IF bandwidth setting to avoid aliasing. The available IF
* bandwidth values effectively dictate the available sample rates
*/
public enum RspSampleRate
{
RATE_0_250(8_000_000, 016_000, Bandwidth.BW_0_300, Decimate.X32, "0.250 MHz (0.234 usable)"),
RATE_0_500(8_000_000, 024_000, Bandwidth.BW_0_600, Decimate.X16, "0.500 MHz (0.476 usable)"),
RATE_1_000(8_000_000, 100_000, Bandwidth.BW_1_536, Decimate.X8, "1.000 MHz (0.900 usable)"),
RATE_1_500(6_000_000, 140_000, Bandwidth.BW_1_536, Decimate.X4, "1.500 MHz (1.360 usable)"),
RATE_3_000(6_000_000, 300_000, Bandwidth.BW_5_000, Decimate.X2, "3.000 MHz (2.700 usable)"),
RATE_4_000(8_000_000, 340_000, Bandwidth.BW_5_000, Decimate.X2, "4.000 MHz (3.560 usable)"),
RATE_5_000(5_000_000, 880_000, Bandwidth.BW_5_000, Decimate.X1, "5.000 MHz (4.120 usable)"),
RATE_6_000(6_000_000, 800_000, Bandwidth.BW_6_000, Decimate.X1, "6.000 MHz (5.200 usable)"),
RATE_7_000(7_000_000, 1_040_000, Bandwidth.BW_7_000, Decimate.X1, "7.000 MHz (5.960 usable)"),
RATE_8_000(8_000_000, 1_060_000, Bandwidth.BW_8_000, Decimate.X1, "8.000 MHz (6.940 usable)"),
RATE_9_000(9_000_000, 1_620_000, Bandwidth.BW_8_000, Decimate.X1, "9.000 MHz (7.380 usable)"),
RATE_10_000(10_000_000, 1_500_000, Bandwidth.BW_8_000, Decimate.X1, "10.000 MHz (8.500 usable)"),
/**
* Note: in dual tuner mode, available sample rates are 6 or 8 MHz with an effective output rate of
* 2 MHz. Decimation is applied against the final 2 MHz rate, not the original 6/8 sampling rate.
*/
DUO_RATE_0_500(8_000_000, 50_000, Bandwidth.BW_8_000, Decimate.X4, "0.500 MHz (0.450 usable)"),
DUO_RATE_1_000(8_000_000, 50_000, Bandwidth.BW_8_000, Decimate.X2, "1.000 MHz (0.950 usable)"),
DUO_RATE_1_500(6_000_000, 0, Bandwidth.BW_6_000, Decimate.X1, "1.500 MHz (1.500 usable)"),
DUO_RATE_2_000(8_000_000, 0, Bandwidth.BW_8_000, Decimate.X1, "2.000 MHz (2.000 usable)"),
UNDEFINED(0, 0, Bandwidth.UNDEFINED, Decimate.X1, "UNDEFINED");
private long mSampleRate;
private long mUnusable;
private Bandwidth mBandwidth;
private Decimate mDecimation;
private String mDescription;
/**
* Constructs an instance
* @param sampleRate in hertz
* @param unusable bandwidth (total) in Hertz due to IF or decimation filter roll-off at spectrum edges
* @param bandwidth of the frequency spectrum
* @param decimation to be applied to the original sample rate to achieve the effective sample rate
* @param description for UI display
*/
RspSampleRate(long sampleRate, long unusable, Bandwidth bandwidth, Decimate decimation, String description)
{
mSampleRate = sampleRate;
mUnusable = unusable;
mBandwidth = bandwidth;
mDecimation = decimation;
mDescription = description;
}
/**
* Single tuner sample rates for all devices operating in single tuner mode
*/
public static EnumSet<RspSampleRate> SINGLE_TUNER_SAMPLE_RATES = EnumSet.range(RATE_0_250, RATE_10_000);
/**
* RSPduo dual-tuner mode sample rates
*/
public static EnumSet<RspSampleRate> DUAL_TUNER_SAMPLE_RATES = EnumSet.range(DUO_RATE_0_500, DUO_RATE_2_000);
/**
* Sample Rate
* @return sample rate (Hz)
*/
public long getSampleRate()
{
return mSampleRate;
}
/**
* Usable bandwidth in range 0.0 to 1.0, where 1.0 is 100% usable bandwidth
*/
public double getUsableBandwidth()
{
if(getSampleRate() != 0)
{
return 1.0 - ((double)mUnusable / (double)getEffectiveSampleRate());
}
return 0.0;
}
/**
* Indicates if this is a sample rate supported by the RSPduo operating in dual-tuner mode.
* @return true if this is a dual-tuner sample rate.
*/
public boolean isDualTunerSampleRate()
{
return DUAL_TUNER_SAMPLE_RATES.contains(this);
}
/**
* Sample size in bits. Can be used to adjust spectral display for effective dynamic range.
* @return sample size in bits.
*/
public int getSampleSize()
{
return mDecimation.getSampleSize();
}
/**
* Decimation rate to be applied against sample rate.
* @return decimation value
*/
public Decimate getDecimation()
{
return mDecimation;
}
/**
* Indicates if this sample rate specifies decimation
*/
public boolean hasDecimation()
{
return getDecimation().isEnabled();
}
/**
* Effective Sample Rate (sample rate / decimation). Note: for RSPduo operating in dual-tuner mode, an
* inherent x4 decimation is applied in the hardware.
* @return effective sample rate (Hz)
*/
public long getEffectiveSampleRate()
{
if(isDualTunerSampleRate())
{
//Dual tuner sample rate is specified at 8 MHz, but there is an inherent x4 decimation to 2 MHz
//on top of the user specified decimation rate.
return getSampleRate() / getDecimation().getValue() / 4;
}
else
{
return getSampleRate() / getDecimation().getValue();
}
}
/**
* Bandwidth entry
*/
public Bandwidth getBandwidth()
{
return mBandwidth;
}
/**
* Overrides the default string representation to use the UI description/label.
* @return string representation of the entry
*/
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,104 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay;
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;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.IControlRspDuoTuner1;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.IControlRspDuoTuner2;
/**
* Generic RSP tuner with a device specific tuner controller implementation.
*/
public class RspTuner extends Tuner
{
/**
* Constructs an instance
* @param tunerController for controlling the tuner
* @param tunerErrorListener to process errors from this tuner
* @param channelizerType to use with this tuner
*/
public RspTuner(RspTunerController tunerController, ITunerErrorListener tunerErrorListener, ChannelizerType channelizerType)
{
super(tunerController, tunerErrorListener, channelizerType);
}
@Override
public int getMaximumUSBBitsPerSecond()
{
//12-bits per sample, 2 samples per frame, 10 MHz sample rate
return 320_000_000;
}
@Override
public String getUniqueID()
{
return getRspTunerController().getControlRsp().getDevice().getSerialNumber();
}
@Override
public TunerClass getTunerClass()
{
return TunerClass.RSP;
}
/**
* RSP Tuner controller for this tuner
*/
public RspTunerController getRspTunerController()
{
return (RspTunerController)getTunerController();
}
@Override
public String getPreferredName()
{
if(getRspTunerController().getControlRsp() instanceof IControlRspDuoTuner1 &&
getRspTunerController().getControlRsp().getDevice() != null)
{
return getRspTunerController().getControlRsp().getDevice().getDeviceType() +
" SER:" + getRspTunerController().getControlRsp().getDevice().getSerialNumber() + " Tuner 1";
}
else if(getRspTunerController().getControlRsp() instanceof IControlRspDuoTuner2 &&
getRspTunerController().getControlRsp().getDevice() != null)
{
return getRspTunerController().getControlRsp().getDevice().getDeviceType() +
" SER:" + getRspTunerController().getControlRsp().getDevice().getSerialNumber() + " Tuner 2";
}
else if(getRspTunerController().getControlRsp() instanceof IControlRsp &&
getRspTunerController().getControlRsp().getDevice() != null)
{
return getRspTunerController().getControlRsp().getDevice().getDeviceType() +
" SER:" + getRspTunerController().getControlRsp().getDevice().getSerialNumber();
}
else
{
return "RSP Tuner - Device Not Available";
}
}
@Override
public double getSampleSize()
{
return getRspTunerController().getControlRsp().getSampleRateEnumeration().getSampleSize();
}
}

View File

@@ -0,0 +1,106 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.GainReduction;
import io.github.dsheirer.source.tuner.sdrplay.rsp1a.Rsp1aTunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.rsp2.Rsp2TunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.RspDuoTuner1Configuration;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.RspDuoTuner2Configuration;
import io.github.dsheirer.source.tuner.sdrplay.rspDx.RspDxTunerConfiguration;
/**
* Abstract RSP tuner configuration
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Rsp1aTunerConfiguration.class, name = "rsp1aTunerConfiguration"),
@JsonSubTypes.Type(value = Rsp2TunerConfiguration.class, name = "rsp2TunerConfiguration"),
@JsonSubTypes.Type(value = RspDuoTuner1Configuration.class, name = "rspDuoTuner1Configuration"),
@JsonSubTypes.Type(value = RspDuoTuner2Configuration.class, name = "rspDuoTuner2Configuration"),
@JsonSubTypes.Type(value = RspDxTunerConfiguration.class, name = "rspDxTunerConfiguration"),
})
public abstract class RspTunerConfiguration extends TunerConfiguration
{
public static final RspSampleRate DEFAULT_SINGLE_TUNER_SAMPLE_RATE = RspSampleRate.RATE_8_000;
public static final RspSampleRate DEFAULT_DUAL_TUNER_SAMPLE_RATE = RspSampleRate.DUO_RATE_2_000;
private RspSampleRate mRspSampleRate = DEFAULT_SINGLE_TUNER_SAMPLE_RATE;
private int mGain = 14;
/**
* JAXB Constructor
*/
public RspTunerConfiguration()
{
}
/**
* Constructs an instance with the specified unique id
* @param uniqueId for the tuner
*/
public RspTunerConfiguration(String uniqueId)
{
super(uniqueId);
}
/**
* Sample rate for the tuner
*/
@JacksonXmlProperty(isAttribute = true, localName = "sampleRate")
public RspSampleRate getSampleRate()
{
return mRspSampleRate;
}
/**
* Sets the sample rate for the tuner
*/
public void setSampleRate(RspSampleRate rspSampleRate)
{
mRspSampleRate = rspSampleRate;
}
/**
* Gain index to use
* @return gain index, 0 - 28
*/
@JacksonXmlProperty(isAttribute = true, localName = "gain")
public int getGain()
{
return mGain;
}
/**
* Sets the gain index
* @param gain index, 0 - 28
*/
public void setGain(int gain)
{
if(GainReduction.MIN_GAIN_INDEX <= gain && gain <= GainReduction.MAX_GAIN_INDEX)
{
mGain = gain;
}
}
}

View File

@@ -0,0 +1,325 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay;
import io.github.dsheirer.buffer.INativeBuffer;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.source.SourceException;
import io.github.dsheirer.source.tuner.ITunerErrorListener;
import io.github.dsheirer.source.tuner.TunerController;
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IDeviceEventListener;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IStreamListener;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.StreamCallbackParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.EventType;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.GainCallbackParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.PowerOverloadCallbackParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.RspDuoModeCallbackParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract/Base RSP tuner controller
*/
public abstract class RspTunerController<I extends IControlRsp> extends TunerController
implements IDeviceEventListener, IStreamListener
{
private static final Logger mLog = LoggerFactory.getLogger(RspTunerController.class);
protected static final long MINIMUM_FREQUENCY = 100_000;
protected static final long MAXIMUM_FREQUENCY = 2_000_000_000;
protected static final int MIDDLE_UNUSABLE_BANDWIDTH = 0;
private I mControlRsp;
/**
* Abstract tuner controller class. The tuner controller manages frequency bandwidth and currently tuned channels
* that are being fed samples from the tuner.
*
* @param controlRsp that is the RSP tuner
* @param tunerErrorListener to monitor errors produced from this tuner controller
*/
public RspTunerController(I controlRsp, ITunerErrorListener tunerErrorListener)
{
super(tunerErrorListener);
mControlRsp = controlRsp;
//Register this controller to receive device events and sample streams when startStream() is invoked.
mControlRsp.resister(this, this);
setMinimumFrequency(MINIMUM_FREQUENCY);
setMaximumFrequency(MAXIMUM_FREQUENCY);
setMiddleUnusableHalfBandwidth(MIDDLE_UNUSABLE_BANDWIDTH);
setUsableBandwidthPercentage(1.0); //Initial value
}
@Override
public void apply(TunerConfiguration config) throws SourceException
{
if(config instanceof RspTunerConfiguration rtc)
{
//This sets the frequency and software PPM
super.apply(config);
try
{
setSampleRate(rtc.getSampleRate());
}
catch(SDRPlayException se)
{
mLog.error("Error setting RSP sample rate to " + rtc.getSampleRate(), se);
}
try
{
getControlRsp().setGain(rtc.getGain());
}
catch(SDRPlayException se)
{
mLog.error("Error setting RSP gain index to " + rtc.getGain());
}
}
}
/**
* The RSP control for this tuner controller
*/
public I getControlRsp()
{
return mControlRsp;
}
@Override
public TunerSelect getTunerSelect()
{
return mControlRsp.getTunerSelect();
}
@Override
public void processStream(short[] inphase, short[] quadrature,
StreamCallbackParameters parameters, boolean reset)
{
//RSP I/Q sample buffers are small and don't currently get fragmented by the RspNativeBuffer, so we don't
//calculate the sub-buffer samples per millisecond value -- just use a constant value of 0.
mNativeBufferBroadcaster.broadcast(new RspNativeBuffer(inphase, quadrature, System.currentTimeMillis(), 0.0f));
if(reset)
{
// mLog.info(getControlRsp().getDeviceDescriptor().getDeviceType() + " - sample stream was reset");
}
if(parameters.isGainReductionChanged())
{
// mLog.info("^^^ Got a gain reduction change");
}
if(parameters.isRfFrequencyChanged())
{
// mLog.info("^^^ Got a frequency changed");
}
if(parameters.isSampleRateChanged())
{
// mLog.info("^^^ Got a sample rate changed");
}
}
/**
* Starts this RSP tuner and attempts to claim the device via the API
* @throws SourceException
*/
@Override
public void start() throws SourceException
{
try
{
mControlRsp.start();
}
catch(SDRPlayException se)
{
throw new SourceException("Unable to select tuner - in use");
}
}
@Override
public void stop()
{
try
{
mControlRsp.stop();
}
catch(SDRPlayException se)
{
mLog.error("Error releasing RSP tuner device", se);
}
}
/**
* Adds the listener to receive native buffers and starts the sample stream when this is the first listener.
* @param listener to add
*/
@Override
public void addBufferListener(Listener<INativeBuffer> listener)
{
mBufferListenerLock.lock();
try
{
if(!hasBufferListeners())
{
mControlRsp.startStream();
}
super.addBufferListener(listener);
}
finally
{
mBufferListenerLock.unlock();
}
}
/**
* Removes the listener from receiving native buffers and stops the sample stream when this is the last listener.
* @param listener to remove
*/
@Override
public void removeBufferListener(Listener<INativeBuffer> listener)
{
mBufferListenerLock.lock();
try
{
super.removeBufferListener(listener);
if(!hasBufferListeners())
{
mControlRsp.stopStream();
}
}
finally
{
mBufferListenerLock.unlock();
}
}
/**
* Currently tuned frequency
* @return frequency in Hertz
* @throws SourceException if there is an error
*/
@Override
public long getTunedFrequency() throws SourceException
{
try
{
return getControlRsp().getTunedFrequency();
}
catch(SDRPlayException se)
{
throw new SourceException("Error setting tuned frequency", se);
}
}
/**
* Sets the center tuned frequency.
* @param frequency in Hertz
* @throws SourceException if there is an error
*/
@Override
public void setTunedFrequency(long frequency) throws SourceException
{
try
{
getControlRsp().setTunedFrequency(frequency);
}
catch(SDRPlayException se)
{
throw new SourceException("Unable to set center frequency [" + frequency + "]", se);
}
}
/**
* Sets the sample rate
* @param rspSampleRate to apply
* @throws SDRPlayException if there is an error
*/
public void setSampleRate(RspSampleRate rspSampleRate) throws SDRPlayException
{
getControlRsp().setSampleRate(rspSampleRate);
try
{
mFrequencyController.setSampleRate((int) rspSampleRate.getEffectiveSampleRate());
}
catch(SourceException se)
{
mLog.error("Error setting sample rate in frequency controller");
}
//Update the usable bandwidth based on the sample rate and filtered bandwidth
setUsableBandwidthPercentage(rspSampleRate.getUsableBandwidth());
}
@Override
public double getCurrentSampleRate() throws SourceException
{
return getControlRsp().getCurrentSampleRate();
}
@Override
public int getBufferSampleCount()
{
return 128;
}
//Device Event Listener interface methods ...
@Override
public void processEvent(EventType eventType, TunerSelect tunerSelect) {}
@Override
public void processGainChange(TunerSelect tunerSelect, GainCallbackParameters parameters) {}
@Override
public void processRspDuoModeChange(TunerSelect tunerSelect, RspDuoModeCallbackParameters parameters) {}
@Override
public void processPowerOverload(TunerSelect tunerSelect, PowerOverloadCallbackParameters parameters)
{
if(getControlRsp() != null)
{
try
{
getControlRsp().acknowledgePowerOverload(tunerSelect);
}
catch(SDRPlayException se)
{
mLog.error("Unable to acknowledge power overload for [" + tunerSelect + "]", se);
}
}
}
@Override
public void processDeviceRemoval(TunerSelect tunerSelect)
{
mLog.info("Processing device removal for tuner [" + tunerSelect + "] controller class [" + getClass().getSimpleName() + "]");
//Command the control RSP to nullify the device so that we cease all attempts to control the device via the API
if(getControlRsp() != null)
{
getControlRsp().deviceRemoved();
}
//Signal that tuner is removed so parent tuner and discovered tuner wrapper can do graceful removal/cleanup
tunerRemoved();
}
}

View File

@@ -0,0 +1,108 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.GainReduction;
import io.github.dsheirer.source.tuner.ui.TunerEditor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSlider;
/**
* Abstract RSP tuner editor
*/
public abstract class RspTunerEditor<C extends RspTunerConfiguration> extends TunerEditor<RspTuner,C>
{
private Logger mLog = LoggerFactory.getLogger(RspTunerEditor.class);
private JSlider mGainSlider;
private JLabel mGainValueLabel;
/**
* Constructs an instance
* @param userPreferences for preference settings
* @param tunerManager to notify for state changes
* @param discoveredTuner to be edited.
*/
public RspTunerEditor(UserPreferences userPreferences, TunerManager tunerManager, DiscoveredRspTuner discoveredTuner)
{
super(userPreferences, tunerManager, discoveredTuner);
}
private RspTunerController getTunerController()
{
return (RspTunerController) getTuner().getTunerController();
}
/**
* Gain reduction slider control
*/
protected JSlider getGainSlider()
{
if(mGainSlider == null)
{
mGainSlider = new JSlider(JSlider.HORIZONTAL, GainReduction.MIN_GAIN_INDEX,
GainReduction.MAX_GAIN_INDEX, GainReduction.MIN_GAIN_INDEX);
mGainSlider.setEnabled(false);
mGainSlider.setMajorTickSpacing(1);
mGainSlider.setPaintTicks(true);
mGainSlider.addChangeListener(event ->
{
int gain = mGainSlider.getValue();
if(hasTuner() && !isLoading())
{
try
{
getTunerController().getControlRsp().setGain(gain);
save();
}
catch(Exception e)
{
mLog.error("Couldn't set RSP gain to:" + gain, e);
JOptionPane.showMessageDialog(mGainSlider, "Couldn't set RSP gain value to " + gain);
}
}
getGainValueLabel().setText(String.valueOf(gain));
});
}
return mGainSlider;
}
/**
* Label for displaying current gain index value
*/
protected JLabel getGainValueLabel()
{
if(mGainValueLabel == null)
{
mGainValueLabel = new JLabel("0");
mGainValueLabel.setEnabled(false);
}
return mGainValueLabel;
}
}

View File

@@ -0,0 +1,106 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api;
import io.github.dsheirer.source.tuner.sdrplay.api.device.RspDuoMode;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
import java.util.EnumSet;
/**
* Enumeration of modes that indicate how each SDRplay RSP device can be selected
*/
public enum DeviceSelectionMode
{
//All RSP devices
SINGLE_TUNER_1("Single Tuner 1", RspDuoMode.SINGLE_TUNER, TunerSelect.TUNER_1),
SINGLE_TUNER_2("Single Tuner 2", RspDuoMode.SINGLE_TUNER, TunerSelect.TUNER_2),
MASTER_TUNER_1("Master - Tuner 1", RspDuoMode.MASTER, TunerSelect.TUNER_1),
SLAVE_TUNER_2("Slave - Tuner 2", RspDuoMode.SLAVE, TunerSelect.TUNER_2);
private String mDescription;
private RspDuoMode mRspDuoMode;
private TunerSelect mTunerSelect;
/**
* Private constructor
* @param description of the mode
* @param rspDuoMode that corresponds to the mode
* @param tunerSelect tuner(s) that correspond to the mode
*/
DeviceSelectionMode(String description, RspDuoMode rspDuoMode, TunerSelect tunerSelect)
{
mDescription = description;
mRspDuoMode = rspDuoMode;
mTunerSelect = tunerSelect;
}
/**
* Set of all selection modes available for the RSPduo
*/
public static final EnumSet<DeviceSelectionMode> MASTER_MODES = EnumSet.of(MASTER_TUNER_1);
public static final EnumSet<DeviceSelectionMode> SLAVE_MODES = EnumSet.of(SLAVE_TUNER_2);
public static final EnumSet<DeviceSelectionMode> SINGLE_TUNER_MODES = EnumSet.of(SINGLE_TUNER_1, SINGLE_TUNER_2);
/**
* RSPduo mode associated with the selection mode
*/
public RspDuoMode getRspDuoMode()
{
return mRspDuoMode;
}
/**
* Indicates if this mode is designated as a master mode.
*/
public boolean isMasterMode()
{
return MASTER_MODES.contains(this);
}
/**
* Indicates if this mode is designated as a slave mode.
*/
public boolean isSlaveMode()
{
return SLAVE_MODES.contains(this);
}
/**
* Indicates if this is a single-tuner mode
*/
public boolean isSingleTunerMode()
{
return SINGLE_TUNER_MODES.contains(this);
}
/**
* Tuner(s) associated with the selection mode
*/
public TunerSelect getTunerSelect()
{
return mTunerSelect;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,15 @@
SDRplay API 3.07
Auto-created from sdrplay api header files using JDK 17 jextract tool:
1. Install the sdrplay api
2. On Linux, headers are located here: /usr/local/include/*.h
3. cd into the (project)/jSDRplay/sdrplay-api/src/main/java/ directory
4. Run: jextract -t io.github.dsheirer.sdrplay.api /usr/local/include/sdrplay_api.h -l libsdrplay_api --source
IntelliJ setup
1. Run configuration
2. JVM Option: --enable-native-access=ALL-UNNAMED
3. Add library location to the java.library.path:
Linux: /usr/local/lib
Windows: ??
MacOS: ??

View File

@@ -0,0 +1,63 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api;
/**
* SDRplay checked exception.
*/
public class SDRPlayException extends Exception
{
private Status mStatus = Status.UNKNOWN;
/**
* Creates an exception
* @param message for the exception
*/
public SDRPlayException(String message)
{
super(message);
}
/**
* Creates an operation exception
* @param message for the exception
* @param status of the operation
*/
public SDRPlayException(String message, Status status)
{
super(message + " Status:" + status);
mStatus = status;
}
/**
* Creates an exception
* @param message for the exception
* @param throwable nested exception
*/
public SDRPlayException(String message, Throwable throwable)
{
super(message, throwable);
}
public Status getStatus()
{
return mStatus;
}
}

View File

@@ -0,0 +1,49 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api;
import java.util.ArrayList;
import java.util.List;
/**
* SDRplay failed update request checked exception.
*/
public class SDRPlayUpdateException extends SDRPlayException
{
private List<UpdateReason> mUpdateReasons = new ArrayList<>();
/**
* Creates an operation exception
* @param status of the operation
* @param updateReasons that were submitted
*/
public SDRPlayUpdateException(Status status, List<UpdateReason> updateReasons)
{
super("Unable to update device parameters: " + updateReasons, status);
}
/**
* List of update reasons that failed.
*/
public List<UpdateReason> getUpdateReasons()
{
return mUpdateReasons;
}
}

View File

@@ -0,0 +1,708 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.CallbackFunctions;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IDeviceEventListener;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IStreamListener;
import io.github.dsheirer.source.tuner.sdrplay.api.device.Device;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceFactory;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceInfo;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceType;
import io.github.dsheirer.source.tuner.sdrplay.api.device.IDeviceStruct;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
import io.github.dsheirer.source.tuner.sdrplay.api.error.DebugLevel;
import io.github.dsheirer.source.tuner.sdrplay.api.error.ErrorInformation;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.CompositeParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.CompositeParametersFactory;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DeviceT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_ErrorInfoT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.ValueLayout;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* SDRplay API wrapper.
*
* Note: the jextract auto-generated RuntimeHelper contains a static block that attempts to load the sdrplay_api
* library. This approach fails because the API is installed to a non-default location. Comment out the library
* load code in the RuntimeHelper and we'll directly load the library.
*
* // System.loadLibrary("libsdrplay_api");
*/
public class SDRplay
{
public static final String SDRPLAY_API_LIBRARY_NAME = "sdrplay_api";
public static final String SDRPLAY_API_PATH_LINUX = "/usr/local/lib/libsdrplay_api.so";
public static final String SDRPLAY_API_PATH_MAC_OS = "/usr/local/lib/libsdrplay_api.dylib";
public static final String SDRPLAY_API_PATH_WINDOWS = System.getenv("ProgramFiles") +
"\\SDRplay\\API\\" + (System.getProperty("sun.arch.data.model").contentEquals("64") ? "x64" : "x86") +
"\\" + SDRPLAY_API_LIBRARY_NAME;
public static final String JAVA_LIBRARY_PATH_KEY = "java.library.path";
private static final Logger mLog = LoggerFactory.getLogger(SDRplay.class);
/**
* Foreign memory allocation resource scope
*/
private final MemorySession mGlobalMemorySession = MemorySession.global();
/**
* Indicates if libsdrplay_api.xx library was found and loaded.
*/
private boolean mSdrplayLibraryLoaded;
/**
* Indicates if the library is available, meaning that the host system library was loaded AND it supports the
* correct API version
*/
private boolean mAvailable;
/**
* Map of (reusable) callback functions for each device. Key value is the device handle memory address
*/
private final Map<MemoryAddress, CallbackFunctions> mDeviceCallbackFunctionsMap = new HashMap<>();
/**
* Detected version of the API installed on the local system.
*/
private Version mVersion;
/**
* Controls logging of library load status so that it only gets logged once. Set to false once initial logging complete
*/
private static boolean sLibraryLoadStatusLogging = true;
/**
* Constructs an instance of the SDRPLay API
*/
public SDRplay()
{
mSdrplayLibraryLoaded = loadLibrary();
if(mSdrplayLibraryLoaded)
{
Status openStatus = open();
if(sLibraryLoadStatusLogging)
{
mLog.info("API library - open status: " + openStatus);
}
mAvailable = openStatus.success() && getVersion().isSupported();
}
else
{
if(sLibraryLoadStatusLogging)
{
mLog.info("API library was not loaded");
}
mAvailable = false;
}
if(isAvailable())
{
if(sLibraryLoadStatusLogging)
{
mLog.info("API library v" + getVersion() + " - loaded");
}
}
else
{
if(sLibraryLoadStatusLogging)
{
mLog.info("API library is not available.");
}
}
sLibraryLoadStatusLogging = false;
}
/**
* Global Memory Session for this API instance
*/
private MemorySession getGlobalMemorySession()
{
return mGlobalMemorySession;
}
/**
* Attempts to load the SDRPlay API library from the local system.
*
* @return true if library was loaded successfully.
*/
private boolean loadLibrary()
{
try
{
String libraryPath = getSDRplayLibraryPath();
if(sLibraryLoadStatusLogging)
{
mLog.info("Loading API Library from default install path: " + libraryPath);
}
System.loadLibrary(SDRPLAY_API_LIBRARY_NAME);
return true;
}
catch(Throwable t)
{
mLog.error("Unable to load SDRplay API library from default install path. Loading from java system library path", t);
try
{
System.loadLibrary(SDRPLAY_API_LIBRARY_NAME);
return true;
}
catch(Throwable t2)
{
String name = System.mapLibraryName(SDRPLAY_API_LIBRARY_NAME);
if(sLibraryLoadStatusLogging)
{
mLog.warn("SDRPlay API library not found/installed on this system. Ensure the API is installed either " +
"in the default install location or the install location is included in the " +
"'java.library.path' JVM property contains path to the library file [" + name +
"]. Current library path property contents: " + System.getProperty(JAVA_LIBRARY_PATH_KEY), t);
}
}
}
return false;
}
/**
* List of devices available via the API
* @return list of device infos.
* @throws SDRPlayException if there is an error
*/
public List<DeviceInfo> getDeviceInfos() throws SDRPlayException
{
return DeviceFactory.parseDeviceInfos(getDeviceStructures());
}
/**
* List of device structures for devices available from the API
* @return list of device structures
* @throws SDRPlayException if there is an error
*/
public List<IDeviceStruct> getDeviceStructures() throws SDRPlayException
{
List<IDeviceStruct> deviceStructs = new ArrayList<>();
//Get a version-correct array of DeviceT structures
MemorySegment devicesArray = DeviceFactory.createDeviceArray(getVersion(), getGlobalMemorySession());
MemorySegment deviceCount = getGlobalMemorySession().allocate(ValueLayout.JAVA_INT, 0);
Status status = Status.fromValue(sdrplay_api_h.sdrplay_api_GetDevices(devicesArray, deviceCount,
sdrplay_api_h.SDRPLAY_MAX_DEVICES()));
if(status.success())
{
int count = deviceCount.get(ValueLayout.JAVA_INT, 0);
deviceStructs.addAll(DeviceFactory.parseDeviceStructs(getVersion(), devicesArray, count));
}
else
{
mLog.error("Couldn't load RSP devices from API. Status: " + status);
}
return deviceStructs;
}
/**
* Find an RSP device descriptor by serial number.
* @param serialNumber to search for
* @return matching device descriptor, or null.
* @throws SDRPlayException if there is an error parsing the device structures
*/
public DeviceInfo getDevice(String serialNumber) throws SDRPlayException
{
for(DeviceInfo deviceInfo: getDeviceInfos())
{
if(deviceInfo.getSerialNumber().equals(serialNumber))
{
return deviceInfo;
}
}
return null;
}
/**
* Obtains the device that matches the device info argument.
* @param deviceInfo to match
* @return non-null device
* @throws SDRPlayException
*/
public Device getDevice(DeviceInfo deviceInfo) throws SDRPlayException
{
Device device = null;
if(isAvailable())
{
List<IDeviceStruct> deviceStructs = getDeviceStructures();
for(IDeviceStruct deviceStruct: deviceStructs)
{
if(deviceInfo.matches(deviceStruct))
{
device = DeviceFactory.createDevice(this, deviceStruct);
break;
}
}
}
if(device == null)
{
throw new SDRPlayException("Unable to find RSP device");
}
return device;
}
/**
* Finds the first device that matches the specified device type.
*
* @param deviceType to find
* @return the specified device type or null.
*/
public DeviceInfo getDeviceInfo(DeviceType deviceType) throws SDRPlayException
{
for(DeviceInfo deviceInfo : getDeviceInfos())
{
if(deviceInfo.getDeviceType() == deviceType)
{
return deviceInfo;
}
}
return null;
}
/**
* Selects the device for exclusive use. This method is invoked by the device instance.
*
* @param memorySegment of the device in foreign memory
* @throws SDRPlayException if the device argument was not created by this API instance or if unable to lock or
* unlock the device API for exclusive use, or if unable to select the device.
*/
public void select(MemorySegment memorySegment) throws SDRPlayException
{
lockDeviceApi();
Status selectStatus = Status.fromValue(sdrplay_api_h.sdrplay_api_SelectDevice(memorySegment));
unlockDeviceApi();
if(selectStatus.fail())
{
throw new SDRPlayException("Unable to select the device", selectStatus);
}
}
/**
* Releases the device from exclusive use. This method is invoked by the device instance.
*
* @param memorySegment of the device in foreign memory
* @throws SDRPlayException if the device argument was not created by this API instance or if unable to release
* the device
*/
public void release(MemorySegment memorySegment) throws SDRPlayException
{
Status status = Status.fromValue(sdrplay_api_h.sdrplay_api_ReleaseDevice(memorySegment));
if(status.fail())
{
mLog.info("API call to release device failed, however device is effectively released now.");
}
}
/**
* Retrieves the initial composite parameters for each device. This should only be invoked once, on
* startup, for each device. Changes made to the device parameters should invoke update() method to apply changes.
*
* @param deviceType to load parameters
* @param deviceHandle to device
* @return constructed device composite paramaters
*/
public CompositeParameters getCompositeParameters(DeviceType deviceType, MemoryAddress deviceHandle) throws SDRPlayException
{
//Allocate a pointer that the api will fill with the memory address of the device parameters in memory.
MemorySegment pointer = getGlobalMemorySession().allocate(ValueLayout.ADDRESS);
Status status = Status.fromValue(sdrplay_api_h.sdrplay_api_GetDeviceParams(deviceHandle, pointer));
if(status.success())
{
//Get the memory address from the pointer's memory segment to where the structure is located
MemoryAddress memoryAddress = pointer.get(ValueLayout.ADDRESS, 0);
//The structure's memory is already allocated ... wrap a memory segment around it
MemorySegment memorySegment = sdrplay_api_DeviceT.ofAddress(memoryAddress, mGlobalMemorySession);
return CompositeParametersFactory.create(deviceType, memorySegment, mGlobalMemorySession);
}
else
{
throw new SDRPlayException("Error retrieving device composite parameters", status);
}
}
/**
* Initializes a device for use.
*
* @param deviceHandle to the device
* @param callbackFunctions to receive stream data from A and (optionally) B channels and events.
* @throws SDRPlayException if the device is not selected of if unable to init the device
*/
private void init(MemoryAddress deviceHandle, MemorySegment callbackFunctions) throws SDRPlayException
{
//Since we don't need/use the callback context ... setup as a pointer to the callback functions
MemorySegment contextPointer = getGlobalMemorySession().allocate(ValueLayout.ADDRESS, callbackFunctions);
Status status = Status.fromValue(sdrplay_api_h.sdrplay_api_Init(deviceHandle, callbackFunctions, contextPointer));
if(!status.success())
{
throw new SDRPlayException("Error while initializing device", status);
}
}
/**
* Initializes a device for single-tuner use or for dual-tuner use as stream A
*
* @param device to initialize
* @param deviceHandle to the device
* @param eventListener to receive events for this device
* @param streamListener to receive samples for stream A
* @throws SDRPlayException if the device is not selected of if unable to init the device
*/
public void initA(Device device, MemoryAddress deviceHandle, IDeviceEventListener eventListener,
IStreamListener streamListener) throws SDRPlayException
{
CallbackFunctions callbackFunctions = mDeviceCallbackFunctionsMap.get(deviceHandle);
if(callbackFunctions == null)
{
callbackFunctions = new CallbackFunctions(getGlobalMemorySession(), eventListener, streamListener,
device.getStreamCallbackListener());
mDeviceCallbackFunctionsMap.put(deviceHandle, callbackFunctions);
}
else
{
callbackFunctions.setDeviceEventListener(eventListener);
callbackFunctions.setStreamAListener(streamListener);
}
init(deviceHandle, callbackFunctions.getCallbackFunctionsMemorySegment());
}
/**
* Initializes a device for dual-tuner use as stream B
*
* @param device to initialize
* @param deviceHandle to the device
* @param eventListener to receive events for this device
* @param streamListener to receive samples for stream B
* @throws SDRPlayException if the device is not selected of if unable to init the device
*/
public void initB(Device device, MemoryAddress deviceHandle, IDeviceEventListener eventListener,
IStreamListener streamListener) throws SDRPlayException
{
CallbackFunctions callbackFunctions = mDeviceCallbackFunctionsMap.get(deviceHandle);
if(callbackFunctions == null)
{
callbackFunctions = new CallbackFunctions(getGlobalMemorySession(), eventListener, streamListener, streamListener,
device.getStreamCallbackListener());
mDeviceCallbackFunctionsMap.put(deviceHandle, callbackFunctions);
}
else
{
callbackFunctions.setDeviceEventListener(eventListener);
callbackFunctions.setStreamAListener(streamListener);
}
init(deviceHandle, callbackFunctions.getCallbackFunctionsMemorySegment());
}
/**
* Un-Initializes a device from use.
*
* @param deviceHandle to the device
* @throws SDRPlayException if error during uninit or if device is not selected
*/
public void uninit(MemoryAddress deviceHandle) throws SDRPlayException
{
Status status = Status.fromValue(sdrplay_api_h.sdrplay_api_Uninit(deviceHandle));
if(status.fail() && status != Status.NOT_INITIALIZED)
{
throw new SDRPlayException("Error while un-initializing device", status);
}
}
/**
* Applies updates made to the device parameters. The device parameter that was updated is specified in the
* update reason.
* <p>
* Note: this method is synchronized to prevent multiple threads from attempting to send update requests
* concurrently, which will cause a failed request.
*
* @param device to update
* @param deviceHandle for the device
* @param tunerSelect identifies which tuner to apply the updates
* @param updateReasons identifying what was updated
* @throws SDRPlayException if the device is not selected, or if unable to update the device parameters
*/
public synchronized void update(Device device, MemoryAddress deviceHandle, TunerSelect tunerSelect,
UpdateReason... updateReasons) throws SDRPlayException
{
int reasons = UpdateReason.getReasons(updateReasons);
int extendedReasons = UpdateReason.getExtendedReasons(updateReasons);
Status status = Status.fromValue(sdrplay_api_h.sdrplay_api_Update(deviceHandle, tunerSelect.getValue(),
reasons, extendedReasons));
if(status.fail())
{
throw new SDRPlayUpdateException(status, Arrays.stream(updateReasons).toList());
}
}
/**
* Retrieve error information for the last error for the specified device.
*
* @param deviceSegment for the device
* @return error information
*/
private ErrorInformation getLastError(MemorySegment deviceSegment)
{
MemoryAddress errorAddress = sdrplay_api_h.sdrplay_api_GetLastError(deviceSegment);
MemorySegment errorSegment = sdrplay_api_ErrorInfoT.ofAddress(errorAddress, mGlobalMemorySession);
return new ErrorInformation(errorSegment);
}
/**
* Sets the debug level logging for the specified device
*
* @param deviceHandle for the device
* @param debugLevel to set
* @throws SDRPlayException if the device is not selected or if unable to set/change the debug level.
*/
public void setDebugLevel(MemoryAddress deviceHandle, DebugLevel debugLevel) throws SDRPlayException
{
Status status = Status.UNKNOWN;
if(getVersion() == Version.V3_07)
{
//V3.07 used a debug level argument
status = Status.fromValue(sdrplay_api_h.sdrplay_api_DebugEnable(deviceHandle, debugLevel.getValue()));
}
else if(getVersion().gte(Version.V3_08))
{
//V3.08+ uses a 0:1 flag to enable debug logging. The method signature didn't change -- still takes an integer
boolean enable = debugLevel != DebugLevel.DISABLE;
status = Status.fromValue(sdrplay_api_h.sdrplay_api_DebugEnable(deviceHandle, Flag.of(enable)));
}
if(status.fail())
{
throw new SDRPlayException("Unable to set debug level", status);
}
}
/**
* Indicates if the SDRplay API is available and that the API library has been located and loaded for use and
* it the API version is supported by this jsdrplay library.
*/
public boolean isAvailable()
{
return mAvailable;
}
/**
* Opens the API service. MUST be invoked before accessing any of the API functions/methods.
*/
private Status open()
{
return Status.fromValue(sdrplay_api_h.sdrplay_api_Open());
}
/**
* Closes the API service. MUST be invoked before shutdown, after all SDRPlay API operations are completed.
*
* Note: when using multiple instances of this class, only invoke close() on a single instance. With linux API
* version 3.07, if you invoked close() on one instance, then all of the other instances become unusable for
* performing device operations (e.g. release(), etc). This may be an artifact of the way that the Java
* Foreign Function support is implemented, but not sure. dls 1-Jan-2023
*/
public Status close()
{
Status closeStatus;
try
{
closeStatus = Status.fromValue(sdrplay_api_h.sdrplay_api_Close());
}
catch(Exception e)
{
closeStatus = Status.FAIL;
mLog.error("Error closing SDRPlay API", e);
}
mSdrplayLibraryLoaded = false;
mAvailable = false;
return closeStatus;
}
/**
* Identifies the API version.
* Note: if the library is not found or loaded, or if the API version is not a supported version, this method
* returns UNKNOWN
*
* @return version.
*/
public Version getVersion()
{
if(mVersion == null)
{
if(mSdrplayLibraryLoaded)
{
MemorySegment apiVersion = getGlobalMemorySession().allocate(ValueLayout.JAVA_FLOAT, 0);
Status status = Status.fromValue(sdrplay_api_h.sdrplay_api_ApiVersion(apiVersion));
if(status.success())
{
float version = apiVersion.get(ValueLayout.JAVA_FLOAT, 0);
mVersion = Version.fromValue(version);
}
}
if(mVersion == null)
{
mVersion = Version.UNKNOWN;
}
}
return mVersion;
}
/**
* Attempts to lock the API for exclusive use of the current application. Once locked, no other applications
* will be able to use the API. Typically used to lock the API prior to calling sdrplay_api_GetDevices() to
* ensure only one application can select a given device. After completing device selection using
* sdrplay_api_SelectDevice(), sdrplay_api_UnlockDeviceApi() can be used to release the API. May also
* be used prior to calling sdrplay_api_ReleaseDevice() if it is necessary to reselect the same device.
*/
private void lockDeviceApi() throws SDRPlayException
{
if(isAvailable())
{
Status status = Status.fromValue(sdrplay_api_h.sdrplay_api_LockDeviceApi());
if(status.fail())
{
throw new SDRPlayException("Unable to lock Device API for exclusive use", status);
}
}
else
{
throw new SDRPlayException("API is unavailable", Status.API_UNAVAILABLE);
}
}
/**
* Unlocks the device from exclusive access.
*
* @throws SDRPlayException if unable to unlock the Device API
*/
private void unlockDeviceApi() throws SDRPlayException
{
if(isAvailable())
{
Status status = Status.fromValue(sdrplay_api_h.sdrplay_api_UnlockDeviceApi());
if(status.fail())
{
throw new SDRPlayException("Unable to unlock Device API", status);
}
}
else
{
throw new SDRPlayException("API is unavailable", Status.API_UNAVAILABLE);
}
}
/**
* Identifies the java library path for the sdrplay api library at runtime.
*/
public static String getSDRplayLibraryPath()
{
if(SystemUtils.IS_OS_WINDOWS)
{
return SDRPLAY_API_PATH_WINDOWS;
}
else if(SystemUtils.IS_OS_LINUX)
{
return SDRPLAY_API_PATH_LINUX;
}
else if(SystemUtils.IS_OS_MAC_OSX)
{
return SDRPLAY_API_PATH_MAC_OS;
}
mLog.error("Unrecognized operating system. Cannot identify sdrplay api library path");
return "";
}
public static void main(String[] args)
{
/**
* Note: on windows, add the following environment variable to the IntelliJ launcher:
* -Djava.library.path="C:\Program Files\SDRplay\API\x64"
*
* Alternately, we can add this location to the Windows PATH environment variable and
* Java will look there for the library, without having to specify it as a launcher
* option. This would allow for users that have installed the API to an alternate location.
*/
SDRplay sdrplay = new SDRplay();
Status status = sdrplay.open();
mLog.info("Open Status: " + status);
try
{
for(DeviceInfo deviceInfo: sdrplay.getDeviceInfos())
{
mLog.info("Found: " + deviceInfo);
}
}
catch(SDRPlayException se)
{
mLog.info("Error", se);
}
Status closeStatus = sdrplay.close();
mLog.info("Close Status: " + closeStatus);
}
}

View File

@@ -0,0 +1,109 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
public enum Status
{
SUCCESS(sdrplay_api_h.sdrplay_api_Success(), "Success"),
FAIL(sdrplay_api_h.sdrplay_api_Fail(), "Fail"),
INVALID_PARAMETER(sdrplay_api_h.sdrplay_api_InvalidParam(), "Invalid Parameter. Null pointer or invalid operating mode"),
OUT_OF_RANGE(sdrplay_api_h.sdrplay_api_OutOfRange(), "Out of Range. One or more parameters are set incorrectly"),
GAIN_UPDATE_ERROR(sdrplay_api_h.sdrplay_api_GainUpdateError(), "Gain Update Error"),
RF_UPDATE_ERROR(sdrplay_api_h.sdrplay_api_RfUpdateError(), "Frequency Update Error"),
FS_UPDATE_ERROR(sdrplay_api_h.sdrplay_api_FsUpdateError(), "Sample Rate Update Error"),
HARDWARE_ERROR(sdrplay_api_h.sdrplay_api_HwError(), "Hardware Error during tuner initialization"),
ALIASING_ERROR(sdrplay_api_h.sdrplay_api_AliasingError(), "Aliasing Error"),
ALREADY_INITIALIZED(sdrplay_api_h.sdrplay_api_AlreadyInitialised(), "Already Initialized"),
NOT_INITIALIZED(sdrplay_api_h.sdrplay_api_NotInitialised(), "Not Initialized"),
NOT_ENABLED(sdrplay_api_h.sdrplay_api_NotEnabled(), "Not Enabled"),
HARDWARE_VERSION_ERROR(sdrplay_api_h.sdrplay_api_HwVerError(), "Hardware Version Error"),
OUT_OF_MEMORY(sdrplay_api_h.sdrplay_api_OutOfMemError(), "Out Of Memory"),
SERVICE_NOT_RESPONDING(sdrplay_api_h.sdrplay_api_ServiceNotResponding(), "Service Not Responding"),
START_PENDING(sdrplay_api_h.sdrplay_api_StartPending(), "Start Pending"),
STOP_PENDING(sdrplay_api_h.sdrplay_api_StopPending(), "Stop Pending"),
INVALID_MODE(sdrplay_api_h.sdrplay_api_InvalidMode(), "Invalid Mode"),
FAILED_VERIFICATION_1(sdrplay_api_h.sdrplay_api_FailedVerification1(), "Failed Verification 1"),
FAILED_VERIFICATION_2(sdrplay_api_h.sdrplay_api_FailedVerification2(), "Failed Verification 2"),
FAILED_VERIFICATION_3(sdrplay_api_h.sdrplay_api_FailedVerification3(), "Failed Verification 3"),
FAILED_VERIFICATION_4(sdrplay_api_h.sdrplay_api_FailedVerification4(), "Failed Verification 4"),
FAILED_VERIFICATION_5(sdrplay_api_h.sdrplay_api_FailedVerification5(), "Failed Verification 5"),
FAILED_VERIFICATION_6(sdrplay_api_h.sdrplay_api_FailedVerification6(), "Failed Verification 6"),
INVALID_SERVICE_VERSION(sdrplay_api_h.sdrplay_api_InvalidServiceVersion(), "Invalid Service Version"),
//Custom status codes
API_UNAVAILABLE(-2, "SDRplay API is not installed or it has an unsupported version"),
UNKNOWN(-1, "Unknown");
private int mValue;
private String mDescription;
Status(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Status code value
*/
public int getValue()
{
return mValue;
}
/**
* Indicates if this is a SUCCESS status.
*/
public boolean success()
{
return this == Status.SUCCESS;
}
public boolean fail()
{
return this != Status.SUCCESS;
}
/**
* Lookup the status from a return code
* @param value to lookup
* @return status or UKNOWN if the code is not recognized
*/
public static Status fromValue(int value)
{
for(Status status: Status.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNKNOWN;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,196 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
import java.util.EnumSet;
/**
* Update reason.
*
* These entries are used to notify the SDRplay API once settings are updated on the device.
*/
public enum UpdateReason
{
//Master Only mode
DEVICE_SAMPLE_RATE(sdrplay_api_h.sdrplay_api_Update_Dev_Fs(), "Sample Rate"),
DEVICE_PPM(sdrplay_api_h.sdrplay_api_Update_Dev_Ppm(), "PPM"),
DEVICE_SYNC_UPDATE(sdrplay_api_h.sdrplay_api_Update_Dev_SyncUpdate(), "Sync Update"),
DEVICE_RESET_FLAGS(sdrplay_api_h.sdrplay_api_Update_Dev_ResetFlags(), "Reset Flags"),
RSP1A_BIAS_T_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp1a_BiasTControl(), "RSP1A Bias-T Control"),
RSP1A_RF_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp1a_RfNotchControl(), "RSP1A RF Notch Control"),
RSP1A_RF_DAB_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp1a_RfDabNotchControl(), "RSP1A RF DAB Notch Control"),
RSP2_BIAS_T_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp2_BiasTControl(), "RSP2 Bias-T Control"),
RSP2_AM_PORT_SELECT(sdrplay_api_h.sdrplay_api_Update_Rsp2_AmPortSelect(), "RSP2 AM Port Select"),
RSP2_ANTENNA_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp2_AntennaControl(), "RSP2 Antenna Control"),
RSP2_RF_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp2_RfNotchControl(), "RSP2 RF Notch Control"),
RSP2_EXT_REF_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp2_ExtRefControl(), "RSP2 External Reference Control"),
RSP_DUO_EXT_REF_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDuo_ExtRefControl(), "RSPduo External Reference Control"),
SPARE_1(sdrplay_api_h.sdrplay_api_Update_Master_Spare_1(), "Spare 1"),
SPARE_2(sdrplay_api_h.sdrplay_api_Update_Master_Spare_2(), "Spare 2"),
//Master and Slave mode
TUNER_GAIN_REDUCTION(sdrplay_api_h.sdrplay_api_Update_Tuner_Gr(), "Tuner Gain Reduction"),
TUNER_GAIN_REDUCTION_LIMITS(sdrplay_api_h.sdrplay_api_Update_Tuner_GrLimits(), "Tuner Gain Reduction Limits"),
TUNER_FREQUENCY_RF(sdrplay_api_h.sdrplay_api_Update_Tuner_Frf(), "Tuner Frequency RF"),
TUNER_BANDWIDTH_TYPE(sdrplay_api_h.sdrplay_api_Update_Tuner_BwType(), "Tuner Bandwidth Type"),
TUNER_IF_TYPE(sdrplay_api_h.sdrplay_api_Update_Tuner_IfType(), "Tuner IF Type"),
TUNER_DC_OFFSET(sdrplay_api_h.sdrplay_api_Update_Tuner_DcOffset(), "Tuner DC Offset"),
TUNER_LO_MODE(sdrplay_api_h.sdrplay_api_Update_Tuner_LoMode(), "Tuner LO Mode"),
CONTROL_DC_OFFSET_IQ_IMBALANCE(sdrplay_api_h.sdrplay_api_Update_Ctrl_DCoffsetIQimbalance(), "Control DC Offset IQ Imbalance"),
CONTROL_DECIMATION(sdrplay_api_h.sdrplay_api_Update_Ctrl_Decimation(), "Control Decimation"),
CONTROL_AGC(sdrplay_api_h.sdrplay_api_Update_Ctrl_Agc(), "Control AGC"),
CONTROL_ADSB_MODE(sdrplay_api_h.sdrplay_api_Update_Ctrl_AdsbMode(), "Control ADSB Mode"),
CONTROL_OVERLOAD_MESSAGE_ACK(sdrplay_api_h.sdrplay_api_Update_Ctrl_OverloadMsgAck(), "Control Overload Message Ack"),
RSP_DUO_BIAS_T_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDuo_BiasTControl(), "RSPduo Bias-T Control"),
RSP_DUO_AM_PORT_SELECT(sdrplay_api_h.sdrplay_api_Update_RspDuo_AmPortSelect(), "RSPduo AM Port Select"),
RSP_DUO_TUNER_1_AM_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDuo_Tuner1AmNotchControl(), "RSPduo Tuner 1 AM Notch Control"),
RSP_DUO_RF_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDuo_RfNotchControl(), "RSPduo RF Notch Control"),
RSP_DUO_RF_DAB_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDuo_RfDabNotchControl(), "RSPduo RF DAB Notch Control"),
//Extension 1
EXTENSION_RSP_DX_HDR_ENABLE(sdrplay_api_h.sdrplay_api_Update_RspDx_HdrEnable(), "RSPdx HDR Enable"),
EXTENSION_RSP_DX_BIAS_T_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDx_BiasTControl(), "RSPdx Bias-T Control"),
EXTENSION_RSP_DX_ANTENNA_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDx_AntennaControl(), "RSPdx Antenna Control"),
EXTENSION_RSP_DX_RF_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDx_RfNotchControl(), "RSPdx RF Notch Control"),
EXTENSION_RSP_DX_RF_DAB_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDx_RfDabNotchControl(), "RSPdx RF DAB Notch Control"),
EXTENSION_RSP_DX_HDR_BANDWIDTH(sdrplay_api_h.sdrplay_api_Update_RspDx_HdrBw(), "RSPdx HDR Bandwidth"),
EXTENSION_NONE(sdrplay_api_h.sdrplay_api_Update_Ext1_None(), "NONE"),
NONE(sdrplay_api_h.sdrplay_api_Update_None(), "NONE");
private int mValue;
private String mDescription;
UpdateReason(int value, String description)
{
mValue = value;
mDescription = description;
}
public static EnumSet<UpdateReason> EXTENSIONS = EnumSet.range(EXTENSION_RSP_DX_HDR_ENABLE, EXTENSION_NONE);
/**
* Many of the update reasons described in this enumeration are submitted asynchronously, since the API is
* non-blocking. However, the device event listener responses are limited to just three events: Frequency, Gain,
* and Sample Rate. This constant describes the three update reasons that correspond to the device events.
*/
public static EnumSet<UpdateReason> ASYNC_UPDATE_RESPONSES = EnumSet.of(DEVICE_SAMPLE_RATE, TUNER_FREQUENCY_RF, TUNER_GAIN_REDUCTION);
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Indicates if this is an extended update reason entry.
*/
public boolean isExtended()
{
return EXTENSIONS.contains(this);
}
/**
* Indicates if this update reason is one of the limited set of asynchronous update operation response types.
*/
public boolean isAsyncUpdateResponse()
{
return ASYNC_UPDATE_RESPONSES.contains(this);
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UNKNOWN if the code is not recognized
*/
public static UpdateReason fromValue(int value)
{
for(UpdateReason status: UpdateReason.values())
{
if(status.getValue() == value)
{
return status;
}
}
return NONE;
}
/**
* Calculates a combined logical OR value of the non-extended update reasons. Extended reason values will
* be ignored for this calculation.
*
* @param reasons to combine
* @return combined (logical OR) value.
*/
public static int getReasons(UpdateReason ... reasons)
{
int combined = UpdateReason.NONE.getValue();
for(UpdateReason reason: reasons)
{
if(!reason.isExtended())
{
combined += reason.getValue();
}
}
return combined;
}
/**
* Calculates a combined logical OR value of the extended update reasons. Non-extended reason values will
* be ignored for this calculation.
*
* @param reasons to combine
* @return combined (logical OR) value.
*/
public static int getExtendedReasons(UpdateReason ... reasons)
{
int combined = UpdateReason.EXTENSION_NONE.getValue();
for(UpdateReason reason: reasons)
{
if(reason.isExtended())
{
combined += reason.getValue();
}
}
return combined;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,99 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* SDRPlay API Versions
*/
public enum Version
{
UNKNOWN(0.0f, false),
V3_07(3.07f, true),
V3_08(3.08f, true),
V3_09(3.09f, true),
V3_10(3.10f, true),
V3_11(3.11f, true);
private float mValue;
private boolean mSupported;
private static final Logger mLog = LoggerFactory.getLogger(Version.class);
Version(float value, boolean supported)
{
mValue = value;
mSupported = supported;
}
/**
* Indicates if the API version is supported by the jsdrplay library
*/
public boolean isSupported()
{
return mSupported;
}
/**
* Indicates if this version is greater than or equal to the specified version.
* @param version to compare
* @return true if this version is greater than or equal to
*/
public boolean gte(Version version)
{
return this.ordinal() >= version.ordinal();
}
/**
* Numeric API version/value
*/
public float getVersion()
{
return mValue;
}
/**
* Lookup the version from the specified value.
* @param value to lookup
* @return version or UNKNOWN
*/
public static Version fromValue(float value)
{
for(Version version: values())
{
if(version.mValue == value)
{
return version;
}
}
mLog.warn("Unrecognized SDRplay API version [" + value + "]");
return UNKNOWN;
}
@Override
public String toString()
{
return String.valueOf(mValue);
}
}

View File

@@ -0,0 +1,227 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.async;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;
/**
* Asynchronous operation that implements the Future interface with utility methods for callback on completion, or
* converting to a synchronous (ie blocking) operation.
* @param <R> expected return type upon completion of the operation
*/
public class AsyncFuture<R> implements Future<R>
{
private R mResult;
private Throwable mError;
private boolean mCancelled;
private boolean mCompleted = false;
private ReentrantLock mLock = new ReentrantLock();
private IAsyncCallback mCallback;
/**
* Sets the result and completes this future.
* @param result to apply.
*/
public synchronized void setResult(R result)
{
if(mCompleted)
{
throw new IllegalStateException("Future is already completed.");
}
mResult = result;
finish();
}
/**
* Sets an error resulting from the operation and completes this future.
* @param error produced from the operation
*/
public synchronized void setError(Throwable error)
{
if(mCompleted)
{
throw new IllegalStateException("Future is already completed.");
}
mError = error;
finish();
}
/**
* (Optional) error produced from the operation.
*/
public Throwable getError()
{
return mError;
}
/**
* Indicates if this future had an error during the operation
*/
public boolean hasError()
{
return mError != null;
}
/**
* Cleanup task that completes the future and notifies an optional registered callback.
*/
private void finish()
{
mLock.lock();
try
{
mCompleted = true;
if(mCallback != null)
{
mCallback.complete(this);
mCallback = null;
}
}
finally
{
mLock.unlock();
}
notifyAll();
}
/**
* Signals a desire to cancel this future operation.
*
* Note: it is up to the implementer to monitor this cancel state.
* @param mayInterruptIfRunning not implemented.
* @return true always.
*/
@Override
public boolean cancel(boolean mayInterruptIfRunning)
{
mCancelled = true;
return true;
}
/**
* Indicates if this future has been cancelled.
*/
@Override
public boolean isCancelled()
{
return mCancelled;
}
/**
* Indicates if this future has completed.
*/
@Override
public boolean isDone()
{
return mCompleted;
}
/**
* Blocking call to wait indefinitely for the result of the operation.
* @return result of the operation
* @throws InterruptedException if the calling thread is interrupted while waiting
* @throws ExecutionException if there is an error produced from the operation
*/
@Override
public synchronized R get() throws InterruptedException, ExecutionException
{
while(!mCompleted)
{
wait();
}
if(mError != null)
{
throw new ExecutionException(mError);
}
return mResult;
}
/**
* Blocking call to synchronously get the result of the operation.
* @param timeout to wait
* @param unit for the timeout
* @return result once completed
* @throws InterruptedException if the calling thread is interrupted while waiting
* @throws ExecutionException if there is an error produced from the operation
* @throws TimeoutException if the timeout is exceeded while waiting.
*/
@Override
public synchronized R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
if(!mCompleted)
{
wait(unit.toMillis(timeout));
}
if(!mCompleted)
{
throw new TimeoutException("Get timeout [" + timeout + " " + unit + "] exceeded without completion");
}
if(mError != null)
{
throw new ExecutionException(mError);
}
return mResult;
}
/**
* Registers the callback to receive the result once the operation completes. If the operation is completed, the
* callback is immediately notified, otherwise the callback will be notified later.
* @param callback to be notified once the operation is completed.
*/
public synchronized void callback(IAsyncCallback callback)
{
if(mCallback != null)
{
throw new IllegalArgumentException("Callback has been registered - only one callback is supported.");
}
mLock.lock();
try
{
if(mCompleted)
{
callback.complete(this);
}
else
{
mCallback = callback;
}
}
finally
{
mLock.unlock();
}
}
}

View File

@@ -0,0 +1,100 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.async;
import io.github.dsheirer.source.tuner.sdrplay.api.Status;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
/**
* Asynchronous future for an SDRplay API update operation.
*/
public class AsyncUpdateFuture extends AsyncFuture<Status>
{
private TunerSelect mTunerSelect;
private UpdateReason mUpdateReason;
private UpdateReason mExpectedResponse;
private boolean mSubmitted;
/**
* Creates a to-be completed future where a successful update with return success or an unsuccessful update will
* return an exception.
* @param tunerSelect for the tuner to be updated
* @param updateReason of what is to be updated
* @param expectedResponse to be received to indicate the async operation is completed
*/
public AsyncUpdateFuture(TunerSelect tunerSelect, UpdateReason updateReason, UpdateReason expectedResponse)
{
mTunerSelect = tunerSelect;
mUpdateReason = updateReason;
mExpectedResponse = expectedResponse;
}
/**
* Tuner(s) for the update
*/
public TunerSelect getTunerSelect()
{
return mTunerSelect;
}
/**
* UpdateReason that is being updated
*/
public UpdateReason getUpdateReason()
{
return mUpdateReason;
}
/**
* Expected response to this update operation
*/
public UpdateReason getExpectedResponse()
{
return mExpectedResponse;
}
/**
* Flag to indicate if this update has been submitted and is currently awaiting results.
*/
public boolean isSubmitted()
{
return mSubmitted;
}
/**
* Sets flag to indicate that this update has been submitted.
*/
public void setSubmitted(boolean submitted)
{
mSubmitted = submitted;
}
/**
* Indicates if the completed async operation matches this submitted async update future
* @param completedAsyncUpdate to compare
* @return true if there is a match
*/
public boolean matches(CompletedAsyncUpdate completedAsyncUpdate)
{
return getTunerSelect().equals(completedAsyncUpdate.getTunerSelect()) &&
getExpectedResponse().equals(completedAsyncUpdate.getUpdateReason());
}
}

View File

@@ -0,0 +1,57 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.async;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
/**
* Completed asynchronous update operation
*/
public class CompletedAsyncUpdate
{
private TunerSelect mTunerSelect;
private UpdateReason mUpdateReason;
/**
* Creates a completed update.
*/
public CompletedAsyncUpdate(TunerSelect tunerSelect, UpdateReason updateReason)
{
mTunerSelect = tunerSelect;
mUpdateReason = updateReason;
}
/**
* Tuner(s) for the update
*/
public TunerSelect getTunerSelect()
{
return mTunerSelect;
}
/**
* UpdateReason that is being updated
*/
public UpdateReason getUpdateReason()
{
return mUpdateReason;
}
}

View File

@@ -0,0 +1,32 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.async;
/**
* Callback interface to be notified when an async future has completed or has resulted in an error
*/
public interface IAsyncCallback
{
/**
* Callback method once the future is completed or produces an error.
* @param future that is being monitored
*/
void complete(AsyncFuture future);
}

View File

@@ -0,0 +1,127 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_CallbackFnsT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_EventCallback_t;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_StreamCallback_t;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
/**
* Callback functions (sdrplay_api_CallbackFnsT) factory
*/
public class CallbackFunctions
{
private DeviceEventAdapter mDeviceEventAdapter;
private StreamCallbackAdapter mStreamACallbackAdapter;
private StreamCallbackAdapter mStreamBCallbackAdapter;
private MemorySegment mCallbackFunctionsMemorySegment;
/**
* Constructs a callback functions for single-tuner use.
* @param memorySession for native memory allocation
* @param deviceEventListener for device events
* @param streamListener for streaming samples
* @param streamCallbackListener for streaming events
*/
public CallbackFunctions(MemorySession memorySession, IDeviceEventListener deviceEventListener,
IStreamListener streamListener, IStreamCallbackListener streamCallbackListener)
{
//Create the event callback function
mDeviceEventAdapter = new DeviceEventAdapter(memorySession, deviceEventListener);
MemorySegment eventFunction = sdrplay_api_EventCallback_t.allocate(mDeviceEventAdapter, memorySession);
//Create the stream A callback function
mStreamACallbackAdapter = new StreamCallbackAdapter(memorySession, streamListener, streamCallbackListener);
MemorySegment streamAFunction = sdrplay_api_StreamCallback_t.allocate(mStreamACallbackAdapter, memorySession);
//Create the callback functions union and populate the callback functions
mCallbackFunctionsMemorySegment = sdrplay_api_CallbackFnsT.allocate(memorySession);
sdrplay_api_CallbackFnsT.EventCbFn$set(mCallbackFunctionsMemorySegment, eventFunction.address());
sdrplay_api_CallbackFnsT.StreamACbFn$set(mCallbackFunctionsMemorySegment, streamAFunction.address());
}
/**
* Constructs a callback functions for dual-tuner use.
* @param memorySession for native memory allocation
* @param deviceEventListener for device events
* @param streamAListener for streaming samples from the master tuner
* @param streamBListener for streaming samples from the slave tuner
* @param streamCallbackListener for streaming events
*/
public CallbackFunctions(MemorySession memorySession, IDeviceEventListener deviceEventListener,
IStreamListener streamAListener, IStreamListener streamBListener,
IStreamCallbackListener streamCallbackListener)
{
//Create the event callback function
mDeviceEventAdapter = new DeviceEventAdapter(memorySession, deviceEventListener);
MemorySegment eventFunction = sdrplay_api_EventCallback_t.allocate(mDeviceEventAdapter, memorySession);
//Create the stream A callback function
mStreamACallbackAdapter = new StreamCallbackAdapter(memorySession, streamAListener, streamCallbackListener);
MemorySegment streamAFunction = sdrplay_api_StreamCallback_t.allocate(mStreamACallbackAdapter, memorySession);
//Create the stream B callback function
mStreamBCallbackAdapter = new StreamCallbackAdapter(memorySession, streamBListener, streamCallbackListener);
MemorySegment streamBFunction = sdrplay_api_StreamCallback_t.allocate(mStreamBCallbackAdapter, memorySession);
//Create the callback functions union and populate the callback functions
mCallbackFunctionsMemorySegment = sdrplay_api_CallbackFnsT.allocate(memorySession);
sdrplay_api_CallbackFnsT.EventCbFn$set(mCallbackFunctionsMemorySegment, eventFunction.address());
sdrplay_api_CallbackFnsT.StreamACbFn$set(mCallbackFunctionsMemorySegment, streamAFunction.address());
sdrplay_api_CallbackFnsT.StreamBCbFn$set(mCallbackFunctionsMemorySegment, streamBFunction.address());
}
/**
* Foreign memory segment for the callback functions.
*/
public MemorySegment getCallbackFunctionsMemorySegment()
{
return mCallbackFunctionsMemorySegment;
}
/**
* Updates the device event listener
* @param listener to receive device events
*/
public void setDeviceEventListener(IDeviceEventListener listener)
{
mDeviceEventAdapter.setListener(listener);
}
/**
* Updates the stream A listener
* @param listener to receive samples for stream A
*/
public void setStreamAListener(IStreamListener listener)
{
mStreamACallbackAdapter.setListener(listener);
}
/**
* Updates the stream B listener
* @param listener to receive samples for stream B
*/
public void setStreamBListener(IStreamListener listener)
{
mStreamBCallbackAdapter.setListener(listener);
}
}

View File

@@ -0,0 +1,111 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.EventParametersFactory;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.EventType;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_EventCallback_t;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_EventParamsT;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Adapter for Device Event callbacks. Implements foreign interface and transfers foreign memory event details to
* native Java and invokes the appropriate interface methods for an event listener.
*/
public class DeviceEventAdapter implements sdrplay_api_EventCallback_t
{
private static final Logger mLog = LoggerFactory.getLogger(DeviceEventAdapter.class);
private MemorySession mMemorySession;
private IDeviceEventListener mDeviceEventListener;
/**
* Constructs an instance.
* @param memorySession to use in creating foreign memory segments to access foreign structures.
* @param listener to receive translated device events.
*/
public DeviceEventAdapter(MemorySession memorySession, IDeviceEventListener listener)
{
if(memorySession == null)
{
throw new IllegalArgumentException("Resource scope must be non-null");
}
mMemorySession = memorySession;
setListener(listener);
}
/**
* Updates the device event listener
* @param listener to receive device events
*/
public void setListener(IDeviceEventListener listener)
{
if(listener == null)
{
throw new IllegalArgumentException("Device event listener must be non-null");
}
mDeviceEventListener = listener;
}
@Override
public void apply(int eventTypeId, int tunerSelectId, MemoryAddress eventParametersPointer,
MemoryAddress callbackContext)
{
MemorySegment memorySegment = sdrplay_api_EventParamsT.ofAddress(eventParametersPointer, mMemorySession);
EventType eventType = EventType.fromValue(eventTypeId);
TunerSelect tunerSelect = TunerSelect.fromValue(tunerSelectId);
switch(eventType)
{
case GAIN_CHANGE -> {
mDeviceEventListener.processGainChange(tunerSelect,
EventParametersFactory.createGainCallbackParameters(memorySegment));
}
case POWER_OVERLOAD_CHANGE -> {
mDeviceEventListener.processPowerOverload(tunerSelect,
EventParametersFactory.createPowerOverloadCallbackParameters(memorySegment));
}
case DEVICE_REMOVED -> {
mDeviceEventListener.processDeviceRemoval(tunerSelect);
}
case RSP_DUO_MODE_CHANGE -> {
mDeviceEventListener.processRspDuoModeChange(tunerSelect,
EventParametersFactory.createRspDuoModeCallbackParameters(memorySegment));
}
case UNKNOWN -> {
mLog.warn("Unknown device event callback ignored. Please contact the library developer as this may " +
"indicate a change to the SDRPlay API change. Tuner:" + tunerSelect + " Event Type ID:" +
eventTypeId);
mDeviceEventListener.processEvent(eventType, tunerSelect);
}
default -> {
throw new IllegalStateException("DeviceEventAdapter must be updated handle EventType." + eventType);
}
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.EventType;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.GainCallbackParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.PowerOverloadCallbackParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.RspDuoModeCallbackParameters;
/**
* Device event listener. Receives events for the device, impacting one or both (if equipped) tuners on the device.
*/
public interface IDeviceEventListener
{
/**
* Process a device event
* @param eventType identifies the type of event
* @param tunerSelect identifies which tuner(s) are included in the event (A, B, BOTH, or NEITHER)
*/
void processEvent(EventType eventType, TunerSelect tunerSelect);
/**
* Process a gain change event
* @param tunerSelect identifies which tuner(s) are included in the event (A, B, BOTH, or NEITHER)
* @param gainCallbackParameters containing event details
*/
void processGainChange(TunerSelect tunerSelect, GainCallbackParameters gainCallbackParameters);
/**
* Process a power overload event
* @param tunerSelect identifies which tuner(s) are included in the event (A, B, BOTH, or NEITHER)
* @param parameters containing event details
*/
void processPowerOverload(TunerSelect tunerSelect, PowerOverloadCallbackParameters parameters);
/**
* Process an RSP-Duo mode change event
* @param tunerSelect identifies which tuner(s) are included in the event (A, B, BOTH, or NEITHER)
* @param parameters containing event details
*/
void processRspDuoModeChange(TunerSelect tunerSelect, RspDuoModeCallbackParameters parameters);
/**
* Process a device removed (ie unplugged) event
* @param tunerSelect identifies which tuner(s) are included in the event (A, B, BOTH, or NEITHER)
*/
void processDeviceRemoval(TunerSelect tunerSelect);
}

View File

@@ -0,0 +1,32 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
public interface IStreamCallbackListener
{
/**
* Process stream callback parameters and reset value received over the stream callback interface.
* @param parameters to process
* @param reset value
*/
void process(TunerSelect tunerSelect, StreamCallbackParameters parameters, int reset);
}

View File

@@ -0,0 +1,45 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
/**
* Stream Listener interface.
*/
public interface IStreamListener
{
/**
* Process samples from a single stream of I/Q samples
* @param xi array of Inphase samples
* @param xq array of Quadrature samples
* @param streamCallbackParameters stream callback parameters
* @param reset indicates if a re-initialization has occurred within the API and that local buffering should be reset
*/
void processStream(short[] xi, short[] xq, StreamCallbackParameters streamCallbackParameters,
boolean reset);
/**
* Indicates which tuner this stream listener is for. Note: this is used to manage asynchronous Updates to ensure
* that submitted updates get correctly mapped and resolved in the Device update manager.
* @return
*/
TunerSelect getTunerSelect();
}

View File

@@ -0,0 +1,107 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_StreamCallback_t;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_StreamCbParamsT;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.ValueLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* I/Q sample stream callback adapter. Implements the native interface and transfers the native callback data to an
* implementation of the Java IStreamListener interface.
*/
public class StreamCallbackAdapter implements sdrplay_api_StreamCallback_t
{
private static final Logger mLog = LoggerFactory.getLogger(StreamCallbackAdapter.class);
private MemorySession mMemorySession;
private IStreamListener mStreamListener;
private IStreamCallbackListener mStreamCallbackListener;
/**
* Constructs an instance of the callback implementation
* @param memorySession for defining new foreign memory segments
* @param streamListener to receive transferred I/Q samples and event details
* @param listener to receive callback parameters
*/
public StreamCallbackAdapter(MemorySession memorySession, IStreamListener streamListener,
IStreamCallbackListener listener)
{
if(memorySession == null)
{
throw new IllegalArgumentException("Resource scope must be non-null");
}
mMemorySession = memorySession;
mStreamCallbackListener = listener;
setListener(streamListener);
}
/**
* Updates the listener for receiving samples
* @param listener to receive stream samples
*/
public void setListener(IStreamListener listener)
{
mStreamListener = listener;
}
/**
* Receives callback of foreign memory data, transfers it to Java, and passes to the listener.
* @param iSamplesPointer array foreign memory address
* @param qSamplesPointer array foreign memory address
* @param parametersPointer associated with the callback - foreign memory address
* @param sampleCount number of samples in each of the I and Q arrays
* @param reset 0 or 1, translated to a boolean
* @param deviceContext of the device that sourced the samples
*/
@Override
public void apply(MemoryAddress iSamplesPointer, MemoryAddress qSamplesPointer, MemoryAddress parametersPointer,
int sampleCount, int reset, MemoryAddress deviceContext)
{
if(mStreamListener != null || mStreamCallbackListener != null)
{
//Translate the callback parameters pointer to a memory segment and re-construct the parameters as a Java object
StreamCallbackParameters parameters = new StreamCallbackParameters(sdrplay_api_StreamCbParamsT
.ofAddress(parametersPointer, mMemorySession));
if(mStreamCallbackListener != null)
{
mStreamCallbackListener.process(mStreamListener.getTunerSelect(), parameters, reset);
}
if(mStreamListener != null)
{
//Allocate memory segments from I/Q pointers, transfer from native to JVM array, and send to listener
long arrayByteSize = ValueLayout.JAVA_SHORT.byteSize() * sampleCount;
MemorySegment iSamples = MemorySegment.ofAddress(iSamplesPointer, arrayByteSize, mMemorySession);
MemorySegment qSamples = MemorySegment.ofAddress(qSamplesPointer, arrayByteSize, mMemorySession);
short[] i = iSamples.toArray(ValueLayout.JAVA_SHORT);
short[] q = qSamples.toArray(ValueLayout.JAVA_SHORT);
mStreamListener.processStream(i, q, parameters, Flag.evaluate(reset));
}
}
}
}

View File

@@ -0,0 +1,88 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_StreamCbParamsT;
import java.lang.foreign.MemorySegment;
/**
* Stream Callback Parameters structure (sdrplay_api_StreamCbParamsT)
*/
public class StreamCallbackParameters
{
private int mFirstSampleNumber;
private boolean mGainReductionChanged;
private boolean mRfFrequencyChanged;
private boolean mSampleRateChanged;
private long mNumberSamples;
/**
* Constructs an instance from the foreign memory segment
*/
public StreamCallbackParameters(MemorySegment memorySegment)
{
mFirstSampleNumber = sdrplay_api_StreamCbParamsT.firstSampleNum$get(memorySegment);
mGainReductionChanged = Flag.evaluate(sdrplay_api_StreamCbParamsT.grChanged$get(memorySegment));
mRfFrequencyChanged = Flag.evaluate(sdrplay_api_StreamCbParamsT.rfChanged$get(memorySegment));
mSampleRateChanged = Flag.evaluate(sdrplay_api_StreamCbParamsT.fsChanged$get(memorySegment));
mNumberSamples = sdrplay_api_StreamCbParamsT.numSamples$get(memorySegment);
}
/**
* First sample number
*/
public int getFirstSampleNumber()
{
return mFirstSampleNumber;
}
/**
* Indicates if gain reduction value has changed
*/
public boolean isGainReductionChanged()
{
return mGainReductionChanged;
}
/**
* Indicates if RF center frequency has changed
*/
public boolean isRfFrequencyChanged()
{
return mRfFrequencyChanged;
}
/**
* Indicates if sample rate has changed
*/
public boolean isSampleRateChanged()
{
return mSampleRateChanged;
}
/**
* Number of samples
*/
public long getNumberSamples()
{
return mNumberSamples;
}
}

View File

@@ -0,0 +1,84 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
/**
* Software decimation rates supported by the API for SDRPlay RSP devices
*/
public enum Decimate
{
X1(1, 16),
X2(2, 16),
X4(4, 17),
X8(8, 17),
X16(16, 18),
X32(32, 20);
private int mValue;
private int mSampleSize;
/**
* Constructs an instance
* @param value
* @param sampleSize in bits to represent effective dynamic range.
*/
Decimate(int value, int sampleSize)
{
mValue = value;
mSampleSize = sampleSize;
}
/**
* Decimation value.
* @return
*/
public int getValue()
{
return mValue;
}
/**
* Sample size in bits to represent effective dynamic range for the decimation value.
*/
public int getSampleSize()
{
return mSampleSize;
}
/**
* Indicates if software decimation is enabled.
* @return true for all values except X1.
*/
public boolean isEnabled()
{
return !this.equals(X1);
}
@Override
public String toString()
{
if(this.equals(X1))
{
return "None";
}
return "x" + getValue();
}
}

View File

@@ -0,0 +1,696 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.Status;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.async.AsyncUpdateFuture;
import io.github.dsheirer.source.tuner.sdrplay.api.async.CompletedAsyncUpdate;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IDeviceEventListener;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IStreamCallbackListener;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IStreamListener;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.StreamCallbackParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.error.DebugLevel;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.CompositeParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.IfMode;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.LoMode;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract device structure (sdrplay_api_DeviceT)
*/
public abstract class Device<T extends CompositeParameters<?,?>, R extends RspTuner<?,?>>
{
private static final Logger mLog = LoggerFactory.getLogger(Device.class);
private SDRplay mSDRplay;
private final UpdateRequestManager mUpdateRequestManager = new UpdateRequestManager();
private final IDeviceStruct mDeviceStruct;
protected boolean mSelected = false;
protected boolean mInitialized = false;
private T mCompositeParameters;
/**
* Constructs an SDRPlay device from the foreign memory segment
* @param sdrPlay api instance that created this device
* @param deviceStruct to parse or access the fields of the device structure
*/
public Device(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
mSDRplay = sdrPlay;
mDeviceStruct = deviceStruct;
}
/**
* Version specific device structure parser
*/
protected IDeviceStruct getDeviceStruct()
{
return mDeviceStruct;
}
/**
* API that owns this device
*/
protected SDRplay getAPI()
{
return mSDRplay;
}
/**
* Stream callback listener for parameter change events.
*/
public IStreamCallbackListener getStreamCallbackListener()
{
return mUpdateRequestManager;
}
/**
* Loads the device parameters for this device. Subsequent calls once the parameters are created are ignored.
* @throws SDRPlayException if the device is not selected or if there is an issue loading the parameters
*/
private void loadDeviceParameters() throws SDRPlayException
{
if(selected())
{
mCompositeParameters = (T)getAPI().getCompositeParameters(getDeviceType(), getDeviceHandle());
}
}
/**
* Sets the debug logging level for this device.
* @param debugLevel to set
*/
public void setDebugLevel(DebugLevel debugLevel)
{
try
{
mSDRplay.setDebugLevel(getDeviceHandle(), debugLevel);
}
catch(SDRPlayException se)
{
mLog.info("Unable to set debug level [" + debugLevel + "] for device - not selected", se);
}
}
/**
* Selects this device for exclusive use and loads the device composite parameters.
* @throws SDRPlayException if unable to select the device or if unable to load the composite parameters for use.
*/
public void select() throws SDRPlayException
{
if(!selected())
{
getAPI().select(getDeviceMemorySegment());
mSelected = true;
loadDeviceParameters();
}
}
/**
* Indicates if this device has been selected via the SDRplay api
*/
protected boolean selected()
{
return mSelected;
}
/**
* Indicates if the device is valid and ready for use
*/
public boolean isValid()
{
return getDeviceStruct().isValid();
}
/**
* Releases this device from exclusive use.
*/
public void release() throws SDRPlayException
{
if(selected())
{
mSelected = false;
getAPI().release(getDeviceMemorySegment());
}
}
/**
* Indicates if this device is initialized for use
*/
public boolean isInitialized()
{
return mInitialized;
}
/**
* Initializes this device for single-tuner use and starts the tuner providing raw signal samples to the stream
* listener and device events to the event listener.
*
* Note: invoke select() to select this device for exclusive use before invoking this method. If this device has
* previously been initialized, an exception is thrown. Use uninit() to uninitialize this device and stop the
* sample stream and event notifications.
*
* @param eventListener to receive device event notifications
* @param streamListener to receive samples from stream. Stream is from either Tuner 1 or Tuner 2 when
* the device is selected for single-tuner mode.
* @throws SDRPlayException if there is an error
*/
public void initStreamA(IDeviceEventListener eventListener, IStreamListener streamListener) throws SDRPlayException
{
if(!isSelected())
{
throw new SDRPlayException("Device must be selected before it can be initialized");
}
if(isInitialized())
{
throw new SDRPlayException("Device has already been initialized with listeners");
}
getAPI().initA(Device.this, getDeviceHandle(), eventListener, streamListener);
mInitialized = true;
}
/**
* Initializes this device for dual-tuner stream B use and starts the tuner providing raw signal samples to the stream
* listener and device events to the event listener.
*
* Note: invoke select() to select this device for exclusive use before invoking this method. If this device has
* previously been initialized, an exception is thrown. Use uninit() to uninitialize this device and stop the
* sample stream and event notifications.
*
* @param eventListener to receive device event notifications
* @param streamListener to receive samples from stream. Stream is from either Tuner 1 or Tuner 2 when
* the device is selected for single-tuner mode.
* @throws SDRPlayException if there is an error
*/
public void initStreamB(IDeviceEventListener eventListener, IStreamListener streamListener) throws SDRPlayException
{
if(!isSelected())
{
throw new SDRPlayException("Device must be selected before it can be initialized");
}
if(isInitialized())
{
throw new SDRPlayException("Device has already been initialized with listeners");
}
getAPI().initB(Device.this, getDeviceHandle(), eventListener, streamListener);
mInitialized = true;
}
/**
* Uninitializes this device from use. Note: call is ignored if this device hasn't been initialized
* @throws SDRPlayException if there is an error
*/
public void uninitialize() throws SDRPlayException
{
if(isInitialized())
{
getAPI().uninit(getDeviceHandle());
mInitialized = false;
}
else
{
throw new SDRPlayException("Attempt to uninit a device that has not been initialized previously");
}
}
/**
* Updates this device after parameter change, only when the device is initialized. If the device is not yet
* initialized, the update request is ignored.
*
* @throws SDRPlayException if unable to apply updates
*/
public void update(TunerSelect tunerSelect, UpdateReason ... updateReasons) throws SDRPlayException
{
if(isInitialized())
{
submitUpdate(tunerSelect, updateReasons);
}
}
private String toString(UpdateReason ... updateReasons)
{
StringBuilder sb = new StringBuilder();
boolean first = true;
for(UpdateReason updateReason: updateReasons)
{
if(first)
{
sb.append("[");
}
else
{
sb.append(", ");
}
sb.append(updateReason.name());
first = false;
}
sb.append("]");
return sb.toString();
}
/**
* Asynchronous update request. This method should only be used for Frequency, Gain and Sample Rate updates.
* @param tunerSelect tuner being updated
* @param updateReason for the parameter that is being updated
* @param expectedResponse that is one of Gain, Frequency, or Sample Rate.
* @return a future that has already been completed, or if initialized a future that will be completed.
*/
protected AsyncUpdateFuture updateAsync(TunerSelect tunerSelect, UpdateReason updateReason, UpdateReason expectedResponse)
{
if(!expectedResponse.isAsyncUpdateResponse())
{
throw new IllegalArgumentException("Invalid expected response: " + expectedResponse +
". Valid values are: " + UpdateReason.ASYNC_UPDATE_RESPONSES);
}
if(isInitialized())
{
return mUpdateRequestManager.update(tunerSelect, updateReason, expectedResponse);
}
//If not initialized, return success.
AsyncUpdateFuture future = new AsyncUpdateFuture(tunerSelect, updateReason, expectedResponse);
future.setResult(Status.SUCCESS);
return future;
}
/**
* Submits an update request to the API. This method is used/managed by the update request manager.
* @param tunerSelect for the update
* @param updateReasons to apply
* @throws SDRPlayException if there is an issue.
*/
private void submitUpdate(TunerSelect tunerSelect, UpdateReason ... updateReasons) throws SDRPlayException
{
getAPI().update(Device.this, getDeviceHandle(), tunerSelect, updateReasons);
}
/**
* Acknowledge tuner power overload events
* @param tunerSelect identifying which tuner(s)
* @throws SDRPlayException on error
*/
public void acknowledgePowerOverload(TunerSelect tunerSelect) throws SDRPlayException
{
// mLog.info("Acknowledging power overload message for tuner [" + tunerSelect + "]");
//There's a bug (feature?) in the API ... when you un-initialize the device, it causes a power overload event
// and if you acknowledge it, you get an error that the device is not initialized.
if(isInitialized())
{
try
{
update(tunerSelect, UpdateReason.CONTROL_OVERLOAD_MESSAGE_ACK);
}
catch(SDRPlayException se)
{
//Ignore the not initialized exception that can happen when shutting down the receiver, otherwise
//rethrow the exception.
if(se.getStatus() != Status.NOT_INITIALIZED)
{
throw se;
}
}
}
}
/**
* Tuner selection.
* @return tuner select. Defaults to TUNER_1 for all but the RSPduo where it is overridden for tuner 2.
*/
public TunerSelect getTunerSelect()
{
return TunerSelect.TUNER_1;
}
/**
* Foreign memory segment representing this device.
*/
protected MemorySegment getDeviceMemorySegment()
{
return getDeviceStruct().getDeviceMemorySegment();
}
/**
* Handle to this device.
*
* Note: this device must be selected for exclusive use before you can access this handle.
*
* @throws SDRPlayException if this method is accessed before the device has been successfully selected
*/
MemoryAddress getDeviceHandle() throws SDRPlayException
{
if(!selected())
{
throw new SDRPlayException("This device must be selected for exclusive use before accessing/using the " +
"device handle");
}
return getDeviceStruct().getDeviceHandle();
}
/**
* Tuner for this device
* @return tuner appropriate for the device type
* @throws SDRPlayException for various reasons include device not selected or API unavailable
*/
public abstract R getTuner() throws SDRPlayException;
/**
* Composite parameters for this device
*/
public T getCompositeParameters()
{
return mCompositeParameters;
}
/**
* Indicates if this device has composite parameters
*/
public boolean hasCompositeParameters()
{
return mCompositeParameters != null;
}
/**
* Indicates if this device is available and has been selected for exclusive use.
*/
public boolean isSelected()
{
return mSelected;
}
/**
* Device type
*/
public DeviceType getDeviceType()
{
return getDeviceStruct().getDeviceType();
}
/**
* Serial number
*/
public String getSerialNumber()
{
return getDeviceStruct().getSerialNumber();
}
/**
* Current sample rate
*/
public double getSampleRate()
{
return getCompositeParameters().getDeviceParameters().getSamplingFrequency().getSampleRate();
}
public void setIfMode(IfMode ifMode)
{
getCompositeParameters().getTunerAParameters().setIfMode(ifMode);
}
public void setLoMode(LoMode loMode)
{
getCompositeParameters().getTunerAParameters().setLoMode(loMode);
}
/**
* Enables or disables wideband signal mode. This should be set according to the IFMode, where IFMode.ZERO is
* wideband and all others are not wideband.
* @param enable
*/
public void setWidebandSignal(boolean enable) throws SDRPlayException
{
getCompositeParameters().getControlAParameters().getDecimation().setWideBandSignal(enable);
if(isInitialized())
{
update(getTunerSelect(), UpdateReason.CONTROL_DECIMATION);
}
}
/**
* Sets the software-based decimation factor for the final sample rate.
* @param decimate value where X1 is no decimation and all others are decimation enabled values.
* @throws SDRPlayException if there is an error while setting decimation
*/
public void setDecimation(Decimate decimate) throws SDRPlayException
{
getCompositeParameters().getControlAParameters().getDecimation().setDecimationFactor(decimate.getValue());
getCompositeParameters().getControlAParameters().getDecimation().setEnabled(decimate.isEnabled());
if(isInitialized())
{
update(getTunerSelect(), UpdateReason.CONTROL_DECIMATION);
}
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("SDRPplay Device").append("\n");
sb.append("\tType: ").append(getDeviceType()).append("\n");
sb.append("\tSerial Number: ").append(getSerialNumber()).append("\n");
sb.append("\tSelected: ").append(isSelected());
if(hasCompositeParameters())
{
sb.append("\t").append(getCompositeParameters());
}
return sb.toString();
}
/**
* Thread-safe manager for asynchronous update request queue processing for an initialized RSP device.
*
* Once a device has been initialized, any changes to frequency, gain or sample rate require submitting an update
* request to the device to apply the parameter change(s). However, since the API supports non-blocking operation,
* the operation executes asynchronously. The API supports only a single update request operation
* to be in-progress at a time and any overlapping update requests are met with an unsuccessful status code return
* from the update method.
*/
class UpdateRequestManager implements IStreamCallbackListener
{
private static final long UPDATE_QUEUE_PROCESSING_INTERVAL_MS = 75;
private final ScheduledExecutorService mExecutorService = Executors.newSingleThreadScheduledExecutor();
private final Queue<AsyncUpdateFuture> mUpdateQueue = new ConcurrentLinkedQueue();
private final Queue<CompletedAsyncUpdate> mCompletedUpdateQueue = new ConcurrentLinkedQueue();
private final ReentrantLock mLock = new ReentrantLock();
/**
* Submits an update request for the specified tuner and update reason for queued processing. This is a
* non-blocking operation and the update is performed by a thread from the thread pool.
* @param tunerSelect to apply the update
* @param updateReason to update
* @return an asynchronous future to monitor the progress of the update request
*/
public AsyncUpdateFuture update(TunerSelect tunerSelect, UpdateReason updateReason, UpdateReason expectedResponse)
{
AsyncUpdateFuture future = new AsyncUpdateFuture(tunerSelect, updateReason, expectedResponse);
mUpdateQueue.add(future);
processQueuesImmediately();
return future;
}
/**
* Schedules a process queues task for immediate execution. Non-blocking.
*/
private void processQueuesImmediately()
{
processQueuesAfterDelay(0);
}
/**
* Schedules a process queues task after the delay. Non-blocking
* @param delay in milliseconds, or zero for immediate.
*/
private void processQueuesAfterDelay(long delay)
{
mExecutorService.schedule(() -> processQueues(), delay, TimeUnit.MILLISECONDS);
}
/**
* Processes the pending and completed update operation queues. Submits new update requests one at a time and
* awaits a stream callback notification that the matching update reason has been applied/updated. Ensures
* that only a single update operation is in-progress at any given time.
*/
private synchronized void processQueues()
{
mLock.lock();
try
{
if(mUpdateQueue.isEmpty())
{
//If we have no pending updates, we don't care about any completed update results
mCompletedUpdateQueue.clear();
}
else
{
boolean processing = true;
while(processing)
{
processing = false;
AsyncUpdateFuture futureUpdate = mUpdateQueue.peek();
if(futureUpdate != null)
{
if(futureUpdate.isSubmitted())
{
//Process the completion queue
while(!mCompletedUpdateQueue.isEmpty())
{
CompletedAsyncUpdate completedUpdate = mCompletedUpdateQueue.poll();
if(completedUpdate != null)
{
if(futureUpdate.matches(completedUpdate))
{
//Clear the remaining completed updates
mCompletedUpdateQueue.clear();
//Remove and (successfully) complete the current future
mUpdateQueue.remove();
futureUpdate.setResult(Status.SUCCESS);
//Signal to immediately reprocess the queue
processing = true;
//Break out of the completed update queue processing
break;
}
}
}
}
else
{
//Clear the completed queue and submit the update
mCompletedUpdateQueue.clear();
try
{
submitUpdate(futureUpdate.getTunerSelect(), futureUpdate.getUpdateReason());
futureUpdate.setSubmitted(true);
}
catch(SDRPlayException se)
{
futureUpdate = mUpdateQueue.poll();
futureUpdate.setError(se);
//Set continuous to true to immediately reprocess the next update
processing = true;
}
}
}
}
}
}
finally
{
mLock.unlock();
}
if(!mUpdateQueue.isEmpty())
{
processQueuesAfterDelay(UPDATE_QUEUE_PROCESSING_INTERVAL_MS);
}
}
/**
* Receives an update completion event. This is a non-blocking operation since this method will be invoked
* by the stream callback thread, and we don't want to impact the delivery of streaming samples or events.
*
* @param tunerSelect tuner that was updated
* @param updateReason for what was updated
*/
public void completed(TunerSelect tunerSelect, UpdateReason updateReason)
{
mCompletedUpdateQueue.add(new CompletedAsyncUpdate(tunerSelect, updateReason));
mExecutorService.schedule(this::processQueues, 0, TimeUnit.MILLISECONDS);
}
/**
* Resets the update queue.
*/
public void reset()
{
mLock.lock();
try
{
while(!mUpdateQueue.isEmpty())
{
AsyncUpdateFuture future = mUpdateQueue.poll();
future.setResult(Status.UNKNOWN);
}
}
finally
{
mLock.unlock();
}
}
/**
* Implements the IStreamCallbackListener interface to receive change notifications from update requests.
* @param parameters to process
* @param reset value with flags
*/
@Override
public void process(TunerSelect tunerSelect, StreamCallbackParameters parameters, int reset)
{
if(parameters.isSampleRateChanged())
{
completed(tunerSelect, UpdateReason.DEVICE_SAMPLE_RATE);
}
if(parameters.isRfFrequencyChanged())
{
completed(tunerSelect, UpdateReason.TUNER_FREQUENCY_RF);
}
if(parameters.isGainReductionChanged())
{
completed(tunerSelect, UpdateReason.TUNER_GAIN_REDUCTION);
}
}
}
}

View File

@@ -0,0 +1,164 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.Version;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DeviceT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SegmentAllocator;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Factory methods for creating new RSP Device instances
*/
public class DeviceFactory
{
private static final Logger mLog = LoggerFactory.getLogger(DeviceFactory.class);
/**
* Creates a foreign memory segment for a DeviceT array, appropriate for the specified version.
* @param version value
* @param segmentAllocator to allocate the foreign memory
* @return devices array
*/
public static MemorySegment createDeviceArray(Version version, SegmentAllocator segmentAllocator)
{
if(version.gte(Version.V3_08))
{
return sdrplay_api_DeviceT.allocateArray(sdrplay_api_h.SDRPLAY_MAX_DEVICES(), segmentAllocator);
}
else if(version == Version.V3_07)
{
return sdrplay_api_DeviceT.allocateArray(sdrplay_api_h.SDRPLAY_MAX_DEVICES(), segmentAllocator);
}
throw new IllegalArgumentException("Unrecognized version: " + version);
}
/**
* Parses device information from a list of device structures
* @param deviceStructs representing devices to parse
* @return a list of device infos
*/
public static List<DeviceInfo> parseDeviceInfos(List<IDeviceStruct> deviceStructs)
{
List<DeviceInfo> deviceInfos = new ArrayList<>();
for(IDeviceStruct deviceStruct: deviceStructs)
{
deviceInfos.add(new DeviceInfo(deviceStruct));
}
return deviceInfos;
}
/**
* Parses device information from a memory segment containing an array of device structures.
* @param version of the API
* @param devicesArray memory segment
* @param count of device structures in the devicesArray.
* @return a list of device infos
* @throws exception if version is unrecognized or unsupported
*/
public static List<IDeviceStruct> parseDeviceStructs(Version version, MemorySegment devicesArray, int count)
throws SDRPlayException
{
List<IDeviceStruct> deviceStructs = new ArrayList<>();
if(version.gte(Version.V3_08))
{
devicesArray.elements(sdrplay_api_DeviceT.$LAYOUT())
.limit(count).forEach(memorySegment ->
deviceStructs.add(DeviceFactory.createDeviceStruct(version, memorySegment)));
}
else if(version == Version.V3_07)
{
devicesArray.elements(sdrplay_api_DeviceT.$LAYOUT()).limit(count).forEach(memorySegment ->
{
deviceStructs.add(DeviceFactory.createDeviceStruct(version, memorySegment));
});
}
else
{
throw new SDRPlayException("Unrecognized version: " + version);
}
return deviceStructs;
}
/**
* Creates an SDRplay device from the foreign memory Device instance.
* @param sdrPlay for device callback support
* @param deviceMemorySegment instance for the device
* @return correctly typed device
*/
public static Device createDevice(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
switch(deviceStruct.getDeviceType())
{
case RSP1 -> {
return new Rsp1Device(sdrPlay, deviceStruct);
}
case RSP1A -> {
return new Rsp1aDevice(sdrPlay, deviceStruct);
}
case RSP2 -> {
return new Rsp2Device(sdrPlay, deviceStruct);
}
case RSPduo -> {
return new RspDuoDevice(sdrPlay, deviceStruct);
}
case RSPdx -> {
return new RspDxDevice(sdrPlay, deviceStruct);
}
default -> {
return new UnknownDevice(sdrPlay, deviceStruct);
}
}
}
/**
* Creates a device structure parser for the specified API version
* @param version to create
* @param deviceMemorySegment for the device
* @return device structure
*/
private static IDeviceStruct createDeviceStruct(Version version, MemorySegment deviceMemorySegment)
{
if(version == Version.V3_07)
{
return new DeviceStruct_v3_07(deviceMemorySegment);
}
else if(version.gte(Version.V3_08))
{
return new DeviceStruct_v3_08(deviceMemorySegment);
}
else
{
throw new IllegalArgumentException("Unsupported version: " + version);
}
}
}

View File

@@ -0,0 +1,140 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.DeviceSelectionMode;
import java.util.Objects;
import org.apache.commons.lang3.Validate;
/**
* RSP device information to support device selection.
*/
public class DeviceInfo
{
private DeviceSelectionMode mDeviceSelectionMode = DeviceSelectionMode.SINGLE_TUNER_1;
private DeviceType mDeviceType;
private String mSerialNumber;
/**
* Constructs an instance
* @param deviceType of the RSP device
* @param serialNumber for the device
*/
public DeviceInfo(DeviceType deviceType, String serialNumber)
{
Validate.notNull(deviceType, "Device type cannot be null");
Validate.notNull(serialNumber, "Device serial number cannot be null");
mDeviceType = deviceType;
mSerialNumber = serialNumber;
}
/**
* Alternate constructor where we get the parameters from a device structure.
* @param deviceStruct containing device type and serial number values.
*/
public DeviceInfo(IDeviceStruct deviceStruct)
{
this(deviceStruct.getDeviceType(), deviceStruct.getSerialNumber());
}
/**
* Device type for this RSP device
* @return type
*/
public DeviceType getDeviceType()
{
return mDeviceType;
}
/**
* Serial number for this RSP device
* @return serial number
*/
public String getSerialNumber()
{
return mSerialNumber;
}
/**
* Device selection mode for this RSP device
* @return device selection mode where single tuner 1 is default
*/
public DeviceSelectionMode getDeviceSelectionMode()
{
return mDeviceSelectionMode;
}
/**
* Sets the device selection mode. This should be left as default of single tuner 1 unless this device is an RSPduo.
* @param deviceSelectionMode to use for this device.
*/
public void setDeviceSelectionMode(DeviceSelectionMode deviceSelectionMode)
{
Validate.notNull(deviceSelectionMode, "Device selection mode cannot be null");
mDeviceSelectionMode = deviceSelectionMode;
}
/**
* Clones this instance
* @return deep copy.
*/
public DeviceInfo clone()
{
return new DeviceInfo(mDeviceType, mSerialNumber);
}
/**
* Indicates if this device type and serial number matches the details of the device structure.
* @param deviceStruct to compare
* @return true if the device type and serial number match.
*/
public boolean matches(IDeviceStruct deviceStruct)
{
return deviceStruct != null && getDeviceType().equals(deviceStruct.getDeviceType()) && getSerialNumber().equals(deviceStruct.getSerialNumber());
}
@Override
public String toString()
{
return "Device: " + getDeviceType() + " Serial Number: " + getSerialNumber() + " Selection Mode: " + getDeviceSelectionMode();
}
@Override
public boolean equals(Object o)
{
if(this == o)
{
return true;
}
if(o == null || getClass() != o.getClass())
{
return false;
}
DeviceInfo that = (DeviceInfo) o;
return mDeviceSelectionMode == that.mDeviceSelectionMode && mDeviceType == that.mDeviceType && mSerialNumber.equals(that.mSerialNumber);
}
@Override
public int hashCode()
{
return Objects.hash(mDeviceSelectionMode, mDeviceType, mSerialNumber);
}
}

View File

@@ -0,0 +1,99 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DeviceT;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
/**
* sdrplay_api_DeviceT structure parser for API version 3.07
*/
public class DeviceStruct_v3_07 implements IDeviceStruct
{
private MemorySegment mDeviceMemorySegment;
private DeviceType mDeviceType;
private String mSerialNumber;
/**
* Constructs an instance
* @param deviceMemorySegment of foreign memory
*/
public DeviceStruct_v3_07(MemorySegment deviceMemorySegment)
{
mDeviceMemorySegment = deviceMemorySegment;
mDeviceType = DeviceType.fromValue(0xFF & sdrplay_api_DeviceT.hwVer$get(mDeviceMemorySegment));
MemorySegment serialSegment = sdrplay_api_DeviceT.SerNo$slice(mDeviceMemorySegment);
mSerialNumber = serialSegment.getUtf8String(0);
}
@Override public MemorySegment getDeviceMemorySegment()
{
return mDeviceMemorySegment;
}
@Override public String getSerialNumber()
{
return mSerialNumber;
}
@Override public DeviceType getDeviceType()
{
return mDeviceType;
}
@Override public TunerSelect getTunerSelect()
{
return TunerSelect.fromValue(sdrplay_api_DeviceT.tuner$get(getDeviceMemorySegment()));
}
@Override public RspDuoMode getRspDuoMode()
{
return RspDuoMode.fromValue(sdrplay_api_DeviceT.rspDuoMode$get(getDeviceMemorySegment()));
}
@Override
public void setRspDuoMode(RspDuoMode mode)
{
sdrplay_api_DeviceT.rspDuoMode$set(getDeviceMemorySegment(), mode.getValue());
}
@Override public boolean isValid()
{
//Always returns true for version 3.07
return true;
}
@Override public double getRspDuoSampleFrequency()
{
return sdrplay_api_DeviceT.rspDuoSampleFreq$get(getDeviceMemorySegment());
}
@Override
public void setRspDuoSampleFrequency(double frequency)
{
sdrplay_api_DeviceT.rspDuoSampleFreq$set(getDeviceMemorySegment(), frequency);
}
@Override public MemoryAddress getDeviceHandle()
{
return sdrplay_api_DeviceT.dev$get(getDeviceMemorySegment());
}
}

View File

@@ -0,0 +1,99 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_08.sdrplay_api_DeviceT;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
/**
* sdrplay_api_DeviceT structure parser for API version 3.07
*/
public class DeviceStruct_v3_08 implements IDeviceStruct
{
private MemorySegment mDeviceMemorySegment;
private DeviceType mDeviceType;
private String mSerialNumber;
/**
* Constructs an instance
* @param deviceMemorySegment of foreign memory
*/
public DeviceStruct_v3_08(MemorySegment deviceMemorySegment)
{
mDeviceMemorySegment = deviceMemorySegment;
mDeviceType = DeviceType.fromValue(0xFF & sdrplay_api_DeviceT.hwVer$get(mDeviceMemorySegment));
MemorySegment serialSegment = sdrplay_api_DeviceT.SerNo$slice(mDeviceMemorySegment);
mSerialNumber = serialSegment.getUtf8String(0);
}
@Override public MemorySegment getDeviceMemorySegment()
{
return mDeviceMemorySegment;
}
@Override public String getSerialNumber()
{
return mSerialNumber;
}
@Override public DeviceType getDeviceType()
{
return mDeviceType;
}
@Override public TunerSelect getTunerSelect()
{
return TunerSelect.fromValue(sdrplay_api_DeviceT.tuner$get(getDeviceMemorySegment()));
}
@Override public RspDuoMode getRspDuoMode()
{
return RspDuoMode.fromValue(sdrplay_api_DeviceT.rspDuoMode$get(getDeviceMemorySegment()));
}
@Override
public void setRspDuoMode(RspDuoMode mode)
{
sdrplay_api_DeviceT.rspDuoMode$set(getDeviceMemorySegment(), mode.getValue());
}
@Override public boolean isValid()
{
//Always returns true for version 3.07
return true;
}
@Override public double getRspDuoSampleFrequency()
{
return sdrplay_api_DeviceT.rspDuoSampleFreq$get(getDeviceMemorySegment());
}
@Override
public void setRspDuoSampleFrequency(double frequency)
{
sdrplay_api_DeviceT.rspDuoSampleFreq$set(getDeviceMemorySegment(), frequency);
}
@Override public MemoryAddress getDeviceHandle()
{
return sdrplay_api_DeviceT.dev$get(getDeviceMemorySegment());
}
}

View File

@@ -0,0 +1,76 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* RSP Device type
*/
public enum DeviceType
{
RSP1(sdrplay_api_h.SDRPLAY_RSP1_ID(), "RSP1"),
RSP1A(sdrplay_api_h.SDRPLAY_RSP1A_ID(), "RSP1A"),
RSP2(sdrplay_api_h.SDRPLAY_RSP2_ID(), "RSP2"),
RSPduo(sdrplay_api_h.SDRPLAY_RSPduo_ID(), "RSPduo"),
RSPdx(sdrplay_api_h.SDRPLAY_RSPdx_ID(), "RSPdx"),
UNKNOWN(Integer.MIN_VALUE, "UNKNOWN");
private int mValue;
private String mDescription;
DeviceType(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UNKNOWN if the code is not recognized
*/
public static DeviceType fromValue(int value)
{
for(DeviceType status: DeviceType.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNKNOWN;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,81 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
/**
* Interface for parsing and accessing the fields of the sdrplay_api_DeviceT structure across
* various versions.
*/
public interface IDeviceStruct
{
/**
* Foreign memory segment for this device structure
*/
MemorySegment getDeviceMemorySegment();
/**
* Serial number of the device
*/
String getSerialNumber();
/**
* Indicates the device type, or model of RSP
*/
DeviceType getDeviceType();
/**
* Indicates single, dual, or master/slave mode for the tuner.
*/
TunerSelect getTunerSelect();
/**
* RSPduo mode
*/
RspDuoMode getRspDuoMode();
/**
* Sets the RSPduo mode
* @param mode to set
*/
void setRspDuoMode(RspDuoMode mode);
/**
* Indicates if the device is valid and ready for use (V3.08 and later)
*/
boolean isValid();
/**
* Sample frequency/rate for the RSPduo when in master/slave mode
*/
double getRspDuoSampleFrequency();
/**
* Sets the sample frequency/rate for the RSPduo when in master (only) mode.
*/
void setRspDuoSampleFrequency(double frequency);
/**
* Device handle. Note this is only available if the device has been selected.
*/
MemoryAddress getDeviceHandle();
}

View File

@@ -0,0 +1,61 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.Rsp1CompositeParameters;
/**
* RSP1 Device
*/
public class Rsp1Device extends Device<Rsp1CompositeParameters, Rsp1Tuner>
{
private Rsp1Tuner mTuner1;
/**
* Constructs an SDRPlay RSP1 device from the foreign memory segment
*
* @param sdrPlay api instance that created this device
* @param deviceStruct parser
*/
Rsp1Device(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
super(sdrPlay, deviceStruct);
}
@Override
public Rsp1Tuner getTuner() throws SDRPlayException
{
if(!isSelected())
{
throw new SDRPlayException("Device must be selected before accessing the tuner");
}
if(mTuner1 == null)
{
mTuner1 = new Rsp1Tuner(Rsp1Device.this, getAPI(), getTunerSelect(),
getCompositeParameters().getDeviceParameters(), getCompositeParameters().getTunerAParameters(),
getCompositeParameters().getControlAParameters());
}
return mTuner1;
}
}

View File

@@ -0,0 +1,46 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.Rsp1DeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp1TunerParameters;
/**
* RSP1 Tuner
*/
public class Rsp1Tuner extends RspTuner<Rsp1DeviceParameters, Rsp1TunerParameters>
{
/**
* Constructs an instance
* @param device parent for this tuner
* @param sdrplay api
* @param tunerSelect to specify which tuner
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public Rsp1Tuner(Device device, SDRplay sdrplay, TunerSelect tunerSelect, Rsp1DeviceParameters deviceParameters,
Rsp1TunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, tunerSelect, deviceParameters, tunerParameters, controlParameters);
}
}

View File

@@ -0,0 +1,61 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.Rsp1aCompositeParameters;
/**
* RSP1A Device
*/
public class Rsp1aDevice extends Device<Rsp1aCompositeParameters, Rsp1aTuner>
{
private Rsp1aTuner mTuner1;
/**
* Constructs an SDRPlay RSP1A device from the foreign memory segment
*
* @param sdrPlay api instance that created this device
* @param deviceStruct parser
*/
Rsp1aDevice(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
super(sdrPlay, deviceStruct);
}
@Override
public Rsp1aTuner getTuner() throws SDRPlayException
{
if(!isSelected())
{
throw new SDRPlayException("Device must be selected before accessing the tuner");
}
if(mTuner1 == null)
{
mTuner1 = new Rsp1aTuner(Rsp1aDevice.this, getAPI(), getTunerSelect(),
getCompositeParameters().getDeviceParameters(), getCompositeParameters().getTunerAParameters(),
getCompositeParameters().getControlAParameters());
}
return mTuner1;
}
}

View File

@@ -0,0 +1,105 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.Rsp1aDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp1aTunerParameters;
/**
* RSP1A Tuner
*/
public class Rsp1aTuner extends RspTuner<Rsp1aDeviceParameters, Rsp1aTunerParameters>
{
/**
* Constructs an instance
* @param device parent for this tuner
* @param sdrplay api
* @param tunerSelect to specify which tuner
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public Rsp1aTuner(Device device, SDRplay sdrplay, TunerSelect tunerSelect, Rsp1aDeviceParameters deviceParameters,
Rsp1aTunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, tunerSelect, deviceParameters, tunerParameters, controlParameters);
}
/**
* Indicates if the RF notch is enabled
*/
public boolean isRfNotch()
{
return getDeviceParameters().isRFNotch();
}
/**
* Enables or disables the RF notch
* @param enable setting
* @throws SDRPlayException if there is an error
*/
public void setRfNotch(boolean enable) throws SDRPlayException
{
getDeviceParameters().setRFNotch(enable);
update(UpdateReason.RSP1A_RF_NOTCH_CONTROL);
}
/**
* Indicates if the RF DAB notch is enabled
*/
public boolean isRfDabNotch()
{
return getDeviceParameters().isRfDabNotch();
}
/**
* Enables or disables the RF DAB notch
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setRfDabNotch(boolean enable) throws SDRPlayException
{
getDeviceParameters().setRfDabNotch(enable);
update(UpdateReason.RSP1A_RF_DAB_NOTCH_CONTROL);
}
/**
* Indicates if the Bias-T is enabled
*/
public boolean isBiasT()
{
return getTunerParameters().isBiasT();
}
/**
* Enables or disables the Bias-T
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setBiasT(boolean enable) throws SDRPlayException
{
getTunerParameters().setBiasT(enable);
update(UpdateReason.RSP1A_BIAS_T_CONTROL);
}
}

View File

@@ -0,0 +1,61 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.Rsp2CompositeParameters;
/**
* RSP2 Device
*/
public class Rsp2Device extends Device<Rsp2CompositeParameters, Rsp2Tuner>
{
private Rsp2Tuner mTuner1;
/**
* Constructs an SDRPlay RSP2 device from the foreign memory segment
*
* @param sdrPlay api instance that created this device
* @param deviceStruct parser
*/
Rsp2Device(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
super(sdrPlay, deviceStruct);
}
@Override
public Rsp2Tuner getTuner() throws SDRPlayException
{
if(!isSelected())
{
throw new SDRPlayException("Device must be selected before accessing the tuner");
}
if(mTuner1 == null)
{
mTuner1 = new Rsp2Tuner(Rsp2Device.this, getAPI(), getTunerSelect(),
getCompositeParameters().getDeviceParameters(), getCompositeParameters().getTunerAParameters(),
getCompositeParameters().getControlAParameters());
}
return mTuner1;
}
}

View File

@@ -0,0 +1,145 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.Rsp2DeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp2AmPort;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp2Antenna;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp2TunerParameters;
/**
* RSP2 Tuner
*/
public class Rsp2Tuner extends RspTuner<Rsp2DeviceParameters, Rsp2TunerParameters>
{
/**
* Constructs an instance
* @param device parent for this tuner
* @param sdrplay api
* @param tunerSelect to specify which tuner
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public Rsp2Tuner(Device device, SDRplay sdrplay, TunerSelect tunerSelect, Rsp2DeviceParameters deviceParameters,
Rsp2TunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, tunerSelect, deviceParameters, tunerParameters, controlParameters);
}
/**
* Indicates if the external reference output is enabled.
*/
public boolean isExternalReferenceOutput()
{
return getDeviceParameters().isExternalReferenceOutput();
}
/**
* Enables or disables the external reference output
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setExternalReferenceOutput(boolean enable) throws SDRPlayException
{
getDeviceParameters().setExternalReferenceOutput(enable);
update(UpdateReason.RSP2_EXT_REF_CONTROL);
}
/**
* Indicates if the Bias-T is enabled
*/
public boolean isBiasT()
{
return getTunerParameters().isBiasT();
}
/**
* Enables or disables the Bias-T
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setBiasT(boolean enable) throws SDRPlayException
{
getTunerParameters().setBiasT(enable);
update(UpdateReason.RSP2_BIAS_T_CONTROL);
}
/**
* Indicates if the RF notch is enabled
*/
public boolean isRfNotch()
{
return getTunerParameters().isRfNotch();
}
/**
* Enables or disables the RF notch
* @param enable setting
* @throws SDRPlayException if there is an error
*/
public void setRfNotch(boolean enable) throws SDRPlayException
{
getTunerParameters().setRfNotch(enable);
update(UpdateReason.RSP2_RF_NOTCH_CONTROL);
}
/**
* AM port selection
*/
public Rsp2AmPort getAmPort()
{
return getTunerParameters().getAmPort();
}
/**
* Sets the AM port
* @param port to select
* @throws SDRPlayException if there is an error
*/
public void setAmPort(Rsp2AmPort port) throws SDRPlayException
{
getTunerParameters().setAmPort(port);
update(UpdateReason.RSP2_AM_PORT_SELECT);
}
/**
* Antenna selection
*/
public Rsp2Antenna getAntenna()
{
return getTunerParameters().getAntenna();
}
/**
* Sets the antenna
* @param antenna to select
* @throws SDRPlayException if there is an error
*/
public void setAntenna(Rsp2Antenna antenna) throws SDRPlayException
{
getTunerParameters().setAntenna(antenna);
update(UpdateReason.RSP2_ANTENNA_CONTROL);
}
}

View File

@@ -0,0 +1,212 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.RspDuoCompositeParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.IfMode;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.LoMode;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DeviceT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* RSPduo Device
*/
public class RspDuoDevice extends Device<RspDuoCompositeParameters, RspDuoTuner>
{
private static final Logger mLog = LoggerFactory.getLogger(RspDuoDevice.class);
private RspDuoTuner mTuner;
/**
* Constructs an SDRPlay RSPduo device from the foreign memory segment
*
* @param sdrPlay api instance that created this device
* @param deviceStruct parser
*/
RspDuoDevice(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
super(sdrPlay, deviceStruct);
}
/**
* Tuner
* @return tuner
* @throws SDRPlayException if there is an error
*/
@Override
public RspDuoTuner getTuner() throws SDRPlayException
{
if(!isSelected())
{
throw new SDRPlayException("Device must be selected before accessing the tuner");
}
if(mTuner == null)
{
if(getTunerSelect().equals(TunerSelect.TUNER_1))
{
mTuner = new RspDuoTuner1(RspDuoDevice.this, getAPI(),
getCompositeParameters().getDeviceParameters(), getCompositeParameters().getTunerAParameters(),
getCompositeParameters().getControlAParameters());
}
else
{
mTuner = new RspDuoTuner2(RspDuoDevice.this, getAPI(),
getCompositeParameters().getDeviceParameters(), getCompositeParameters().getTunerBParameters(),
getCompositeParameters().getControlBParameters());
}
}
return mTuner;
}
/**
* Selected tuner(s).
*/
@Override
public TunerSelect getTunerSelect()
{
return TunerSelect.fromValue(sdrplay_api_DeviceT.tuner$get(getDeviceMemorySegment()));
}
/**
* Sets the selected tuner(s)
*/
public void setTunerSelect(TunerSelect tunerSelect)
{
sdrplay_api_DeviceT.tuner$set(getDeviceMemorySegment(), tunerSelect.getValue());
}
/**
* RSPduo mode
*/
public RspDuoMode getRspDuoMode()
{
return getDeviceStruct().getRspDuoMode();
}
/**
* Sets RSPduo mode. Note this must be set before selecting the device for use.
* @param mode to set
* @throws SDRPlayException if the device has already been selected
*/
public void setRspDuoMode(RspDuoMode mode) throws SDRPlayException
{
if(isSelected())
{
throw new SDRPlayException("RSPduo device is already selected. Mode can only be set/changed before the " +
"device is selected for use.");
}
getDeviceStruct().setRspDuoMode(mode);
}
/**
* Sample rate when in master/slave mode
*/
public double getRspDuoSampleFrequency()
{
return getDeviceStruct().getRspDuoSampleFrequency();
}
/**
* Sets the sample rate when the device is configured for master mode.
* @param frequency
*/
public void setRspDuoSampleFrequency(double frequency) throws SDRPlayException
{
if(!getRspDuoMode().equals(RspDuoMode.MASTER))
{
throw new SDRPlayException("This method can only be used to set the overall sample rate when the RSPduo " +
"device is configured for master mode.");
}
getDeviceStruct().setRspDuoSampleFrequency(frequency);
}
/**
* Sets the decimation factor for the final sample rate.
* @param decimation as an integer multiple of two (e.g. 1, 2, 4, 8)
* @throws SDRPlayException if there is an error while setting decimation
*/
@Override
public void setDecimation(Decimate decimation) throws SDRPlayException
{
if(getTunerSelect() == TunerSelect.TUNER_1)
{
getCompositeParameters().getControlAParameters().getDecimation().setDecimationFactor(decimation.getValue());
getCompositeParameters().getControlAParameters().getDecimation().setEnabled(decimation.isEnabled());
update(getTunerSelect(), UpdateReason.CONTROL_DECIMATION);
}
else if(getTunerSelect() == TunerSelect.TUNER_2)
{
getCompositeParameters().getControlBParameters().getDecimation().setDecimationFactor(decimation.getValue());
getCompositeParameters().getControlBParameters().getDecimation().setEnabled(decimation.isEnabled());
update(getTunerSelect(), UpdateReason.CONTROL_DECIMATION);
}
else if(getTunerSelect() == TunerSelect.TUNER_BOTH)
{
//Dual-synchronized tuner mode ... let the parent Device class set the value
super.setDecimation(decimation);
}
}
/**
* Sets the IF mode when tuner 2 is selected in single-tuner mode.
* @param ifMode to set
*/
public void setIfModeTuner2(IfMode ifMode)
{
getCompositeParameters().getTunerBParameters().setIfMode(ifMode);
}
/**
* Sets the LO mode when tuner 2 is selected in single-tuner mode.
* @param loMode to set
*/
public void setLoModeTuner2(LoMode loMode)
{
getCompositeParameters().getTunerBParameters().setLoMode(loMode);
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("SDRPplay Device").append("\n");
sb.append("\tType: " + getDeviceType()).append("\n");
sb.append("\tSerial Number: " + getSerialNumber()).append("\n");
sb.append("\tTuner: " + getTunerSelect()).append("\n");
sb.append("\tRSP Duo: " + getRspDuoMode()).append("\n");
sb.append("\tRSP Duo Sample Rate: " + getRspDuoSampleFrequency()).append("\n");
sb.append("\tSelected: " + isSelected());
if(hasCompositeParameters())
{
sb.append("\t").append(getCompositeParameters());
}
return sb.toString();
}
}

View File

@@ -0,0 +1,75 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* RSP-Duo Mode
*/
public enum RspDuoMode
{
SINGLE_TUNER(sdrplay_api_h.sdrplay_api_RspDuoMode_Single_Tuner(), "SINGLE TUNER"),
DUAL_TUNER(sdrplay_api_h.sdrplay_api_RspDuoMode_Dual_Tuner(), "DUAL TUNER"),
MASTER(sdrplay_api_h.sdrplay_api_RspDuoMode_Master(), "MASTER"),
SLAVE(sdrplay_api_h.sdrplay_api_RspDuoMode_Slave(), "SLAVE"),
UNKNOWN(sdrplay_api_h.sdrplay_api_RspDuoMode_Unknown(), "UNKNOWN");
private int mValue;
private String mDescription;
RspDuoMode(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UKNOWN if the code is not recognized
*/
public static RspDuoMode fromValue(int value)
{
for(RspDuoMode status: RspDuoMode.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNKNOWN;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,105 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.RspDuoDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDuoTunerParameters;
/**
* RSPduo Tuner
*/
public abstract class RspDuoTuner extends RspTuner<RspDuoDeviceParameters, RspDuoTunerParameters>
{
/**
* Constructs an instance
* @param device parent for this tuner
* @param sdrplay api
* @param tunerSelect to specify which tuner
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public RspDuoTuner(Device device, SDRplay sdrplay, TunerSelect tunerSelect, RspDuoDeviceParameters deviceParameters,
RspDuoTunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, tunerSelect, deviceParameters, tunerParameters, controlParameters);
}
/**
* Indicates if the RF notch is enabled
*/
public boolean isRFNotch()
{
return getTunerParameters().isRfNotch();
}
/**
* Enables or disables the RF notch
* @param enable setting
* @throws SDRPlayException if there is an error
*/
public void setRfNotch(boolean enable) throws SDRPlayException
{
getTunerParameters().setRfNotch(enable);
update(UpdateReason.RSP_DUO_RF_NOTCH_CONTROL);
}
/**
* Indicates if the RF DAB notch is enabled
*/
public boolean isRfDabNotch()
{
return getTunerParameters().isRfDabNotch();
}
/**
* Enables or disables the RF DAB notch
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setRfDabNotch(boolean enable) throws SDRPlayException
{
getTunerParameters().setRfDabNotch(enable);
update(UpdateReason.RSP_DUO_RF_DAB_NOTCH_CONTROL);
}
/**
* Indicates if the external reference output is enabled.
*/
public boolean isExternalReferenceOutput()
{
return getDeviceParameters().isExternalReferenceOutput();
}
/**
* Enables or disables the external reference output
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setExternalReferenceOutput(boolean enable) throws SDRPlayException
{
getDeviceParameters().setExternalReferenceOutput(enable);
update(UpdateReason.RSP_DUO_EXT_REF_CONTROL);
}
}

View File

@@ -0,0 +1,87 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.RspDuoDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDuoAmPort;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDuoTunerParameters;
/**
* RSPduo Tuner 1
*/
public class RspDuoTuner1 extends RspDuoTuner
{
/**
* Constructs an instance
*
* @param device parent for this tuner
* @param sdrplay api
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public RspDuoTuner1(Device device, SDRplay sdrplay, RspDuoDeviceParameters deviceParameters,
RspDuoTunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, TunerSelect.TUNER_1, deviceParameters, tunerParameters, controlParameters);
}
/**
* Indicates which AM port is selected
*/
public RspDuoAmPort getAmPort()
{
return getTunerParameters().getTuner1AmPort();
}
/**
* Selects the AM port to use
* @param port to use
* @throws SDRPlayException if there is an error
*/
public void setAmPort(RspDuoAmPort port) throws SDRPlayException
{
getTunerParameters().setTuner1AmPort(port);
update(UpdateReason.RSP_DUO_AM_PORT_SELECT);
}
/**
* Indicates if the AM notch is enabled
*/
public boolean isAmNotch()
{
return getTunerParameters().isTuner1AmNotch();
}
/**
* Enables or disables the AM notch
* @param enable for the notch
* @throws SDRPlayException if there is an error
*/
public void setAmNotch(boolean enable) throws SDRPlayException
{
getTunerParameters().setTuner1AmNotch(enable);
update(UpdateReason.RSP_DUO_TUNER_1_AM_NOTCH_CONTROL);
}
}

View File

@@ -0,0 +1,67 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.RspDuoDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDuoTunerParameters;
/**
* RSPduo Tuner 2
*/
public class RspDuoTuner2 extends RspDuoTuner
{
/**
* Constructs an instance
*
* @param device parent for this tuner
* @param sdrplay api
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public RspDuoTuner2(Device device, SDRplay sdrplay, RspDuoDeviceParameters deviceParameters,
RspDuoTunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, TunerSelect.TUNER_2, deviceParameters, tunerParameters, controlParameters);
}
/**
* Indicates if the Bias-T is enabled
*/
public boolean isBiasT()
{
return getTunerParameters().isBiasT();
}
/**
* Enables or disables the Bias-T
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setBiasT(boolean enable) throws SDRPlayException
{
getTunerParameters().setBiasT(enable);
update(UpdateReason.RSP_DUO_BIAS_T_CONTROL);
}
}

View File

@@ -0,0 +1,62 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.RspDxCompositeParameters;
/**
* RSPdx Device
*/
public class RspDxDevice extends Device<RspDxCompositeParameters, RspDxTuner>
{
private RspDxTuner mTuner1;
/**
* Constructs an SDRPlay RSPdx device from the foreign memory segment
*
* @param sdrPlay api instance that created this device
* @param deviceStruct parser
*/
RspDxDevice(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
super(sdrPlay, deviceStruct);
}
@Override
public RspDxTuner getTuner() throws SDRPlayException
{
if(!isSelected())
{
throw new SDRPlayException("Device must be selected before accessing the tuner");
}
if(mTuner1 == null)
{
mTuner1 = new RspDxTuner(RspDxDevice.this, getAPI(), getTunerSelect(),
getCompositeParameters().getDeviceParameters(), getCompositeParameters().getTunerAParameters(),
getCompositeParameters().getControlAParameters());
}
return mTuner1;
}
}

View File

@@ -0,0 +1,164 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.RspDxDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.HdrModeBandwidth;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDxAntenna;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDxTunerParameters;
/**
* RSPdx Tuner
*/
public class RspDxTuner extends RspTuner<RspDxDeviceParameters, RspDxTunerParameters>
{
/**
* Constructs an instance
* @param device parent for this tuner
* @param sdrplay api
* @param tunerSelect to specify which tuner
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public RspDxTuner(Device device, SDRplay sdrplay, TunerSelect tunerSelect, RspDxDeviceParameters deviceParameters,
RspDxTunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, tunerSelect, deviceParameters, tunerParameters, controlParameters);
}
/**
* Indicates if HDR mode is enabled
*/
public boolean isHdrMode()
{
return getDeviceParameters().isHdr();
}
/**
* Enables or disables HDR mode
* @param enable mode
* @throws SDRPlayException if there is an error
*/
public void setHdrMode(boolean enable) throws SDRPlayException
{
getDeviceParameters().setHdr(enable);
update(UpdateReason.EXTENSION_RSP_DX_HDR_ENABLE);
}
/**
* HDR mode bandwidth
*/
public HdrModeBandwidth getHdrModeBandwidth()
{
return getTunerParameters().getHdrModeBandwidth();
}
/**
* Sets HDR mode bandwidth
* @param bandwidth to select
* @throws SDRPlayException if there is an error
*/
public void setHdrModeBandwidth(HdrModeBandwidth bandwidth) throws SDRPlayException
{
getTunerParameters().setHdrModeBandwidth(bandwidth);
update(UpdateReason.EXTENSION_RSP_DX_HDR_BANDWIDTH);
}
/**
* Indicates if the RF notch is enabled
*/
public boolean isRfNotch()
{
return getDeviceParameters().isRfNotch();
}
/**
* Enables or disables the RF notch
* @param enable setting
* @throws SDRPlayException if there is an error
*/
public void setRfNotch(boolean enable) throws SDRPlayException
{
getDeviceParameters().setRfNotch(enable);
update(UpdateReason.EXTENSION_RSP_DX_RF_NOTCH_CONTROL);
}
/**
* Indicates if the RF DAB notch is enabled
*/
public boolean isRfDabNotch()
{
return getDeviceParameters().isRfDabNotch();
}
/**
* Enables or disables the RF DAB notch
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setRfDabNotch(boolean enable) throws SDRPlayException
{
getDeviceParameters().setRfDabNotch(enable);
update(UpdateReason.EXTENSION_RSP_DX_RF_DAB_NOTCH_CONTROL);
}
/**
* Indicates if the Bias-T is enabled
*/
public boolean isBiasT()
{
return getDeviceParameters().isBiasT();
}
/**
* Enables or disables the Bias-T
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setBiasT(boolean enable) throws SDRPlayException
{
getDeviceParameters().setBiasT(enable);
update(UpdateReason.EXTENSION_RSP_DX_BIAS_T_CONTROL);
}
/**
* Antenna selection
*/
public RspDxAntenna getAntenna()
{
return getDeviceParameters().getRspDxAntenna();
}
/**
* Sets the antenna selection
* @param antenna to select
* @throws SDRPlayException if there is an error
*/
public void setAntenna(RspDxAntenna antenna) throws SDRPlayException
{
getDeviceParameters().setRspDxAntenna(antenna);
update(UpdateReason.EXTENSION_RSP_DX_ANTENNA_CONTROL);
}
}

View File

@@ -0,0 +1,419 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.async.AsyncUpdateFuture;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.AgcMode;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.DeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Bandwidth;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Gain;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.GainReduction;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.IfMode;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.LoMode;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.TunerParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract RSP device tuner
* @param <T> RSP device implementation
*/
public abstract class RspTuner<D extends DeviceParameters, T extends TunerParameters>
{
private static final Logger mLog = LoggerFactory.getLogger(RspTuner.class);
private final SDRplay mSDRplay;
private final Device mDevice;
private final TunerSelect mTunerSelect;
private final D mDeviceParameters;
private final T mTunerParameters;
private final ControlParameters mControlParameters;
private GainReduction mGainReduction;
RspTuner(Device device, SDRplay sdrplay, TunerSelect tunerSelect, D deviceParameters, T tunerParameters,
ControlParameters controlParameters)
{
mDevice = device;
mSDRplay = sdrplay;
mTunerSelect = tunerSelect;
mDeviceParameters = deviceParameters;
mTunerParameters = tunerParameters;
mControlParameters = controlParameters;
}
/**
* SDRplay API
*/
private SDRplay getSDRplay()
{
return mSDRplay;
}
/**
* Parent device for this tuner
*/
private Device getDevice()
{
return mDevice;
}
/**
* Selected tuner
*/
public TunerSelect getTunerSelect()
{
return mTunerSelect;
}
/**
* Device parameters
*/
protected D getDeviceParameters()
{
return mDeviceParameters;
}
/**
* Tuner parameters for the selected tuner
*/
public T getTunerParameters()
{
return mTunerParameters;
}
/**
* Control parameters for the selected tuner
*/
protected ControlParameters getControlParameters()
{
return mControlParameters;
}
/**
* Convenience method for notifying the API that parameters for the device have been updated, when the device is
* initialized.
*
* @param updateReasons indicating what has been updated
* @throws SDRPlayException if there is an error
*/
protected void update(UpdateReason... updateReasons) throws SDRPlayException
{
getDevice().update(getTunerSelect(), updateReasons);
}
/**
* Convenience method for notifying the device that a parameter for this tuner have been updated.
*
* Note: the asynchronous device event responses are limited to Frequency, Gain and Sample Rate. For example,
* if you update the RSPduo DAB Notch parameter, it will generate a Gain change notification, so we submit
* an async update for the DAB Notch, but anticipate a Gain update response.
*
* @param updateReason indicating what has been updated
* @param expectedResponse that will be received indicating that the async operation is completed.
*/
protected AsyncUpdateFuture updateAsync(UpdateReason updateReason, UpdateReason expectedResponse)
{
return getDevice().updateAsync(getTunerSelect(), updateReason, expectedResponse);
}
/**
* Current tuner bandwidth
*/
public Bandwidth getBandwidth()
{
return getTunerParameters().getBandwidth();
}
/**
* Sets tuner bandwidth
* @param bandwidth to apply
* @throws SDRPlayException if there is an error
*/
public void setBandwidth(Bandwidth bandwidth) throws SDRPlayException
{
getTunerParameters().setBandwidth(bandwidth);
update(UpdateReason.TUNER_BANDWIDTH_TYPE);
}
/**
* Center frequency for the tuner
*/
public long getFrequency()
{
return (long) getTunerParameters().getRfFrequency().getFrequency();
}
/**
* Requests to set the center frequency for the tuner asynchronously.
*
* Note: the API supports the notion of synchronous frequency updates, but in testing I found that you cannot
* submit a second frequency change update request until a previously submitted frequency change update
* operation had completed, otherwise it would generate a fail status. Therefore, this is method is strictly
* an async operation.
*
* @param frequency in Hertz
* @return future that can be monitored for completion of the set frequency operation.
*/
public AsyncUpdateFuture setFrequency(long frequency)
{
try
{
getTunerParameters().getRfFrequency().setFrequency(frequency, false);
updateGainReduction(frequency);
return updateAsync(UpdateReason.TUNER_FREQUENCY_RF, UpdateReason.TUNER_FREQUENCY_RF);
}
catch(SDRPlayException se)
{
AsyncUpdateFuture future = new AsyncUpdateFuture(getTunerSelect(), UpdateReason.TUNER_FREQUENCY_RF,
UpdateReason.TUNER_FREQUENCY_RF);
future.setError(se);
return future;
}
}
/**
* Gain reduction in use for this device with the current RF frequency
*/
public GainReduction getGainReduction()
{
if(mGainReduction == null)
{
updateGainReduction(getFrequency());
}
return mGainReduction;
}
/**
* Updates the gain reduction, if necessary, for the specified RF frequency
*
* @param frequency value
*/
private void updateGainReduction(long frequency)
{
if(mGainReduction == null || !mGainReduction.isValidFor(frequency))
{
mGainReduction = GainReduction.lookup(getDevice().getDeviceType(), frequency);
}
}
/**
* Selects a gain value index from the current gain reduction values
*
* @param index of the gain reduction values to use
*/
public void setGain(int index) throws SDRPlayException
{
getTunerParameters().getGain().setGain(getGainReduction(), index);
update(UpdateReason.TUNER_GAIN_REDUCTION);
}
/**
* Sets the automatic gain contral (AGC) mode
*
* @param mode to set
* @throws SDRPlayException if there is an error
*/
public void setAGC(AgcMode mode) throws SDRPlayException
{
getControlParameters().getAgc().setAgcMode(mode);
update(UpdateReason.CONTROL_AGC);
}
/**
* AGC Mode
*/
public AgcMode getAGC()
{
return getControlParameters().getAgc().getAgcMode();
}
/**
* Gain for the tuner.
*/
public Gain getGain()
{
return getTunerParameters().getGain();
}
/**
* Current gain index value.
* @return current gain index value or -1 if the current gain setting does not match the possible gain reduction options.
*/
public int getGainIndex()
{
int gainDb = getGain().getGainReductionDb();
return getGainReduction().getGainIndex(gainDb);
}
/**
* Enables or disables DC correction
*
* @param enable true or false
* @throws SDRPlayException if there is an error
*/
public void setDCCorrection(boolean enable) throws SDRPlayException
{
getControlParameters().getDcOffset().setDC(enable);
update(UpdateReason.CONTROL_DC_OFFSET_IQ_IMBALANCE);
}
/**
* Enables or disables IQ imbalance correction
*
* @param enable true or false
* @throws SDRPlayException if there is an error
*/
public void setIQCorrection(boolean enable) throws SDRPlayException
{
getControlParameters().getDcOffset().setIQ(enable);
update(UpdateReason.CONTROL_DC_OFFSET_IQ_IMBALANCE);
}
/**
* Sets or updates the parts per million (ppm) frequency correction
*
* @param ppm value
* @throws SDRPlayException
*/
public AsyncUpdateFuture setPPM(double ppm) throws SDRPlayException
{
getDeviceParameters().setPPM(ppm);
//Note: async ppm updates effect both frequency and sample rate, so we expect the completion of the
//operation will be first FREQUENCY and then SAMPLE RATE, so we watch for sample rate.
return updateAsync(UpdateReason.DEVICE_PPM, UpdateReason.DEVICE_SAMPLE_RATE);
}
/**
* Parts per million (PPM) frequency correction value
*
* @return ppm value
*/
public double getPPM()
{
return getDeviceParameters().getPPM();
}
/**
* Perform synchronous update
*
* @param sampleNumber value
* @param period value
* @throws SDRPlayException if there is an error
*/
public void setSynchronousUpdate(int sampleNumber, int period) throws SDRPlayException
{
getDeviceParameters().getSynchronousUpdate().set(sampleNumber, period);
update(UpdateReason.DEVICE_SYNC_UPDATE);
}
/**
* Resets device functions to default
*
* @param frequency to reset
* @param sampleRate to reset
* @param gain to reset
* @throws SDRPlayException if there is an error
*/
public void reset(boolean frequency, boolean sampleRate, boolean gain) throws SDRPlayException
{
getDeviceParameters().getResetFlags().resetGain(gain);
getDeviceParameters().getResetFlags().resetFrequency(frequency);
getDeviceParameters().getResetFlags().resetSampleRate(sampleRate);
update(UpdateReason.DEVICE_RESET_FLAGS);
}
/**
* Resets the frequency.
*
* @param frequency true to reset
* @throws SDRPlayException if there is an error
*/
public void resetFrequency(boolean frequency) throws SDRPlayException
{
reset(frequency, false, false);
}
/**
* Resets the sample rate.
*
* @param sampleRate true to reset
* @throws SDRPlayException if there is an error
*/
public void resetSampleRate(boolean sampleRate) throws SDRPlayException
{
reset(false, sampleRate, false);
}
/**
* Resets the gain (reduction).
*
* @param gain true to reset
* @throws SDRPlayException if there is an error
*/
public void resetGain(boolean gain) throws SDRPlayException
{
reset(false, false, gain);
}
/**
* IF mode (type)
*/
public IfMode getIfMode()
{
return getTunerParameters().getIfMode();
}
/**
* Sets the IF mode (type)
* @param mode to set
* @throws SDRPlayException if there is an error
*/
public void setIfMode(IfMode mode) throws SDRPlayException
{
getTunerParameters().setIfMode(mode);
update(UpdateReason.TUNER_IF_TYPE);
}
/**
* Local Oscillator (LO) mode
* @return mode
*/
public LoMode getLoMode()
{
return getTunerParameters().getLoMode();
}
/**
* Sets the Local Oscillator (LO) mode
* @param mode to set
* @throws SDRPlayException if there is an error
*/
public void setLoMode(LoMode mode) throws SDRPlayException
{
getTunerParameters().setLoMode(mode);
update(UpdateReason.TUNER_LO_MODE);
}
}

View File

@@ -0,0 +1,74 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* Tuner Select
*/
public enum TunerSelect
{
TUNER_1(sdrplay_api_h.sdrplay_api_Tuner_A(), "TUNER 1"),
TUNER_2(sdrplay_api_h.sdrplay_api_Tuner_B(), "TUNER 2"),
TUNER_BOTH(sdrplay_api_h.sdrplay_api_Tuner_Both(), "TUNER 1 & 2"),
NEITHER(sdrplay_api_h.sdrplay_api_Tuner_Neither(), "NEITHER");
private int mValue;
private String mDescription;
TunerSelect(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or NEITHER if the code is not recognized
*/
public static TunerSelect fromValue(int value)
{
for(TunerSelect status: TunerSelect.values())
{
if(status.getValue() == value)
{
return status;
}
}
return NEITHER;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,46 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
/**
* Unknown or Unrecognized SDRplay Device
*/
public class UnknownDevice extends Device
{
/**
* Constructs an Unknown SDRPlay device from the foreign memory segment
*
* @param sdrPlay api instance that created this device
* @param deviceStruct parser
*/
UnknownDevice(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
super(sdrPlay, deviceStruct);
}
@Override
public RspTuner getTuner() throws SDRPlayException
{
throw new SDRPlayException("Unrecognized device type. Cannot construct tuner");
}
}

View File

@@ -0,0 +1,76 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.error;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* Debug Level
*/
public enum DebugLevel
{
DISABLE(sdrplay_api_h.sdrplay_api_DbgLvl_Disable(), "DISABLE"),
VERBOSE(sdrplay_api_h.sdrplay_api_DbgLvl_Verbose(), "VERBOSE"),
WARNING(sdrplay_api_h.sdrplay_api_DbgLvl_Warning(), "WARNING"),
ERROR(sdrplay_api_h.sdrplay_api_DbgLvl_Error(), "ERROR"),
MESSAGE(sdrplay_api_h.sdrplay_api_DbgLvl_Message(), "MESSAGE"),
UNKNOWN(-1, "UNKNOWN");
private int mValue;
private String mDescription;
DebugLevel(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UNKNOWN if the code is not recognized
*/
public static DebugLevel fromValue(int value)
{
for(DebugLevel status: DebugLevel.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNKNOWN;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,77 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.error;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_ErrorInfoT;
import java.lang.foreign.MemorySegment;
/**
* Error Information structure (sdrplay_api_ErrorInfoT)
*/
public class ErrorInformation
{
private String mFile;
private String mFunction;
private int mLine;
private String mMessage;
/**
* Constructs an instance from the foreign memory segment
*/
public ErrorInformation(MemorySegment memorySegment)
{
mFile = sdrplay_api_ErrorInfoT.file$slice(memorySegment).getUtf8String(0);
mFunction = sdrplay_api_ErrorInfoT.function$slice(memorySegment).getUtf8String(0);
mLine = sdrplay_api_ErrorInfoT.line$get(memorySegment);
mMessage = sdrplay_api_ErrorInfoT.message$slice(memorySegment).getUtf8String(0);
}
public String getFile()
{
return mFile;
}
public String getFunction()
{
return mFunction;
}
public int getLine()
{
return mLine;
}
public String getMessage()
{
return mMessage;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Error Information:").append("\n");
sb.append("\t File: ").append(getFile()).append("\n");
sb.append("\tFunction: ").append(getFunction()).append("\n");
sb.append("\t Line: ").append(getLine()).append("\n");
sb.append("\t Message: ").append(getMessage()).append("\n");
return sb.toString();
}
}

View File

@@ -0,0 +1,108 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.composite;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceType;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.DeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.DeviceParametersFactory;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.TunerParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.TunerParametersFactory;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DevParamsT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DeviceParamsT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_RxChannelParamsT;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
/**
* Composite Device Parameters structure (sdrplay_api_DeviceParamsT) providing access to the device parameters and
* the tuner 1 parameters. Tuner 2 parameters are only accessible via the RSPduo sub-class implementation.
*
* Note: sub-class implementations will constrain access to the appropriate sub-structures of the DeviceParamsT
* structure for each specific device.
*/
public class CompositeParameters<D extends DeviceParameters, T extends TunerParameters>
{
private D mDeviceParameters;
private T mTunerAParameters;
private ControlParameters mControlAParameters;
/**
* Constructs an instance from the foreign memory segment
*
* @param deviceType to create
* @param memorySegment for the composite structure in foreign memory
* @param memorySession for allocating additional memory segments for the sub-structures.
*/
public CompositeParameters(DeviceType deviceType, MemorySegment memorySegment, MemorySession memorySession)
{
MemoryAddress parametersMemoryAddress = sdrplay_api_DeviceParamsT.devParams$get(memorySegment);
MemorySegment parametersMemorySegment = sdrplay_api_DevParamsT.ofAddress(parametersMemoryAddress, memorySession);
mDeviceParameters = (D) DeviceParametersFactory.create(deviceType, parametersMemorySegment);
MemoryAddress memoryAddressRxA = sdrplay_api_DeviceParamsT.rxChannelA$get(memorySegment);
MemorySegment memorySegmentRxA = sdrplay_api_RxChannelParamsT.ofAddress(memoryAddressRxA, memorySession);
mTunerAParameters = (T) TunerParametersFactory.create(deviceType, memorySegmentRxA);
MemorySegment tunerAControlParametersMemorySegment = sdrplay_api_RxChannelParamsT.ctrlParams$slice(memorySegmentRxA);
mControlAParameters = new ControlParameters(tunerAControlParametersMemorySegment);
}
/**
* Device parameters
*/
public D getDeviceParameters()
{
return mDeviceParameters;
}
/**
* Tuner A Parameters.
*
* Note: this is normally mapped to tuner 1. In the RSPduo, this is mapped to Tuner 1 or Tuner 2, according to how
* the user has setup the TunerSelect.
*/
public T getTunerAParameters()
{
return mTunerAParameters;
}
/**
* Tuner A Control Parameters
*
* Note: this is normally mapped to tuner 1. In the RSPduo, this is mapped to Tuner 1 or Tuner 2, according to how
* the user has setup the TunerSelect.
*/
public ControlParameters getControlAParameters()
{
return mControlAParameters;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Composite Parameters\n");
sb.append("\tDevice Parameters:\n").append(getDeviceParameters()).append("\n");
sb.append("\tTuner A Parameters:\n").append(getTunerAParameters()).append("\n");
return sb.toString();
}
}

View File

@@ -0,0 +1,61 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.composite;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceType;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
/**
* Creates a composite parameters instance for a device type
*/
public class CompositeParametersFactory
{
/**
* Creates a composite parameters instance for the specified device type
* @param deviceType to create
* @param memorySegment of foreign memory structure for the composite parameters
* @param memorySession to allocate additional memory structures
* @return instance
*/
public static CompositeParameters create(DeviceType deviceType, MemorySegment memorySegment, MemorySession memorySession)
{
switch(deviceType)
{
case RSP1 -> {
return new Rsp1CompositeParameters(memorySegment, memorySession);
}
case RSP1A -> {
return new Rsp1aCompositeParameters(memorySegment, memorySession);
}
case RSP2 -> {
return new Rsp2CompositeParameters(memorySegment, memorySession);
}
case RSPduo -> {
return new RspDuoCompositeParameters(memorySegment, memorySession);
}
case RSPdx -> {
return new RspDxCompositeParameters(memorySegment, memorySession);
}
}
throw new IllegalArgumentException("Unrecognized device type: " + deviceType);
}
}

View File

@@ -0,0 +1,43 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.composite;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceType;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.Rsp1DeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp1TunerParameters;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
/**
* RSP1 Composite parameters (device and tuner)
*/
public class Rsp1CompositeParameters extends CompositeParameters<Rsp1DeviceParameters, Rsp1TunerParameters>
{
/**
* Constructs an instance from the foreign memory segment
*
* @param memorySegment for the composite structure in foreign memory
* @param memorySession for allocating additional memory segments for the sub-structures.
*/
public Rsp1CompositeParameters(MemorySegment memorySegment, MemorySession memorySession)
{
super(DeviceType.RSP1, memorySegment, memorySession);
}
}

View File

@@ -0,0 +1,43 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.composite;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceType;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.Rsp1aDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp1aTunerParameters;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
/**
* RSP1A Composite parameters (device and tuner)
*/
public class Rsp1aCompositeParameters extends CompositeParameters<Rsp1aDeviceParameters, Rsp1aTunerParameters>
{
/**
* Constructs an instance from the foreign memory segment
*
* @param memorySegment for the composite structure in foreign memory
* @param memorySession for allocating additional memory segments for the sub-structures.
*/
public Rsp1aCompositeParameters(MemorySegment memorySegment, MemorySession memorySession)
{
super(DeviceType.RSP1A, memorySegment, memorySession);
}
}

View File

@@ -0,0 +1,43 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.composite;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceType;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.Rsp2DeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp2TunerParameters;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
/**
* RSP2 Composite parameters (device and tuner)
*/
public class Rsp2CompositeParameters extends CompositeParameters<Rsp2DeviceParameters, Rsp2TunerParameters>
{
/**
* Constructs an instance from the foreign memory segment
*
* @param memorySegment for the composite structure in foreign memory
* @param memorySession for allocating additional memory segments for the sub-structures.
*/
public Rsp2CompositeParameters(MemorySegment memorySegment, MemorySession memorySession)
{
super(DeviceType.RSP2, memorySegment, memorySession);
}
}

View File

@@ -0,0 +1,85 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.composite;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceType;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.RspDuoDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDuoTunerParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.TunerParametersFactory;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DeviceParamsT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_RxChannelParamsT;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
/**
* RSPduo Composite parameters (device and two tuners)
*/
public class RspDuoCompositeParameters extends CompositeParameters<RspDuoDeviceParameters, RspDuoTunerParameters>
{
private RspDuoTunerParameters mTunerBParameters;
private ControlParameters mControlBParameters;
/**
* Constructs an instance from the foreign memory segment
*
* @param memorySegment for the composite structure in foreign memory
* @param memorySession for allocating additional memory segments for the sub-structures.
*/
public RspDuoCompositeParameters(MemorySegment memorySegment, MemorySession memorySession)
{
super(DeviceType.RSPduo, memorySegment, memorySession);
MemoryAddress memoryAddressRxB = sdrplay_api_DeviceParamsT.rxChannelB$get(memorySegment);
MemorySegment memorySegmentRxB = sdrplay_api_RxChannelParamsT.ofAddress(memoryAddressRxB, memorySession);
mTunerBParameters = (RspDuoTunerParameters) TunerParametersFactory.create(DeviceType.RSPduo, memorySegmentRxB);
MemorySegment tunerBControlParametersMemorySegment = sdrplay_api_RxChannelParamsT.ctrlParams$slice(memorySegmentRxB);
mControlBParameters = new ControlParameters(tunerBControlParametersMemorySegment);
}
/**
* Tuner B Tuner Parameters
*/
public RspDuoTunerParameters getTunerBParameters()
{
return mTunerBParameters;
}
/**
* Tuner B Control Parameters
*/
public ControlParameters getControlBParameters()
{
return mControlBParameters;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Device Composite Parameters\n");
sb.append("\tDevice Parameters:\n").append(getDeviceParameters()).append("\n");
sb.append("\tTuner Channel A:\n").append(getTunerAParameters()).append("\n");
sb.append("\tTuner Channel B:\n").append(getTunerBParameters()).append("\n");
return sb.toString();
}
}

View File

@@ -0,0 +1,43 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.composite;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceType;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.RspDxDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDxTunerParameters;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
/**
* RSPdx Composite parameters (device and receiver)
*/
public class RspDxCompositeParameters extends CompositeParameters<RspDxDeviceParameters, RspDxTunerParameters>
{
/**
* Constructs an instance from the foreign memory segment
*
* @param memorySegment for the composite structure in foreign memory
* @param memorySession for allocating additional memory segments for the sub-structures.
*/
public RspDxCompositeParameters(MemorySegment memorySegment, MemorySession memorySession)
{
super(DeviceType.RSPdx, memorySegment, memorySession);
}
}

View File

@@ -0,0 +1,74 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.control;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* ADSB Mode (for ADS-B decoding applications)
*/
public enum AdsbMode
{
NO_DECIMATION_LOWPASS(sdrplay_api_h.sdrplay_api_ADSB_NO_DECIMATION_LOWPASS(), "No Decimation-Lowpass"),
NO_DECIMATION_BANDPASS_2_MHZ(sdrplay_api_h.sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_2MHZ(), "No Decimation-Bandpass 2 MHz"),
NO_DECIMATION_BANDPASS_3_MHZ(sdrplay_api_h.sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_3MHZ(), "No Decimation-Bandpass 3 MHz"),
DECIMATION(sdrplay_api_h.sdrplay_api_ADSB_DECIMATION(), "Decimation");
private int mValue;
private String mDescription;
AdsbMode(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or DECIMATION if the code is not recognized
*/
public static AdsbMode fromValue(int value)
{
for(AdsbMode status: AdsbMode.values())
{
if(status.getValue() == value)
{
return status;
}
}
return DECIMATION;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,153 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.control;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_AgcT;
import java.lang.foreign.MemorySegment;
/**
* AGC structure (sdrplay_api_AgcT)
*/
public class Agc
{
private MemorySegment mMemorySegment;
/**
* Constructs an instance from the foreign memory segment
*/
public Agc(MemorySegment memorySegment)
{
mMemorySegment = memorySegment;
}
/**
* Foreign memory segment for this structure
*/
private MemorySegment getMemorySegment()
{
return mMemorySegment;
}
/**
* AGC Control (mode)
*/
public AgcMode getAgcMode()
{
return AgcMode.fromValue(sdrplay_api_AgcT.enable$get(getMemorySegment()));
}
/**
* Sets AGC Control (mode)
*/
public void setAgcMode(AgcMode mode)
{
sdrplay_api_AgcT.enable$set(getMemorySegment(), mode.getValue());
}
/**
* Set point dBfs
*/
public int getSetPointDbfs()
{
return sdrplay_api_AgcT.setPoint_dBfs$get(getMemorySegment());
}
/**
* Sets the set point dBfs
*/
public void setSetPointDbfs(int setPointDbfs)
{
sdrplay_api_AgcT.setPoint_dBfs$set(getMemorySegment(), setPointDbfs);
}
/**
* Attack rate in milliseconds
*/
public int getAttackMs()
{
return sdrplay_api_AgcT.attack_ms$get(getMemorySegment());
}
/**
* Sets the attack rate in milliseconds
*/
public void setAttackMs(int attackMs)
{
sdrplay_api_AgcT.attack_ms$set(getMemorySegment(), (short)attackMs);
}
/**
* Decay rate in milliseconds
*/
public int getDecayMs()
{
return sdrplay_api_AgcT.decay_ms$get(getMemorySegment());
}
/**
* Sets the decay rate in milliseconds
*/
public void setDecayMs(int decayMs)
{
sdrplay_api_AgcT.decay_ms$set(getMemorySegment(), (short)decayMs);
}
/**
* Decay delay rate in milliseconds
*/
public int getDecayDelayMs()
{
return sdrplay_api_AgcT.decay_delay_ms$get(getMemorySegment());
}
/**
* Sets the decay delay rate in milliseconds
*/
public void setDecayDelayMs(int decayDelayMs)
{
sdrplay_api_AgcT.decay_delay_ms$set(getMemorySegment(), (short)decayDelayMs);
}
/**
* Decay threshold in dB
*/
public int getDecayThresholdDb()
{
return sdrplay_api_AgcT.decay_threshold_dB$get(getMemorySegment());
}
/**
* Sets the decay threshold in dB
*/
public void setDecayThresholdDb(int decayThresholdDb)
{
sdrplay_api_AgcT.decay_threshold_dB$set(getMemorySegment(), (short)decayThresholdDb);
}
/**
* Sets the changes to be applied as a synchronous update
*/
public void setSynchronousUpdate(boolean syncUpdate)
{
//Note: this is supposed to be an integer value ... does it represent a boolean (0 or 1) or something else??
sdrplay_api_AgcT.syncUpdate$set(getMemorySegment(), Flag.of(syncUpdate));
}
}

View File

@@ -0,0 +1,75 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.control;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* Automatic Gain Control (AGC) Control (mode)
*/
public enum AgcMode
{
DISABLE(sdrplay_api_h.sdrplay_api_AGC_DISABLE(), "DISABLE"),
AGC_100_HZ(sdrplay_api_h.sdrplay_api_AGC_100HZ(), "100 Hz"),
AGC_50_HZ(sdrplay_api_h.sdrplay_api_AGC_50HZ(), "50 Hz"),
AGC_5_HZ(sdrplay_api_h.sdrplay_api_AGC_5HZ(), "5 Hz"),
ENABLE(sdrplay_api_h.sdrplay_api_AGC_CTRL_EN(), "ENABLE");
private int mValue;
private String mDescription;
AgcMode(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or DISABLE if the code is not recognized
*/
public static AgcMode fromValue(int value)
{
for(AgcMode status: AgcMode.values())
{
if(status.getValue() == value)
{
return status;
}
}
return DISABLE;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,93 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.control;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_ControlParamsT;
import java.lang.foreign.MemorySegment;
/**
* Control Parameters structure (sdrplay_api_ControlParamsT)
*/
public class ControlParameters
{
private MemorySegment mMemorySegment;
private DcOffset mDcOffset;
private Decimation mDecimation;
private Agc mAgc;
/**
* Creates an instance from the foreign memory segment
*/
public ControlParameters(MemorySegment memorySegment)
{
mMemorySegment = memorySegment;
mDcOffset = new DcOffset(sdrplay_api_ControlParamsT.dcOffset$slice(memorySegment));
mDecimation = new Decimation(sdrplay_api_ControlParamsT.decimation$slice(memorySegment));
mAgc = new Agc(sdrplay_api_ControlParamsT.agc$slice(memorySegment));
}
/**
* Foreign memory segment for this structure
*/
private MemorySegment getMemorySegment()
{
return mMemorySegment;
}
/**
* DC offset settings for DC and IQ correction
*/
public DcOffset getDcOffset()
{
return mDcOffset;
}
/**
* Decimation settings
*/
public Decimation getDecimation()
{
return mDecimation;
}
/**
* Automatic Gain Control (AGC) settings
*/
public Agc getAgc()
{
return mAgc;
}
/**
* Current ADSB mode
*/
public AdsbMode getAdsbMode()
{
return AdsbMode.fromValue(sdrplay_api_ControlParamsT.adsbMode$get(getMemorySegment()));
}
/**
* Sets ADSB mode
*/
public void setAdsbMode(AdsbMode mode)
{
sdrplay_api_ControlParamsT.adsbMode$set(getMemorySegment(), mode.getValue());
}
}

View File

@@ -0,0 +1,80 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.control;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DcOffsetT;
import java.lang.foreign.MemorySegment;
/**
* DC Offset structure (sdrplay_api_DCOffsetT)
*/
public class DcOffset
{
private MemorySegment mMemorySegment;
/**
* Constructs an instance from the foreign memory segment
*/
public DcOffset(MemorySegment memorySegment)
{
mMemorySegment = memorySegment;
}
/**
* Foreign memory segment for this structure
*/
private MemorySegment getMemorySegment()
{
return mMemorySegment;
}
/**
* Indicates if DC correction is enabled.
*/
public boolean isDC()
{
return Flag.evaluate(sdrplay_api_DcOffsetT.DCenable$get(getMemorySegment()));
}
/**
* Enable or disable DC correction
*/
public void setDC(boolean enable)
{
sdrplay_api_DcOffsetT.DCenable$set(getMemorySegment(), Flag.of(enable));
}
/**
* Indicates if IQ correction is enabled
*/
public boolean isIQ()
{
return Flag.evaluate(sdrplay_api_DcOffsetT.IQenable$get(getMemorySegment()));
}
/**
* Enable or disable IQ correction
*/
public void setIQ(boolean enable)
{
sdrplay_api_DcOffsetT.IQenable$set(getMemorySegment(), Flag.of(enable));
}
}

View File

@@ -0,0 +1,96 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.control;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DecimationT;
import java.lang.foreign.MemorySegment;
/**
* Decimation structure (sdrplay_api_DecimationT)
*/
public class Decimation
{
private MemorySegment mMemorySegment;
/**
* Constructs an instance from the foreign memory segment
*/
public Decimation(MemorySegment memorySegment)
{
mMemorySegment = memorySegment;
}
/**
* Foreign memory segment for this structure
*/
public MemorySegment getMemorySegment()
{
return mMemorySegment;
}
/**
* Indicates if decimation is enabled
*/
public boolean isEnabled()
{
return Flag.evaluate(sdrplay_api_DecimationT.enable$get(getMemorySegment()));
}
/**
* Enable or disable decimation
*/
public void setEnabled(boolean enable)
{
sdrplay_api_DecimationT.enable$set(getMemorySegment(), Flag.of(enable));
}
/**
* Decimation factor
*/
public int getDecimationFactor()
{
return sdrplay_api_DecimationT.decimationFactor$get(getMemorySegment());
}
/**
* Sets the decimation factor
*/
public void setDecimationFactor(int decimationFactor)
{
sdrplay_api_DecimationT.decimationFactor$set(getMemorySegment(), (byte)decimationFactor);
}
/**
* Indicates if the wideband signal setting is enabled
*/
public boolean isWideBandSignal()
{
return Flag.evaluate(sdrplay_api_DecimationT.wideBandSignal$get(getMemorySegment()));
}
/**
* Enables or disables the wideband signal setting
*/
public void setWideBandSignal(boolean enable)
{
sdrplay_api_DecimationT.wideBandSignal$set(getMemorySegment(), Flag.of(enable));
}
}

View File

@@ -0,0 +1,131 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DevParamsT;
import java.lang.foreign.MemorySegment;
/**
* Device Parameters structure (sdrplay_api_DevParamsT)
*/
public abstract class DeviceParameters
{
private MemorySegment mMemorySegment;
private SamplingFrequency mSamplingFrequency;
private SynchronousUpdate mSynchronousUpdate;
private ResetFlags mResetFlags;
public DeviceParameters(MemorySegment memorySegment)
{
mMemorySegment = memorySegment;
mSamplingFrequency = new SamplingFrequency(sdrplay_api_DevParamsT.fsFreq$slice(memorySegment));
mSynchronousUpdate = new SynchronousUpdate(sdrplay_api_DevParamsT.syncUpdate$slice(memorySegment));
mResetFlags = new ResetFlags(sdrplay_api_DevParamsT.resetFlags$slice(memorySegment));
}
/**
* Foreign memory segment for this device parameters instance
*/
protected MemorySegment getMemorySegment()
{
return mMemorySegment;
}
/**
* Parts Per Million (ppm) center frequency correction value.
* @return ppm
*/
public double getPPM()
{
return sdrplay_api_DevParamsT.ppm$get(getMemorySegment());
}
/**
* Sets the parts per million (ppm) center frequency correction value
* @param ppm parts per million
*/
public void setPPM(double ppm)
{
sdrplay_api_DevParamsT.ppm$set(getMemorySegment(), ppm);
}
/**
* Sampling frequency structure.
*/
public SamplingFrequency getSamplingFrequency()
{
return mSamplingFrequency;
}
/**
* Synchronous update structure
*/
public SynchronousUpdate getSynchronousUpdate()
{
return mSynchronousUpdate;
}
/**
* Reset request flags
*/
public ResetFlags getResetFlags()
{
return mResetFlags;
}
/**
* USB Transfer mode currently used by the device
*/
public TransferMode getTransferMode()
{
return TransferMode.fromValue(sdrplay_api_DevParamsT.mode$get(getMemorySegment()));
}
/**
* Sets the USB transfer mode used by the device
*/
public void setTransferMode(TransferMode transferMode)
{
if(transferMode != TransferMode.UNKNOWN)
{
sdrplay_api_DevParamsT.mode$set(getMemorySegment(), transferMode.getValue());
}
}
public long getSamplesPerPacket()
{
return sdrplay_api_DevParamsT.samplesPerPkt$get(getMemorySegment());
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("\tDevice Parameters").append("\n");
sb.append("\t\tPPM: ").append(getPPM()).append("\n");
sb.append("\t\tSample Rate: ").append(getSamplingFrequency()).append("\n");
sb.append("\t\tSamples Per Packet: ").append(getSamplesPerPacket()).append("\n");
sb.append("\t\tSync Update: ").append(getSynchronousUpdate()).append("\n");
sb.append("\t\tReset Flags: ").append(getResetFlags()).append("\n");
sb.append("\t\tTransfer Mode: ").append(getTransferMode()).append("\n");
return sb.toString();
}
}

View File

@@ -0,0 +1,59 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.device;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceType;
import java.lang.foreign.MemorySegment;
/**
* Creates device parameters instance from a foreign memory segment
*/
public class DeviceParametersFactory
{
/**
* Create a device parameters instance
* @param deviceType for the device
* @param memorySegment of foreign memory representing the device type
* @return instance
*/
public static DeviceParameters create(DeviceType deviceType, MemorySegment memorySegment)
{
switch(deviceType)
{
case RSP1 -> {
return new Rsp1DeviceParameters(memorySegment);
}
case RSP1A -> {
return new Rsp1aDeviceParameters(memorySegment);
}
case RSP2 -> {
return new Rsp2DeviceParameters(memorySegment);
}
case RSPduo -> {
return new RspDuoDeviceParameters(memorySegment);
}
case RSPdx -> {
return new RspDxDeviceParameters(memorySegment);
}
}
throw new IllegalArgumentException("Unrecognized Device Type: " + deviceType);
}
}

View File

@@ -0,0 +1,73 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.device;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_ResetFlagsT;
import java.lang.foreign.MemorySegment;
/**
* Reset Flags structure
*/
public class ResetFlags
{
private MemorySegment mMemorySegment;
/**
* Constructs an instance from a foreign memory segment and transfers the structure fields into this instance.
* @param memorySegment pointer
*/
public ResetFlags(MemorySegment memorySegment)
{
mMemorySegment = memorySegment;
}
/**
* Foreign memory segment
*/
private MemorySegment getMemorySegment()
{
return mMemorySegment;
}
/**
* Request a reset of the gain reduction
*/
public void resetGain(boolean reset)
{
sdrplay_api_ResetFlagsT.resetGainUpdate$set(getMemorySegment(), reset ? Flag.TRUE : Flag.FALSE);
}
/**
* Request a reset of the center frequency value
*/
public void resetFrequency(boolean reset)
{
sdrplay_api_ResetFlagsT.resetRfUpdate$set(getMemorySegment(), reset ? Flag.TRUE : Flag.FALSE);
}
/**
* Request a reset of the sample rate value.
*/
public void resetSampleRate(boolean reset)
{
sdrplay_api_ResetFlagsT.resetFsUpdate$set(getMemorySegment(), reset ? Flag.TRUE : Flag.FALSE);
}
}

View File

@@ -0,0 +1,37 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.device;
import java.lang.foreign.MemorySegment;
/**
* RSP-1 Device Parameters structure
*/
public class Rsp1DeviceParameters extends DeviceParameters
{
/**
* Constructs an instance
* @param memorySegment for this structure
*/
public Rsp1DeviceParameters(MemorySegment memorySegment)
{
super(memorySegment);
}
}

View File

@@ -0,0 +1,83 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.device;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DevParamsT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_Rsp1aParamsT;
import java.lang.foreign.MemorySegment;
/**
* RSP-1A Device Parameters structure
*/
public class Rsp1aDeviceParameters extends DeviceParameters
{
private MemorySegment mRsp1AMemorySegment;
/**
* Constructs an instance
* @param memorySegment for this structure
*/
public Rsp1aDeviceParameters(MemorySegment memorySegment)
{
super(memorySegment);
mRsp1AMemorySegment = sdrplay_api_DevParamsT.rsp1aParams$slice(memorySegment);
}
/**
* Foreign memory segment representing this structure
*/
private MemorySegment getRsp1AMemorySegment()
{
return mRsp1AMemorySegment;
}
/**
* Indicates if RF notch is enabled.
*/
public boolean isRFNotch()
{
return Flag.evaluate(sdrplay_api_Rsp1aParamsT.rfNotchEnable$get(getRsp1AMemorySegment()));
}
/**
* Enables or disables the RF notch.
*/
public void setRFNotch(boolean enable)
{
sdrplay_api_Rsp1aParamsT.rfNotchEnable$set(getRsp1AMemorySegment(), Flag.of(enable));
}
/**
* Indicates if DAB RF notch is enabled
*/
public boolean isRfDabNotch()
{
return Flag.evaluate(sdrplay_api_Rsp1aParamsT.rfDabNotchEnable$get(getRsp1AMemorySegment()));
}
/**
* Enables or disables the DAB RF notch
*/
public void setRfDabNotch(boolean enable)
{
sdrplay_api_Rsp1aParamsT.rfDabNotchEnable$set(getRsp1AMemorySegment(), Flag.of(enable));
}
}

View File

@@ -0,0 +1,67 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.device;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DevParamsT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_Rsp2ParamsT;
import java.lang.foreign.MemorySegment;
/**
* RSP-2 Device Parameters structure
*/
public class Rsp2DeviceParameters extends DeviceParameters
{
private MemorySegment mRsp2MemorySegment;
/**
* Constructs an instance
* @param memorySegment for this structure
*/
public Rsp2DeviceParameters(MemorySegment memorySegment)
{
super(memorySegment);
mRsp2MemorySegment = sdrplay_api_DevParamsT.rsp2Params$slice(memorySegment);
}
/**
* Foreign memory segment representing this structure
*/
private MemorySegment getRsp2MemorySegment()
{
return mRsp2MemorySegment;
}
/**
* Indicates if the external reference output is enabled
*/
public boolean isExternalReferenceOutput()
{
return Flag.evaluate(sdrplay_api_Rsp2ParamsT.extRefOutputEn$get(getRsp2MemorySegment()));
}
/**
* Enables or disables the external reference output
*/
public void setExternalReferenceOutput(boolean enable)
{
sdrplay_api_Rsp2ParamsT.extRefOutputEn$set(getRsp2MemorySegment(), Flag.of(enable));
}
}

View File

@@ -0,0 +1,67 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.device;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DevParamsT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_RspDuoParamsT;
import java.lang.foreign.MemorySegment;
/**
* RSPduo Device Parameters structure
*/
public class RspDuoDeviceParameters extends DeviceParameters
{
private MemorySegment mRspDuoMemorySegment;
/**
* Constructs an instance
* @param memorySegment for this structure
*/
public RspDuoDeviceParameters(MemorySegment memorySegment)
{
super(memorySegment);
mRspDuoMemorySegment = sdrplay_api_DevParamsT.rspDuoParams$slice(memorySegment);
}
/**
* Foreign memory segment representing this structure
*/
private MemorySegment getRspDuoMemorySegment()
{
return mRspDuoMemorySegment;
}
/**
* Indicates if the external reference output is enabled
*/
public boolean isExternalReferenceOutput()
{
return Flag.evaluate(sdrplay_api_RspDuoParamsT.extRefOutputEn$get(getRspDuoMemorySegment()));
}
/**
* Enables or disables the external reference output
*/
public void setExternalReferenceOutput(boolean enable)
{
sdrplay_api_RspDuoParamsT.extRefOutputEn$set(getRspDuoMemorySegment(), Flag.of(enable));
}
}

View File

@@ -0,0 +1,131 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.device;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDxAntenna;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DevParamsT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_RspDxParamsT;
import java.lang.foreign.MemorySegment;
/**
* RSP-DX Device Parameters structure
*/
public class RspDxDeviceParameters extends DeviceParameters
{
private MemorySegment mRspDxMemorySegment;
/**
* Constructs an instance from the foreign memory segment.
*/
public RspDxDeviceParameters(MemorySegment memorySegment)
{
super(memorySegment);
mRspDxMemorySegment = sdrplay_api_DevParamsT.rspDxParams$slice(memorySegment);
}
/**
* Foreign memory segment for this structure
*/
private MemorySegment getRspDxMemorySegment()
{
return mRspDxMemorySegment;
}
/**
* Indicates if High Dynamic Range (HDR) is enabled
*/
public boolean isHdr()
{
return Flag.evaluate(sdrplay_api_RspDxParamsT.hdrEnable$get(getRspDxMemorySegment()));
}
/**
* Enables or disables High Dynamic Range (HDR)
*/
public void setHdr(boolean enable)
{
sdrplay_api_RspDxParamsT.hdrEnable$set(getRspDxMemorySegment(), Flag.of(enable));
}
/**
* Indicates if Bias-T is enabled
*/
public boolean isBiasT()
{
return Flag.evaluate(sdrplay_api_RspDxParamsT.biasTEnable$get(getRspDxMemorySegment()));
}
/**
* Enables or disables Bias-T
*/
public void setBiasT(boolean enable)
{
sdrplay_api_RspDxParamsT.biasTEnable$set(getRspDxMemorySegment(), Flag.of(enable));
}
/**
* RSPdx Antenna Setting
*/
public RspDxAntenna getRspDxAntenna()
{
return RspDxAntenna.fromValue(sdrplay_api_RspDxParamsT.antennaSel$get(getRspDxMemorySegment()));
}
/**
* Selects the RSPdx Antenna
*/
public void setRspDxAntenna(RspDxAntenna rspDxAntenna)
{
sdrplay_api_RspDxParamsT.antennaSel$set(getRspDxMemorySegment(), rspDxAntenna.getValue());
}
/**
* Indicates if RF notch is enabled
*/
public boolean isRfNotch()
{
return Flag.evaluate(sdrplay_api_RspDxParamsT.rfNotchEnable$get(getRspDxMemorySegment()));
}
/**
* Enables or disables RF notch
*/
public void setRfNotch(boolean enable)
{
sdrplay_api_RspDxParamsT.rfNotchEnable$set(getRspDxMemorySegment(), Flag.of(enable));
}
/**
* Indicates if the RF DAB notch is enabled
*/
public boolean isRfDabNotch()
{
return Flag.evaluate(sdrplay_api_RspDxParamsT.rfDabNotchEnable$get(getRspDxMemorySegment()));
}
/**
* Enables or disables the RF DAB notch
*/
public void setRfDabNotch(boolean enable)
{
sdrplay_api_RspDxParamsT.rfDabNotchEnable$set(getRspDxMemorySegment(), Flag.of(enable));
}
}

View File

@@ -0,0 +1,86 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.device;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_FsFreqT;
import java.lang.foreign.MemorySegment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Sample Rate structure
*/
public class SamplingFrequency
{
private Logger mLog = LoggerFactory.getLogger(SamplingFrequency.class);
private MemorySegment mMemorySegment;
/**
* Constructs an instance from a foreign memory segment and transfers the structure fields into this instance.
* @param memorySegment pointer
*/
public SamplingFrequency(MemorySegment memorySegment)
{
mMemorySegment = memorySegment;
}
private MemorySegment getMemorySegment()
{
return mMemorySegment;
}
/**
* Sample rate frequency
* @return frequency in Hertz
*/
public double getSampleRate()
{
return sdrplay_api_FsFreqT.fsHz$get(getMemorySegment());
}
/**
* Applies the requested sample rate to the device parameters
* @param sampleRate requested rate
* @param synchronousUpdate request
* @param recalibrate request
*/
public void setSampleRate(double sampleRate, boolean synchronousUpdate, boolean recalibrate)
{
sdrplay_api_FsFreqT.fsHz$set(getMemorySegment(), sampleRate);
sdrplay_api_FsFreqT.syncUpdate$set(getMemorySegment(), synchronousUpdate ? Flag.TRUE : Flag.FALSE);
sdrplay_api_FsFreqT.reCal$set(getMemorySegment(), recalibrate ? Flag.TRUE : Flag.FALSE);
}
/**
* Applies the requested sample rate to the device parameters with synchronous update and recalibrate set to false.
* @param sampleRate requested rate
*/
public void setSampleRate(double sampleRate)
{
setSampleRate(sampleRate, false, false);
}
@Override
public String toString()
{
return "Sample Rate:" + getSampleRate();
}
}

View File

@@ -0,0 +1,56 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_SyncUpdateT;
import java.lang.foreign.MemorySegment;
/**
* Sync Update structure
*/
public class SynchronousUpdate
{
private MemorySegment mMemorySegment;
/**
* Constructs an instance from a foreign memory segment
* @param memorySegment pointer
*/
public SynchronousUpdate(MemorySegment memorySegment)
{
mMemorySegment = memorySegment;
}
private MemorySegment getMemorySegment()
{
return mMemorySegment;
}
/**
* Sets the sample number and period to apply to both tuners for a synchronous update.
* @param sampleNumber value
* @param period value
*/
public void set(int sampleNumber, int period)
{
sdrplay_api_SyncUpdateT.sampleNum$set(getMemorySegment(), sampleNumber);
sdrplay_api_SyncUpdateT.period$set(getMemorySegment(), period);
}
}

View File

@@ -0,0 +1,73 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* USB Transfer Mode
*/
public enum TransferMode
{
ISOCHRONOUS(sdrplay_api_h.sdrplay_api_ISOCH(), "ISOCHRONOUS"),
BULK(sdrplay_api_h.sdrplay_api_BULK(), "BULK"),
UNKNOWN(-1, "UNKNOWN");
private int mValue;
private String mDescription;
TransferMode(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UNKNOWN if the code is not recognized
*/
public static TransferMode fromValue(int value)
{
for(TransferMode status: TransferMode.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNKNOWN;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,57 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.event;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_EventParamsT;
import java.lang.foreign.MemorySegment;
/**
* Event Parameters structure (sdrplay_api_EventParamsT)
*/
public class EventParametersFactory
{
private GainCallbackParameters mGainCallbackParameters;
private PowerOverloadCallbackParameters mPowerOverloadCallbackParameters;
private RspDuoModeCallbackParameters mRspDuoModeCallbackParameters;
/**
* Gain event callback parameters
*/
public static GainCallbackParameters createGainCallbackParameters(MemorySegment memorySegment)
{
return new GainCallbackParameters(sdrplay_api_EventParamsT.gainParams$slice(memorySegment));
}
/**
* Power overload event callback parameters
*/
public static PowerOverloadCallbackParameters createPowerOverloadCallbackParameters(MemorySegment memorySegment)
{
return new PowerOverloadCallbackParameters(sdrplay_api_EventParamsT.powerOverloadParams$slice(memorySegment));
}
/**
* RSPduo mode event callback parameters
*/
public static RspDuoModeCallbackParameters createRspDuoModeCallbackParameters(MemorySegment memorySegment)
{
return new RspDuoModeCallbackParameters(sdrplay_api_EventParamsT.rspDuoModeParams$slice(memorySegment));
}
}

View File

@@ -0,0 +1,75 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.event;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* (Callback) Event Type (sdrplay_api_EventT)
*/
public enum EventType
{
GAIN_CHANGE(sdrplay_api_h.sdrplay_api_GainChange(), "GAIN CHANGE"),
POWER_OVERLOAD_CHANGE(sdrplay_api_h.sdrplay_api_PowerOverloadChange(), "POWER OVERLOAD CHANGE"),
DEVICE_REMOVED(sdrplay_api_h.sdrplay_api_DeviceRemoved(), "DEVICE REMOVED"),
RSP_DUO_MODE_CHANGE(sdrplay_api_h.sdrplay_api_RspDuoModeChange(), "RSP-DUO MODE CHANGE"),
UNKNOWN(-1, "UNKNOWN");
private int mValue;
private String mDescription;
EventType(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UNKNOWN if the code is not recognized
*/
public static EventType fromValue(int value)
{
for(EventType status: EventType.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNKNOWN;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,80 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.event;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_GainCbParamT;
import java.lang.foreign.MemorySegment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Gain Callback Parameters structure (sdrplay_api_GainCbParamT)
*/
public class GainCallbackParameters
{
private static final Logger mLog = LoggerFactory.getLogger(GainCallbackParameters.class);
private int mGainReductionDb;
private int mLnaGainReductionDb;
private double mCurrentGain;
/**
* Constructs an instance from the foreign memory segment
*/
public GainCallbackParameters(MemorySegment memorySegment)
{
mGainReductionDb = sdrplay_api_GainCbParamT.gRdB$get(memorySegment);
mLnaGainReductionDb = sdrplay_api_GainCbParamT.lnaGRdB$get(memorySegment);
mCurrentGain = sdrplay_api_GainCbParamT.currGain$get(memorySegment);
}
/**
* Current gain reduction value
*/
public int getGainReductionDb()
{
return mGainReductionDb;
}
/**
* Current LNA state setting
*/
public int getLnaGainReductionDb()
{
return mLnaGainReductionDb;
}
/**
* Current gain value
*/
public double getCurrentGain()
{
return mCurrentGain;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("GR:").append(getGainReductionDb());
sb.append(" LNA:").append(getLnaGainReductionDb());
sb.append(" CURRENT GAIN:").append(getCurrentGain());
return sb.toString();
}
}

View File

@@ -0,0 +1,48 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.event;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_PowerOverloadCbParamT;
import java.lang.foreign.MemorySegment;
/**
* Power Overload Callback Parameters (sdrplay_api_PowerOverloadCbParamT)
*/
public class PowerOverloadCallbackParameters
{
private PowerOverloadEventType mPowerOverloadEventType;
/**
* Constructs an instance from the foreign memory segment
*/
public PowerOverloadCallbackParameters(MemorySegment memorySegment)
{
mPowerOverloadEventType = PowerOverloadEventType
.fromValue(sdrplay_api_PowerOverloadCbParamT.powerOverloadChangeType$get(memorySegment));
}
/**
* Event type
*/
public PowerOverloadEventType getPowerOverloadEvent()
{
return mPowerOverloadEventType;
}
}

View File

@@ -0,0 +1,73 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.event;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* Power Overload Callback Event type
*/
public enum PowerOverloadEventType
{
OVERLOAD_DETECTED(sdrplay_api_h.sdrplay_api_Overload_Detected(), "OVERLOAD DETECTED"),
OVERLOAD_CORRECTED(sdrplay_api_h.sdrplay_api_Overload_Corrected(), "OVERLOAD CORRECTED"),
UNKNOWN(-1, "UNKNOWN");
private int mValue;
private String mDescription;
PowerOverloadEventType(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UNKNOWN if the code is not recognized
*/
public static PowerOverloadEventType fromValue(int value)
{
for(PowerOverloadEventType status: PowerOverloadEventType.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNKNOWN;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,47 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.event;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_RspDuoModeCbParamT;
import java.lang.foreign.MemorySegment;
/**
* RSP-Duo Mode Callback Parameters (sdrplay_api_RspDuoModeCbParamT)
*/
public class RspDuoModeCallbackParameters
{
private RspDuoModeEventType mRspDuoModeEventType;
/**
* Constructs an instance from the foreign memory segment
*/
public RspDuoModeCallbackParameters(MemorySegment memorySegment)
{
mRspDuoModeEventType = RspDuoModeEventType.fromValue(sdrplay_api_RspDuoModeCbParamT.modeChangeType$get(memorySegment));
}
/**
* Event type
*/
public RspDuoModeEventType getRspDuoModeEvent()
{
return mRspDuoModeEventType;
}
}

View File

@@ -0,0 +1,78 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.event;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* RSP-Duo Mode Callback Event type
*/
public enum RspDuoModeEventType
{
MASTER_INITIALIZED(sdrplay_api_h.sdrplay_api_MasterInitialised(), "MASTER INITIALIZED"),
SLAVE_ATTACHED(sdrplay_api_h.sdrplay_api_SlaveAttached(), "SLAVE ATTACHED"),
SLAVE_DETACHED(sdrplay_api_h.sdrplay_api_SlaveDetached(), "SLAVE DETACHED"),
SLAVE_INITIALIZED(sdrplay_api_h.sdrplay_api_SlaveInitialised(), "SLAVE INITIALIZED"),
SLAVE_UNINITIALIZED(sdrplay_api_h.sdrplay_api_SlaveUninitialised(), "SLAVE UNINITIALIZED"),
MASTER_DLL_DISAPPEARED(sdrplay_api_h.sdrplay_api_MasterDllDisappeared(), "MASTER DLL DISAPPEARED"),
SLAVE_DLL_DISAPPEARED(sdrplay_api_h.sdrplay_api_SlaveDllDisappeared(), "SLAVE DLL DISAPPEARED"),
UNKNOWN(-1, "UNKNOWN");
private int mValue;
private String mDescription;
RspDuoModeEventType(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UNKNOWN if the code is not recognized
*/
public static RspDuoModeEventType fromValue(int value)
{
for(RspDuoModeEventType status: RspDuoModeEventType.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNKNOWN;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,89 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.tuner;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* Bandwidth
*/
public enum Bandwidth
{
BW_0_200(sdrplay_api_h.sdrplay_api_BW_0_200(), 200_000, "0.200 MHz"),
BW_0_300(sdrplay_api_h.sdrplay_api_BW_0_300(), 300_000, "0.300 MHz"),
BW_0_600(sdrplay_api_h.sdrplay_api_BW_0_600(), 600_000, "0.600 MHz"),
BW_1_536(sdrplay_api_h.sdrplay_api_BW_1_536(), 1_536_000, "1.536 MHz"),
BW_5_000(sdrplay_api_h.sdrplay_api_BW_5_000(), 5_000_000, "5.000 MHz"),
BW_6_000(sdrplay_api_h.sdrplay_api_BW_6_000(), 6_000_000, "6.000 MHz"),
BW_7_000(sdrplay_api_h.sdrplay_api_BW_7_000(), 7_000_000, "7.000 MHz"),
BW_8_000(sdrplay_api_h.sdrplay_api_BW_8_000(), 8_000_000, "8.000 MHz"),
UNDEFINED(sdrplay_api_h.sdrplay_api_BW_Undefined(), 0, "UNDEFINED");
private int mValue;
private long mBandwidth;
private String mDescription;
Bandwidth(int value, long bandwidth, String description)
{
mValue = value;
mBandwidth = bandwidth;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Bandwidth (Hz)
*/
public long getBandwidth()
{
return mBandwidth;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UNDEFINED if the code is not recognized
*/
public static Bandwidth fromValue(int value)
{
for(Bandwidth status: Bandwidth.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNDEFINED;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,101 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 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.sdrplay.api.parameter.tuner;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DcOffsetTunerT;
import java.lang.foreign.MemorySegment;
/**
* DC Offset Tuner structure (sdrplay_api_DcOffsetTunerT)
*/
public class DcOffsetTuner
{
private MemorySegment mMemorySegment;
/**
* Constructs an instance from the foreign memory segment
*/
public DcOffsetTuner(MemorySegment memorySegment)
{
mMemorySegment = memorySegment;
}
/**
* Foreign memory segment for this structure
*/
private MemorySegment getMemorySegment()
{
return mMemorySegment;
}
/**
* DC calibration mode.
* @return
*/
public int getDcCal()
{
return sdrplay_api_DcOffsetTunerT.dcCal$get(getMemorySegment());
}
public void setDcCal(int dcCal)
{
sdrplay_api_DcOffsetTunerT.dcCal$set(getMemorySegment(), (byte)dcCal);
}
public boolean isSpeedUp()
{
return Flag.evaluate(sdrplay_api_DcOffsetTunerT.speedUp$get(getMemorySegment()));
}
public void setSpeedUp(boolean speedUp)
{
sdrplay_api_DcOffsetTunerT.speedUp$set(getMemorySegment(), Flag.of(speedUp));
}
public int getTrackTime()
{
return sdrplay_api_DcOffsetTunerT.trackTime$get(getMemorySegment());
}
public void setTrackTime(int trackTime)
{
sdrplay_api_DcOffsetTunerT.trackTime$set(getMemorySegment(), trackTime);
}
public int getRefreshRateTime()
{
return sdrplay_api_DcOffsetTunerT.refreshRateTime$get(getMemorySegment());
}
public void setRefreshRateTime(int refreshRateTime)
{
sdrplay_api_DcOffsetTunerT.refreshRateTime$set(getMemorySegment(), refreshRateTime);
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("DC Cal:").append(getDcCal()).append(" Speed Up:").append(isSpeedUp());
sb.append(" Track Time:").append(getTrackTime()).append(" Refresh Rate Time:").append(getRefreshRateTime());
return sb.toString();
}
}

Some files were not shown because too many files have changed in this diff Show More