diff --git a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/DeviceDescriptor.java b/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/DeviceDescriptor.java deleted file mode 100644 index f87172cb9..000000000 --- a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/DeviceDescriptor.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - * **************************************************************************** - */ - -package com.github.dsheirer.sdrplay; - -import com.github.dsheirer.sdrplay.device.Device; -import com.github.dsheirer.sdrplay.device.DeviceType; -import java.util.Collections; -import java.util.List; - -/** - * Descriptor that provides limited details for an RSP device and the available selection modes. - */ -public class DeviceDescriptor -{ - private Device mDevice; - private List mDeviceSelectionModes; - - /** - * Constructs a device descriptor - * @param device to be described - * @param deviceSelectionModes that are available for the device - */ - public DeviceDescriptor(Device device, List deviceSelectionModes) - { - mDevice = device; - mDeviceSelectionModes = deviceSelectionModes; - } - - /** - * Device that backs this descriptor. - * - * Note: package private. This method is not intended to be exposed to the library user. - */ - Device getDevice() - { - return mDevice; - } - - /** - * Serial number for the device - */ - public String getSerialNumber() - { - return mDevice.getSerialNumber(); - } - - /** - * Indicates if this device descriptor's serial number matches the specified serial number - * @param serialNumber to compare - * @return true if there is a match - */ - public boolean matches(String serialNumber) - { - return getSerialNumber() != null && getSerialNumber().equalsIgnoreCase(serialNumber); - } - - /** - * Type of RSP device - */ - public DeviceType getDeviceType() - { - return mDevice.getDeviceType(); - } - - /** - * List of selection modes available for this device. Most RSP devices will only be available for selection as - * as single tuner. The RSPduo has several selection modes available, depending on how the device is currently - * being used. - */ - public List getDeviceSelectionModes() - { - return Collections.unmodifiableList(mDeviceSelectionModes); - } - - /** - * Indicates if the device supports the device selection mode - * @param deviceSelectionMode - * @return true if supported - */ - public boolean supports(DeviceSelectionMode deviceSelectionMode) - { - return mDeviceSelectionModes.contains(deviceSelectionMode); - } - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append("Device: ").append(getDeviceType()); - sb.append(" Serial #:").append(getSerialNumber()); - sb.append(" Available Selection Modes ").append(getDeviceSelectionModes()); - return sb.toString(); - } -} diff --git a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/DeviceSelectionMode.java b/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/DeviceSelectionMode.java index 85745a903..cdfc76c67 100644 --- a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/DeviceSelectionMode.java +++ b/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/DeviceSelectionMode.java @@ -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,7 +19,6 @@ package com.github.dsheirer.sdrplay; - import com.github.dsheirer.sdrplay.device.RspDuoMode; import com.github.dsheirer.sdrplay.device.TunerSelect; import java.util.EnumSet; @@ -32,15 +31,7 @@ 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), - - //RSPduo devices only - //Note: dual independent tuners - the device is first claimed as master/tuner1, then a second api instance is - //created and the second tuner is claimed as slave/tuner2 - DUAL_INDEPENDENT_TUNERS("Dual Independent Tuners", RspDuoMode.MASTER, TunerSelect.TUNER_1), - DUAL_SYNCHRONIZED_TUNERS("Dual Synchronized Tuners", RspDuoMode.DUAL_TUNER, TunerSelect.TUNER_BOTH), MASTER_TUNER_1("Master - Tuner 1", RspDuoMode.MASTER, TunerSelect.TUNER_1), - MASTER_TUNER_2("Master - Tuner 2", RspDuoMode.MASTER, TunerSelect.TUNER_2), - SLAVE_TUNER_1("Slave - Tuner 1", RspDuoMode.SLAVE, TunerSelect.TUNER_1), SLAVE_TUNER_2("Slave - Tuner 2", RspDuoMode.SLAVE, TunerSelect.TUNER_2); private String mDescription; @@ -63,9 +54,8 @@ public enum DeviceSelectionMode /** * Set of all selection modes available for the RSPduo */ - public static final EnumSet ALL_DUO_SELECTION_MODES = EnumSet.range(DUAL_INDEPENDENT_TUNERS, SLAVE_TUNER_2); - public static final EnumSet MASTER_MODES = EnumSet.of(MASTER_TUNER_1, MASTER_TUNER_2); - public static final EnumSet SLAVE_MODES = EnumSet.of(SLAVE_TUNER_1, SLAVE_TUNER_2); + public static final EnumSet MASTER_MODES = EnumSet.of(MASTER_TUNER_1); + public static final EnumSet SLAVE_MODES = EnumSet.of(SLAVE_TUNER_2); public static final EnumSet SINGLE_TUNER_MODES = EnumSet.of(SINGLE_TUNER_1, SINGLE_TUNER_2); /** diff --git a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/SDRplay.java b/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/SDRplay.java index ce3efa5f4..fd0548f4b 100644 --- a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/SDRplay.java +++ b/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/SDRplay.java @@ -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 @@ -27,30 +27,27 @@ import com.github.dsheirer.sdrplay.callback.IStreamListener; import com.github.dsheirer.sdrplay.device.Device; import com.github.dsheirer.sdrplay.device.DeviceFactory; +import com.github.dsheirer.sdrplay.device.DeviceInfo; import com.github.dsheirer.sdrplay.device.DeviceType; -import com.github.dsheirer.sdrplay.device.RspDuoDevice; -import com.github.dsheirer.sdrplay.device.RspDuoDualIndependentTunerDevice; -import com.github.dsheirer.sdrplay.device.RspDuoMode; +import com.github.dsheirer.sdrplay.device.IDeviceStruct; import com.github.dsheirer.sdrplay.device.TunerSelect; import com.github.dsheirer.sdrplay.error.DebugLevel; import com.github.dsheirer.sdrplay.error.ErrorInformation; import com.github.dsheirer.sdrplay.parameter.composite.CompositeParameters; import com.github.dsheirer.sdrplay.parameter.composite.CompositeParametersFactory; import com.github.dsheirer.sdrplay.util.Flag; -import org.apache.commons.lang3.SystemUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - 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.Collections; 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. @@ -90,19 +87,19 @@ public class SDRplay private boolean mAvailable; /** - * RSP tuner devices (potentially) available for use + * Map of (reusable) callback functions for each device. Key value is the device handle memory address */ - private final List mDevices = new ArrayList<>(); + private final Map mDeviceCallbackFunctionsMap = new HashMap<>(); /** - * Map of (reusable) callback functions for each device. + * Detected version of the API installed on the local system. */ - private final Map mDeviceCallbackFunctionsMap = new HashMap<>(); + private Version mVersion; /** - * Detected version of the API installed on the local system. + * Controls logging of library load status so that it only gets logged once. Set to false once initial logging complete */ - private Version mVersion; + private static boolean sLibraryLoadStatusLogging = true; /** * Constructs an instance of the SDRPLay API @@ -114,28 +111,37 @@ public SDRplay() if(mSdrplayLibraryLoaded) { Status openStatus = open(); - mLog.info("SDRPlay open() status: " + openStatus); + if(sLibraryLoadStatusLogging) + { + mLog.info("API library - open status: " + openStatus); + } mAvailable = openStatus.success() && getVersion().isSupported(); } else { - mLog.info("SDRPlay API library was not loaded"); + if(sLibraryLoadStatusLogging) + { + mLog.info("API library was not loaded"); + } mAvailable = false; } if(isAvailable()) { - mLog.info("SDRPlay API library v" + getVersion() + " - loaded"); - //TODO: this class should maintain a list of devices and it should register as a listener for the device - //to detect when the device is disconnected, so that the device can be removed from the list, in addition - //to providing that event to any other users of the device. - - loadDevices(); + if(sLibraryLoadStatusLogging) + { + mLog.info("API library v" + getVersion() + " - loaded"); + } } else { - mLog.info("SDRPlay API library is not available."); + if(sLibraryLoadStatusLogging) + { + mLog.info("API library is not available."); + } } + + sLibraryLoadStatusLogging = false; } /** @@ -156,14 +162,16 @@ private boolean loadLibrary() try { String libraryPath = getSDRplayLibraryPath(); - mLog.info("Loading SDRplay Library from default install path: " + libraryPath); -// System.load(libraryPath); + 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 library from default install path. Loading from java system library path", t); + mLog.error("Unable to load SDRplay API library from default install path. Loading from java system library path", t); try { @@ -173,10 +181,14 @@ private boolean loadLibrary() catch(Throwable t2) { String name = System.mapLibraryName(SDRPLAY_API_LIBRARY_NAME); - 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); + + 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); + } } } @@ -184,12 +196,26 @@ private boolean loadLibrary() } /** - * Loads the list of devices from the API + * List of devices available via the API + * @return list of device infos. + * @throws SDRPlayException if there is an error */ - public void loadDevices() + public List 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 getDeviceStructures() throws SDRPlayException + { + List deviceStructs = new ArrayList<>(); + //Get a version-correct array of DeviceT structures - MemorySegment devicesArray = DeviceFactory.createForeignDeviceArray(getVersion(), getGlobalMemorySession()); + MemorySegment devicesArray = DeviceFactory.createDeviceArray(getVersion(), getGlobalMemorySession()); MemorySegment deviceCount = getGlobalMemorySession().allocate(ValueLayout.JAVA_INT, 0); @@ -199,43 +225,29 @@ public void loadDevices() if(status.success()) { int count = deviceCount.get(ValueLayout.JAVA_INT, 0); - mDevices.clear(); - mDevices.addAll(DeviceFactory.parseDevices(getVersion(), SDRplay.this, devicesArray, count)); - mLog.info("Loaded Device Count: " + mDevices.size()); + deviceStructs.addAll(DeviceFactory.parseDeviceStructs(getVersion(), devicesArray, count)); } else { - mLog.error("Couldn't load devices. Status: " + status); - } - } - - /** - * List of RSP tuner device descriptors available from this SDRplay instance. - */ - public List getDevices() - { - List descriptors = new ArrayList<>(); - - for(Device device : mDevices) - { - descriptors.add(getDeviceDescriptor(device)); + mLog.error("Couldn't load RSP devices from API. Status: " + status); } - return Collections.unmodifiableList(descriptors); + 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 DeviceDescriptor getDevice(String serialNumber) + public DeviceInfo getDevice(String serialNumber) throws SDRPlayException { - for(DeviceDescriptor deviceDescriptor: getDevices()) + for(DeviceInfo deviceInfo: getDeviceInfos()) { - if(deviceDescriptor.matches(serialNumber)) + if(deviceInfo.getSerialNumber().equals(serialNumber)) { - return deviceDescriptor; + return deviceInfo; } } @@ -243,93 +255,68 @@ public DeviceDescriptor getDevice(String serialNumber) } /** - * Creates a device descriptor for the specified device - * - * @param device to describe - * @return descriptor + * Obtains the device that matches the device info argument. + * @param deviceInfo to match + * @return non-null device + * @throws SDRPlayException */ - private DeviceDescriptor getDeviceDescriptor(Device device) + public Device getDevice(DeviceInfo deviceInfo) throws SDRPlayException { - List deviceSelectionModes = new ArrayList<>(); + Device device = null; - if(device.getDeviceType().equals(DeviceType.RSPduo) && device instanceof RspDuoDevice rsp) + if(isAvailable()) { - RspDuoMode mode = rsp.getRspDuoMode(); - TunerSelect tunerSelect = rsp.getTunerSelect(); + List deviceStructs = getDeviceStructures(); - switch(mode) + for(IDeviceStruct deviceStruct: deviceStructs) { - case SLAVE -> { - if(tunerSelect.equals(TunerSelect.TUNER_1)) - { - deviceSelectionModes.add(DeviceSelectionMode.SLAVE_TUNER_1); - } - else if(tunerSelect.equals(TunerSelect.TUNER_2)) - { - deviceSelectionModes.add(DeviceSelectionMode.SLAVE_TUNER_2); - } - } - case MASTER -> { - if(tunerSelect.equals(TunerSelect.TUNER_1)) - { - deviceSelectionModes.add(DeviceSelectionMode.MASTER_TUNER_1); - } - else if(tunerSelect.equals(TunerSelect.TUNER_2)) - { - deviceSelectionModes.add(DeviceSelectionMode.MASTER_TUNER_2); - } + if(deviceInfo.matches(deviceStruct)) + { + device = DeviceFactory.createDevice(this, deviceStruct); + break; } - case UNKNOWN -> deviceSelectionModes.addAll(Arrays.stream(DeviceSelectionMode.values()).toList()); } - } - else + + if(device == null) { - deviceSelectionModes.add(DeviceSelectionMode.SINGLE_TUNER_1); + throw new SDRPlayException("Unable to find RSP device"); } - return new DeviceDescriptor(device, deviceSelectionModes); + return device; } + /** * Finds the first device that matches the specified device type. * * @param deviceType to find * @return the specified device type or null. */ - public DeviceDescriptor getDevice(DeviceType deviceType) + public DeviceInfo getDeviceInfo(DeviceType deviceType) throws SDRPlayException { - for(DeviceDescriptor deviceDescriptor : getDevices()) + for(DeviceInfo deviceInfo : getDeviceInfos()) { - if(deviceDescriptor.getDeviceType() == deviceType) + if(deviceInfo.getDeviceType() == deviceType) { - return deviceDescriptor; + return deviceInfo; } } return null; } - //TODO: can we segment off the API calls that should only used by/from the device instance, so that a user of - //TODO: this API doesn't have access to those methods? Thinking of using a private final inner class that can be - //TODO: passed to the device constructor. - /** * Selects the device for exclusive use. This method is invoked by the device instance. * - * @param device to select * @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(Device device, MemorySegment memorySegment) throws SDRPlayException + public void select(MemorySegment memorySegment) throws SDRPlayException { - checkValidDevice(device); - lockDeviceApi(); - Status selectStatus = Status.fromValue(sdrplay_api_h.sdrplay_api_SelectDevice(memorySegment)); - unlockDeviceApi(); if(selectStatus.fail()) @@ -338,73 +325,15 @@ public void select(Device device, MemorySegment memorySegment) throws SDRPlayExc } } - /** - * Configures the device for the specified selection mode and selects it for use. - * - * @param deviceDescriptor to select - * @param deviceSelectionMode to configure - * @throws SDRPlayException if the device cannot be selected for the specified selection mode - */ - public Device select(DeviceDescriptor deviceDescriptor, DeviceSelectionMode deviceSelectionMode) throws SDRPlayException - { - Device device = deviceDescriptor.getDevice(); - - if(deviceDescriptor.supports(deviceSelectionMode)) - { - if(device instanceof RspDuoDevice duo) - { - mLog.info("RSPduo device - setting duo mode and tuner select: " + deviceSelectionMode.getTunerSelect()); - duo.setRspDuoMode(deviceSelectionMode.getRspDuoMode()); - duo.setTunerSelect(deviceSelectionMode.getTunerSelect()); - - //In master mode, we have to set the sample rate here, before we select the device - if(deviceSelectionMode.isMasterMode()) - { - duo.setRspDuoSampleFrequency(8_000_000); - } - - if(deviceSelectionMode.equals(DeviceSelectionMode.DUAL_INDEPENDENT_TUNERS)) - { - //Select the first device as Master/Tuner 1. - device.select(); - - //Create a second API instance and find the matching device by serial number - SDRplay api2 = new SDRplay(); - DeviceDescriptor slaveDeviceDescriptor = api2.getDevice(deviceDescriptor.getSerialNumber()); - - if(slaveDeviceDescriptor != null && slaveDeviceDescriptor.getDevice() instanceof RspDuoDevice slaveDevice) - { - slaveDevice.setRspDuoMode(RspDuoMode.SLAVE); - slaveDevice.setTunerSelect(TunerSelect.TUNER_2); - slaveDevice.select(); - return new RspDuoDualIndependentTunerDevice(duo, slaveDevice, slaveDeviceDescriptor); - } - - //Release the first instance and throw an exception to indicate we couldn't configure as requested - device.release(); - throw new SDRPlayException("Unable to acquire second device instance for RSPduo to configure as " + - "dual-independent tuners"); - } - } - - device.select(); - return device; - } - - throw new SDRPlayException("Selection mode [" + deviceSelectionMode + "] is not supported by " + deviceDescriptor); - } - /** * Releases the device from exclusive use. This method is invoked by the device instance. * - * @param device to release * @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(Device device, MemorySegment memorySegment) throws SDRPlayException + public void release(MemorySegment memorySegment) throws SDRPlayException { - checkValidDevice(device); Status status = Status.fromValue(sdrplay_api_h.sdrplay_api_ReleaseDevice(memorySegment)); if(status.fail()) @@ -417,14 +346,12 @@ public void release(Device device, MemorySegment memorySegment) throws SDRPlayEx * 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 device to load parameters + * @param deviceType to load parameters * @param deviceHandle to device * @return constructed device composite paramaters */ - public CompositeParameters getCompositeParameters(Device device, MemoryAddress deviceHandle) throws SDRPlayException + public CompositeParameters getCompositeParameters(DeviceType deviceType, MemoryAddress deviceHandle) throws SDRPlayException { - checkValidDevice(device); - //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)); @@ -436,7 +363,7 @@ public CompositeParameters getCompositeParameters(Device device, MemoryAddress d //The structure's memory is already allocated ... wrap a memory segment around it MemorySegment memorySegment = sdrplay_api_DeviceT.ofAddress(memoryAddress, mGlobalMemorySession); - return CompositeParametersFactory.create(device.getDeviceType(), memorySegment, mGlobalMemorySession); + return CompositeParametersFactory.create(deviceType, memorySegment, mGlobalMemorySession); } else { @@ -447,15 +374,12 @@ public CompositeParameters getCompositeParameters(Device device, MemoryAddress d /** * Initializes a device for use. * - * @param device to initialize * @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(Device device, MemoryAddress deviceHandle, MemorySegment callbackFunctions) throws SDRPlayException + private void init(MemoryAddress deviceHandle, MemorySegment callbackFunctions) throws SDRPlayException { - checkValidDevice(device); - //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)); @@ -478,13 +402,13 @@ private void init(Device device, MemoryAddress deviceHandle, MemorySegment callb public void initA(Device device, MemoryAddress deviceHandle, IDeviceEventListener eventListener, IStreamListener streamListener) throws SDRPlayException { - CallbackFunctions callbackFunctions = mDeviceCallbackFunctionsMap.get(device); + CallbackFunctions callbackFunctions = mDeviceCallbackFunctionsMap.get(deviceHandle); if(callbackFunctions == null) { callbackFunctions = new CallbackFunctions(getGlobalMemorySession(), eventListener, streamListener, device.getStreamCallbackListener()); - mDeviceCallbackFunctionsMap.put(device, callbackFunctions); + mDeviceCallbackFunctionsMap.put(deviceHandle, callbackFunctions); } else { @@ -492,7 +416,7 @@ public void initA(Device device, MemoryAddress deviceHandle, IDeviceEventListene callbackFunctions.setStreamAListener(streamListener); } - init(device, deviceHandle, callbackFunctions.getCallbackFunctionsMemorySegment()); + init(deviceHandle, callbackFunctions.getCallbackFunctionsMemorySegment()); } /** @@ -507,13 +431,13 @@ public void initA(Device device, MemoryAddress deviceHandle, IDeviceEventListene public void initB(Device device, MemoryAddress deviceHandle, IDeviceEventListener eventListener, IStreamListener streamListener) throws SDRPlayException { - CallbackFunctions callbackFunctions = mDeviceCallbackFunctionsMap.get(device); + CallbackFunctions callbackFunctions = mDeviceCallbackFunctionsMap.get(deviceHandle); if(callbackFunctions == null) { callbackFunctions = new CallbackFunctions(getGlobalMemorySession(), eventListener, streamListener, streamListener, device.getStreamCallbackListener()); - mDeviceCallbackFunctionsMap.put(device, callbackFunctions); + mDeviceCallbackFunctionsMap.put(deviceHandle, callbackFunctions); } else { @@ -521,19 +445,17 @@ public void initB(Device device, MemoryAddress deviceHandle, IDeviceEventListene callbackFunctions.setStreamAListener(streamListener); } - init(device, deviceHandle, callbackFunctions.getCallbackFunctionsMemorySegment()); + init(deviceHandle, callbackFunctions.getCallbackFunctionsMemorySegment()); } /** * Un-Initializes a device from use. * - * @param device to un-initialize * @param deviceHandle to the device * @throws SDRPlayException if error during uninit or if device is not selected */ - public void uninit(Device device, MemoryAddress deviceHandle) throws SDRPlayException + public void uninit(MemoryAddress deviceHandle) throws SDRPlayException { - checkValidDevice(device); Status status = Status.fromValue(sdrplay_api_h.sdrplay_api_Uninit(deviceHandle)); if(status.fail() && status != Status.NOT_INITIALIZED) @@ -558,8 +480,6 @@ public void uninit(Device device, MemoryAddress deviceHandle) throws SDRPlayExce public synchronized void update(Device device, MemoryAddress deviceHandle, TunerSelect tunerSelect, UpdateReason... updateReasons) throws SDRPlayException { - checkValidDevice(device); - int reasons = UpdateReason.getReasons(updateReasons); int extendedReasons = UpdateReason.getExtendedReasons(updateReasons); @@ -588,15 +508,12 @@ private ErrorInformation getLastError(MemorySegment deviceSegment) /** * Sets the debug level logging for the specified device * - * @param device to set debug level on * @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(Device device, MemoryAddress deviceHandle, DebugLevel debugLevel) throws SDRPlayException + public void setDebugLevel(MemoryAddress deviceHandle, DebugLevel debugLevel) throws SDRPlayException { - checkValidDevice(device); - Status status = Status.UNKNOWN; if(getVersion() == Version.V3_07) @@ -617,19 +534,6 @@ else if(getVersion().gte(Version.V3_08)) } } - /** - * Checks that the device was constructed by this API instance and continues to be a usable device. - * - * @param device to check - */ - private void checkValidDevice(Device device) throws SDRPlayException - { - if(!mDevices.contains(device)) - { - throw new SDRPlayException("Unrecognized device argument -- must be device created by this API instance"); - } - } - /** * 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. @@ -649,6 +553,11 @@ private Status 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() { @@ -781,9 +690,16 @@ public static void main(String[] args) Status status = sdrplay.open(); mLog.info("Open Status: " + status); - for(DeviceDescriptor deviceDescriptor: sdrplay.getDevices()) + try + { + for(DeviceInfo deviceInfo: sdrplay.getDeviceInfos()) + { + mLog.info("Found: " + deviceInfo); + } + } + catch(SDRPlayException se) { - mLog.info("Found: " + deviceDescriptor); + mLog.info("Error", se); } Status closeStatus = sdrplay.close(); diff --git a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/Device.java b/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/Device.java index e725037d9..dfd95f7f8 100644 --- a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/Device.java +++ b/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/Device.java @@ -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 @@ -29,6 +29,7 @@ import com.github.dsheirer.sdrplay.callback.IStreamCallbackListener; import com.github.dsheirer.sdrplay.callback.IStreamListener; import com.github.dsheirer.sdrplay.callback.StreamCallbackParameters; +import com.github.dsheirer.sdrplay.error.DebugLevel; import com.github.dsheirer.sdrplay.parameter.composite.CompositeParameters; import com.github.dsheirer.sdrplay.parameter.tuner.IfMode; import com.github.dsheirer.sdrplay.parameter.tuner.LoMode; @@ -50,7 +51,7 @@ public abstract class Device, R extends RspTu { private static final Logger mLog = LoggerFactory.getLogger(Device.class); - private final SDRplay mSDRplay; + private SDRplay mSDRplay; private final UpdateRequestManager mUpdateRequestManager = new UpdateRequestManager(); private final IDeviceStruct mDeviceStruct; protected boolean mSelected = false; @@ -100,7 +101,23 @@ private void loadDeviceParameters() throws SDRPlayException { if(selected()) { - mCompositeParameters = (T)getAPI().getCompositeParameters(Device.this, getDeviceHandle()); + 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); } } @@ -112,7 +129,7 @@ public void select() throws SDRPlayException { if(!selected()) { - getAPI().select(Device.this, getDeviceMemorySegment()); + getAPI().select(getDeviceMemorySegment()); mSelected = true; loadDeviceParameters(); } @@ -142,7 +159,7 @@ public void release() throws SDRPlayException if(selected()) { mSelected = false; - getAPI().release(Device.this, getDeviceMemorySegment()); + getAPI().release(getDeviceMemorySegment()); } } @@ -220,7 +237,7 @@ public void uninitialize() throws SDRPlayException { if(isInitialized()) { - getAPI().uninit(this, getDeviceHandle()); + getAPI().uninit(getDeviceHandle()); mInitialized = false; } else @@ -314,7 +331,8 @@ private void submitUpdate(TunerSelect tunerSelect, UpdateReason ... updateReason */ public void acknowledgePowerOverload(TunerSelect tunerSelect) throws SDRPlayException { - mLog.info("Acknowledging power overload message for tuner [" + tunerSelect + "]"); +// 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()) diff --git a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/DeviceFactory.java b/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/DeviceFactory.java index 9c70d1a70..1d3cc4cf8 100644 --- a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/DeviceFactory.java +++ b/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/DeviceFactory.java @@ -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,28 +19,32 @@ package com.github.dsheirer.sdrplay.device; +import com.github.dsheirer.sdrplay.SDRPlayException; import com.github.dsheirer.sdrplay.SDRplay; import com.github.dsheirer.sdrplay.Version; import com.github.dsheirer.sdrplay.api.v3_07.sdrplay_api_DeviceT; import com.github.dsheirer.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 Device instances + * 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 createForeignDeviceArray(Version version, SegmentAllocator segmentAllocator) + public static MemorySegment createDeviceArray(Version version, SegmentAllocator segmentAllocator) { if(version.gte(Version.V3_08)) { @@ -55,37 +59,53 @@ else if(version == Version.V3_07) } /** - * Parses individual device memory segments from the devices array and creates Device instances for each - * RSP model detected. - * @param version of the API being used - * @param sdrplay instance - * @param devicesArray foreign memory segment - * @param count of devices contained in the foreign memory segment devices array - * @return zero or more RSP devices + * Parses device information from a list of device structures + * @param deviceStructs representing devices to parse + * @return a list of device infos + */ + public static List parseDeviceInfos(List deviceStructs) + { + List 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 parseDevices(Version version, SDRplay sdrplay, MemorySegment devicesArray, int count) + public static List parseDeviceStructs(Version version, MemorySegment devicesArray, int count) throws SDRPlayException { - List devices = new ArrayList<>(); + List deviceStructs = new ArrayList<>(); if(version.gte(Version.V3_08)) { devicesArray.elements(com.github.dsheirer.sdrplay.api.v3_08.sdrplay_api_DeviceT.$LAYOUT()) .limit(count).forEach(memorySegment -> - devices.add(DeviceFactory.createDevice(sdrplay, memorySegment))); + deviceStructs.add(DeviceFactory.createDeviceStruct(version, memorySegment))); } else if(version == Version.V3_07) { devicesArray.elements(sdrplay_api_DeviceT.$LAYOUT()).limit(count).forEach(memorySegment -> { - devices.add(DeviceFactory.createDevice(sdrplay, memorySegment)); + deviceStructs.add(DeviceFactory.createDeviceStruct(version, memorySegment)); }); } else { - throw new IllegalArgumentException("Unrecognized version: " + version); + throw new SDRPlayException("Unrecognized version: " + version); } - return devices; + return deviceStructs; } /** @@ -94,10 +114,8 @@ else if(version == Version.V3_07) * @param deviceMemorySegment instance for the device * @return correctly typed device */ - public static Device createDevice(SDRplay sdrPlay, MemorySegment deviceMemorySegment) + public static Device createDevice(SDRplay sdrPlay, IDeviceStruct deviceStruct) { - IDeviceStruct deviceStruct = createDeviceStruct(sdrPlay.getVersion(), deviceMemorySegment); - switch(deviceStruct.getDeviceType()) { case RSP1 -> { diff --git a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/DeviceInfo.java b/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/DeviceInfo.java new file mode 100644 index 000000000..977533c35 --- /dev/null +++ b/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/DeviceInfo.java @@ -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 + * **************************************************************************** + */ + +package com.github.dsheirer.sdrplay.device; + +import com.github.dsheirer.sdrplay.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); + } +} diff --git a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/RspDuoDualIndependentTunerDevice.java b/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/RspDuoDualIndependentTunerDevice.java deleted file mode 100644 index b93344f4d..000000000 --- a/jsdrplay/src/main/java/com/github/dsheirer/sdrplay/device/RspDuoDualIndependentTunerDevice.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * ***************************************************************************** - * Copyright (C) 2014-2022 Dennis Sheirer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - * **************************************************************************** - */ - -package com.github.dsheirer.sdrplay.device; - -import com.github.dsheirer.sdrplay.DeviceDescriptor; -import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.callback.IDeviceEventListener; -import com.github.dsheirer.sdrplay.callback.IStreamListener; -import com.github.dsheirer.sdrplay.parameter.composite.RspDuoCompositeParameters; -import com.github.dsheirer.sdrplay.parameter.tuner.Bandwidth; -import com.github.dsheirer.sdrplay.util.Retry; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Composite device encapsulating two RSPduo device instances, one configured as master for tuner 1 and the other - * configured as slave for tuner 2. - * - * In this configuration, both tuners are initialized and de-initialized at the same time to ensure that the master - * device is initialized first so that tuner 2 can be accessed. Likewise, it ensures that the slave device is - * de-initialized first, so that tuner 1 can be de-initialized. - */ -public class RspDuoDualIndependentTunerDevice extends Device -{ - private Logger mLog = LoggerFactory.getLogger(RspDuoDualIndependentTunerDevice.class); - private RspDuoDevice mMasterDevice; - private RspDuoDevice mSlaveDevice; - private DeviceDescriptor mSlaveDeviceDescriptor; - - /** - * Constructs a composite SDRPlay RSPduo device with support for dual independent tuners. - */ - public RspDuoDualIndependentTunerDevice(RspDuoDevice masterDevice, RspDuoDevice slaveDevice, DeviceDescriptor slaveDeviceDescriptor) - { - super(masterDevice.getAPI(), masterDevice.getDeviceStruct()); - - mMasterDevice = masterDevice; - mSlaveDevice = slaveDevice; - mSlaveDeviceDescriptor = slaveDeviceDescriptor; - - if(!mMasterDevice.isSelected() || !mSlaveDevice.isSelected()) - { - throw new IllegalStateException("Master and Slave devices must both be selected prior to constructing " + - "composite device"); - } - - mSelected = true; - } - - /** - * Device descriptor for the slave tuner 2 device. Note: this is a convenience accessor since the second device - * descriptor isn't accessible from the API select call. - * @return slave tuner 2 device descriptor - */ - public DeviceDescriptor getSlaveDeviceDescriptor() - { - return mSlaveDeviceDescriptor; - } - - /** - * Tuner 1 configured as master - * @return tuner 1 - * @throws SDRPlayException if there is an issue accessing the tuner - */ - @Override - public RspDuoTuner1 getTuner() throws SDRPlayException - { - return (RspDuoTuner1) mMasterDevice.getTuner(); - } - - /** - * Tuner 2 configured as the slave device - * @return tuner 2 - * @throws SDRPlayException if there is an issue accessing the tuner - */ - public RspDuoTuner2 getTuner2() throws SDRPlayException - { - return (RspDuoTuner2) mSlaveDevice.getTuner(); - } - - /** - * Overrides the parent select() method to be a non-operation. Both master and slave devices should already be - * selected before they are joined via this composite device. - * @throws SDRPlayException always. - */ - @Override - public void select() throws SDRPlayException - { - throw new SDRPlayException("Device has already been selected"); - } - - /** - * Indicates if the master device is initialized - * @return true if initialized - */ - private boolean isMasterInitialized() - { - return mMasterDevice.isInitialized(); - } - - /** - * Indicates if the slave device is initialized - * @return true if initialized - */ - private boolean isSlaveInitialized() - { - return mSlaveDevice.isInitialized(); - } - - /** - * Un-initializes both the master and slave devices - * @throws SDRPlayException if there is an error - */ - @Override - public void uninitialize() throws SDRPlayException - { - throw new SDRPlayException("Use either uninitializeMaster() or uninitializeSlave() to stop sample stream"); - } - - /** - * Uninitializes the master device and stops the sample stream - * @throws SDRPlayException if there is an error. - */ - public void uninitializeMaster() throws SDRPlayException - { - mMasterDevice.uninitialize(); - } - - /** - * Uninitializes the slave device and stops the sample stream - * @throws SDRPlayException if there is an error. - */ - public void uninitializeSlave() throws SDRPlayException - { - mSlaveDevice.uninitialize(); - } - - /** - * Overrides default behavior and throws an exception. Use initMaster() or initSlave() instead. - * @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 - */ - @Override - public void initStreamA(IDeviceEventListener eventListener, IStreamListener streamListener) throws SDRPlayException - { - throw new SDRPlayException("Use either initMaster() or initSlave() to start sample stream"); - } - - /** - * Initializes the master device for use and starts providing raw signal samples to the stream listener and - * device events to the event listener. - * - * @param eventListener to receive device event notifications - * @param streamListeners two stream listeners to receive samples from the tuner where the first listener - * will receive samples from tuner 1 and the second listener will receive samples from tuner 2. - * - * @throws SDRPlayException if there is an error - */ - public void initMaster(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"); - } - - mMasterDevice.initStreamA(eventListener, streamListener); - mInitialized = true; - } - - @Override - public void release() throws SDRPlayException - { - if(selected()) - { - mSelected = false; - mSlaveDevice.release(); - Retry.quietly(5, 20, () -> mMasterDevice.release()); - } - } - - /** - * Sets the tuner bandwidth and final decimation for both the master and the slave devices. - * - * Note: this does not set the initial sample rate which can only be 6 or 8 MHz and which must also be set on the - * master device before the device is selected. - * - * @param sampleRate to apply only the bandwidth and final decimation values - * @throws SDRPlayException if there is an error - */ - public void setSampleRate(double sampleRate) throws SDRPlayException - { - mMasterDevice.setRspDuoSampleFrequency(sampleRate); - } - - /** - * Sets the bandwidth on both the master and slave devices. - * @param bandwidth to use - * @throws SDRPlayException if there is an error - */ - public void setBandwidth(Bandwidth bandwidth) throws SDRPlayException - { - mMasterDevice.getTuner().setBandwidth(bandwidth); - mSlaveDevice.getTuner().setBandwidth(bandwidth); - } - - /** - * Sets the decimation value to use for both master and slave devices. - * @param decimate value where X1 is no decimation and all others are decimation enabled values. - * @throws SDRPlayException - */ - public void setDecimation(Decimate decimate) throws SDRPlayException - { - mMasterDevice.setDecimation(decimate); - mSlaveDevice.setDecimation(decimate); - } - - /** - * Acknowledge tuner power overload events - * @param tunerSelect identifying which tuner(s) - * @throws SDRPlayException on error - */ - public void acknowledgePowerOverload(TunerSelect tunerSelect) throws SDRPlayException - { - switch(tunerSelect) - { - case TUNER_1 -> mMasterDevice.acknowledgePowerOverload(tunerSelect); - case TUNER_2 -> mSlaveDevice.acknowledgePowerOverload(tunerSelect); - case TUNER_BOTH -> { - mMasterDevice.acknowledgePowerOverload(TunerSelect.TUNER_1); - mSlaveDevice.acknowledgePowerOverload(TunerSelect.TUNER_2); - } - case NEITHER -> {} - } - } -} diff --git a/jsdrplay/src/test/java/io/github/dsherer/sdrplay/test/RspDeviceTest.java b/jsdrplay/src/test/java/io/github/dsherer/sdrplay/test/RspDeviceTest.java index 35bc71e7d..e2309ca79 100644 --- a/jsdrplay/src/test/java/io/github/dsherer/sdrplay/test/RspDeviceTest.java +++ b/jsdrplay/src/test/java/io/github/dsherer/sdrplay/test/RspDeviceTest.java @@ -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,11 +19,11 @@ package io.github.dsherer.sdrplay.test; -import com.github.dsheirer.sdrplay.DeviceDescriptor; import com.github.dsheirer.sdrplay.DeviceSelectionMode; import com.github.dsheirer.sdrplay.SDRPlayException; import com.github.dsheirer.sdrplay.SDRplay; import com.github.dsheirer.sdrplay.device.Device; +import com.github.dsheirer.sdrplay.device.DeviceInfo; import com.github.dsheirer.sdrplay.device.DeviceType; import io.github.dsherer.sdrplay.test.listener.LoggingStreamConsumer; import org.junit.jupiter.api.DisplayName; @@ -43,13 +43,14 @@ public class RspDeviceTest public void listDevices() { SDRplay api = new SDRplay(); - for(DeviceDescriptor deviceDescriptor: api.getDevices()) - { - mLog.info(deviceDescriptor.toString()); - } try { + for(DeviceInfo deviceInfo: api.getDeviceInfos()) + { + mLog.info(deviceInfo.toString()); + } + api.close(); } catch(Exception se) @@ -86,52 +87,39 @@ private void testDevice(DeviceType deviceType, DeviceSelectionMode deviceSelecti { SDRplay api = new SDRplay(); mLog.info("Version: " + api.getVersion()); - - DeviceDescriptor deviceDescriptor = api.getDevice(deviceType); - - if(deviceDescriptor != null) + try { - mLog.info("Testing: " + deviceDescriptor + " With Device Selection Mode: " + deviceSelectionMode); - mLog.info("Available Selection Modes: " + deviceDescriptor.getDeviceSelectionModes()); - if(deviceDescriptor.getDeviceSelectionModes().contains(deviceSelectionMode)) - { - try - { - Device device = api.select(deviceDescriptor, deviceSelectionMode); + DeviceInfo deviceInfo = api.getDeviceInfo(deviceType); + mLog.info("Testing: " + deviceInfo + " With Device Selection Mode: " + deviceSelectionMode); + Device device = api.getDevice(deviceInfo); + device.select(); + mLog.info("Device: " + device.toString()); - mLog.info("Device: " + device.toString()); + mLog.info("Selected: " + device.getClass()); - mLog.info("Selected: " + device.getClass()); - - mLog.info("Setting Sample Rate"); + mLog.info("Setting Sample Rate"); // device.setSampleRate(SampleRate.RATE_0_250); - mLog.info("Setting Frequencies"); - device.getTuner().setFrequency(460_450_000); + mLog.info("Setting Frequencies"); + device.getTuner().setFrequency(460_450_000); - mLog.info("Gain Reduction: " + device.getTuner().getGainReduction()); - mLog.info("AGC Mode: " + device.getTuner().getAGC()); - mLog.info("Gain: " + device.getTuner().getGain()); - mLog.info("LO Mode:" + device.getTuner().getLoMode()); - mLog.info("IF Mode:" + device.getTuner().getIfMode()); + mLog.info("Gain Reduction: " + device.getTuner().getGainReduction()); + mLog.info("AGC Mode: " + device.getTuner().getAGC()); + mLog.info("Gain: " + device.getTuner().getGain()); + mLog.info("LO Mode:" + device.getTuner().getLoMode()); + mLog.info("IF Mode:" + device.getTuner().getIfMode()); - mLog.info("Capturing Samples ..."); - LoggingStreamConsumer loggingStreamConsumer = new LoggingStreamConsumer(device); - loggingStreamConsumer.process(5); + mLog.info("Capturing Samples ..."); + LoggingStreamConsumer loggingStreamConsumer = new LoggingStreamConsumer(device); + loggingStreamConsumer.process(5); // loggingStreamConsumer.logSpectrum1(); - device.release(); - mLog.info("Released"); - } - catch(SDRPlayException se) - { - mLog.error("Error testing device", se); - } - } + device.release(); + mLog.info("Released"); } - else + catch(SDRPlayException se) { - mLog.info("Unable to obtain RSP device to test"); + mLog.error("Error testing device", se); } try diff --git a/jsdrplay/src/test/java/io/github/dsherer/sdrplay/test/RspDuoTest.java b/jsdrplay/src/test/java/io/github/dsherer/sdrplay/test/RspDuoTest.java index c86caa525..eeb1dca1d 100644 --- a/jsdrplay/src/test/java/io/github/dsherer/sdrplay/test/RspDuoTest.java +++ b/jsdrplay/src/test/java/io/github/dsherer/sdrplay/test/RspDuoTest.java @@ -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,18 +19,6 @@ package io.github.dsherer.sdrplay.test; -import com.github.dsheirer.sdrplay.DeviceDescriptor; -import com.github.dsheirer.sdrplay.DeviceSelectionMode; -import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.SDRplay; -import com.github.dsheirer.sdrplay.device.Device; -import com.github.dsheirer.sdrplay.device.DeviceType; -import com.github.dsheirer.sdrplay.device.RspDuoDevice; -import com.github.dsheirer.sdrplay.device.RspDuoDualIndependentTunerDevice; -import com.github.dsheirer.sdrplay.parameter.tuner.IfMode; -import io.github.dsherer.sdrplay.test.listener.LoggingStreamConsumer; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,174 +31,114 @@ public class RspDuoTest { private static Logger mLog = LoggerFactory.getLogger(RspDuoTest.class); - /** - * Tests an RSPduo configured for dual independent tuners, each controlled by a separate SDRplay API instance. - */ - @Test - @DisplayName("Test an RSPduo device using dual independent tuners") - public void testDualIndependentTuners() - { - testDuo(DeviceSelectionMode.DUAL_INDEPENDENT_TUNERS); - } - - /** - * Tests an RSPduo configured for dual synchronized tuners (ie diversity mode). - */ - @Test - @DisplayName("Test an RSPduo device using dual synchronized tuners") - public void testDualSynchronizedTuners() - { - testDuo(DeviceSelectionMode.DUAL_SYNCHRONIZED_TUNERS); - } - - /** - * Tests an RSPduo configured for single tuner 1. - */ - @Test - @DisplayName("Test an RSPduo device using single tuner mode with tuner 1") - public void testSingleTuner1() - { - testDuo(DeviceSelectionMode.SINGLE_TUNER_1); - } - - /** - * Tests an RSPduo configured for single tuner 2. - */ - @Test - @DisplayName("Test an RSPduo device using single tuner mode with tuner 2") - public void testSingleTuner2() - { - testDuo(DeviceSelectionMode.SINGLE_TUNER_2); - } - - /** - * Tests an RSPduo configured for master with tuner 1. - */ - @Test - @DisplayName("Test an RSPduo device using master tuner mode with tuner 1") - public void testMasterTuner1() - { - testDuo(DeviceSelectionMode.MASTER_TUNER_1); - } - - /** - * Tests an RSPduo configured for master with tuner 2. - */ - @Test - @DisplayName("Test an RSPduo device using master tuner mode with tuner 2") - public void testMasterTuner2() - { - testDuo(DeviceSelectionMode.MASTER_TUNER_2); - } - - /** - * Tests the RSPduo with the specified device selection mode - * @param deviceSelectionMode - */ - private void testDuo(DeviceSelectionMode deviceSelectionMode) - { - SDRplay api = new SDRplay(); - - DeviceDescriptor deviceDescriptor = api.getDevice(DeviceType.RSPduo); - - if(deviceDescriptor != null) - { - mLog.info("Testing: " + deviceDescriptor + " With Device Selection Mode: " + deviceSelectionMode); - - if(deviceDescriptor.getDeviceSelectionModes().contains(deviceSelectionMode)) - { - try - { - Device device = api.select(deviceDescriptor, deviceSelectionMode); - - if(device instanceof RspDuoDevice) - { - mLog.info("Selected: " + device.getClass()); - - if(deviceSelectionMode.isMasterMode()) - { - mLog.info("Setting IF Mode"); - device.getTuner().setIfMode(IfMode.IF_2048); - - mLog.info("Setting Sample Rate"); -// device.setSampleRate(SampleRate.DUO_RATE_0_500); - } - else if(deviceSelectionMode.equals(DeviceSelectionMode.DUAL_SYNCHRONIZED_TUNERS)) - { - mLog.info("Setting Sample Rate"); -// device.setSampleRate(SampleRate.RATE_0_600); - } - else - { - mLog.info("Setting Sample Rate"); -// device.setSampleRate(SampleRate.RATE_10_000); - } - - mLog.info("Setting Frequencies"); - device.getTuner().setFrequency(460_450_000); - - mLog.info("Gain Reduction: " + device.getTuner().getGainReduction()); - mLog.info("AGC Mode: " + device.getTuner().getAGC()); - mLog.info("Gain: " + device.getTuner().getGain()); - mLog.info("LO Mode:" + device.getTuner().getLoMode()); - mLog.info("IF Mode:" + device.getTuner().getIfMode()); - - mLog.info("Capturing Samples ..."); - LoggingStreamConsumer loggingStreamConsumer = new LoggingStreamConsumer(device); - loggingStreamConsumer.process(5); - loggingStreamConsumer.logSpectrumA(); - - if(deviceSelectionMode.equals(DeviceSelectionMode.DUAL_SYNCHRONIZED_TUNERS)) - { - loggingStreamConsumer.logSpectrumB(); - } - } - else if(device instanceof RspDuoDualIndependentTunerDevice dual) - { - mLog.info("Selected: " + device.getClass()); - - //IF Mode 2048 is the correct mode for master/slave configurations with 2.0 MHz sample rate - device.getTuner().setIfMode(IfMode.IF_2048); - - mLog.info("Setting Sample Rate"); -// device.setSampleRate(SampleRate.DUO_RATE_2_000); - - mLog.info("Setting Frequencies"); - device.getTuner().setFrequency(460_250_000); - dual.getTuner2().setFrequency(453_250_000); - - mLog.info("Capturing Samples ..."); - LoggingStreamConsumer loggingStreamConsumer = new LoggingStreamConsumer(device); - loggingStreamConsumer.process(5); - loggingStreamConsumer.logSpectrumA(); - loggingStreamConsumer.logSpectrumB(); - } - else - { - mLog.error("Unrecognized Device Type: " + device.getClass()); - } - - device.release(); - mLog.info("Released"); - } - catch(SDRPlayException se) - { - mLog.error("Error testing device", se); - } - } - } - else - { - mLog.info("Unable to obtain RSPduo device to test"); - } - - try - { - api.close(); - } - catch(Exception se) - { - mLog.error("Error closing api"); - } - } +// /** +// * Tests an RSPduo configured for single tuner 1. +// */ +// @Test +// @DisplayName("Test an RSPduo device using single tuner mode with tuner 1") +// public void testSingleTuner1() +// { +// testDuo(DeviceSelectionMode.SINGLE_TUNER_1); +// } +// +// /** +// * Tests an RSPduo configured for single tuner 2. +// */ +// @Test +// @DisplayName("Test an RSPduo device using single tuner mode with tuner 2") +// public void testSingleTuner2() +// { +// testDuo(DeviceSelectionMode.SINGLE_TUNER_2); +// } +// +// /** +// * Tests an RSPduo configured for master with tuner 1. +// */ +// @Test +// @DisplayName("Test an RSPduo device using master tuner mode with tuner 1") +// public void testMasterTuner1() +// { +// testDuo(DeviceSelectionMode.MASTER_TUNER_1); +// } +// +// /** +// * Tests the RSPduo with the specified device selection mode +// * @param deviceSelectionMode +// */ +// private void testDuo(DeviceSelectionMode deviceSelectionMode) +// { +// SDRplay api = new SDRplay(); +// +// DeviceInfo deviceInfo = api.getDeviceInfo(DeviceType.RSPduo); +// +// if(deviceInfo != null) +// { +// mLog.info("Testing: " + deviceInfo + " With Device Selection Mode: " + deviceSelectionMode); +// +// if(deviceInfo.getDeviceSelectionModes().contains(deviceSelectionMode)) +// { +// try +// { +// Device device = api.select(deviceInfo, deviceSelectionMode); +// +// if(device instanceof RspDuoDevice) +// { +// mLog.info("Selected: " + device.getClass()); +// +// if(deviceSelectionMode.isMasterMode()) +// { +// mLog.info("Setting IF Mode"); +// device.getTuner().setIfMode(IfMode.IF_2048); +// +// mLog.info("Setting Sample Rate"); +//// device.setSampleRate(SampleRate.DUO_RATE_0_500); +// } +// else +// { +// mLog.info("Setting Sample Rate"); +//// device.setSampleRate(SampleRate.RATE_10_000); +// } +// +// mLog.info("Setting Frequencies"); +// device.getTuner().setFrequency(460_450_000); +// +// mLog.info("Gain Reduction: " + device.getTuner().getGainReduction()); +// mLog.info("AGC Mode: " + device.getTuner().getAGC()); +// mLog.info("Gain: " + device.getTuner().getGain()); +// mLog.info("LO Mode:" + device.getTuner().getLoMode()); +// mLog.info("IF Mode:" + device.getTuner().getIfMode()); +// +// mLog.info("Capturing Samples ..."); +// LoggingStreamConsumer loggingStreamConsumer = new LoggingStreamConsumer(device); +// loggingStreamConsumer.process(5); +// loggingStreamConsumer.logSpectrumA(); +// } +// else +// { +// mLog.error("Unrecognized Device Type: " + device.getClass()); +// } +// +// device.release(); +// mLog.info("Released"); +// } +// catch(SDRPlayException se) +// { +// mLog.error("Error testing device", se); +// } +// } +// } +// else +// { +// mLog.info("Unable to obtain RSPduo device to test"); +// } +// +// try +// { +// api.close(); +// } +// catch(Exception se) +// { +// mLog.error("Error closing api"); +// } +// } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerFactory.java b/src/main/java/io/github/dsheirer/source/tuner/TunerFactory.java index 6a6113dcf..b748f81ce 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerFactory.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerFactory.java @@ -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,9 +19,16 @@ package io.github.dsheirer.source.tuner; -import com.github.dsheirer.sdrplay.DeviceDescriptor; import com.github.dsheirer.sdrplay.DeviceSelectionMode; +import com.github.dsheirer.sdrplay.SDRPlayException; import com.github.dsheirer.sdrplay.SDRplay; +import com.github.dsheirer.sdrplay.device.Device; +import com.github.dsheirer.sdrplay.device.DeviceInfo; +import com.github.dsheirer.sdrplay.device.Rsp1aDevice; +import com.github.dsheirer.sdrplay.device.Rsp2Device; +import com.github.dsheirer.sdrplay.device.RspDuoDevice; +import com.github.dsheirer.sdrplay.device.RspDxDevice; +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; @@ -57,16 +64,19 @@ 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.rsp1.Rsp1TunerConfiguration; 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; @@ -78,15 +88,20 @@ 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; @@ -99,82 +114,166 @@ public class TunerFactory { private static final Logger mLog = LoggerFactory.getLogger(TunerFactory.class); - /** - * Creates an RSP tuner, or two tuners for RSPduo devices. - * @param api for communicating with the tuner - * @param deviceDescriptor representing the tuner - * @param channelizerType to use for the tuner - * @param selectionMode for selecting the tuner - * @return one or two constructed RSP tuners + * 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 DiscoveredRspTuner getRspTuner(SDRplay api, DeviceDescriptor deviceDescriptor, - ChannelizerType channelizerType, DeviceSelectionMode selectionMode) + public static List getRspTuners(DeviceInfo deviceInfo, ChannelizerType channelizerType, RspDuoSelectionMode selectionMode) { - return getRspTuner(api, deviceDescriptor, channelizerType, selectionMode, null); - } + List tuners = new ArrayList<>(); - /** - * Creates an RSP tuner and optionally registers the tuner with a master-slave bridge. - * @param api for communicating with the tuner - * @param deviceDescriptor representing the tuner - * @param channelizerType to use for the tuner - * @param selectionMode for selecting the tuner - * @param bridge (optional) bridging device between Tuner1/Master and Tuner2/Slave RSPduo configuration. - * @return one or two constructed RSP tuners - */ - public static DiscoveredRspTuner getRspTuner(SDRplay api, DeviceDescriptor deviceDescriptor, - ChannelizerType channelizerType, DeviceSelectionMode selectionMode, - MasterSlaveBridge bridge) - { - //Configure RSPduo to user preference - either single (wide) tuner or dual (narrow) tuners - switch(deviceDescriptor.getDeviceType()) + switch(deviceInfo.getDeviceType()) { case RSP1A: - IControlRsp1a controlRsp1a = new ControlRsp1a(api, deviceDescriptor); - return new DiscoveredRsp1aTuner(controlRsp1a, channelizerType); + tuners.add(new DiscoveredRsp1aTuner(deviceInfo, channelizerType)); + break; case RSP2: - IControlRsp2 controlRsp2 = new ControlRsp2(api, deviceDescriptor); - return new DiscoveredRsp2Tuner(controlRsp2, channelizerType); + tuners.add(new DiscoveredRsp2Tuner(deviceInfo, channelizerType)); + break; case RSPdx: - IControlRspDx controlRspDx = new ControlRspDx(api, deviceDescriptor); - return new DiscoveredRspDxTuner(controlRspDx, channelizerType); + tuners.add(new DiscoveredRspDxTuner(deviceInfo, channelizerType)); + break; case RSPduo: - if(deviceDescriptor.supports(selectionMode)) + switch(selectionMode) { - 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 RSP1A: + if(device instanceof Rsp1aDevice rsp1aDevice) { - case SINGLE_TUNER_1 -> - { - IControlRspDuoTuner1 controlTuner1Single = new ControlRspDuoTuner1Single(api, deviceDescriptor); - return new DiscoveredRspDuoTuner1(controlTuner1Single, channelizerType); - } - case SINGLE_TUNER_2 -> - { - IControlRspDuoTuner2 controlTuner2Single = new ControlRspDuoTuner2Single(api, deviceDescriptor); - return new DiscoveredRspDuoTuner2(controlTuner2Single, channelizerType); - } - case MASTER_TUNER_1 -> + 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()) { - ControlRspDuoTuner1Master controlTuner1Master = new ControlRspDuoTuner1Master(api, deviceDescriptor); - //Cross register the master with the master-slave bridge - controlTuner1Master.setBridge(bridge); - return new DiscoveredRspDuoTuner1(controlTuner1Master, channelizerType); + 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"); } - case SLAVE_TUNER_2 -> + } + 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()) { - ControlRspDuoTuner2Slave controlTuner2Slave = new ControlRspDuoTuner2Slave(api, deviceDescriptor); - //Cross register the slave with the master-slave bridge - controlTuner2Slave.setBridge(bridge); - return new DiscoveredRspDuoTuner2(controlTuner2Slave, channelizerType); + 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"); } - default -> mLog.warn("Unrecognized RSPduo device selection mode: " + selectionMode); } - } - break; + break; + } } - return null; + throw new SDRPlayException("Unable to obtain RSPduo tuner"); } /** diff --git a/src/main/java/io/github/dsheirer/source/tuner/manager/TunerManager.java b/src/main/java/io/github/dsheirer/source/tuner/manager/TunerManager.java index 224ea58b9..a65c4b004 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/manager/TunerManager.java +++ b/src/main/java/io/github/dsheirer/source/tuner/manager/TunerManager.java @@ -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,9 +19,9 @@ package io.github.dsheirer.source.tuner.manager; -import com.github.dsheirer.sdrplay.DeviceSelectionMode; +import com.github.dsheirer.sdrplay.SDRPlayException; import com.github.dsheirer.sdrplay.SDRplay; -import com.github.dsheirer.sdrplay.device.DeviceType; +import com.github.dsheirer.sdrplay.device.DeviceInfo; import io.github.dsheirer.gui.preference.tuner.RspDuoSelectionMode; import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.preference.source.ChannelizerType; @@ -42,11 +42,7 @@ 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.rspDuo.ControlRspDuoTuner1Master; import io.github.dsheirer.source.tuner.sdrplay.rspDuo.DiscoveredRspDuoTuner1; -import io.github.dsheirer.source.tuner.sdrplay.rspDuo.MasterSlaveBridge; -import io.github.dsheirer.source.tuner.sdrplay.rspDuo.RspDuoTuner1Controller; -import io.github.dsheirer.source.tuner.sdrplay.rspDuo.RspDuoTuner2Controller; import io.github.dsheirer.source.tuner.ui.DiscoveredTunerModel; import io.github.dsheirer.util.ThreadPool; import java.nio.ByteBuffer; @@ -74,16 +70,13 @@ 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 SDRplay mSdrplayApi1; - private SDRplay mSdrplayApi2; private boolean mLibUsbInitialized = false; + private SDRplay mSDRplay; /** * Constructs an instance @@ -155,6 +148,13 @@ public void stop() //Stop all tuners mDiscoveredTunerModel.releaseDiscoveredTuners(); + //Shutdown SDRplay API instance + if(mSDRplay != null) + { + mSDRplay.close(); + mSDRplay = null; + } + //Shutdown LibUsb if(mLibUsbInitialized) { @@ -162,19 +162,6 @@ public void stop() LibUsb.exit(mLibUsbApplicationContext); mLibUsbInitialized = false; } - - //Close SDRPlay API instance(s) - if(mSdrplayApi1 != null) - { - mSdrplayApi1.close(); - mSdrplayApi1 = null; - } - - if(mSdrplayApi2 != null) - { - mSdrplayApi2.close(); - mSdrplayApi2 = null; - } } /** @@ -308,139 +295,47 @@ private void startAndConfigureTuner(DiscoveredTuner discoveredTuner) private void discoverSdrPlayTuners() { ChannelizerType channelizerType = mUserPreferences.getTunerPreference().getChannelizerType(); + RspDuoSelectionMode duoSelectionMode = mUserPreferences.getTunerPreference().getRspDuoTunerMode(); - RspDuoSelectionMode preferredSelectionMode = 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(getSdrplayApi1().isAvailable()) + if(mSDRplay.isAvailable()) { - List deviceDescriptors = getSdrplayApi1().getDevices(); - - mLog.info("SDRPlay found [" + deviceDescriptors.size() + "] device descriptors"); - for(com.github.dsheirer.sdrplay.DeviceDescriptor deviceDescriptor: deviceDescriptors) + try { - if(deviceDescriptor.getDeviceType() == DeviceType.RSPduo) - { - switch(preferredSelectionMode) - { - case SINGLE_1: - DiscoveredRspTuner singleTuner1 = TunerFactory.getRspTuner(getSdrplayApi1(), deviceDescriptor, - channelizerType, DeviceSelectionMode.SINGLE_TUNER_1); - if(singleTuner1 == null) - { - mLog.warn("Unable to create tuner 1 for RSP device: " + deviceDescriptor.getDeviceType() + - " " + deviceDescriptor.getSerialNumber()); - } - else - { - startAndConfigureTuner(singleTuner1); - } - break; - case SINGLE_2: - DiscoveredRspTuner singleTuner2 = TunerFactory.getRspTuner(getSdrplayApi1(), deviceDescriptor, - channelizerType, DeviceSelectionMode.SINGLE_TUNER_2); - if(singleTuner2 == null) - { - mLog.warn("Unable to create tuner 2 for RSP device: " + deviceDescriptor.getDeviceType() + - " " + deviceDescriptor.getSerialNumber()); - } - else - { - startAndConfigureTuner(singleTuner2); - } - break; - case DUAL: - //Create a bridge across the master and slave tuners. - MasterSlaveBridge bridge = new MasterSlaveBridge(); - - DiscoveredRspTuner masterTuner1 = TunerFactory.getRspTuner(getSdrplayApi1(), deviceDescriptor, - channelizerType, DeviceSelectionMode.MASTER_TUNER_1, bridge); - - if(masterTuner1 == null) - { - mLog.warn("Unable to create master tuner 1 device: " + deviceDescriptor.getDeviceType() + " " + - deviceDescriptor.getSerialNumber()); - continue; - } - else - { - startAndConfigureTuner(masterTuner1); - } - - String serialNumber = deviceDescriptor.getSerialNumber(); - - com.github.dsheirer.sdrplay.DeviceDescriptor slaveDescriptor = getSdrplayApi2().getDevice(serialNumber); - DiscoveredRspTuner slaveTuner2 = TunerFactory.getRspTuner(getSdrplayApi2(), slaveDescriptor, - channelizerType, DeviceSelectionMode.SLAVE_TUNER_2, bridge); + List deviceInfos = mSDRplay.getDeviceInfos(); - if(slaveTuner2 == null) - { - mLog.warn("Unable to create slave tuner 2 device: " + deviceDescriptor.getDeviceType() + " " + - deviceDescriptor.getSerialNumber()); - continue; - } - else - { - startAndConfigureTuner(slaveTuner2); - } + mLog.info("Discovered [" + deviceInfos.size() + "] RSP devices from SDRplay API"); - //Setup two-way linking between tuner bridge and tuners - if(masterTuner1 != null && masterTuner1.hasTuner()) - { - bridge.setMaster((RspDuoTuner1Controller)masterTuner1.getTuner().getTunerController()); - } - if(slaveTuner2 != null && slaveTuner2.hasTuner()) - { - bridge.setSlave((RspDuoTuner2Controller)slaveTuner2.getTuner().getTunerController()); - } - break; - } + if(deviceInfos.isEmpty()) + { + mSDRplay.close(); + mSDRplay = null; + return; } - else + + for(DeviceInfo deviceInfo: deviceInfos) { - DiscoveredRspTuner tuner = TunerFactory.getRspTuner(getSdrplayApi1(), deviceDescriptor, channelizerType, - DeviceSelectionMode.SINGLE_TUNER_1); - if(tuner == null) - { - mLog.warn("Unable to create tuner for RSP device: " + deviceDescriptor.getDeviceType() + " " + - deviceDescriptor.getSerialNumber()); - } - else + List 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"); + } } - } - - /** - * Access SDRPlay API instance #1. - * @return api - */ - private SDRplay getSdrplayApi1() - { - if(mSdrplayApi1 == null) - { - mLog.info("Creating SDRPlay API instance #1"); - mSdrplayApi1 = new SDRplay(); - } - - return mSdrplayApi1; - } - - /** - * Access SDRPlay API instance #2. - * @return api - */ - private SDRplay getSdrplayApi2() - { - if(mSdrplayApi2 == null) + else { - mLog.info("Creating SDRPlay API instance #2"); - mSdrplayApi2 = new SDRplay(); + mSDRplay.close(); + mSDRplay = null; } - - return mSdrplayApi2; } /** @@ -482,15 +377,13 @@ private void discoverRecordingTuners() @Override public void tunerStatusUpdated(DiscoveredTuner discoveredTuner, TunerStatus previous, TunerStatus current) { - mLog.info("Tuner status updated - previous [" + previous + "] current [" + current + "] tuner: " + discoveredTuner.getId()); if(current == TunerStatus.ENABLED) { discoveredTuner.start(); } //Special handling for RSPduo to auto-update enabled state for slave device when configured for master/slave operation - if(discoveredTuner instanceof DiscoveredRspDuoTuner1 rspDuoTuner1 && - rspDuoTuner1.getControlRsp() instanceof ControlRspDuoTuner1Master) + 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"); diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/ControlRsp.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/ControlRsp.java index 79271bcc6..566071e81 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/ControlRsp.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/ControlRsp.java @@ -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,23 +19,28 @@ package io.github.dsheirer.source.tuner.sdrplay; -import com.github.dsheirer.sdrplay.DeviceDescriptor; import com.github.dsheirer.sdrplay.DeviceSelectionMode; import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.SDRplay; +import com.github.dsheirer.sdrplay.UpdateReason; import com.github.dsheirer.sdrplay.callback.IDeviceEventListener; import com.github.dsheirer.sdrplay.callback.IStreamListener; +import com.github.dsheirer.sdrplay.device.Device; +import com.github.dsheirer.sdrplay.device.TunerSelect; +import com.github.dsheirer.sdrplay.parameter.control.AgcMode; import com.github.dsheirer.sdrplay.parameter.tuner.GainReduction; - +import com.github.dsheirer.sdrplay.parameter.tuner.IfMode; +import com.github.dsheirer.sdrplay.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 implements IControlRsp +public abstract class ControlRsp implements IControlRsp { - private SDRplay mSDRplayApi; - private DeviceDescriptor mDeviceDescriptor; + 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; @@ -47,13 +52,110 @@ public abstract class ControlRsp implements IControlRsp /** * Constructs an instance - * @param sdrplayApi to use - * @param deviceDescriptor for the device, obtained from the API + * @param device for the device, obtained from the API */ - public ControlRsp(SDRplay sdrplayApi, DeviceDescriptor deviceDescriptor) + 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 RSP1A sample stream - device not started"); + } + } + catch(SDRPlayException se) + { + mLog.error("Unable to initialize/start streaming for RSP1A"); + } + finally + { + mStreamingLock.unlock(); + } + } + + @Override + public void stopStream() { - mSDRplayApi = sdrplayApi; - mDeviceDescriptor = deviceDescriptor; + mStreamingLock.lock(); + + try + { + if(hasDevice()) + { + if(mStreaming) + { + getDevice().uninitialize(); + mStreaming = false; + } + } + else + { + mLog.error("Unable to stop RSP sample stream - device not started"); + } + } + catch(SDRPlayException se) + { + mLog.error("Unable to uninitialize/stop streaming for RSP1A"); + } + finally + { + mStreamingLock.unlock(); + } } @Override @@ -64,19 +166,110 @@ public DeviceSelectionMode getDeviceSelectionMode() } /** - * SDRplay API for controlling the device + * Device descriptor for this device */ - protected SDRplay getApi() + public T getDevice() { - return mSDRplayApi; + return mDevice; } /** - * Device descriptor for this device + * Clears/nullifies the device. This should be invoked after stopping the device to prevent reuse. */ - public DeviceDescriptor getDeviceDescriptor() + public void clearDevice() { - return mDeviceDescriptor; + 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() && !sampleRate.equals(mSampleRate)) + { + 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("Device is not initialized"); + } + } + + /** + * 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"); + } } /** diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/DiscoveredRspTuner.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/DiscoveredRspTuner.java index 6c82ca8e0..af990cfe9 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/DiscoveredRspTuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/DiscoveredRspTuner.java @@ -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,9 +19,11 @@ package io.github.dsheirer.source.tuner.sdrplay; +import com.github.dsheirer.sdrplay.device.DeviceInfo; import com.github.dsheirer.sdrplay.device.DeviceType; 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; /** @@ -29,33 +31,34 @@ */ public abstract class DiscoveredRspTuner extends DiscoveredTuner { - private final R mControlRsp; + private final DeviceInfo mDeviceInfo; private final ChannelizerType mChannelizerType; /** * Constructs an instance - * @param controlRsp wrapper around device descriptor + * @param deviceInfo to select the device from the API */ - public DiscoveredRspTuner(R controlRsp, ChannelizerType channelizerType) + public DiscoveredRspTuner(DeviceInfo deviceInfo, ChannelizerType channelizerType) { - mControlRsp = controlRsp; + mDeviceInfo = deviceInfo; mChannelizerType = channelizerType; } /** - * Channelizer type to use for the tuner + * Information about the discovered RSP device + * @return device info */ - protected ChannelizerType getChannelizerType() + public DeviceInfo getDeviceInfo() { - return mChannelizerType; + return mDeviceInfo; } /** - * RSP control + * Channelizer type to use for the tuner */ - public R getControlRsp() + protected ChannelizerType getChannelizerType() { - return mControlRsp; + return mChannelizerType; } @Override @@ -69,7 +72,46 @@ public TunerClass getTunerClass() */ public DeviceType getDeviceType() { - return getControlRsp().getDeviceDescriptor().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 diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/IControlRsp.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/IControlRsp.java index 4a99f7f86..43faf9d22 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/IControlRsp.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/IControlRsp.java @@ -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,11 +19,11 @@ package io.github.dsheirer.source.tuner.sdrplay; -import com.github.dsheirer.sdrplay.DeviceDescriptor; import com.github.dsheirer.sdrplay.DeviceSelectionMode; import com.github.dsheirer.sdrplay.SDRPlayException; import com.github.dsheirer.sdrplay.callback.IDeviceEventListener; import com.github.dsheirer.sdrplay.callback.IStreamListener; +import com.github.dsheirer.sdrplay.device.Device; import com.github.dsheirer.sdrplay.device.TunerSelect; /** @@ -37,7 +37,7 @@ public interface IControlRsp * Device descriptor for this RSP * @return device descriptor */ - DeviceDescriptor getDeviceDescriptor(); + Device getDevice(); /** * Selected tuner for this RSP. diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTuner.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTuner.java index 94291ccf7..59a7762be 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTuner.java @@ -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 @@ -52,7 +52,7 @@ public int getMaximumUSBBitsPerSecond() @Override public String getUniqueID() { - return getRspTunerController().getControlRsp().getDeviceDescriptor().getSerialNumber(); + return getRspTunerController().getControlRsp().getDevice().getSerialNumber(); } @Override @@ -74,18 +74,18 @@ public String getPreferredName() { if(getRspTunerController().getControlRsp() instanceof IControlRspDuoTuner1) { - return getRspTunerController().getControlRsp().getDeviceDescriptor().getDeviceType() + - " SER:" + getRspTunerController().getControlRsp().getDeviceDescriptor().getSerialNumber() + " Tuner 1"; + return getRspTunerController().getControlRsp().getDevice().getDeviceType() + + " SER:" + getRspTunerController().getControlRsp().getDevice().getSerialNumber() + " Tuner 1"; } else if(getRspTunerController().getControlRsp() instanceof IControlRspDuoTuner2) { - return getRspTunerController().getControlRsp().getDeviceDescriptor().getDeviceType() + - " SER:" + getRspTunerController().getControlRsp().getDeviceDescriptor().getSerialNumber() + " Tuner 2"; + return getRspTunerController().getControlRsp().getDevice().getDeviceType() + + " SER:" + getRspTunerController().getControlRsp().getDevice().getSerialNumber() + " Tuner 2"; } else { - return getRspTunerController().getControlRsp().getDeviceDescriptor().getDeviceType() + - " SER:" + getRspTunerController().getControlRsp().getDeviceDescriptor().getSerialNumber(); + return getRspTunerController().getControlRsp().getDevice().getDeviceType() + + " SER:" + getRspTunerController().getControlRsp().getDevice().getSerialNumber(); } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerController.java index 670c04a1d..ca84002ae 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/RspTunerController.java @@ -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 @@ -242,7 +242,6 @@ public long getTunedFrequency() throws SourceException @Override public void setTunedFrequency(long frequency) throws SourceException { - mLog.info("Setting tuned frequency to [" + frequency + "] tuner: " + getClass()); try { getControlRsp().setTunedFrequency(frequency); diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1a/ControlRsp1a.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1a/ControlRsp1a.java index aecfb44ff..af1dd02c3 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1a/ControlRsp1a.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1a/ControlRsp1a.java @@ -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,234 +19,26 @@ package io.github.dsheirer.source.tuner.sdrplay.rsp1a; -import com.github.dsheirer.sdrplay.DeviceDescriptor; -import com.github.dsheirer.sdrplay.DeviceSelectionMode; import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.SDRplay; -import com.github.dsheirer.sdrplay.UpdateReason; -import com.github.dsheirer.sdrplay.device.Device; import com.github.dsheirer.sdrplay.device.Rsp1aDevice; -import com.github.dsheirer.sdrplay.device.TunerSelect; -import com.github.dsheirer.sdrplay.parameter.control.AgcMode; -import com.github.dsheirer.sdrplay.parameter.tuner.IfMode; -import com.github.dsheirer.sdrplay.parameter.tuner.LoMode; import io.github.dsheirer.source.tuner.sdrplay.ControlRsp; -import io.github.dsheirer.source.tuner.sdrplay.RspSampleRate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Control wrapper for an RSP1A Device */ -public class ControlRsp1a extends ControlRsp implements IControlRsp1a +public class ControlRsp1a extends ControlRsp implements IControlRsp1a { private Logger mLog = LoggerFactory.getLogger(ControlRsp1a.class); - private Rsp1aDevice mDevice; /** * Constructs an instance - * @param sdrplayApi to control the device - * @param deviceDescriptor for the device + * @param device for the device */ - public ControlRsp1a(SDRplay sdrplayApi, DeviceDescriptor deviceDescriptor) + public ControlRsp1a(Rsp1aDevice device) { - super(sdrplayApi, deviceDescriptor); - } - - /** - * Indicates if this control has been started and has a non-null device - */ - private boolean hasDevice() - { - return getDevice() != null; - } - - /** - * Access the device. - * @return device or null. - */ - private Rsp1aDevice getDevice() - { - return mDevice; - } - - @Override - public TunerSelect getTunerSelect() - { - return TunerSelect.TUNER_1; - } - - @Override - public void start() throws SDRPlayException - { - Device device = getApi().select(getDeviceDescriptor(), DeviceSelectionMode.SINGLE_TUNER_1); - - if(device instanceof Rsp1aDevice rsp1aDevice) - { - mDevice = rsp1aDevice; - 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); - } - } - - @Override - public void stop() throws SDRPlayException - { - if(hasDevice()) - { - getDevice().release(); - mDevice = null; - } - } - - @Override - public void startStream() - { - mStreamingLock.lock(); - - try - { - if(hasDevice()) - { - if(!mStreaming) - { - getDevice().initStreamA(getDeviceEventListener(), getStreamListener()); - mStreaming = true; - } - } - else - { - mLog.error("Unable to start RSP1A sample stream - device not started"); - } - } - catch(SDRPlayException se) - { - mLog.error("Unable to initialize/start streaming for RSP1A"); - } - finally - { - mStreamingLock.unlock(); - } - } - - @Override - public void stopStream() - { - mStreamingLock.lock(); - - try - { - if(hasDevice()) - { - if(mStreaming) - { - getDevice().uninitialize(); - mStreaming = false; - } - } - else - { - mLog.error("Unable to stop RSP1A sample stream - device not started"); - } - } - catch(SDRPlayException se) - { - mLog.error("Unable to uninitialize/stop streaming for RSP1A"); - } - finally - { - mStreamingLock.unlock(); - } - } - - /** - * Sets the sample rate - * @param sampleRate enumeration value. - * @throws SDRPlayException - */ - @Override - public void setSampleRate(RspSampleRate sampleRate) throws SDRPlayException - { - if(hasDevice() && !sampleRate.equals(mSampleRate)) - { - 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("Device is not initialized"); - } - } - - /** - * 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"); - } + super(device); } @Override diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1a/DiscoveredRsp1aTuner.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1a/DiscoveredRsp1aTuner.java index 58677b447..c2994f0ab 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1a/DiscoveredRsp1aTuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp1a/DiscoveredRsp1aTuner.java @@ -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,10 +19,9 @@ package io.github.dsheirer.source.tuner.sdrplay.rsp1a; +import com.github.dsheirer.sdrplay.device.DeviceInfo; import io.github.dsheirer.preference.source.ChannelizerType; -import io.github.dsheirer.source.SourceException; import io.github.dsheirer.source.tuner.sdrplay.DiscoveredRspTuner; -import io.github.dsheirer.source.tuner.sdrplay.RspTuner; /** * RSP1A discovered tuner. @@ -31,39 +30,11 @@ public class DiscoveredRsp1aTuner extends DiscoveredRspTuner { /** * Constructs an instance - * @param controlRsp1a for controlling the RSP1A after it's been started + * @param deviceInfo for controlling the RSP1A after it's been started * @param channelizerType to use for the tuner once started */ - public DiscoveredRsp1aTuner(IControlRsp1a controlRsp1a, ChannelizerType channelizerType) + public DiscoveredRsp1aTuner(DeviceInfo deviceInfo, ChannelizerType channelizerType) { - super(controlRsp1a, channelizerType); - } - - /** - * Constructs and starts the tuner - */ - @Override - public void start() - { - if(isAvailable() && !hasTuner()) - { - Rsp1aTunerController tunerController = new Rsp1aTunerController(getControlRsp(), this); - mTuner = new RspTuner(tunerController, this, getChannelizerType()); - try - { - mTuner.start(); - } - catch(SourceException se) - { - setErrorMessage("Error starting RSP1A [" + getId() + "]"); - mTuner = null; - } - } - } - - @Override - public String getId() - { - return "RSP1A SER#" + getControlRsp().getDeviceDescriptor().getSerialNumber(); + super(deviceInfo, channelizerType); } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp2/ControlRsp2.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp2/ControlRsp2.java index 0e2cf8beb..33b6dd7da 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp2/ControlRsp2.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp2/ControlRsp2.java @@ -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,236 +19,29 @@ package io.github.dsheirer.source.tuner.sdrplay.rsp2; -import com.github.dsheirer.sdrplay.DeviceDescriptor; -import com.github.dsheirer.sdrplay.DeviceSelectionMode; import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.SDRplay; -import com.github.dsheirer.sdrplay.UpdateReason; -import com.github.dsheirer.sdrplay.device.Device; import com.github.dsheirer.sdrplay.device.Rsp2Device; -import com.github.dsheirer.sdrplay.device.TunerSelect; -import com.github.dsheirer.sdrplay.parameter.control.AgcMode; -import com.github.dsheirer.sdrplay.parameter.tuner.IfMode; -import com.github.dsheirer.sdrplay.parameter.tuner.LoMode; import com.github.dsheirer.sdrplay.parameter.tuner.Rsp2AntennaSelection; import io.github.dsheirer.source.tuner.sdrplay.ControlRsp; -import io.github.dsheirer.source.tuner.sdrplay.RspSampleRate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Control wrapper for an RSP2 Device */ -public class ControlRsp2 extends ControlRsp implements IControlRsp2 +public class ControlRsp2 extends ControlRsp implements IControlRsp2 { private Logger mLog = LoggerFactory.getLogger(ControlRsp2.class); - private Rsp2Device mDevice; private Rsp2AntennaSelection mAntennaSelection = Rsp2AntennaSelection.ANT_A; /** * Constructs an instance * @param sdrplayApi to control the device - * @param deviceDescriptor for the device + * @param device to control */ - public ControlRsp2(SDRplay sdrplayApi, DeviceDescriptor deviceDescriptor) + public ControlRsp2(Rsp2Device device) { - super(sdrplayApi, deviceDescriptor); - } - - /** - * Indicates if this control has been started and has a non-null device - */ - private boolean hasDevice() - { - return getDevice() != null; - } - - /** - * Access the device. - * @return device or null. - */ - private Rsp2Device getDevice() - { - return mDevice; - } - - @Override - public TunerSelect getTunerSelect() - { - return TunerSelect.TUNER_1; - } - - @Override - public void start() throws SDRPlayException - { - Device device = getApi().select(getDeviceDescriptor(), DeviceSelectionMode.SINGLE_TUNER_1); - - if(device instanceof Rsp2Device rsp2Device) - { - mDevice = rsp2Device; - 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); - } - } - - @Override - public void stop() throws SDRPlayException - { - if(hasDevice()) - { - getDevice().release(); - mDevice = null; - } - } - - @Override - public void startStream() - { - mStreamingLock.lock(); - - try - { - if(hasDevice()) - { - if(!mStreaming) - { - getDevice().initStreamA(getDeviceEventListener(), getStreamListener()); - mStreaming = true; - } - } - else - { - mLog.error("Unable to start RSP1A sample stream - device not started"); - } - } - catch(SDRPlayException se) - { - mLog.error("Unable to initialize/start streaming for RSP1A"); - } - finally - { - mStreamingLock.unlock(); - } - } - - @Override - public void stopStream() - { - mStreamingLock.lock(); - - try - { - if(hasDevice()) - { - if(mStreaming) - { - getDevice().uninitialize(); - mStreaming = false; - } - } - else - { - mLog.error("Unable to stop RSP1A sample stream - device not started"); - } - } - catch(SDRPlayException se) - { - mLog.error("Unable to uninitialize/stop streaming for RSP1A"); - } - finally - { - mStreamingLock.unlock(); - } - } - - /** - * Sets the sample rate - * @param sampleRate enumeration value. - * @throws SDRPlayException - */ - @Override - public void setSampleRate(RspSampleRate sampleRate) throws SDRPlayException - { - if(hasDevice() && !sampleRate.equals(mSampleRate)) - { - 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("Device is not initialized"); - } - } - - /** - * 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"); - } + super(device); } @Override diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp2/DiscoveredRsp2Tuner.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp2/DiscoveredRsp2Tuner.java index cd648b554..9032a87d3 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp2/DiscoveredRsp2Tuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rsp2/DiscoveredRsp2Tuner.java @@ -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,10 +19,9 @@ package io.github.dsheirer.source.tuner.sdrplay.rsp2; +import com.github.dsheirer.sdrplay.device.DeviceInfo; import io.github.dsheirer.preference.source.ChannelizerType; -import io.github.dsheirer.source.SourceException; import io.github.dsheirer.source.tuner.sdrplay.DiscoveredRspTuner; -import io.github.dsheirer.source.tuner.sdrplay.RspTuner; /** * RSP2 discovered tuner. @@ -31,39 +30,11 @@ public class DiscoveredRsp2Tuner extends DiscoveredRspTuner { /** * Constructs an instance - * @param controlRsp2 for controlling the RSP2 after it's been started + * @param deviceInfo for the tuner * @param channelizerType to use for the tuner once started */ - public DiscoveredRsp2Tuner(IControlRsp2 controlRsp2, ChannelizerType channelizerType) + public DiscoveredRsp2Tuner(DeviceInfo deviceInfo, ChannelizerType channelizerType) { - super(controlRsp2, channelizerType); - } - - /** - * Constructs and starts the tuner - */ - @Override - public void start() - { - if(isAvailable() && !hasTuner()) - { - Rsp2TunerController tunerController = new Rsp2TunerController(getControlRsp(), this); - mTuner = new RspTuner(tunerController, this, getChannelizerType()); - try - { - mTuner.start(); - } - catch(SourceException se) - { - setErrorMessage("Error starting RSP2 [" + getId() + "]"); - mTuner = null; - } - } - } - - @Override - public String getId() - { - return "RSP2 SER#" + getControlRsp().getDeviceDescriptor().getSerialNumber(); + super(deviceInfo, channelizerType); } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuo.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuo.java index 7b73a1a67..6fd63520d 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuo.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuo.java @@ -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,12 +19,9 @@ package io.github.dsheirer.source.tuner.sdrplay.rspDuo; -import com.github.dsheirer.sdrplay.DeviceDescriptor; import com.github.dsheirer.sdrplay.DeviceSelectionMode; import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.SDRplay; import com.github.dsheirer.sdrplay.UpdateReason; -import com.github.dsheirer.sdrplay.device.Device; import com.github.dsheirer.sdrplay.device.RspDuoDevice; import com.github.dsheirer.sdrplay.device.RspDuoTuner; import com.github.dsheirer.sdrplay.device.TunerSelect; @@ -41,20 +38,18 @@ /** * Base control wrapper for an RSPduo operating in either single-tuner or master or slave mode. */ -public abstract class ControlRspDuo extends ControlRsp implements IControlRspDuo +public abstract class ControlRspDuo extends ControlRsp implements IControlRspDuo { private final Logger mLog = LoggerFactory.getLogger(ControlRspDuo.class); - protected RspDuoDevice mDevice; /** * Constructs an instance * - * @param sdrplayApi to use - * @param deviceDescriptor for the device, obtained from the API + * @param device for the device, obtained from the API */ - public ControlRspDuo(SDRplay sdrplayApi, DeviceDescriptor deviceDescriptor) + public ControlRspDuo(RspDuoDevice device) { - super(sdrplayApi, deviceDescriptor); + super(device); } /** @@ -81,32 +76,20 @@ public ControlRspDuo(SDRplay sdrplayApi, DeviceDescriptor deviceDescriptor) */ protected abstract TunerParameters getTunerParameters(); - /** - * Indicates if this control has been started and has a non-null device - */ - protected boolean hasDevice() - { - return getDevice() != null; - } - - /** - * Access the device. - * @return device or null. - */ - protected RspDuoDevice getDevice() - { - return mDevice; - } - @Override public void start() throws SDRPlayException { - Device device = getApi().select(getDeviceDescriptor(), getDeviceSelectionMode()); - - if(device instanceof RspDuoDevice rspDuoDevice) + if(hasDevice()) { - mLog.info("*** Starting ControlRspDuo ...."); - mDevice = rspDuoDevice; + getDevice().setRspDuoMode(getDeviceSelectionMode().getRspDuoMode()); + getDevice().setTunerSelect(getDeviceSelectionMode().getTunerSelect()); + + //In master mode, we have to set the sample rate here, before we select the device + if(getDeviceSelectionMode().isMasterMode()) + { + getDevice().setRspDuoSampleFrequency(8_000_000); + } + getDevice().select(); //Enable automatic DC and I/Q correction @@ -127,16 +110,9 @@ public void start() throws SDRPlayException getTunerParameters().setIfMode(IfMode.IF_2048); } } - } - - @Override - public void stop() throws SDRPlayException - { - if(hasDevice()) + else { - stopStream(); - getDevice().release(); - mDevice = null; + throw new SDRPlayException("Unable to start - no device"); } } @@ -202,25 +178,20 @@ public void stopStream() @Override public void setSampleRate(RspSampleRate sampleRate) throws SDRPlayException { - mLog.info("Setting sample rate to: " + sampleRate.name() + " device: " + this.getClass()); if(hasDevice()) { mSampleRate = sampleRate; - mLog.info("Setting bandwidth: " + sampleRate.getBandwidth().name()); getDevice().getTuner().setBandwidth(sampleRate.getBandwidth()); - mLog.info("Setting sample rate: " + sampleRate.getSampleRate()); getDevice().getCompositeParameters().getDeviceParameters().getSamplingFrequency() .setSampleRate(sampleRate.getSampleRate()); //Only send an update if we're in single-tuner mode ... not sure why we don't have to for dual-tuner mode. if(getDeviceSelectionMode() != DeviceSelectionMode.MASTER_TUNER_1) { - mLog.info("Sending update for tuner select [" + getTunerSelect() + "]"); getDevice().update(getTunerSelect(), UpdateReason.DEVICE_SAMPLE_RATE); } - mLog.info("Setting wideband signal to true"); + getControlParameters().getDecimation().setWideBandSignal(true); - mLog.info("Setting decimation to: " + sampleRate.getDecimation()); getDevice().setDecimation(sampleRate.getDecimation()); } else diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner1.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner1.java index 4bd3c2083..4e05307eb 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner1.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner1.java @@ -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,9 +19,8 @@ package io.github.dsheirer.source.tuner.sdrplay.rspDuo; -import com.github.dsheirer.sdrplay.DeviceDescriptor; import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.SDRplay; +import com.github.dsheirer.sdrplay.device.RspDuoDevice; import com.github.dsheirer.sdrplay.device.RspDuoTuner1; import com.github.dsheirer.sdrplay.device.TunerSelect; import com.github.dsheirer.sdrplay.parameter.control.ControlParameters; @@ -40,12 +39,11 @@ public abstract class ControlRspDuoTuner1 extends ControlRspDuo im /** * Constructs an instance * - * @param sdrplayApi to use - * @param deviceDescriptor for the device, obtained from the API + * @param device to control */ - public ControlRspDuoTuner1(SDRplay sdrplayApi, DeviceDescriptor deviceDescriptor) + public ControlRspDuoTuner1(RspDuoDevice device) { - super(sdrplayApi, deviceDescriptor); + super(device); } /** @@ -57,7 +55,7 @@ protected RspDuoTuner1 getTuner() throws SDRPlayException { if(hasDevice()) { - return (RspDuoTuner1)getDevice().getTuner(); + return (RspDuoTuner1) getDevice().getTuner(); } throw new SDRPlayException("RSPduo device is not started"); diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner1Master.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner1Master.java index eb266f261..641921df0 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner1Master.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner1Master.java @@ -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,16 +19,14 @@ package io.github.dsheirer.source.tuner.sdrplay.rspDuo; -import com.github.dsheirer.sdrplay.DeviceDescriptor; import com.github.dsheirer.sdrplay.DeviceSelectionMode; import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.SDRplay; +import com.github.dsheirer.sdrplay.device.RspDuoDevice; import io.github.dsheirer.source.tuner.sdrplay.RspSampleRate; +import java.util.EnumSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.EnumSet; - /** * RSPduo operating in dual-tuner mode with tuner 1 configured as master. */ @@ -49,20 +47,11 @@ public class ControlRspDuoTuner1Master extends ControlRspDuoTuner1 /** * Constructs an instance * - * @param sdrplayApi to use - * @param deviceDescriptor for the device, obtained from the API - */ - public ControlRspDuoTuner1Master(SDRplay sdrplayApi, DeviceDescriptor deviceDescriptor) - { - super(sdrplayApi, deviceDescriptor); - } - - /** - * Assigns the streaming control bridge to this master and registers this master with the bridge. - * @param bridge to assign + * @param device to control */ - public void setBridge(MasterSlaveBridge bridge) + public ControlRspDuoTuner1Master(RspDuoDevice device, MasterSlaveBridge bridge) { + super(device); mMasterSlaveBridge = bridge; } diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner1Single.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner1Single.java index a819e56ff..022707dfc 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner1Single.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner1Single.java @@ -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,12 +19,10 @@ package io.github.dsheirer.source.tuner.sdrplay.rspDuo; -import com.github.dsheirer.sdrplay.DeviceDescriptor; import com.github.dsheirer.sdrplay.DeviceSelectionMode; import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.SDRplay; +import com.github.dsheirer.sdrplay.device.RspDuoDevice; import io.github.dsheirer.source.tuner.sdrplay.RspSampleRate; - import java.util.EnumSet; /** @@ -35,12 +33,11 @@ public class ControlRspDuoTuner1Single extends ControlRspDuoTuner1 /** * Constructs an instance * - * @param sdrplayApi to use - * @param deviceDescriptor for the device, obtained from the API + * @param device to control */ - public ControlRspDuoTuner1Single(SDRplay sdrplayApi, DeviceDescriptor deviceDescriptor) + public ControlRspDuoTuner1Single(RspDuoDevice device) { - super(sdrplayApi, deviceDescriptor); + super(device); } @Override diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner2.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner2.java index 048d64fe9..d054436af 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner2.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner2.java @@ -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,9 +19,8 @@ package io.github.dsheirer.source.tuner.sdrplay.rspDuo; -import com.github.dsheirer.sdrplay.DeviceDescriptor; import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.SDRplay; +import com.github.dsheirer.sdrplay.device.RspDuoDevice; import com.github.dsheirer.sdrplay.device.RspDuoTuner2; import com.github.dsheirer.sdrplay.device.TunerSelect; import com.github.dsheirer.sdrplay.parameter.control.ControlParameters; @@ -39,12 +38,11 @@ public abstract class ControlRspDuoTuner2 extends ControlRspDuo im /** * Constructs an instance * - * @param sdrplayApi to use - * @param deviceDescriptor for the device, obtained from the API + * @param device for the device, obtained from the API */ - public ControlRspDuoTuner2(SDRplay sdrplayApi, DeviceDescriptor deviceDescriptor) + public ControlRspDuoTuner2(RspDuoDevice device) { - super(sdrplayApi, deviceDescriptor); + super(device); } /** @@ -56,7 +54,7 @@ protected RspDuoTuner2 getTuner() throws SDRPlayException { if(hasDevice()) { - return (RspDuoTuner2)getDevice().getTuner(); + return (RspDuoTuner2) getDevice().getTuner(); } throw new SDRPlayException("RSPduo device is not started"); diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner2Single.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner2Single.java index fb815d0ee..64bf8ccfe 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner2Single.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner2Single.java @@ -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,16 +19,14 @@ package io.github.dsheirer.source.tuner.sdrplay.rspDuo; -import com.github.dsheirer.sdrplay.DeviceDescriptor; import com.github.dsheirer.sdrplay.DeviceSelectionMode; import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.SDRplay; +import com.github.dsheirer.sdrplay.device.RspDuoDevice; import io.github.dsheirer.source.tuner.sdrplay.RspSampleRate; +import java.util.EnumSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.EnumSet; - /** * Control wrapper for an RSPduo Tuner 2 operating in single-tuner mode. */ @@ -39,12 +37,11 @@ public class ControlRspDuoTuner2Single extends ControlRspDuoTuner2 /** * Constructs an instance * - * @param sdrplayApi to use - * @param deviceDescriptor for the device, obtained from the API + * @param device to control */ - public ControlRspDuoTuner2Single(SDRplay sdrplayApi, DeviceDescriptor deviceDescriptor) + public ControlRspDuoTuner2Single(RspDuoDevice device) { - super(sdrplayApi, deviceDescriptor); + super(device); } @Override diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner2Slave.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner2Slave.java index 20adb64ec..f31cc2c6c 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner2Slave.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/ControlRspDuoTuner2Slave.java @@ -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,12 +19,10 @@ package io.github.dsheirer.source.tuner.sdrplay.rspDuo; -import com.github.dsheirer.sdrplay.DeviceDescriptor; import com.github.dsheirer.sdrplay.DeviceSelectionMode; import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.SDRplay; +import com.github.dsheirer.sdrplay.device.RspDuoDevice; import io.github.dsheirer.source.tuner.sdrplay.RspSampleRate; - import java.util.EnumSet; /** @@ -37,12 +35,12 @@ public class ControlRspDuoTuner2Slave extends ControlRspDuoTuner2 /** * Constructs an instance * - * @param sdrplayApi to use - * @param deviceDescriptor for the device, obtained from the API + * @param device to control */ - public ControlRspDuoTuner2Slave(SDRplay sdrplayApi, DeviceDescriptor deviceDescriptor) + public ControlRspDuoTuner2Slave(RspDuoDevice device, MasterSlaveBridge bridge) { - super(sdrplayApi, deviceDescriptor); + super(device); + mMasterSlaveBridge = bridge; } /** @@ -61,15 +59,6 @@ public void startStream() super.startStream(); } - /** - * Assigns the streaming control bridge to this slave and registers this slave with the bridge. - * @param bridge to assign - */ - public void setBridge(MasterSlaveBridge bridge) - { - mMasterSlaveBridge = bridge; - } - @Override public boolean isSlaveMode() { diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/DiscoveredRspDuoTuner1.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/DiscoveredRspDuoTuner1.java index d4e9bdb87..b817f9ded 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/DiscoveredRspDuoTuner1.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/DiscoveredRspDuoTuner1.java @@ -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,26 +19,46 @@ package io.github.dsheirer.source.tuner.sdrplay.rspDuo; +import com.github.dsheirer.sdrplay.device.DeviceInfo; import io.github.dsheirer.preference.source.ChannelizerType; -import io.github.dsheirer.source.SourceException; +import io.github.dsheirer.source.tuner.TunerFactory; import io.github.dsheirer.source.tuner.sdrplay.DiscoveredRspTuner; import io.github.dsheirer.source.tuner.sdrplay.RspTuner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * RSPduo Tuner 1 discovered tuner. + * + * When constructed with a master-slave bridge, this device will be used in master-slave mode. If the bridge is not + * provided as construction time, the device will be configured for single-tuner operation. */ public class DiscoveredRspDuoTuner1 extends DiscoveredRspTuner { + private static final Logger mLog = LoggerFactory.getLogger(DiscoveredRspTuner.class); public static final String RSP_DUO_ID_PREFIX = "RSPduo Tuner "; + private MasterSlaveBridge mMasterSlaveBridge; /** - * Constructs an instance - * @param controlRspDuoTuner1 for controlling the RSPduo after it's been started + * Constructs an instance configured for a single-tuner + * @param deviceInfo describing the tuner * @param channelizerType to use for the tuner once started */ - public DiscoveredRspDuoTuner1(IControlRspDuoTuner1 controlRspDuoTuner1, ChannelizerType channelizerType) + public DiscoveredRspDuoTuner1(DeviceInfo deviceInfo, ChannelizerType channelizerType) { - super(controlRspDuoTuner1, channelizerType); + super(deviceInfo, channelizerType); + } + + /** + * Constructs an instance configured as Master Tuner 1. + * @param deviceInfo describing the tuner + * @param channelizerType to use for the tuner once started + * @param bridge for synchronizing with the slaved tuner 2. + */ + public DiscoveredRspDuoTuner1(DeviceInfo deviceInfo, ChannelizerType channelizerType, MasterSlaveBridge bridge) + { + super(deviceInfo, channelizerType); + mMasterSlaveBridge = bridge; } /** @@ -49,23 +69,48 @@ public void start() { if(isAvailable() && !hasTuner()) { - RspDuoTuner1Controller tunerController = new RspDuoTuner1Controller(getControlRsp(), this); - mTuner = new RspTuner(tunerController, this, getChannelizerType()); try { - mTuner.start(); + if(mMasterSlaveBridge != null) + { + mTuner = TunerFactory.getRspDuoTuner(getDeviceInfo(), getChannelizerType(), this, mMasterSlaveBridge); + + if(mTuner instanceof RspTuner rspTuner && + rspTuner.getRspTunerController() instanceof RspDuoTuner1Controller rspDuoTuner1Controller) + { + mMasterSlaveBridge.setMaster(rspDuoTuner1Controller); + } + } + else + { + mTuner = TunerFactory.getRspTuner(getDeviceInfo(), getChannelizerType(), this); + } } - catch(SourceException se) + catch(Exception se) { - setErrorMessage("Error starting RSPduo Tuner 1 [" + getId() + "]"); + setErrorMessage("Tuner unavailable [" + getId() + "]"); mTuner = null; } + + if(hasTuner()) + { + try + { + mTuner.start(); + } + catch(Exception se) + { + mLog.error("Error", se); + setErrorMessage("Error starting tuner [" + getId() + "]"); + mTuner = null; + } + } } } @Override public String getId() { - return RSP_DUO_ID_PREFIX + "1 SER#" + getControlRsp().getDeviceDescriptor().getSerialNumber(); + return RSP_DUO_ID_PREFIX + "1 SER#" + getDeviceInfo().getSerialNumber(); } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/DiscoveredRspDuoTuner2.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/DiscoveredRspDuoTuner2.java index f9809c2d3..24beee645 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/DiscoveredRspDuoTuner2.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/DiscoveredRspDuoTuner2.java @@ -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,24 +19,41 @@ package io.github.dsheirer.source.tuner.sdrplay.rspDuo; +import com.github.dsheirer.sdrplay.device.DeviceInfo; import io.github.dsheirer.preference.source.ChannelizerType; -import io.github.dsheirer.source.SourceException; +import io.github.dsheirer.source.tuner.TunerFactory; import io.github.dsheirer.source.tuner.sdrplay.DiscoveredRspTuner; -import io.github.dsheirer.source.tuner.sdrplay.RspTuner; /** * RSPduo Tuner 2 discovered tuner. + * + * When constructed with a master-slave bridge, this device will be used in master-slave mode. If the bridge is not + * provided as construction time, the device will be configured for single-tuner operation. */ public class DiscoveredRspDuoTuner2 extends DiscoveredRspTuner { + private MasterSlaveBridge mMasterSlaveBridge; + + /** + * Constructs an instance configured for a single-tuner + * @param deviceInfo describing the tuner + * @param channelizerType to use for the tuner once started + */ + public DiscoveredRspDuoTuner2(DeviceInfo deviceInfo, ChannelizerType channelizerType) + { + super(deviceInfo, channelizerType); + } + /** - * Constructs an instance - * @param controlRspDuoTuner2 for controlling the RSPduo after it's been started + * Constructs an instance configured as Slave Tuner 2. + * @param deviceInfo describing the tuner * @param channelizerType to use for the tuner once started + * @param bridge for synchronizing with the master tuner 1. */ - public DiscoveredRspDuoTuner2(IControlRspDuoTuner2 controlRspDuoTuner2, ChannelizerType channelizerType) + public DiscoveredRspDuoTuner2(DeviceInfo deviceInfo, ChannelizerType channelizerType, MasterSlaveBridge bridge) { - super(controlRspDuoTuner2, channelizerType); + super(deviceInfo, channelizerType); + mMasterSlaveBridge = bridge; } /** @@ -47,23 +64,49 @@ public void start() { if(isAvailable() && !hasTuner()) { - RspDuoTuner2Controller tunerController = new RspDuoTuner2Controller(getControlRsp(), this); - mTuner = new RspTuner(tunerController, this, getChannelizerType()); try { - mTuner.start(); + if(mMasterSlaveBridge != null) + { + mTuner = TunerFactory.getRspDuoTuner(getDeviceInfo(), getChannelizerType(), this, mMasterSlaveBridge); + } + else + { + mTuner = TunerFactory.getRspTuner(getDeviceInfo(), getChannelizerType(), this); + } } - catch(SourceException se) + catch(Exception se) { - setErrorMessage("Error starting RSPduo Tuner 2 [" + getId() + "]"); + setErrorMessage("Tuner unavailable [" + getId() + "]"); mTuner = null; } + + if(hasTuner()) + { + try + { + mTuner.start(); + + if(mMasterSlaveBridge != null) + { + if(mTuner.getTunerController() instanceof RspDuoTuner2Controller rspDuoTuner2Controller) + { + mMasterSlaveBridge.setSlave(rspDuoTuner2Controller); + } + } + } + catch(Exception se) + { + setErrorMessage("Error starting tuner [" + getId() + "]"); + mTuner = null; + } + } } } @Override public String getId() { - return DiscoveredRspDuoTuner1.RSP_DUO_ID_PREFIX + "2 SER#" + getControlRsp().getDeviceDescriptor().getSerialNumber(); + return DiscoveredRspDuoTuner1.RSP_DUO_ID_PREFIX + "2 SER#" + getDeviceInfo().getSerialNumber(); } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/MasterSlaveBridge.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/MasterSlaveBridge.java index a94523ad8..b4b21817f 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/MasterSlaveBridge.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/MasterSlaveBridge.java @@ -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 @@ -109,6 +109,7 @@ public void stopSlave() if(mSlave != null) { mSlave.stop(); + mSlave = null; } } diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/RspDuoTuner2Editor.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/RspDuoTuner2Editor.java index 3fdb9a6dd..5d691727c 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/RspDuoTuner2Editor.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDuo/RspDuoTuner2Editor.java @@ -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 @@ -28,6 +28,7 @@ import io.github.dsheirer.source.tuner.sdrplay.DiscoveredRspTuner; import io.github.dsheirer.source.tuner.sdrplay.RspSampleRate; import io.github.dsheirer.source.tuner.sdrplay.RspTunerEditor; +import java.util.EnumSet; import net.miginfocom.swing.MigLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,7 +40,6 @@ import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.SpinnerNumberModel; -import java.util.EnumSet; /** * RSPduo Tuner 2 Editor @@ -130,7 +130,7 @@ private RspDuoTuner2Controller getTunerController() */ private boolean isSlaveMode() { - return getDiscoveredRspTuner().getControlRsp() instanceof ControlRspDuoTuner2Slave; + return getDiscoveredRspTuner().getDeviceInfo().getDeviceSelectionMode().isSlaveMode(); } @Override diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDx/ControlRspDx.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDx/ControlRspDx.java index 0f0df7d85..8c3c9ffbc 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDx/ControlRspDx.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDx/ControlRspDx.java @@ -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,236 +19,28 @@ package io.github.dsheirer.source.tuner.sdrplay.rspDx; -import com.github.dsheirer.sdrplay.DeviceDescriptor; -import com.github.dsheirer.sdrplay.DeviceSelectionMode; import com.github.dsheirer.sdrplay.SDRPlayException; -import com.github.dsheirer.sdrplay.SDRplay; -import com.github.dsheirer.sdrplay.UpdateReason; -import com.github.dsheirer.sdrplay.device.Device; import com.github.dsheirer.sdrplay.device.RspDxDevice; -import com.github.dsheirer.sdrplay.device.TunerSelect; -import com.github.dsheirer.sdrplay.parameter.control.AgcMode; import com.github.dsheirer.sdrplay.parameter.tuner.HdrModeBandwidth; -import com.github.dsheirer.sdrplay.parameter.tuner.IfMode; -import com.github.dsheirer.sdrplay.parameter.tuner.LoMode; import com.github.dsheirer.sdrplay.parameter.tuner.RspDxAntenna; import io.github.dsheirer.source.tuner.sdrplay.ControlRsp; -import io.github.dsheirer.source.tuner.sdrplay.RspSampleRate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Control wrapper for an RSPdx Device */ -public class ControlRspDx extends ControlRsp implements IControlRspDx +public class ControlRspDx extends ControlRsp implements IControlRspDx { private Logger mLog = LoggerFactory.getLogger(ControlRspDx.class); - private RspDxDevice mDevice; /** * Constructs an instance - * @param sdrplayApi to control the device - * @param deviceDescriptor for the device + * @param device for the device */ - public ControlRspDx(SDRplay sdrplayApi, DeviceDescriptor deviceDescriptor) + public ControlRspDx(RspDxDevice device) { - super(sdrplayApi, deviceDescriptor); - } - - /** - * Indicates if this control has been started and has a non-null device - */ - private boolean hasDevice() - { - return getDevice() != null; - } - - /** - * Access the device. - * @return device or null. - */ - private RspDxDevice getDevice() - { - return mDevice; - } - - @Override - public TunerSelect getTunerSelect() - { - return TunerSelect.TUNER_1; - } - - @Override - public void start() throws SDRPlayException - { - Device device = getApi().select(getDeviceDescriptor(), DeviceSelectionMode.SINGLE_TUNER_1); - - if(device instanceof RspDxDevice rspDxDevice) - { - mDevice = rspDxDevice; - 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); - } - } - - @Override - public void stop() throws SDRPlayException - { - if(hasDevice()) - { - getDevice().release(); - mDevice = null; - } - } - - @Override - public void startStream() - { - mStreamingLock.lock(); - - try - { - if(hasDevice()) - { - if(!mStreaming) - { - getDevice().initStreamA(getDeviceEventListener(), getStreamListener()); - mStreaming = true; - } - } - else - { - mLog.error("Unable to start RSPdx sample stream - device not started"); - } - } - catch(SDRPlayException se) - { - mLog.error("Unable to initialize/start streaming for RSPdx"); - } - finally - { - mStreamingLock.unlock(); - } - } - - @Override - public void stopStream() - { - mStreamingLock.lock(); - - try - { - if(hasDevice()) - { - if(mStreaming) - { - getDevice().uninitialize(); - mStreaming = false; - } - } - else - { - mLog.error("Unable to stop RSPdx sample stream - device not started"); - } - } - catch(SDRPlayException se) - { - mLog.error("Unable to uninitialize/stop streaming for RSPdx"); - } - finally - { - mStreamingLock.unlock(); - } - } - - /** - * Sets the sample rate - * @param sampleRate enumeration value. - * @throws SDRPlayException - */ - @Override - public void setSampleRate(RspSampleRate sampleRate) throws SDRPlayException - { - if(hasDevice() && !sampleRate.equals(mSampleRate)) - { - 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("Device is not initialized"); - } - } - - /** - * 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"); - } + super(device); } @Override diff --git a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDx/DiscoveredRspDxTuner.java b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDx/DiscoveredRspDxTuner.java index 76db4cee7..0f8d927db 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDx/DiscoveredRspDxTuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/sdrplay/rspDx/DiscoveredRspDxTuner.java @@ -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,10 +19,9 @@ package io.github.dsheirer.source.tuner.sdrplay.rspDx; +import com.github.dsheirer.sdrplay.device.DeviceInfo; import io.github.dsheirer.preference.source.ChannelizerType; -import io.github.dsheirer.source.SourceException; import io.github.dsheirer.source.tuner.sdrplay.DiscoveredRspTuner; -import io.github.dsheirer.source.tuner.sdrplay.RspTuner; /** * RSPdx discovered tuner. @@ -31,39 +30,11 @@ public class DiscoveredRspDxTuner extends DiscoveredRspTuner { /** * Constructs an instance - * @param controlRspDx for controlling the RSPdx after it's been started + * @param deviceInfo for the tuner * @param channelizerType to use for the tuner once started */ - public DiscoveredRspDxTuner(IControlRspDx controlRspDx, ChannelizerType channelizerType) + public DiscoveredRspDxTuner(DeviceInfo deviceInfo, ChannelizerType channelizerType) { - super(controlRspDx, channelizerType); - } - - /** - * Constructs and starts the tuner - */ - @Override - public void start() - { - if(isAvailable() && !hasTuner()) - { - RspDxTunerController tunerController = new RspDxTunerController(getControlRsp(), this); - mTuner = new RspTuner(tunerController, this, getChannelizerType()); - try - { - mTuner.start(); - } - catch(SourceException se) - { - setErrorMessage("Error starting RSPdx [" + getId() + "]"); - mTuner = null; - } - } - } - - @Override - public String getId() - { - return "RSPdx SER#" + getControlRsp().getDeviceDescriptor().getSerialNumber(); + super(deviceInfo, channelizerType); } }