#52 SDRPlay RSP tuner support. (#1453)

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

View File

@@ -22,10 +22,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up JDK 17
- name: Set up JDK 19
uses: actions/setup-java@v2
with:
java-version: '17'
java-version: '19'
distribution: 'liberica'
java-package: 'jdk+fx'
- name: Build with Gradle

2
.idea/misc.xml generated
View File

@@ -4,7 +4,7 @@
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="liberica-19.0.1.fx" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_19_PREVIEW" project-jdk-name="liberica-19.0.1.fx" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@@ -0,0 +1,36 @@
Auto-generating Java code from SDRPlay API using jextract.
Note: the api headers in the 3.11 folder are equivalent to the 3.08 headers. The only
difference from the 3.07 headers is the addition of the boolean 'valid' flag to DeviceT structure.
1. Download JDK19 compatible build of jextract JDK: https://jdk.java.net/jextract/
2. If generating on windows platform, modify the sdrplay_api.h to remove the windows
pieces of the file. Specifically:
2a. Comment out these lines but leave the *HANDLE typedef:
//#if defined(_M_X64) || defined(_M_IX86) || defined(_M_ARM64)
//#include "windows.h"
//#elif defined (__GNUC__)
typedef void *HANDLE;
//#endif
//#ifndef _SDRPLAY_DLL_QUALIFIER
//#if !defined(STATIC_LIB) && (defined(_M_X64) || defined(_M_IX86) || defined(_M_ARM64))
//#define _SDRPLAY_DLL_QUALIFIER __declspec(dllimport)
//#elif defined(STATIC_LIB) || defined(__GNUC__)
//#define _SDRPLAY_DLL_QUALIFIER
//#endif
//#endif // _SDRPLAY_DLL_QUALIFIER
2b. Remove the '_SDRPLAY_DLL_QUALIFIER' from in front of the method declarations
2c. Change the 3.11 version string to 3.08 either in the header file, or in the generated java class
3. Open command prompt to the root source code where the generated files should be placed:
..\SDRtrunk\sdrplay-api\src\main\java
4. Generate the code:
c:\Users\Denny\Downloads\jdk-19-ea2-panama\bin\jextract "C:\Users\Denny\git\sdrtrunk\sdrplay-api\api\v3_11\sdrplay_api.h" -l libsdrplay_api --source
5. Do this for all versions of the API.

View File

@@ -0,0 +1,229 @@
#ifndef SDRPLAY_API_H
#define SDRPLAY_API_H
#include "sdrplay_api_dev.h"
#include "sdrplay_api_rx_channel.h"
#include "sdrplay_api_callback.h"
//#if defined(_M_X64) || defined(_M_IX86)
//#include "windows.h"
//#elif defined (__GNUC__)
typedef void *HANDLE;
//#endif
//#ifndef _SDRPLAY_DLL_QUALIFIER
//#if !defined(STATIC_LIB) && (defined(_M_X64) || defined(_M_IX86))
//#define _SDRPLAY_DLL_QUALIFIER __declspec(dllimport)
//#elif defined(STATIC_LIB) || defined(__GNUC__)
//#define _SDRPLAY_DLL_QUALIFIER
//#endif
//#endif // _SDRPLAY_DLL_QUALIFIER
// Application code should check that it is compiled against the same API version
// sdrplay_api_ApiVersion() returns the API version
#define SDRPLAY_API_VERSION (float)(3.07)
// API Constants
#define SDRPLAY_MAX_DEVICES (16)
#define SDRPLAY_MAX_TUNERS_PER_DEVICE (2)
#define SDRPLAY_MAX_SER_NO_LEN (64)
#define SDRPLAY_MAX_ROOT_NM_LEN (32)
#define SDRPLAY_RSP1_ID (1)
#define SDRPLAY_RSP1A_ID (255)
#define SDRPLAY_RSP2_ID (2)
#define SDRPLAY_RSPduo_ID (3)
#define SDRPLAY_RSPdx_ID (4)
// Enum types
typedef enum
{
sdrplay_api_Success = 0,
sdrplay_api_Fail = 1,
sdrplay_api_InvalidParam = 2,
sdrplay_api_OutOfRange = 3,
sdrplay_api_GainUpdateError = 4,
sdrplay_api_RfUpdateError = 5,
sdrplay_api_FsUpdateError = 6,
sdrplay_api_HwError = 7,
sdrplay_api_AliasingError = 8,
sdrplay_api_AlreadyInitialised = 9,
sdrplay_api_NotInitialised = 10,
sdrplay_api_NotEnabled = 11,
sdrplay_api_HwVerError = 12,
sdrplay_api_OutOfMemError = 13,
sdrplay_api_ServiceNotResponding = 14,
sdrplay_api_StartPending = 15,
sdrplay_api_StopPending = 16,
sdrplay_api_InvalidMode = 17,
sdrplay_api_FailedVerification1 = 18,
sdrplay_api_FailedVerification2 = 19,
sdrplay_api_FailedVerification3 = 20,
sdrplay_api_FailedVerification4 = 21,
sdrplay_api_FailedVerification5 = 22,
sdrplay_api_FailedVerification6 = 23,
sdrplay_api_InvalidServiceVersion = 24
} sdrplay_api_ErrT;
typedef enum
{
sdrplay_api_Update_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_Dev_Fs = 0x00000001,
sdrplay_api_Update_Dev_Ppm = 0x00000002,
sdrplay_api_Update_Dev_SyncUpdate = 0x00000004,
sdrplay_api_Update_Dev_ResetFlags = 0x00000008,
sdrplay_api_Update_Rsp1a_BiasTControl = 0x00000010,
sdrplay_api_Update_Rsp1a_RfNotchControl = 0x00000020,
sdrplay_api_Update_Rsp1a_RfDabNotchControl = 0x00000040,
sdrplay_api_Update_Rsp2_BiasTControl = 0x00000080,
sdrplay_api_Update_Rsp2_AmPortSelect = 0x00000100,
sdrplay_api_Update_Rsp2_AntennaControl = 0x00000200,
sdrplay_api_Update_Rsp2_RfNotchControl = 0x00000400,
sdrplay_api_Update_Rsp2_ExtRefControl = 0x00000800,
sdrplay_api_Update_RspDuo_ExtRefControl = 0x00001000,
sdrplay_api_Update_Master_Spare_1 = 0x00002000,
sdrplay_api_Update_Master_Spare_2 = 0x00004000,
// Reasons for master and slave mode
// Note: sdrplay_api_Update_Tuner_Gr MUST be the first value defined in this section!
sdrplay_api_Update_Tuner_Gr = 0x00008000,
sdrplay_api_Update_Tuner_GrLimits = 0x00010000,
sdrplay_api_Update_Tuner_Frf = 0x00020000,
sdrplay_api_Update_Tuner_BwType = 0x00040000,
sdrplay_api_Update_Tuner_IfType = 0x00080000,
sdrplay_api_Update_Tuner_DcOffset = 0x00100000,
sdrplay_api_Update_Tuner_LoMode = 0x00200000,
sdrplay_api_Update_Ctrl_DCoffsetIQimbalance = 0x00400000,
sdrplay_api_Update_Ctrl_Decimation = 0x00800000,
sdrplay_api_Update_Ctrl_Agc = 0x01000000,
sdrplay_api_Update_Ctrl_AdsbMode = 0x02000000,
sdrplay_api_Update_Ctrl_OverloadMsgAck = 0x04000000,
sdrplay_api_Update_RspDuo_BiasTControl = 0x08000000,
sdrplay_api_Update_RspDuo_AmPortSelect = 0x10000000,
sdrplay_api_Update_RspDuo_Tuner1AmNotchControl = 0x20000000,
sdrplay_api_Update_RspDuo_RfNotchControl = 0x40000000,
sdrplay_api_Update_RspDuo_RfDabNotchControl = 0x80000000,
} sdrplay_api_ReasonForUpdateT;
typedef enum
{
sdrplay_api_Update_Ext1_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_RspDx_HdrEnable = 0x00000001,
sdrplay_api_Update_RspDx_BiasTControl = 0x00000002,
sdrplay_api_Update_RspDx_AntennaControl = 0x00000004,
sdrplay_api_Update_RspDx_RfNotchControl = 0x00000008,
sdrplay_api_Update_RspDx_RfDabNotchControl = 0x00000010,
sdrplay_api_Update_RspDx_HdrBw = 0x00000020,
// Reasons for master and slave mode
} sdrplay_api_ReasonForUpdateExtension1T;
typedef enum
{
sdrplay_api_DbgLvl_Disable = 0,
sdrplay_api_DbgLvl_Verbose = 1,
sdrplay_api_DbgLvl_Warning = 2,
sdrplay_api_DbgLvl_Error = 3,
sdrplay_api_DbgLvl_Message = 4,
} sdrplay_api_DbgLvl_t;
// Device structure
typedef struct
{
char SerNo[SDRPLAY_MAX_SER_NO_LEN];
unsigned char hwVer;
sdrplay_api_TunerSelectT tuner;
sdrplay_api_RspDuoModeT rspDuoMode;
double rspDuoSampleFreq;
HANDLE dev;
} sdrplay_api_DeviceT;
// Device parameter structure
typedef struct
{
sdrplay_api_DevParamsT *devParams;
sdrplay_api_RxChannelParamsT *rxChannelA;
sdrplay_api_RxChannelParamsT *rxChannelB;
} sdrplay_api_DeviceParamsT;
// Extended error message structure
typedef struct
{
char file[256];
char function[256];
int line;
char message[1024];
} sdrplay_api_ErrorInfoT;
// Comman API function types
typedef sdrplay_api_ErrT (*sdrplay_api_Open_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_Close_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_ApiVersion_t)(float *apiVer);
typedef sdrplay_api_ErrT (*sdrplay_api_LockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_UnlockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDevices_t)(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
typedef sdrplay_api_ErrT (*sdrplay_api_SelectDevice_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_ReleaseDevice_t)(sdrplay_api_DeviceT *device);
typedef const char* (*sdrplay_api_GetErrorString_t)(sdrplay_api_ErrT err);
typedef sdrplay_api_ErrorInfoT* (*sdrplay_api_GetLastError_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_DisableHeartbeat_t)(void);
// Device API function types
typedef sdrplay_api_ErrT (*sdrplay_api_DebugEnable_t)(HANDLE dev, sdrplay_api_DbgLvl_t dbgLvl);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDeviceParams_t)(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
typedef sdrplay_api_ErrT (*sdrplay_api_Init_t)(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
typedef sdrplay_api_ErrT (*sdrplay_api_Uninit_t)(HANDLE dev);
typedef sdrplay_api_ErrT (*sdrplay_api_Update_t)(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoActiveTuner_t)(HANDLE dev, sdrplay_api_TunerSelectT *tuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoDualTunerModeSampleRate_t)(double *currentSampleRate);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoMode_t)(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
// API function definitions
#ifdef __cplusplus
extern "C"
{
#endif
// Comman API function definitions
sdrplay_api_ErrT sdrplay_api_Open(void);
sdrplay_api_ErrT sdrplay_api_Close(void);
sdrplay_api_ErrT sdrplay_api_ApiVersion(float *apiVer);
sdrplay_api_ErrT sdrplay_api_LockDeviceApi(void);
sdrplay_api_ErrT sdrplay_api_UnlockDeviceApi(void);
sdrplay_api_ErrT sdrplay_api_GetDevices(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
sdrplay_api_ErrT sdrplay_api_SelectDevice(sdrplay_api_DeviceT *device);
sdrplay_api_ErrT sdrplay_api_ReleaseDevice(sdrplay_api_DeviceT *device);
const char* sdrplay_api_GetErrorString(sdrplay_api_ErrT err);
sdrplay_api_ErrorInfoT* sdrplay_api_GetLastError(sdrplay_api_DeviceT *device);
sdrplay_api_ErrT sdrplay_api_DisableHeartbeat(void); // Must be called before sdrplay_api_SelectDevice()
// Device API function definitions
sdrplay_api_ErrT sdrplay_api_DebugEnable(HANDLE dev, sdrplay_api_DbgLvl_t enable);
sdrplay_api_ErrT sdrplay_api_GetDeviceParams(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
sdrplay_api_ErrT sdrplay_api_Init(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
sdrplay_api_ErrT sdrplay_api_Uninit(HANDLE dev);
sdrplay_api_ErrT sdrplay_api_Update(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoActiveTuner(HANDLE dev, sdrplay_api_TunerSelectT *currentTuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoDualTunerModeSampleRate(HANDLE dev, double *currentSampleRate);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoMode(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
#ifdef __cplusplus
}
#endif
#endif //SDRPLAY_API_H

View File

@@ -0,0 +1,78 @@
#ifndef SDRPLAY_API_CALLBACK_H
#define SDRPLAY_API_CALLBACK_H
// Event callback enums
typedef enum
{
sdrplay_api_Overload_Detected = 0,
sdrplay_api_Overload_Corrected = 1,
} sdrplay_api_PowerOverloadCbEventIdT;
typedef enum
{
sdrplay_api_MasterInitialised = 0,
sdrplay_api_SlaveAttached = 1,
sdrplay_api_SlaveDetached = 2,
sdrplay_api_SlaveInitialised = 3,
sdrplay_api_SlaveUninitialised = 4,
sdrplay_api_MasterDllDisappeared = 5,
sdrplay_api_SlaveDllDisappeared = 6,
} sdrplay_api_RspDuoModeCbEventIdT;
typedef enum
{
sdrplay_api_GainChange = 0,
sdrplay_api_PowerOverloadChange = 1,
sdrplay_api_DeviceRemoved = 2,
sdrplay_api_RspDuoModeChange = 3,
} sdrplay_api_EventT;
// Event callback parameter structs
typedef struct
{
unsigned int gRdB;
unsigned int lnaGRdB;
double currGain;
} sdrplay_api_GainCbParamT;
typedef struct
{
sdrplay_api_PowerOverloadCbEventIdT powerOverloadChangeType;
} sdrplay_api_PowerOverloadCbParamT;
typedef struct
{
sdrplay_api_RspDuoModeCbEventIdT modeChangeType;
} sdrplay_api_RspDuoModeCbParamT;
// Event parameters overlay
typedef union
{
sdrplay_api_GainCbParamT gainParams;
sdrplay_api_PowerOverloadCbParamT powerOverloadParams;
sdrplay_api_RspDuoModeCbParamT rspDuoModeParams;
} sdrplay_api_EventParamsT;
// Stream callback parameter structs
typedef struct
{
unsigned int firstSampleNum;
int grChanged;
int rfChanged;
int fsChanged;
unsigned int numSamples;
} sdrplay_api_StreamCbParamsT;
// Callback function prototypes
typedef void (*sdrplay_api_StreamCallback_t)(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext);
typedef void (*sdrplay_api_EventCallback_t)(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tuner, sdrplay_api_EventParamsT *params, void *cbContext);
// Callback function struct
typedef struct
{
sdrplay_api_StreamCallback_t StreamACbFn;
sdrplay_api_StreamCallback_t StreamBCbFn;
sdrplay_api_EventCallback_t EventCbFn;
} sdrplay_api_CallbackFnsT;
#endif //SDRPLAY_API_CALLBACK_H

View File

@@ -0,0 +1,55 @@
#ifndef SDRPLAY_API_CONTROL_H
#define SDRPLAY_API_CONTROL_H
// Control parameter enums
typedef enum
{
sdrplay_api_AGC_DISABLE = 0,
sdrplay_api_AGC_100HZ = 1,
sdrplay_api_AGC_50HZ = 2,
sdrplay_api_AGC_5HZ = 3,
sdrplay_api_AGC_CTRL_EN = 4
} sdrplay_api_AgcControlT;
typedef enum
{
sdrplay_api_ADSB_DECIMATION = 0,
sdrplay_api_ADSB_NO_DECIMATION_LOWPASS = 1,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_2MHZ = 2,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_3MHZ = 3
} sdrplay_api_AdsbModeT;
// Control parameter structs
typedef struct
{
unsigned char DCenable; // default: 1
unsigned char IQenable; // default: 1
} sdrplay_api_DcOffsetT;
typedef struct
{
unsigned char enable; // default: 0
unsigned char decimationFactor; // default: 1
unsigned char wideBandSignal; // default: 0
} sdrplay_api_DecimationT;
typedef struct
{
sdrplay_api_AgcControlT enable; // default: sdrplay_api_AGC_50HZ
int setPoint_dBfs; // default: -60
unsigned short attack_ms; // default: 0
unsigned short decay_ms; // default: 0
unsigned short decay_delay_ms; // default: 0
unsigned short decay_threshold_dB; // default: 0
int syncUpdate; // default: 0
} sdrplay_api_AgcT;
typedef struct
{
sdrplay_api_DcOffsetT dcOffset;
sdrplay_api_DecimationT decimation;
sdrplay_api_AgcT agc;
sdrplay_api_AdsbModeT adsbMode; //default: sdrplay_api_ADSB_DECIMATION
} sdrplay_api_ControlParamsT;
#endif //SDRPLAY_API_CONTROL_H

View File

@@ -0,0 +1,51 @@
#ifndef SDRPLAY_API_DEV_H
#define SDRPLAY_API_DEV_H
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
// Dev parameter enums
typedef enum
{
sdrplay_api_ISOCH = 0,
sdrplay_api_BULK = 1
} sdrplay_api_TransferModeT;
// Dev parameter structs
typedef struct
{
double fsHz; // default: 2000000.0
unsigned char syncUpdate; // default: 0
unsigned char reCal; // default: 0
} sdrplay_api_FsFreqT;
typedef struct
{
unsigned int sampleNum; // default: 0
unsigned int period; // default: 0
} sdrplay_api_SyncUpdateT;
typedef struct
{
unsigned char resetGainUpdate; // default: 0
unsigned char resetRfUpdate; // default: 0
unsigned char resetFsUpdate; // default: 0
} sdrplay_api_ResetFlagsT;
typedef struct
{
double ppm; // default: 0.0
sdrplay_api_FsFreqT fsFreq;
sdrplay_api_SyncUpdateT syncUpdate;
sdrplay_api_ResetFlagsT resetFlags;
sdrplay_api_TransferModeT mode; // default: sdrplay_api_ISOCH
unsigned int samplesPerPkt; // default: 0 (output param)
sdrplay_api_Rsp1aParamsT rsp1aParams;
sdrplay_api_Rsp2ParamsT rsp2Params;
sdrplay_api_RspDuoParamsT rspDuoParams;
sdrplay_api_RspDxParamsT rspDxParams;
} sdrplay_api_DevParamsT;
#endif //SDRPLAY_API_DEV_H

View File

@@ -0,0 +1,22 @@
#ifndef SDRPLAY_API_RSP1A_H
#define SDRPLAY_API_RSP1A_H
#define RSPIA_NUM_LNA_STATES 10
#define RSPIA_NUM_LNA_STATES_AM 7
#define RSPIA_NUM_LNA_STATES_LBAND 9
// RSP1A parameter enums
// RSP1A parameter structs
typedef struct
{
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_Rsp1aParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
} sdrplay_api_Rsp1aTunerParamsT;
#endif //SDRPLAY_API_RSP1A_H

View File

@@ -0,0 +1,35 @@
#ifndef SDRPLAY_API_RSP2_H
#define SDRPLAY_API_RSP2_H
#define RSPII_NUM_LNA_STATES 9
#define RSPII_NUM_LNA_STATES_AMPORT 5
#define RSPII_NUM_LNA_STATES_420MHZ 6
// RSP2 parameter enums
typedef enum
{
sdrplay_api_Rsp2_ANTENNA_A = 5,
sdrplay_api_Rsp2_ANTENNA_B = 6,
} sdrplay_api_Rsp2_AntennaSelectT;
typedef enum
{
sdrplay_api_Rsp2_AMPORT_1 = 1,
sdrplay_api_Rsp2_AMPORT_2 = 0,
} sdrplay_api_Rsp2_AmPortSelectT;
// RSP2 parameter structs
typedef struct
{
unsigned char extRefOutputEn; // default: 0
} sdrplay_api_Rsp2ParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_Rsp2_AmPortSelectT amPortSel; // default: sdrplay_api_Rsp2_AMPORT_2
sdrplay_api_Rsp2_AntennaSelectT antennaSel; // default: sdrplay_api_Rsp2_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
} sdrplay_api_Rsp2TunerParamsT;
#endif //SDRPLAY_API_RSP2_H

View File

@@ -0,0 +1,40 @@
#ifndef SDRPLAY_API_RSPduo_H
#define SDRPLAY_API_RSPduo_H
#define RSPDUO_NUM_LNA_STATES 10
#define RSPDUO_NUM_LNA_STATES_AMPORT 5
#define RSPDUO_NUM_LNA_STATES_AM 7
#define RSPDUO_NUM_LNA_STATES_LBAND 9
// RSPduo parameter enums
typedef enum
{
sdrplay_api_RspDuoMode_Unknown = 0,
sdrplay_api_RspDuoMode_Single_Tuner = 1,
sdrplay_api_RspDuoMode_Dual_Tuner = 2,
sdrplay_api_RspDuoMode_Master = 4,
sdrplay_api_RspDuoMode_Slave = 8,
} sdrplay_api_RspDuoModeT;
typedef enum
{
sdrplay_api_RspDuo_AMPORT_1 = 1,
sdrplay_api_RspDuo_AMPORT_2 = 0,
} sdrplay_api_RspDuo_AmPortSelectT;
// RSPduo parameter structs
typedef struct
{
int extRefOutputEn; // default: 0
} sdrplay_api_RspDuoParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel; // default: sdrplay_api_RspDuo_AMPORT_2
unsigned char tuner1AmNotchEnable; // default: 0
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDuoTunerParamsT;
#endif //SDRPLAY_API_RSPduo_H

View File

@@ -0,0 +1,45 @@
#ifndef SDRPLAY_API_RSPDX_H
#define SDRPLAY_API_RSPDX_H
#include "sdrplay_api_tuner.h"
#define RSPDX_NUM_LNA_STATES 28 // Number of LNA states in all bands (except where defined differently below)
#define RSPDX_NUM_LNA_STATES_AMPORT2_0_12 19 // Number of LNA states when using AM Port 2 between 0 and 12MHz
#define RSPDX_NUM_LNA_STATES_AMPORT2_12_60 20 // Number of LNA states when using AM Port 2 between 12 and 60MHz
#define RSPDX_NUM_LNA_STATES_VHF_BAND3 27 // Number of LNA states in VHF and Band3
#define RSPDX_NUM_LNA_STATES_420MHZ 21 // Number of LNA states in 420MHz band
#define RSPDX_NUM_LNA_STATES_LBAND 19 // Number of LNA states in L-band
#define RSPDX_NUM_LNA_STATES_DX 26 // Number of LNA states in DX path
// RSPdx parameter enums
typedef enum
{
sdrplay_api_RspDx_ANTENNA_A = 0,
sdrplay_api_RspDx_ANTENNA_B = 1,
sdrplay_api_RspDx_ANTENNA_C = 2,
} sdrplay_api_RspDx_AntennaSelectT;
typedef enum
{
sdrplay_api_RspDx_HDRMODE_BW_0_200 = 0,
sdrplay_api_RspDx_HDRMODE_BW_0_500 = 1,
sdrplay_api_RspDx_HDRMODE_BW_1_200 = 2,
sdrplay_api_RspDx_HDRMODE_BW_1_700 = 3,
} sdrplay_api_RspDx_HdrModeBwT;
// RSPdx parameter structs
typedef struct
{
unsigned char hdrEnable; // default: 0
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDx_AntennaSelectT antennaSel; // default: sdrplay_api_RspDx_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDxParamsT;
typedef struct
{
sdrplay_api_RspDx_HdrModeBwT hdrBw; // default: sdrplay_api_RspDx_HDRMODE_BW_1_700
} sdrplay_api_RspDxTunerParamsT;
#endif //SDRPLAY_API_RSPDX_H

View File

@@ -0,0 +1,21 @@
#ifndef SDRPLAY_API_RX_CHANNEL_H
#define SDRPLAY_API_RX_CHANNEL_H
#include "sdrplay_api_tuner.h"
#include "sdrplay_api_control.h"
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
typedef struct
{
sdrplay_api_TunerParamsT tunerParams;
sdrplay_api_ControlParamsT ctrlParams;
sdrplay_api_Rsp1aTunerParamsT rsp1aTunerParams;
sdrplay_api_Rsp2TunerParamsT rsp2TunerParams;
sdrplay_api_RspDuoTunerParamsT rspDuoTunerParams;
sdrplay_api_RspDxTunerParamsT rspDxTunerParams;
} sdrplay_api_RxChannelParamsT;
#endif //SDRPLAY_API_RX_CHANNEL_H

View File

@@ -0,0 +1,93 @@
#ifndef SDRPLAY_API_TUNER_H
#define SDRPLAY_API_TUNER_H
#define MAX_BB_GR (59)
// Tuner parameter enums
typedef enum
{
sdrplay_api_BW_Undefined = 0,
sdrplay_api_BW_0_200 = 200,
sdrplay_api_BW_0_300 = 300,
sdrplay_api_BW_0_600 = 600,
sdrplay_api_BW_1_536 = 1536,
sdrplay_api_BW_5_000 = 5000,
sdrplay_api_BW_6_000 = 6000,
sdrplay_api_BW_7_000 = 7000,
sdrplay_api_BW_8_000 = 8000
} sdrplay_api_Bw_MHzT;
typedef enum
{
sdrplay_api_IF_Undefined = -1,
sdrplay_api_IF_Zero = 0,
sdrplay_api_IF_0_450 = 450,
sdrplay_api_IF_1_620 = 1620,
sdrplay_api_IF_2_048 = 2048
} sdrplay_api_If_kHzT;
typedef enum
{
sdrplay_api_LO_Undefined = 0,
sdrplay_api_LO_Auto = 1,
sdrplay_api_LO_120MHz = 2,
sdrplay_api_LO_144MHz = 3,
sdrplay_api_LO_168MHz = 4
} sdrplay_api_LoModeT;
typedef enum
{
sdrplay_api_EXTENDED_MIN_GR = 0,
sdrplay_api_NORMAL_MIN_GR = 20
} sdrplay_api_MinGainReductionT;
typedef enum
{
sdrplay_api_Tuner_Neither = 0,
sdrplay_api_Tuner_A = 1,
sdrplay_api_Tuner_B = 2,
sdrplay_api_Tuner_Both = 3,
} sdrplay_api_TunerSelectT;
// Tuner parameter structs
typedef struct
{
float curr;
float max;
float min;
} sdrplay_api_GainValuesT;
typedef struct
{
int gRdB; // default: 50
unsigned char LNAstate; // default: 0
unsigned char syncUpdate; // default: 0
sdrplay_api_MinGainReductionT minGr; // default: sdrplay_api_NORMAL_MIN_GR
sdrplay_api_GainValuesT gainVals; // output parameter
} sdrplay_api_GainT;
typedef struct
{
double rfHz; // default: 200000000.0
unsigned char syncUpdate; // default: 0
} sdrplay_api_RfFreqT;
typedef struct
{
unsigned char dcCal; // default: 3 (Periodic mode)
unsigned char speedUp; // default: 0 (No speedup)
int trackTime; // default: 1 (=> time in uSec = (72 * 3 * trackTime) / 24e6 = 9uSec)
int refreshRateTime; // default: 2048 (=> time in uSec = (72 * 3 * refreshRateTime) / 24e6 = 18432uSec)
} sdrplay_api_DcOffsetTunerT;
typedef struct
{
sdrplay_api_Bw_MHzT bwType; // default: sdrplay_api_BW_0_200
sdrplay_api_If_kHzT ifType; // default: sdrplay_api_IF_Zero
sdrplay_api_LoModeT loMode; // default: sdrplay_api_LO_Auto
sdrplay_api_GainT gain;
sdrplay_api_RfFreqT rfFreq;
sdrplay_api_DcOffsetTunerT dcOffsetTuner;
} sdrplay_api_TunerParamsT;
#endif //SDRPLAY_API_TUNER_H

View File

@@ -0,0 +1,230 @@
#ifndef SDRPLAY_API_H
#define SDRPLAY_API_H
#include "sdrplay_api_dev.h"
#include "sdrplay_api_rx_channel.h"
#include "sdrplay_api_callback.h"
//#if defined(_M_X64) || defined(_M_IX86) || defined(_M_ARM64)
//#include "windows.h"
//#elif defined (__GNUC__)
typedef void *HANDLE;
//#endif
//#ifndef _SDRPLAY_DLL_QUALIFIER
//#if !defined(STATIC_LIB) && (defined(_M_X64) || defined(_M_IX86) || defined(_M_ARM64))
//#define _SDRPLAY_DLL_QUALIFIER __declspec(dllimport)
//#elif defined(STATIC_LIB) || defined(__GNUC__)
//#define _SDRPLAY_DLL_QUALIFIER
//#endif
//#endif // _SDRPLAY_DLL_QUALIFIER
// Application code should check that it is compiled against the same API version
// sdrplay_api_ApiVersion() returns the API version
#define SDRPLAY_API_VERSION (float)(3.11)
// API Constants
#define SDRPLAY_MAX_DEVICES (16)
#define SDRPLAY_MAX_TUNERS_PER_DEVICE (2)
#define SDRPLAY_MAX_SER_NO_LEN (64)
#define SDRPLAY_MAX_ROOT_NM_LEN (32)
#define SDRPLAY_RSP1_ID (1)
#define SDRPLAY_RSP1A_ID (255)
#define SDRPLAY_RSP2_ID (2)
#define SDRPLAY_RSPduo_ID (3)
#define SDRPLAY_RSPdx_ID (4)
// Enum types
typedef enum
{
sdrplay_api_Success = 0,
sdrplay_api_Fail = 1,
sdrplay_api_InvalidParam = 2,
sdrplay_api_OutOfRange = 3,
sdrplay_api_GainUpdateError = 4,
sdrplay_api_RfUpdateError = 5,
sdrplay_api_FsUpdateError = 6,
sdrplay_api_HwError = 7,
sdrplay_api_AliasingError = 8,
sdrplay_api_AlreadyInitialised = 9,
sdrplay_api_NotInitialised = 10,
sdrplay_api_NotEnabled = 11,
sdrplay_api_HwVerError = 12,
sdrplay_api_OutOfMemError = 13,
sdrplay_api_ServiceNotResponding = 14,
sdrplay_api_StartPending = 15,
sdrplay_api_StopPending = 16,
sdrplay_api_InvalidMode = 17,
sdrplay_api_FailedVerification1 = 18,
sdrplay_api_FailedVerification2 = 19,
sdrplay_api_FailedVerification3 = 20,
sdrplay_api_FailedVerification4 = 21,
sdrplay_api_FailedVerification5 = 22,
sdrplay_api_FailedVerification6 = 23,
sdrplay_api_InvalidServiceVersion = 24
} sdrplay_api_ErrT;
typedef enum
{
sdrplay_api_Update_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_Dev_Fs = 0x00000001,
sdrplay_api_Update_Dev_Ppm = 0x00000002,
sdrplay_api_Update_Dev_SyncUpdate = 0x00000004,
sdrplay_api_Update_Dev_ResetFlags = 0x00000008,
sdrplay_api_Update_Rsp1a_BiasTControl = 0x00000010,
sdrplay_api_Update_Rsp1a_RfNotchControl = 0x00000020,
sdrplay_api_Update_Rsp1a_RfDabNotchControl = 0x00000040,
sdrplay_api_Update_Rsp2_BiasTControl = 0x00000080,
sdrplay_api_Update_Rsp2_AmPortSelect = 0x00000100,
sdrplay_api_Update_Rsp2_AntennaControl = 0x00000200,
sdrplay_api_Update_Rsp2_RfNotchControl = 0x00000400,
sdrplay_api_Update_Rsp2_ExtRefControl = 0x00000800,
sdrplay_api_Update_RspDuo_ExtRefControl = 0x00001000,
sdrplay_api_Update_Master_Spare_1 = 0x00002000,
sdrplay_api_Update_Master_Spare_2 = 0x00004000,
// Reasons for master and slave mode
// Note: sdrplay_api_Update_Tuner_Gr MUST be the first value defined in this section!
sdrplay_api_Update_Tuner_Gr = 0x00008000,
sdrplay_api_Update_Tuner_GrLimits = 0x00010000,
sdrplay_api_Update_Tuner_Frf = 0x00020000,
sdrplay_api_Update_Tuner_BwType = 0x00040000,
sdrplay_api_Update_Tuner_IfType = 0x00080000,
sdrplay_api_Update_Tuner_DcOffset = 0x00100000,
sdrplay_api_Update_Tuner_LoMode = 0x00200000,
sdrplay_api_Update_Ctrl_DCoffsetIQimbalance = 0x00400000,
sdrplay_api_Update_Ctrl_Decimation = 0x00800000,
sdrplay_api_Update_Ctrl_Agc = 0x01000000,
sdrplay_api_Update_Ctrl_AdsbMode = 0x02000000,
sdrplay_api_Update_Ctrl_OverloadMsgAck = 0x04000000,
sdrplay_api_Update_RspDuo_BiasTControl = 0x08000000,
sdrplay_api_Update_RspDuo_AmPortSelect = 0x10000000,
sdrplay_api_Update_RspDuo_Tuner1AmNotchControl = 0x20000000,
sdrplay_api_Update_RspDuo_RfNotchControl = 0x40000000,
sdrplay_api_Update_RspDuo_RfDabNotchControl = 0x80000000,
} sdrplay_api_ReasonForUpdateT;
typedef enum
{
sdrplay_api_Update_Ext1_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_RspDx_HdrEnable = 0x00000001,
sdrplay_api_Update_RspDx_BiasTControl = 0x00000002,
sdrplay_api_Update_RspDx_AntennaControl = 0x00000004,
sdrplay_api_Update_RspDx_RfNotchControl = 0x00000008,
sdrplay_api_Update_RspDx_RfDabNotchControl = 0x00000010,
sdrplay_api_Update_RspDx_HdrBw = 0x00000020,
// Reasons for master and slave mode
} sdrplay_api_ReasonForUpdateExtension1T;
typedef enum
{
sdrplay_api_DbgLvl_Disable = 0,
sdrplay_api_DbgLvl_Verbose = 1,
sdrplay_api_DbgLvl_Warning = 2,
sdrplay_api_DbgLvl_Error = 3,
sdrplay_api_DbgLvl_Message = 4,
} sdrplay_api_DbgLvl_t;
// Device structure
typedef struct
{
char SerNo[SDRPLAY_MAX_SER_NO_LEN];
unsigned char hwVer;
sdrplay_api_TunerSelectT tuner;
sdrplay_api_RspDuoModeT rspDuoMode;
unsigned char valid;
double rspDuoSampleFreq;
HANDLE dev;
} sdrplay_api_DeviceT;
// Device parameter structure
typedef struct
{
sdrplay_api_DevParamsT *devParams;
sdrplay_api_RxChannelParamsT *rxChannelA;
sdrplay_api_RxChannelParamsT *rxChannelB;
} sdrplay_api_DeviceParamsT;
// Extended error message structure
typedef struct
{
char file[256];
char function[256];
int line;
char message[1024];
} sdrplay_api_ErrorInfoT;
// Comman API function types
typedef sdrplay_api_ErrT (*sdrplay_api_Open_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_Close_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_ApiVersion_t)(float *apiVer);
typedef sdrplay_api_ErrT (*sdrplay_api_LockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_UnlockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDevices_t)(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
typedef sdrplay_api_ErrT (*sdrplay_api_SelectDevice_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_ReleaseDevice_t)(sdrplay_api_DeviceT *device);
typedef const char* (*sdrplay_api_GetErrorString_t)(sdrplay_api_ErrT err);
typedef sdrplay_api_ErrorInfoT* (*sdrplay_api_GetLastError_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_DisableHeartbeat_t)(void);
// Device API function types
typedef sdrplay_api_ErrT (*sdrplay_api_DebugEnable_t)(HANDLE dev, sdrplay_api_DbgLvl_t dbgLvl);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDeviceParams_t)(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
typedef sdrplay_api_ErrT (*sdrplay_api_Init_t)(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
typedef sdrplay_api_ErrT (*sdrplay_api_Uninit_t)(HANDLE dev);
typedef sdrplay_api_ErrT (*sdrplay_api_Update_t)(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoActiveTuner_t)(HANDLE dev, sdrplay_api_TunerSelectT *tuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoDualTunerModeSampleRate_t)(double *currentSampleRate, double newSampleRate);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoMode_t)(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
// API function definitions
#ifdef __cplusplus
extern "C"
{
#endif
// Comman API function definitions
sdrplay_api_ErrT sdrplay_api_Open(void);
sdrplay_api_ErrT sdrplay_api_Close(void);
sdrplay_api_ErrT sdrplay_api_ApiVersion(float *apiVer);
sdrplay_api_ErrT sdrplay_api_LockDeviceApi(void);
sdrplay_api_ErrT sdrplay_api_UnlockDeviceApi(void);
sdrplay_api_ErrT sdrplay_api_GetDevices(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
sdrplay_api_ErrT sdrplay_api_SelectDevice(sdrplay_api_DeviceT *device);
sdrplay_api_ErrT sdrplay_api_ReleaseDevice(sdrplay_api_DeviceT *device);
const char* sdrplay_api_GetErrorString(sdrplay_api_ErrT err);
sdrplay_api_ErrorInfoT* sdrplay_api_GetLastError(sdrplay_api_DeviceT *device);
sdrplay_api_ErrT sdrplay_api_DisableHeartbeat(void); // Must be called before sdrplay_api_SelectDevice()
// Device API function definitions
sdrplay_api_ErrT sdrplay_api_DebugEnable(HANDLE dev, sdrplay_api_DbgLvl_t enable);
sdrplay_api_ErrT sdrplay_api_GetDeviceParams(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
sdrplay_api_ErrT sdrplay_api_Init(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
sdrplay_api_ErrT sdrplay_api_Uninit(HANDLE dev);
sdrplay_api_ErrT sdrplay_api_Update(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoActiveTuner(HANDLE dev, sdrplay_api_TunerSelectT *currentTuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoDualTunerModeSampleRate(HANDLE dev, double *currentSampleRate, double newSampleRate);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoMode(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
#ifdef __cplusplus
}
#endif
#endif //SDRPLAY_API_H

View File

@@ -0,0 +1,79 @@
#ifndef SDRPLAY_API_CALLBACK_H
#define SDRPLAY_API_CALLBACK_H
// Event callback enums
typedef enum
{
sdrplay_api_Overload_Detected = 0,
sdrplay_api_Overload_Corrected = 1,
} sdrplay_api_PowerOverloadCbEventIdT;
typedef enum
{
sdrplay_api_MasterInitialised = 0,
sdrplay_api_SlaveAttached = 1,
sdrplay_api_SlaveDetached = 2,
sdrplay_api_SlaveInitialised = 3,
sdrplay_api_SlaveUninitialised = 4,
sdrplay_api_MasterDllDisappeared = 5,
sdrplay_api_SlaveDllDisappeared = 6,
} sdrplay_api_RspDuoModeCbEventIdT;
typedef enum
{
sdrplay_api_GainChange = 0,
sdrplay_api_PowerOverloadChange = 1,
sdrplay_api_DeviceRemoved = 2,
sdrplay_api_RspDuoModeChange = 3,
sdrplay_api_DeviceFailure = 4,
} sdrplay_api_EventT;
// Event callback parameter structs
typedef struct
{
unsigned int gRdB;
unsigned int lnaGRdB;
double currGain;
} sdrplay_api_GainCbParamT;
typedef struct
{
sdrplay_api_PowerOverloadCbEventIdT powerOverloadChangeType;
} sdrplay_api_PowerOverloadCbParamT;
typedef struct
{
sdrplay_api_RspDuoModeCbEventIdT modeChangeType;
} sdrplay_api_RspDuoModeCbParamT;
// Event parameters overlay
typedef union
{
sdrplay_api_GainCbParamT gainParams;
sdrplay_api_PowerOverloadCbParamT powerOverloadParams;
sdrplay_api_RspDuoModeCbParamT rspDuoModeParams;
} sdrplay_api_EventParamsT;
// Stream callback parameter structs
typedef struct
{
unsigned int firstSampleNum;
int grChanged;
int rfChanged;
int fsChanged;
unsigned int numSamples;
} sdrplay_api_StreamCbParamsT;
// Callback function prototypes
typedef void (*sdrplay_api_StreamCallback_t)(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext);
typedef void (*sdrplay_api_EventCallback_t)(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tuner, sdrplay_api_EventParamsT *params, void *cbContext);
// Callback function struct
typedef struct
{
sdrplay_api_StreamCallback_t StreamACbFn;
sdrplay_api_StreamCallback_t StreamBCbFn;
sdrplay_api_EventCallback_t EventCbFn;
} sdrplay_api_CallbackFnsT;
#endif //SDRPLAY_API_CALLBACK_H

View File

@@ -0,0 +1,55 @@
#ifndef SDRPLAY_API_CONTROL_H
#define SDRPLAY_API_CONTROL_H
// Control parameter enums
typedef enum
{
sdrplay_api_AGC_DISABLE = 0,
sdrplay_api_AGC_100HZ = 1,
sdrplay_api_AGC_50HZ = 2,
sdrplay_api_AGC_5HZ = 3,
sdrplay_api_AGC_CTRL_EN = 4
} sdrplay_api_AgcControlT;
typedef enum
{
sdrplay_api_ADSB_DECIMATION = 0,
sdrplay_api_ADSB_NO_DECIMATION_LOWPASS = 1,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_2MHZ = 2,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_3MHZ = 3
} sdrplay_api_AdsbModeT;
// Control parameter structs
typedef struct
{
unsigned char DCenable; // default: 1
unsigned char IQenable; // default: 1
} sdrplay_api_DcOffsetT;
typedef struct
{
unsigned char enable; // default: 0
unsigned char decimationFactor; // default: 1
unsigned char wideBandSignal; // default: 0
} sdrplay_api_DecimationT;
typedef struct
{
sdrplay_api_AgcControlT enable; // default: sdrplay_api_AGC_50HZ
int setPoint_dBfs; // default: -60
unsigned short attack_ms; // default: 0
unsigned short decay_ms; // default: 0
unsigned short decay_delay_ms; // default: 0
unsigned short decay_threshold_dB; // default: 0
int syncUpdate; // default: 0
} sdrplay_api_AgcT;
typedef struct
{
sdrplay_api_DcOffsetT dcOffset;
sdrplay_api_DecimationT decimation;
sdrplay_api_AgcT agc;
sdrplay_api_AdsbModeT adsbMode; //default: sdrplay_api_ADSB_DECIMATION
} sdrplay_api_ControlParamsT;
#endif //SDRPLAY_API_CONTROL_H

View File

@@ -0,0 +1,51 @@
#ifndef SDRPLAY_API_DEV_H
#define SDRPLAY_API_DEV_H
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
// Dev parameter enums
typedef enum
{
sdrplay_api_ISOCH = 0,
sdrplay_api_BULK = 1
} sdrplay_api_TransferModeT;
// Dev parameter structs
typedef struct
{
double fsHz; // default: 2000000.0
unsigned char syncUpdate; // default: 0
unsigned char reCal; // default: 0
} sdrplay_api_FsFreqT;
typedef struct
{
unsigned int sampleNum; // default: 0
unsigned int period; // default: 0
} sdrplay_api_SyncUpdateT;
typedef struct
{
unsigned char resetGainUpdate; // default: 0
unsigned char resetRfUpdate; // default: 0
unsigned char resetFsUpdate; // default: 0
} sdrplay_api_ResetFlagsT;
typedef struct
{
double ppm; // default: 0.0
sdrplay_api_FsFreqT fsFreq;
sdrplay_api_SyncUpdateT syncUpdate;
sdrplay_api_ResetFlagsT resetFlags;
sdrplay_api_TransferModeT mode; // default: sdrplay_api_ISOCH
unsigned int samplesPerPkt; // default: 0 (output param)
sdrplay_api_Rsp1aParamsT rsp1aParams;
sdrplay_api_Rsp2ParamsT rsp2Params;
sdrplay_api_RspDuoParamsT rspDuoParams;
sdrplay_api_RspDxParamsT rspDxParams;
} sdrplay_api_DevParamsT;
#endif //SDRPLAY_API_DEV_H

View File

@@ -0,0 +1,22 @@
#ifndef SDRPLAY_API_RSP1A_H
#define SDRPLAY_API_RSP1A_H
#define RSPIA_NUM_LNA_STATES 10
#define RSPIA_NUM_LNA_STATES_AM 7
#define RSPIA_NUM_LNA_STATES_LBAND 9
// RSP1A parameter enums
// RSP1A parameter structs
typedef struct
{
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_Rsp1aParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
} sdrplay_api_Rsp1aTunerParamsT;
#endif //SDRPLAY_API_RSP1A_H

View File

@@ -0,0 +1,35 @@
#ifndef SDRPLAY_API_RSP2_H
#define SDRPLAY_API_RSP2_H
#define RSPII_NUM_LNA_STATES 9
#define RSPII_NUM_LNA_STATES_AMPORT 5
#define RSPII_NUM_LNA_STATES_420MHZ 6
// RSP2 parameter enums
typedef enum
{
sdrplay_api_Rsp2_ANTENNA_A = 5,
sdrplay_api_Rsp2_ANTENNA_B = 6,
} sdrplay_api_Rsp2_AntennaSelectT;
typedef enum
{
sdrplay_api_Rsp2_AMPORT_1 = 1,
sdrplay_api_Rsp2_AMPORT_2 = 0,
} sdrplay_api_Rsp2_AmPortSelectT;
// RSP2 parameter structs
typedef struct
{
unsigned char extRefOutputEn; // default: 0
} sdrplay_api_Rsp2ParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_Rsp2_AmPortSelectT amPortSel; // default: sdrplay_api_Rsp2_AMPORT_2
sdrplay_api_Rsp2_AntennaSelectT antennaSel; // default: sdrplay_api_Rsp2_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
} sdrplay_api_Rsp2TunerParamsT;
#endif //SDRPLAY_API_RSP2_H

View File

@@ -0,0 +1,40 @@
#ifndef SDRPLAY_API_RSPduo_H
#define SDRPLAY_API_RSPduo_H
#define RSPDUO_NUM_LNA_STATES 10
#define RSPDUO_NUM_LNA_STATES_AMPORT 5
#define RSPDUO_NUM_LNA_STATES_AM 7
#define RSPDUO_NUM_LNA_STATES_LBAND 9
// RSPduo parameter enums
typedef enum
{
sdrplay_api_RspDuoMode_Unknown = 0,
sdrplay_api_RspDuoMode_Single_Tuner = 1,
sdrplay_api_RspDuoMode_Dual_Tuner = 2,
sdrplay_api_RspDuoMode_Master = 4,
sdrplay_api_RspDuoMode_Slave = 8,
} sdrplay_api_RspDuoModeT;
typedef enum
{
sdrplay_api_RspDuo_AMPORT_1 = 1,
sdrplay_api_RspDuo_AMPORT_2 = 0,
} sdrplay_api_RspDuo_AmPortSelectT;
// RSPduo parameter structs
typedef struct
{
int extRefOutputEn; // default: 0
} sdrplay_api_RspDuoParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel; // default: sdrplay_api_RspDuo_AMPORT_2
unsigned char tuner1AmNotchEnable; // default: 0
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDuoTunerParamsT;
#endif //SDRPLAY_API_RSPduo_H

View File

@@ -0,0 +1,46 @@
#ifndef SDRPLAY_API_RSPDX_H
#define SDRPLAY_API_RSPDX_H
#include "sdrplay_api_tuner.h"
#define RSPDX_NUM_LNA_STATES 28 // Number of LNA states in all bands (except where defined differently below)
#define RSPDX_NUM_LNA_STATES_AMPORT2_0_12 19 // Number of LNA states when using AM Port 2 between 0 and 12MHz
#define RSPDX_NUM_LNA_STATES_AMPORT2_12_50 20 // Number of LNA states when using AM Port 2 between 12 and 50MHz
#define RSPDX_NUM_LNA_STATES_AMPORT2_50_60 25 // Number of LNA states when using AM Port 2 between 50 and 60MHz
#define RSPDX_NUM_LNA_STATES_VHF_BAND3 27 // Number of LNA states in VHF and Band3
#define RSPDX_NUM_LNA_STATES_420MHZ 21 // Number of LNA states in 420MHz band
#define RSPDX_NUM_LNA_STATES_LBAND 19 // Number of LNA states in L-band
#define RSPDX_NUM_LNA_STATES_DX 22 // Number of LNA states in DX path
// RSPdx parameter enums
typedef enum
{
sdrplay_api_RspDx_ANTENNA_A = 0,
sdrplay_api_RspDx_ANTENNA_B = 1,
sdrplay_api_RspDx_ANTENNA_C = 2,
} sdrplay_api_RspDx_AntennaSelectT;
typedef enum
{
sdrplay_api_RspDx_HDRMODE_BW_0_200 = 0,
sdrplay_api_RspDx_HDRMODE_BW_0_500 = 1,
sdrplay_api_RspDx_HDRMODE_BW_1_200 = 2,
sdrplay_api_RspDx_HDRMODE_BW_1_700 = 3,
} sdrplay_api_RspDx_HdrModeBwT;
// RSPdx parameter structs
typedef struct
{
unsigned char hdrEnable; // default: 0
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDx_AntennaSelectT antennaSel; // default: sdrplay_api_RspDx_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDxParamsT;
typedef struct
{
sdrplay_api_RspDx_HdrModeBwT hdrBw; // default: sdrplay_api_RspDx_HDRMODE_BW_1_700
} sdrplay_api_RspDxTunerParamsT;
#endif //SDRPLAY_API_RSPDX_H

View File

@@ -0,0 +1,21 @@
#ifndef SDRPLAY_API_RX_CHANNEL_H
#define SDRPLAY_API_RX_CHANNEL_H
#include "sdrplay_api_tuner.h"
#include "sdrplay_api_control.h"
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
typedef struct
{
sdrplay_api_TunerParamsT tunerParams;
sdrplay_api_ControlParamsT ctrlParams;
sdrplay_api_Rsp1aTunerParamsT rsp1aTunerParams;
sdrplay_api_Rsp2TunerParamsT rsp2TunerParams;
sdrplay_api_RspDuoTunerParamsT rspDuoTunerParams;
sdrplay_api_RspDxTunerParamsT rspDxTunerParams;
} sdrplay_api_RxChannelParamsT;
#endif //SDRPLAY_API_RX_CHANNEL_H

View File

@@ -0,0 +1,93 @@
#ifndef SDRPLAY_API_TUNER_H
#define SDRPLAY_API_TUNER_H
#define MAX_BB_GR (59)
// Tuner parameter enums
typedef enum
{
sdrplay_api_BW_Undefined = 0,
sdrplay_api_BW_0_200 = 200,
sdrplay_api_BW_0_300 = 300,
sdrplay_api_BW_0_600 = 600,
sdrplay_api_BW_1_536 = 1536,
sdrplay_api_BW_5_000 = 5000,
sdrplay_api_BW_6_000 = 6000,
sdrplay_api_BW_7_000 = 7000,
sdrplay_api_BW_8_000 = 8000
} sdrplay_api_Bw_MHzT;
typedef enum
{
sdrplay_api_IF_Undefined = -1,
sdrplay_api_IF_Zero = 0,
sdrplay_api_IF_0_450 = 450,
sdrplay_api_IF_1_620 = 1620,
sdrplay_api_IF_2_048 = 2048
} sdrplay_api_If_kHzT;
typedef enum
{
sdrplay_api_LO_Undefined = 0,
sdrplay_api_LO_Auto = 1,
sdrplay_api_LO_120MHz = 2,
sdrplay_api_LO_144MHz = 3,
sdrplay_api_LO_168MHz = 4
} sdrplay_api_LoModeT;
typedef enum
{
sdrplay_api_EXTENDED_MIN_GR = 0,
sdrplay_api_NORMAL_MIN_GR = 20
} sdrplay_api_MinGainReductionT;
typedef enum
{
sdrplay_api_Tuner_Neither = 0,
sdrplay_api_Tuner_A = 1,
sdrplay_api_Tuner_B = 2,
sdrplay_api_Tuner_Both = 3,
} sdrplay_api_TunerSelectT;
// Tuner parameter structs
typedef struct
{
float curr;
float max;
float min;
} sdrplay_api_GainValuesT;
typedef struct
{
int gRdB; // default: 50
unsigned char LNAstate; // default: 0
unsigned char syncUpdate; // default: 0
sdrplay_api_MinGainReductionT minGr; // default: sdrplay_api_NORMAL_MIN_GR
sdrplay_api_GainValuesT gainVals; // output parameter
} sdrplay_api_GainT;
typedef struct
{
double rfHz; // default: 200000000.0
unsigned char syncUpdate; // default: 0
} sdrplay_api_RfFreqT;
typedef struct
{
unsigned char dcCal; // default: 3 (Periodic mode)
unsigned char speedUp; // default: 0 (No speedup)
int trackTime; // default: 1 (=> time in uSec = (72 * 3 * trackTime) / 24e6 = 9uSec)
int refreshRateTime; // default: 2048 (=> time in uSec = (72 * 3 * refreshRateTime) / 24e6 = 18432uSec)
} sdrplay_api_DcOffsetTunerT;
typedef struct
{
sdrplay_api_Bw_MHzT bwType; // default: sdrplay_api_BW_0_200
sdrplay_api_If_kHzT ifType; // default: sdrplay_api_IF_Zero
sdrplay_api_LoModeT loMode; // default: sdrplay_api_LO_Auto
sdrplay_api_GainT gain;
sdrplay_api_RfFreqT rfFreq;
sdrplay_api_DcOffsetTunerT dcOffsetTuner;
} sdrplay_api_TunerParamsT;
#endif //SDRPLAY_API_TUNER_H

View File

@@ -1,3 +1,5 @@
import java.text.SimpleDateFormat
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
@@ -28,8 +30,14 @@ repositories {
maven { url "https://jitpack.io" }
}
version = '0.5.1'
sourceCompatibility = '17'
version = '0.6.0-alpha1'
//Java 19 is required for this version of the Project Panama preview/incubator feature
java {
toolchain {
languageVersion = JavaLanguageVersion.of(19)
}
}
sourceSets {
main.java.srcDirs 'src/main'
@@ -91,9 +99,10 @@ dependencies {
}
/**
* This is needed for the JDK17 vector API ... until it moves out of incubation
* This is needed for the JDK19 panama and vector API ... until it moves out of incubation or preview
*/
tasks.withType(JavaCompile) {
options.compilerArgs.add("--enable-preview") //Panama Foreign Function/Memory is preview in JDK 19
options.compilerArgs.add("--add-modules=jdk.incubator.vector") //Needed while Panama Vector API remains in incubator
}
@@ -101,8 +110,21 @@ application {
mainClassName = "io.github.dsheirer.gui.SDRTrunk"
applicationDefaultJvmArgs =
['--add-exports=javafx.base/com.sun.javafx.event=ALL-UNNAMED', //Needed for controls-fx.jar
'--add-modules=jdk.incubator.vector', //Needed while Panama Vector API remains in incubator
'--add-exports=java.desktop/com.sun.java.swing.plaf.windows=ALL-UNNAMED'] //Windows Swing - jide-oss library
'--add-modules=jdk.incubator.vector', //Needed while Project Panama API is still in incubator
'--enable-preview', //Project Panama Vector & Foreign Function APIs remain in incubator
'--enable-native-access=ALL-UNNAMED'] //Allows Project Panama Foreign Function access to system library
OperatingSystem os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem;
if(os.isWindows()) {
//Replace the default Java system library path with an explicit location for the SDRplay API library (Windows)
applicationDefaultJvmArgs.add('-Djava.library.path=c:\\Program Files\\SDRplay\\API\\x64')
//On windows, we also need to export the windows swing look & feel module
applicationDefaultJvmArgs.add('--add-exports=java.desktop/com.sun.java.swing.plaf.windows=ALL-UNNAMED')
}
else {
//Replace the default Java system library path with an explicit location for the SDRplay API library (Linux/OS-X)
applicationDefaultJvmArgs.add("-Djava.library.path=/usr/local/lib")
}
}
jar {
@@ -111,7 +133,7 @@ jar {
'Implementation-Title' : 'sdrtrunk project',
'Implementation-Version' : archiveVersion,
'Created-By' : "Gradle ${gradle.gradleVersion}",
'Build-Timestamp' : new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date()),
'Build-Timestamp' : new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date()),
'Build-JDK' : "${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']}",
'Build-OS' : "${System.properties['os.name']} (${System.properties['os.arch']} ${System.properties['os.version']}"
)
@@ -212,9 +234,10 @@ runtime {
}
//Additional modules to include with auto-detected modules.
//jdk.crypto.ec needed for HTTPS connections (broadcastify calls & map tile server)
//jdk.crypto.ec - needed for HTTPS connections (broadcastify calls & map tile server)
//jdk.incubator.vector - needed for Project Panama foreign function and vector apis
//jdk.accessibility is used with assistive technologies like screen readers
modules = ['jdk.crypto.ec','jdk.accessibility']
modules = ['jdk.crypto.ec','jdk.incubator.vector','jdk.accessibility']
//Use auto-detected modules and 'add' any specified modules.
additive = true

View File

@@ -248,7 +248,11 @@ public class SDRTrunk implements Listener<TunerEvent>
{
mMainGui.setVisible(true);
Tuner tuner = tunerSpectralDisplayManager.showFirstTuner();
updateTitle(tuner);
if(tuner != null)
{
updateTitle(tuner.getPreferredName());
}
}
if(calibrating && !GraphicsEnvironment.isHeadless())
@@ -630,21 +634,34 @@ public class SDRTrunk implements Listener<TunerEvent>
@Override
public void receive(TunerEvent event)
{
if(event.getEvent() == TunerEvent.Event.REQUEST_MAIN_SPECTRAL_DISPLAY)
switch(event.getEvent())
{
updateTitle(event.getTuner());
case REQUEST_MAIN_SPECTRAL_DISPLAY:
updateTitle(event.getTuner().getPreferredName());
break;
case REQUEST_CLEAR_MAIN_SPECTRAL_DISPLAY:
updateTitle(null);
break;
case NOTIFICATION_SHUTTING_DOWN:
Tuner currentTuner = mSpectralPanel.getTuner();
if(event.hasTuner() && event.getTuner().equals(currentTuner) || currentTuner == null)
{
updateTitle(null);
}
break;
}
}
/**
* Updates the title bar with the tuner name
* @param tuner optional
* @param tunerName optional
*/
private void updateTitle(Tuner tuner)
private void updateTitle(String tunerName)
{
if(tuner != null)
if(tunerName != null)
{
mMainGui.setTitle(mTitle + " - " + tuner.getPreferredName());
mMainGui.setTitle(mTitle + " - " + tunerName);
}
else
{

View File

@@ -53,7 +53,7 @@ public class PreferenceEditorFactory
return new DirectoryPreferenceEditor(userPreferences);
case JMBE_LIBRARY:
return new JmbeLibraryPreferenceEditor(userPreferences);
case SOURCE_TUNER_CHANNELIZER:
case SOURCE_TUNERS:
return new TunerPreferenceEditor(userPreferences);
case TALKGROUP_FORMAT:
return new TalkgroupFormatPreferenceEditor(userPreferences);

View File

@@ -31,7 +31,7 @@ public enum PreferenceEditorType
AUDIO_RECORD("Record"),
AUDIO_OUTPUT("Output/Tones"),
AUDIO_DUPLICATE_CALL_DETECTION("Duplicate Calls"),
SOURCE_TUNER_CHANNELIZER("Tuner Channelizer"),
SOURCE_TUNERS("Tuners"),
TALKGROUP_FORMAT("Talkgroup & Radio ID"),
VECTOR_CALIBRATION("Vector Calibration"),
DEFAULT("Default");

View File

@@ -22,6 +22,8 @@ package io.github.dsheirer.gui.preference;
import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.gui.playlist.ViewPlaylistRequest;
import io.github.dsheirer.preference.UserPreferences;
import java.util.EnumMap;
import java.util.Map;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
@@ -44,9 +46,6 @@ import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.EnumMap;
import java.util.Map;
/**
* Preferences editor dialog
*/
@@ -196,7 +195,7 @@ public class UserPreferencesEditor extends BorderPane
storageItem.setExpanded(true);
TreeItem<String> sourceItem = new TreeItem<>("Source");
sourceItem.getChildren().add(new TreeItem(PreferenceEditorType.SOURCE_TUNER_CHANNELIZER));
sourceItem.getChildren().add(new TreeItem(PreferenceEditorType.SOURCE_TUNERS));
treeRoot.getChildren().add(sourceItem);
sourceItem.setExpanded(true);

View File

@@ -0,0 +1,62 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.gui.preference.tuner;
/**
* RSPduo tuner select mode preferences.
*/
public enum RspDuoSelectionMode
{
DUAL("Dual Tuner"),
SINGLE_1("Single Tuner 1"),
SINGLE_2("Single Tuner 2");
private String mLabel;
RspDuoSelectionMode(String label)
{
mLabel = label;
}
@Override
public String toString()
{
return mLabel;
}
/**
* Lookup the enum entry from the value.
* @param value to match
* @return matched value or (default) DUAL if the value couldn't be matched.
*/
public static RspDuoSelectionMode fromValue(String value)
{
try
{
return RspDuoSelectionMode.valueOf(value);
}
catch(Exception e)
{
//Do nothing
}
return DUAL;
}
}

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.gui.preference.tuner;
@@ -55,6 +52,8 @@ public class TunerPreferenceEditor extends HBox
private Label mHelpTextPolyphaseLabel;
private Label mHeterodyneLabel;
private Label mHelpTextHeterodyneLabel;
private ChoiceBox<RspDuoSelectionMode> mRspDuoTunerModeChoiceBox;
private Label mRspDuoModeLabel;
public TunerPreferenceEditor(UserPreferences userPreferences)
{
@@ -66,19 +65,24 @@ public class TunerPreferenceEditor extends HBox
{
if(mEditorPane == null)
{
int row = 0;
mEditorPane = new GridPane();
mEditorPane.setVgap(10);
mEditorPane.setHgap(10);
mEditorPane.setPadding(new Insets(10, 10, 10, 10));
GridPane.setHalignment(getChannelizerLabel(), HPos.LEFT);
mEditorPane.add(getChannelizerLabel(), 0, 0);
mEditorPane.add(getChannelizerTypeChoiceBox(), 1, 0);
mEditorPane.add(new Separator(Orientation.HORIZONTAL), 0, 1, 2, 1);
mEditorPane.add(getPolyphaseLabel(), 0, 2, 2, 1);
mEditorPane.add(getHelpTextPolyphaseLabel(), 0, 3, 2, 3);
mEditorPane.add(new Label(" "), 0, 6);
mEditorPane.add(getHeterodyneLabel(), 0, 7, 2, 1);
mEditorPane.add(getHelpTextHeterodyneLabel(), 0, 8, 2, 3);
GridPane.setHalignment(getChannelizerLabel(), HPos.RIGHT);
mEditorPane.add(getChannelizerLabel(), 0, row);
mEditorPane.add(getChannelizerTypeChoiceBox(), 1, row);
mEditorPane.add(getPolyphaseLabel(), 0, ++row, 2, 1);
mEditorPane.add(getHelpTextPolyphaseLabel(), 0, ++row, 2, 3);
row += 3;
mEditorPane.add(new Label(" "), 0, row);
mEditorPane.add(getHeterodyneLabel(), 0, ++row, 2, 1);
mEditorPane.add(getHelpTextHeterodyneLabel(), 0, ++row, 2, 3);
row += 3;
mEditorPane.add(new Separator(Orientation.HORIZONTAL), 0, row, 2, 1);
mEditorPane.add(getRspDuoModeLabel(), 0, ++row);
mEditorPane.add(getRspDuoTunerModeChoiceBox(), 1, row);
}
return mEditorPane;
@@ -161,4 +165,40 @@ public class TunerPreferenceEditor extends HBox
return mHelpTextHeterodyneLabel;
}
private ChoiceBox<RspDuoSelectionMode> getRspDuoTunerModeChoiceBox()
{
if(mRspDuoTunerModeChoiceBox == null)
{
mRspDuoTunerModeChoiceBox = new ChoiceBox<>();
mRspDuoTunerModeChoiceBox.getItems().addAll(RspDuoSelectionMode.values());
RspDuoSelectionMode current = mTunerPreference.getRspDuoTunerMode();
mRspDuoTunerModeChoiceBox.getSelectionModel().select(current);
mRspDuoTunerModeChoiceBox.setOnAction(event -> {
RspDuoSelectionMode selected = mRspDuoTunerModeChoiceBox.getSelectionModel().getSelectedItem();
mTunerPreference.setRspDuoTunerMode(selected);
Label label = new Label("Please restart the application for this change to take effect");
label.setWrapText(true);
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.getDialogPane().setContent(label);
alert.initOwner(((Node)getRspDuoTunerModeChoiceBox()).getScene().getWindow());
alert.show();
});
}
return mRspDuoTunerModeChoiceBox;
}
private Label getRspDuoModeLabel()
{
if(mRspDuoModeLabel == null)
{
mRspDuoModeLabel = new Label("SDRPlay RSPduo Selection Mode");
}
return mRspDuoModeLabel;
}
}

View File

@@ -19,14 +19,14 @@
package io.github.dsheirer.preference.source;
import io.github.dsheirer.gui.preference.tuner.RspDuoSelectionMode;
import io.github.dsheirer.preference.Preference;
import io.github.dsheirer.preference.PreferenceType;
import io.github.dsheirer.sample.Listener;
import java.util.prefs.Preferences;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.prefs.Preferences;
/**
* Tuner preferences
*/
@@ -35,8 +35,10 @@ public class TunerPreference extends Preference
private final static Logger mLog = LoggerFactory.getLogger(TunerPreference.class);
private Preferences mPreferences = Preferences.userNodeForPackage(TunerPreference.class);
private static final String PREFERENCE_KEY_CHANNELIZER_TYPE = "channelizer.type";
private static final String PREFERENCE_KEY_RSP_DUO_TUNER_MODE = "rsp.duo.tuner.mode";
private ChannelizerType mChannelizerType;
private RspDuoSelectionMode mRspDuoSelectionMode;
/**
* Constructs a tuner preference with the update listener
@@ -94,4 +96,30 @@ public class TunerPreference extends Preference
mPreferences.put(PREFERENCE_KEY_CHANNELIZER_TYPE, mChannelizerType.name());
notifyPreferenceUpdated();
}
/**
* RSPduo tuner select mode.
* @return mode or a default value of DUAL
*/
public RspDuoSelectionMode getRspDuoTunerMode()
{
if(mRspDuoSelectionMode == null)
{
String mode = mPreferences.get(PREFERENCE_KEY_RSP_DUO_TUNER_MODE, RspDuoSelectionMode.DUAL.name());
mRspDuoSelectionMode = RspDuoSelectionMode.fromValue(mode);
}
return mRspDuoSelectionMode;
}
/**
* Sets the RSPduo tuner select mode
* @param mode to use
*/
public void setRspDuoTunerMode(RspDuoSelectionMode mode)
{
mRspDuoSelectionMode = mode;
mPreferences.put(PREFERENCE_KEY_RSP_DUO_TUNER_MODE, mRspDuoSelectionMode.name());
notifyPreferenceUpdated();
}
}

View File

@@ -18,12 +18,13 @@
*/
package io.github.dsheirer.sample;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Broadcasts an item to multiple listeners
@@ -100,6 +101,10 @@ public class Broadcaster<T> implements Listener<T>
mListeners.add(listener);
}
}
catch(Exception e)
{
mLog.error("Unexpected error while adding listener", e);
}
finally
{
mLock.unlock();
@@ -120,6 +125,10 @@ public class Broadcaster<T> implements Listener<T>
{
mListeners.remove(listener);
}
catch(Exception e)
{
mLog.error("Unexpected error while removing listener", e);
}
finally
{
mLock.unlock();
@@ -151,6 +160,10 @@ public class Broadcaster<T> implements Listener<T>
listener.receive(t);
}
}
catch(Exception e)
{
mLog.error("Unexpected error while broadcasting to listeners", e);
}
finally
{
mLock.unlock();

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 Dennis Sheirer
* *
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <http://www.gnu.org/licenses/>
* * *****************************************************************************
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner;
@@ -29,4 +26,9 @@ public interface ITunerErrorListener
* @param errorMessage to set
*/
void setErrorMessage(String errorMessage);
/**
* Indicates that the tuner has been removed from the system.
*/
void tunerRemoved();
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,4 +34,10 @@ public class LoggingTunerErrorListener implements ITunerErrorListener
{
mLog.error("Tuner Error: " + errorMessage);
}
@Override
public void tunerRemoved()
{
mLog.warn("Tuner removal detected");
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -149,6 +149,20 @@ public abstract class Tuner implements ISourceEventProcessor, ITunerErrorListene
}
}
/**
* Process tuner removal error from tuner controller and propagate to an external listener.
*/
@Override
public void tunerRemoved()
{
stop();
if(mTunerErrorListener != null)
{
mTunerErrorListener.tunerRemoved();
}
}
/**
* Sets the channel source manager
* @param manager to use

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -54,6 +54,24 @@ public class TunerEvent
return mTuner != null;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Tuner Event [").append(getEvent().name()).append("] for tuner [");
if(hasTuner())
{
sb.append(getTuner());
}
else
{
sb.append("No Tuner");
}
sb.append("]");
return sb.toString();
}
/**
* Event type
*/
@@ -75,6 +93,7 @@ public class TunerEvent
NOTIFICATION_SHUTTING_DOWN,
REQUEST_CLEAR_MAIN_SPECTRAL_DISPLAY,
REQUEST_ENABLE_RSP_SLAVE_DEVICE,
REQUEST_MAIN_SPECTRAL_DISPLAY,
REQUEST_NEW_SPECTRAL_DISPLAY;
}

View File

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

View File

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

View File

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

View File

@@ -147,6 +147,12 @@ public class TunerConfigurationManager implements IDiscoveredTunerStatusListener
}
}
/**
* Monitors discovered tuner enabled status and applies configurations or updates disable state of tuners.
* @param discoveredTuner that has a status change.
* @param previous tuner status
* @param current tuner status
*/
@Override
public void tunerStatusUpdated(DiscoveredTuner discoveredTuner, TunerStatus previous, TunerStatus current)
{
@@ -157,6 +163,23 @@ public class TunerConfigurationManager implements IDiscoveredTunerStatusListener
else if(current == TunerStatus.ENABLED)
{
removeDisabledTuner(discoveredTuner);
if(discoveredTuner.hasTuner())
{
TunerType tunerType = discoveredTuner.getTuner().getTunerType();
if(tunerType != TunerType.RECORDING)
{
TunerConfiguration tunerConfiguration = getTunerConfiguration(tunerType, discoveredTuner.getId());
if(tunerConfiguration != null)
{
discoveredTuner.setTunerConfiguration(tunerConfiguration);
saveConfigurations();
}
}
}
}
}

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,6 +34,12 @@ public enum TunerStatus
*/
DISABLED("Disabled"),
/**
* Indicates that the tuner has been removed from the system.
*/
REMOVED("Removed"),
/**
* A tuner that has an error state and is unusable
*/

View File

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

View File

@@ -0,0 +1,122 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay;
import io.github.dsheirer.preference.source.ChannelizerType;
import io.github.dsheirer.source.tuner.TunerClass;
import io.github.dsheirer.source.tuner.TunerFactory;
import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceInfo;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceType;
/**
* Discovered SDRplay RSP tuner
*/
public abstract class DiscoveredRspTuner<R extends IControlRsp> extends DiscoveredTuner
{
private final DeviceInfo mDeviceInfo;
private final ChannelizerType mChannelizerType;
/**
* Constructs an instance
* @param deviceInfo to select the device from the API
*/
public DiscoveredRspTuner(DeviceInfo deviceInfo, ChannelizerType channelizerType)
{
mDeviceInfo = deviceInfo;
mChannelizerType = channelizerType;
}
/**
* Information about the discovered RSP device
* @return device info
*/
public DeviceInfo getDeviceInfo()
{
return mDeviceInfo;
}
/**
* Channelizer type to use for the tuner
*/
protected ChannelizerType getChannelizerType()
{
return mChannelizerType;
}
@Override
public TunerClass getTunerClass()
{
return TunerClass.RSP;
}
/**
* Type of RSP tuner device
*/
public DeviceType getDeviceType()
{
return mDeviceInfo.getDeviceType();
}
/**
* Constructs and starts the tuner
*/
@Override
public void start()
{
if(isAvailable() && !hasTuner())
{
try
{
mTuner = TunerFactory.getRspTuner(getDeviceInfo(), getChannelizerType(), this);
}
catch(Exception se)
{
setErrorMessage("Tuner unavailable [" + getId() + "]");
mTuner = null;
}
if(hasTuner())
{
try
{
mTuner.start();
}
catch(Exception se)
{
setErrorMessage("Error starting tuner [" + getId() + "]");
mTuner = null;
}
}
}
}
@Override
public String getId()
{
return getDeviceType().name() + " SER#" + getDeviceInfo().getSerialNumber();
}
@Override
public String toString()
{
return getId();
}
}

View File

@@ -0,0 +1,128 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay;
import io.github.dsheirer.source.tuner.sdrplay.api.DeviceSelectionMode;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IDeviceEventListener;
import io.github.dsheirer.source.tuner.sdrplay.api.callback.IStreamListener;
import io.github.dsheirer.source.tuner.sdrplay.api.device.Device;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
/**
* Control interface for base RSP device
*/
public interface IControlRsp
{
DeviceSelectionMode getDeviceSelectionMode();
/**
* Device descriptor for this RSP
* @return device descriptor
*/
Device getDevice();
/**
* Process an RSP device removal. Device memory resources should be nullified and the software should not attempt
* any further interaction with the device via the API.
*/
void deviceRemoved();
/**
* Selected tuner for this RSP.
* @return selected tuner.
*/
TunerSelect getTunerSelect();
/**
* Starts the device
*/
void start() throws SDRPlayException;
/**
* Stops the device
*/
void stop() throws SDRPlayException;
/**
* Registers listeners to receive device events and streaming samples when startStream() is invoked.
* @param deviceEventListener to receive device events
* @param streamListener to receive sample stream and related parameters.
*/
void resister(IDeviceEventListener deviceEventListener, IStreamListener streamListener);
/**
* Starts the sample stream and delivers the samples to the registered listener.
*/
void startStream();
/**
* Stops the sample stream.
*/
void stopStream();
/**
* Callback to acknowledge a power overload event.
* @param tunerSelect identifies the tuner where the power overload is happening.
*/
void acknowledgePowerOverload(TunerSelect tunerSelect) throws SDRPlayException;
/**
* Current center tune frequency
* @return frequency in Hertz
*/
long getTunedFrequency() throws SDRPlayException;
/**
* Sets the center tune frequency
* @param frequency in Hertz
*/
void setTunedFrequency(long frequency) throws SDRPlayException;
/**
* Current sample rate enumeration value
* @return sample rate enumeration.
*/
RspSampleRate getSampleRateEnumeration();
/**
* Sets the sample rate.
* @param rspSampleRate enumeration value.
*/
void setSampleRate(RspSampleRate rspSampleRate) throws SDRPlayException;
/**
* Current sample rate value.
* @return sample rate in Hertz
*/
double getCurrentSampleRate();
/**
* Sets the gain index value.
* @param gain index value (0 - 28)
*/
void setGain(int gain) throws SDRPlayException;
/**
* Current gain index value
* @return gain index value (0 - 28)
*/
int getGain();
}

View File

@@ -0,0 +1,141 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay;
import io.github.dsheirer.buffer.AbstractNativeBuffer;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
import java.util.Iterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Native buffer implementation for RSP tuner I/Q sample buffers.
*
* Note: in testing with API v3.07, the daemon returns 2016 samples in each of the I and Q arrays.
*/
public class RspNativeBuffer extends AbstractNativeBuffer
{
private static final Logger mLog = LoggerFactory.getLogger(RspNativeBuffer.class);
private static final float SAMPLE_TO_FLOAT = 1.0f / 32768.0f;
private short[] mISamples;
private short[] mQSamples;
/**
* Constructs an instance
* @param i samples array
* @param q samples array
* @param timestamp for the first sample
* @param samplesPerMillisecond used to calculate sub-buffer fragment timestamp offsets from the start of this buffer.
*/
public RspNativeBuffer(short[] i, short[] q, long timestamp, float samplesPerMillisecond)
{
super(timestamp, samplesPerMillisecond);
mISamples = i;
mQSamples = q;
}
/**
* Iterator over samples that produces complex sample buffers.
*/
@Override
public Iterator<ComplexSamples> iterator()
{
return new SampleIterator();
}
/**
* Iterator over samples that produces interleaved complex sample buffers
*/
@Override
public Iterator<InterleavedComplexSamples> iteratorInterleaved()
{
return new InterleavedSampleIterator();
}
@Override
public int sampleCount()
{
return mISamples.length * 2;
}
/**
* Iterator providing (non-interleaved) complex sample buffers
*/
private class SampleIterator implements Iterator<ComplexSamples>
{
private int mSamplePointer;
@Override
public boolean hasNext()
{
return mSamplePointer < mISamples.length;
}
@Override
public ComplexSamples next()
{
float[] i = new float[mISamples.length];
float[] q = new float[mISamples.length];
for(int x = 0; x < mISamples.length; x++)
{
i[x] = mISamples[x] * SAMPLE_TO_FLOAT;
q[x] = mQSamples[x] * SAMPLE_TO_FLOAT;
}
mSamplePointer += mISamples.length;
return new ComplexSamples(i, q, getTimestamp());
}
}
/**
* Interator providing interleaved sample buffers.
*/
private class InterleavedSampleIterator implements Iterator<InterleavedComplexSamples>
{
private int mSamplePointer;
@Override
public boolean hasNext()
{
return mSamplePointer < mISamples.length;
}
@Override
public InterleavedComplexSamples next()
{
float[] samples = new float[mISamples.length * 2];
int index = 0;
for(int x = 0; x < mISamples.length; x++)
{
samples[index++] = mISamples[x] * SAMPLE_TO_FLOAT;
samples[index++] = mQSamples[x] * SAMPLE_TO_FLOAT;
}
mSamplePointer += mISamples.length;
return new InterleavedComplexSamples(samples, getTimestamp());
}
}
}

View File

@@ -0,0 +1,184 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay;
import io.github.dsheirer.source.tuner.sdrplay.api.device.Decimate;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Bandwidth;
import java.util.EnumSet;
/**
* RSP device Sample Rate, Bandwidth and Decimation enumeration
*
* Note: final effective sample rate must be greater than IF bandwidth setting to avoid aliasing. The available IF
* bandwidth values effectively dictate the available sample rates
*/
public enum RspSampleRate
{
RATE_0_250(8_000_000, 016_000, Bandwidth.BW_0_300, Decimate.X32, "0.250 MHz (0.234 usable)"),
RATE_0_500(8_000_000, 024_000, Bandwidth.BW_0_600, Decimate.X16, "0.500 MHz (0.476 usable)"),
RATE_1_000(8_000_000, 100_000, Bandwidth.BW_1_536, Decimate.X8, "1.000 MHz (0.900 usable)"),
RATE_1_500(6_000_000, 140_000, Bandwidth.BW_1_536, Decimate.X4, "1.500 MHz (1.360 usable)"),
RATE_3_000(6_000_000, 300_000, Bandwidth.BW_5_000, Decimate.X2, "3.000 MHz (2.700 usable)"),
RATE_4_000(8_000_000, 340_000, Bandwidth.BW_5_000, Decimate.X2, "4.000 MHz (3.560 usable)"),
RATE_5_000(5_000_000, 880_000, Bandwidth.BW_5_000, Decimate.X1, "5.000 MHz (4.120 usable)"),
RATE_6_000(6_000_000, 800_000, Bandwidth.BW_6_000, Decimate.X1, "6.000 MHz (5.200 usable)"),
RATE_7_000(7_000_000, 1_040_000, Bandwidth.BW_7_000, Decimate.X1, "7.000 MHz (5.960 usable)"),
RATE_8_000(8_000_000, 1_060_000, Bandwidth.BW_8_000, Decimate.X1, "8.000 MHz (6.940 usable)"),
RATE_9_000(9_000_000, 1_620_000, Bandwidth.BW_8_000, Decimate.X1, "9.000 MHz (7.380 usable)"),
RATE_10_000(10_000_000, 1_500_000, Bandwidth.BW_8_000, Decimate.X1, "10.000 MHz (8.500 usable)"),
/**
* Note: in dual tuner mode, available sample rates are 6 or 8 MHz with an effective output rate of
* 2 MHz. Decimation is applied against the final 2 MHz rate, not the original 6/8 sampling rate.
*/
DUO_RATE_0_500(8_000_000, 50_000, Bandwidth.BW_8_000, Decimate.X4, "0.500 MHz (0.450 usable)"),
DUO_RATE_1_000(8_000_000, 50_000, Bandwidth.BW_8_000, Decimate.X2, "1.000 MHz (0.950 usable)"),
DUO_RATE_1_500(6_000_000, 0, Bandwidth.BW_6_000, Decimate.X1, "1.500 MHz (1.500 usable)"),
DUO_RATE_2_000(8_000_000, 0, Bandwidth.BW_8_000, Decimate.X1, "2.000 MHz (2.000 usable)"),
UNDEFINED(0, 0, Bandwidth.UNDEFINED, Decimate.X1, "UNDEFINED");
private long mSampleRate;
private long mUnusable;
private Bandwidth mBandwidth;
private Decimate mDecimation;
private String mDescription;
/**
* Constructs an instance
* @param sampleRate in hertz
* @param unusable bandwidth (total) in Hertz due to IF or decimation filter roll-off at spectrum edges
* @param bandwidth of the frequency spectrum
* @param decimation to be applied to the original sample rate to achieve the effective sample rate
* @param description for UI display
*/
RspSampleRate(long sampleRate, long unusable, Bandwidth bandwidth, Decimate decimation, String description)
{
mSampleRate = sampleRate;
mUnusable = unusable;
mBandwidth = bandwidth;
mDecimation = decimation;
mDescription = description;
}
/**
* Single tuner sample rates for all devices operating in single tuner mode
*/
public static EnumSet<RspSampleRate> SINGLE_TUNER_SAMPLE_RATES = EnumSet.range(RATE_0_250, RATE_10_000);
/**
* RSPduo dual-tuner mode sample rates
*/
public static EnumSet<RspSampleRate> DUAL_TUNER_SAMPLE_RATES = EnumSet.range(DUO_RATE_0_500, DUO_RATE_2_000);
/**
* Sample Rate
* @return sample rate (Hz)
*/
public long getSampleRate()
{
return mSampleRate;
}
/**
* Usable bandwidth in range 0.0 to 1.0, where 1.0 is 100% usable bandwidth
*/
public double getUsableBandwidth()
{
if(getSampleRate() != 0)
{
return 1.0 - ((double)mUnusable / (double)getEffectiveSampleRate());
}
return 0.0;
}
/**
* Indicates if this is a sample rate supported by the RSPduo operating in dual-tuner mode.
* @return true if this is a dual-tuner sample rate.
*/
public boolean isDualTunerSampleRate()
{
return DUAL_TUNER_SAMPLE_RATES.contains(this);
}
/**
* Sample size in bits. Can be used to adjust spectral display for effective dynamic range.
* @return sample size in bits.
*/
public int getSampleSize()
{
return mDecimation.getSampleSize();
}
/**
* Decimation rate to be applied against sample rate.
* @return decimation value
*/
public Decimate getDecimation()
{
return mDecimation;
}
/**
* Indicates if this sample rate specifies decimation
*/
public boolean hasDecimation()
{
return getDecimation().isEnabled();
}
/**
* Effective Sample Rate (sample rate / decimation). Note: for RSPduo operating in dual-tuner mode, an
* inherent x4 decimation is applied in the hardware.
* @return effective sample rate (Hz)
*/
public long getEffectiveSampleRate()
{
if(isDualTunerSampleRate())
{
//Dual tuner sample rate is specified at 8 MHz, but there is an inherent x4 decimation to 2 MHz
//on top of the user specified decimation rate.
return getSampleRate() / getDecimation().getValue() / 4;
}
else
{
return getSampleRate() / getDecimation().getValue();
}
}
/**
* Bandwidth entry
*/
public Bandwidth getBandwidth()
{
return mBandwidth;
}
/**
* Overrides the default string representation to use the UI description/label.
* @return string representation of the entry
*/
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,104 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay;
import io.github.dsheirer.preference.source.ChannelizerType;
import io.github.dsheirer.source.tuner.ITunerErrorListener;
import io.github.dsheirer.source.tuner.Tuner;
import io.github.dsheirer.source.tuner.TunerClass;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.IControlRspDuoTuner1;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.IControlRspDuoTuner2;
/**
* Generic RSP tuner with a device specific tuner controller implementation.
*/
public class RspTuner extends Tuner
{
/**
* Constructs an instance
* @param tunerController for controlling the tuner
* @param tunerErrorListener to process errors from this tuner
* @param channelizerType to use with this tuner
*/
public RspTuner(RspTunerController tunerController, ITunerErrorListener tunerErrorListener, ChannelizerType channelizerType)
{
super(tunerController, tunerErrorListener, channelizerType);
}
@Override
public int getMaximumUSBBitsPerSecond()
{
//12-bits per sample, 2 samples per frame, 10 MHz sample rate
return 320_000_000;
}
@Override
public String getUniqueID()
{
return getRspTunerController().getControlRsp().getDevice().getSerialNumber();
}
@Override
public TunerClass getTunerClass()
{
return TunerClass.RSP;
}
/**
* RSP Tuner controller for this tuner
*/
public RspTunerController getRspTunerController()
{
return (RspTunerController)getTunerController();
}
@Override
public String getPreferredName()
{
if(getRspTunerController().getControlRsp() instanceof IControlRspDuoTuner1 &&
getRspTunerController().getControlRsp().getDevice() != null)
{
return getRspTunerController().getControlRsp().getDevice().getDeviceType() +
" SER:" + getRspTunerController().getControlRsp().getDevice().getSerialNumber() + " Tuner 1";
}
else if(getRspTunerController().getControlRsp() instanceof IControlRspDuoTuner2 &&
getRspTunerController().getControlRsp().getDevice() != null)
{
return getRspTunerController().getControlRsp().getDevice().getDeviceType() +
" SER:" + getRspTunerController().getControlRsp().getDevice().getSerialNumber() + " Tuner 2";
}
else if(getRspTunerController().getControlRsp() instanceof IControlRsp &&
getRspTunerController().getControlRsp().getDevice() != null)
{
return getRspTunerController().getControlRsp().getDevice().getDeviceType() +
" SER:" + getRspTunerController().getControlRsp().getDevice().getSerialNumber();
}
else
{
return "RSP Tuner - Device Not Available";
}
}
@Override
public double getSampleSize()
{
return getRspTunerController().getControlRsp().getSampleRateEnumeration().getSampleSize();
}
}

View File

@@ -0,0 +1,106 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.GainReduction;
import io.github.dsheirer.source.tuner.sdrplay.rsp1a.Rsp1aTunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.rsp2.Rsp2TunerConfiguration;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.RspDuoTuner1Configuration;
import io.github.dsheirer.source.tuner.sdrplay.rspDuo.RspDuoTuner2Configuration;
import io.github.dsheirer.source.tuner.sdrplay.rspDx.RspDxTunerConfiguration;
/**
* Abstract RSP tuner configuration
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Rsp1aTunerConfiguration.class, name = "rsp1aTunerConfiguration"),
@JsonSubTypes.Type(value = Rsp2TunerConfiguration.class, name = "rsp2TunerConfiguration"),
@JsonSubTypes.Type(value = RspDuoTuner1Configuration.class, name = "rspDuoTuner1Configuration"),
@JsonSubTypes.Type(value = RspDuoTuner2Configuration.class, name = "rspDuoTuner2Configuration"),
@JsonSubTypes.Type(value = RspDxTunerConfiguration.class, name = "rspDxTunerConfiguration"),
})
public abstract class RspTunerConfiguration extends TunerConfiguration
{
public static final RspSampleRate DEFAULT_SINGLE_TUNER_SAMPLE_RATE = RspSampleRate.RATE_8_000;
public static final RspSampleRate DEFAULT_DUAL_TUNER_SAMPLE_RATE = RspSampleRate.DUO_RATE_2_000;
private RspSampleRate mRspSampleRate = DEFAULT_SINGLE_TUNER_SAMPLE_RATE;
private int mGain = 14;
/**
* JAXB Constructor
*/
public RspTunerConfiguration()
{
}
/**
* Constructs an instance with the specified unique id
* @param uniqueId for the tuner
*/
public RspTunerConfiguration(String uniqueId)
{
super(uniqueId);
}
/**
* Sample rate for the tuner
*/
@JacksonXmlProperty(isAttribute = true, localName = "sampleRate")
public RspSampleRate getSampleRate()
{
return mRspSampleRate;
}
/**
* Sets the sample rate for the tuner
*/
public void setSampleRate(RspSampleRate rspSampleRate)
{
mRspSampleRate = rspSampleRate;
}
/**
* Gain index to use
* @return gain index, 0 - 28
*/
@JacksonXmlProperty(isAttribute = true, localName = "gain")
public int getGain()
{
return mGain;
}
/**
* Sets the gain index
* @param gain index, 0 - 28
*/
public void setGain(int gain)
{
if(GainReduction.MIN_GAIN_INDEX <= gain && gain <= GainReduction.MAX_GAIN_INDEX)
{
mGain = gain;
}
}
}

View File

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

View File

@@ -0,0 +1,108 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.GainReduction;
import io.github.dsheirer.source.tuner.ui.TunerEditor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSlider;
/**
* Abstract RSP tuner editor
*/
public abstract class RspTunerEditor<C extends RspTunerConfiguration> extends TunerEditor<RspTuner,C>
{
private Logger mLog = LoggerFactory.getLogger(RspTunerEditor.class);
private JSlider mGainSlider;
private JLabel mGainValueLabel;
/**
* Constructs an instance
* @param userPreferences for preference settings
* @param tunerManager to notify for state changes
* @param discoveredTuner to be edited.
*/
public RspTunerEditor(UserPreferences userPreferences, TunerManager tunerManager, DiscoveredRspTuner discoveredTuner)
{
super(userPreferences, tunerManager, discoveredTuner);
}
private RspTunerController getTunerController()
{
return (RspTunerController) getTuner().getTunerController();
}
/**
* Gain reduction slider control
*/
protected JSlider getGainSlider()
{
if(mGainSlider == null)
{
mGainSlider = new JSlider(JSlider.HORIZONTAL, GainReduction.MIN_GAIN_INDEX,
GainReduction.MAX_GAIN_INDEX, GainReduction.MIN_GAIN_INDEX);
mGainSlider.setEnabled(false);
mGainSlider.setMajorTickSpacing(1);
mGainSlider.setPaintTicks(true);
mGainSlider.addChangeListener(event ->
{
int gain = mGainSlider.getValue();
if(hasTuner() && !isLoading())
{
try
{
getTunerController().getControlRsp().setGain(gain);
save();
}
catch(Exception e)
{
mLog.error("Couldn't set RSP gain to:" + gain, e);
JOptionPane.showMessageDialog(mGainSlider, "Couldn't set RSP gain value to " + gain);
}
}
getGainValueLabel().setText(String.valueOf(gain));
});
}
return mGainSlider;
}
/**
* Label for displaying current gain index value
*/
protected JLabel getGainValueLabel()
{
if(mGainValueLabel == null)
{
mGainValueLabel = new JLabel("0");
mGainValueLabel.setEnabled(false);
}
return mGainValueLabel;
}
}

View File

@@ -0,0 +1,106 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api;
import io.github.dsheirer.source.tuner.sdrplay.api.device.RspDuoMode;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
import java.util.EnumSet;
/**
* Enumeration of modes that indicate how each SDRplay RSP device can be selected
*/
public enum DeviceSelectionMode
{
//All RSP devices
SINGLE_TUNER_1("Single Tuner 1", RspDuoMode.SINGLE_TUNER, TunerSelect.TUNER_1),
SINGLE_TUNER_2("Single Tuner 2", RspDuoMode.SINGLE_TUNER, TunerSelect.TUNER_2),
MASTER_TUNER_1("Master - Tuner 1", RspDuoMode.MASTER, TunerSelect.TUNER_1),
SLAVE_TUNER_2("Slave - Tuner 2", RspDuoMode.SLAVE, TunerSelect.TUNER_2);
private String mDescription;
private RspDuoMode mRspDuoMode;
private TunerSelect mTunerSelect;
/**
* Private constructor
* @param description of the mode
* @param rspDuoMode that corresponds to the mode
* @param tunerSelect tuner(s) that correspond to the mode
*/
DeviceSelectionMode(String description, RspDuoMode rspDuoMode, TunerSelect tunerSelect)
{
mDescription = description;
mRspDuoMode = rspDuoMode;
mTunerSelect = tunerSelect;
}
/**
* Set of all selection modes available for the RSPduo
*/
public static final EnumSet<DeviceSelectionMode> MASTER_MODES = EnumSet.of(MASTER_TUNER_1);
public static final EnumSet<DeviceSelectionMode> SLAVE_MODES = EnumSet.of(SLAVE_TUNER_2);
public static final EnumSet<DeviceSelectionMode> SINGLE_TUNER_MODES = EnumSet.of(SINGLE_TUNER_1, SINGLE_TUNER_2);
/**
* RSPduo mode associated with the selection mode
*/
public RspDuoMode getRspDuoMode()
{
return mRspDuoMode;
}
/**
* Indicates if this mode is designated as a master mode.
*/
public boolean isMasterMode()
{
return MASTER_MODES.contains(this);
}
/**
* Indicates if this mode is designated as a slave mode.
*/
public boolean isSlaveMode()
{
return SLAVE_MODES.contains(this);
}
/**
* Indicates if this is a single-tuner mode
*/
public boolean isSingleTunerMode()
{
return SINGLE_TUNER_MODES.contains(this);
}
/**
* Tuner(s) associated with the selection mode
*/
public TunerSelect getTunerSelect()
{
return mTunerSelect;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

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

View File

@@ -0,0 +1,63 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api;
/**
* SDRplay checked exception.
*/
public class SDRPlayException extends Exception
{
private Status mStatus = Status.UNKNOWN;
/**
* Creates an exception
* @param message for the exception
*/
public SDRPlayException(String message)
{
super(message);
}
/**
* Creates an operation exception
* @param message for the exception
* @param status of the operation
*/
public SDRPlayException(String message, Status status)
{
super(message + " Status:" + status);
mStatus = status;
}
/**
* Creates an exception
* @param message for the exception
* @param throwable nested exception
*/
public SDRPlayException(String message, Throwable throwable)
{
super(message, throwable);
}
public Status getStatus()
{
return mStatus;
}
}

View File

@@ -0,0 +1,49 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api;
import java.util.ArrayList;
import java.util.List;
/**
* SDRplay failed update request checked exception.
*/
public class SDRPlayUpdateException extends SDRPlayException
{
private List<UpdateReason> mUpdateReasons = new ArrayList<>();
/**
* Creates an operation exception
* @param status of the operation
* @param updateReasons that were submitted
*/
public SDRPlayUpdateException(Status status, List<UpdateReason> updateReasons)
{
super("Unable to update device parameters: " + updateReasons, status);
}
/**
* List of update reasons that failed.
*/
public List<UpdateReason> getUpdateReasons()
{
return mUpdateReasons;
}
}

View File

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

View File

@@ -0,0 +1,109 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
public enum Status
{
SUCCESS(sdrplay_api_h.sdrplay_api_Success(), "Success"),
FAIL(sdrplay_api_h.sdrplay_api_Fail(), "Fail"),
INVALID_PARAMETER(sdrplay_api_h.sdrplay_api_InvalidParam(), "Invalid Parameter. Null pointer or invalid operating mode"),
OUT_OF_RANGE(sdrplay_api_h.sdrplay_api_OutOfRange(), "Out of Range. One or more parameters are set incorrectly"),
GAIN_UPDATE_ERROR(sdrplay_api_h.sdrplay_api_GainUpdateError(), "Gain Update Error"),
RF_UPDATE_ERROR(sdrplay_api_h.sdrplay_api_RfUpdateError(), "Frequency Update Error"),
FS_UPDATE_ERROR(sdrplay_api_h.sdrplay_api_FsUpdateError(), "Sample Rate Update Error"),
HARDWARE_ERROR(sdrplay_api_h.sdrplay_api_HwError(), "Hardware Error during tuner initialization"),
ALIASING_ERROR(sdrplay_api_h.sdrplay_api_AliasingError(), "Aliasing Error"),
ALREADY_INITIALIZED(sdrplay_api_h.sdrplay_api_AlreadyInitialised(), "Already Initialized"),
NOT_INITIALIZED(sdrplay_api_h.sdrplay_api_NotInitialised(), "Not Initialized"),
NOT_ENABLED(sdrplay_api_h.sdrplay_api_NotEnabled(), "Not Enabled"),
HARDWARE_VERSION_ERROR(sdrplay_api_h.sdrplay_api_HwVerError(), "Hardware Version Error"),
OUT_OF_MEMORY(sdrplay_api_h.sdrplay_api_OutOfMemError(), "Out Of Memory"),
SERVICE_NOT_RESPONDING(sdrplay_api_h.sdrplay_api_ServiceNotResponding(), "Service Not Responding"),
START_PENDING(sdrplay_api_h.sdrplay_api_StartPending(), "Start Pending"),
STOP_PENDING(sdrplay_api_h.sdrplay_api_StopPending(), "Stop Pending"),
INVALID_MODE(sdrplay_api_h.sdrplay_api_InvalidMode(), "Invalid Mode"),
FAILED_VERIFICATION_1(sdrplay_api_h.sdrplay_api_FailedVerification1(), "Failed Verification 1"),
FAILED_VERIFICATION_2(sdrplay_api_h.sdrplay_api_FailedVerification2(), "Failed Verification 2"),
FAILED_VERIFICATION_3(sdrplay_api_h.sdrplay_api_FailedVerification3(), "Failed Verification 3"),
FAILED_VERIFICATION_4(sdrplay_api_h.sdrplay_api_FailedVerification4(), "Failed Verification 4"),
FAILED_VERIFICATION_5(sdrplay_api_h.sdrplay_api_FailedVerification5(), "Failed Verification 5"),
FAILED_VERIFICATION_6(sdrplay_api_h.sdrplay_api_FailedVerification6(), "Failed Verification 6"),
INVALID_SERVICE_VERSION(sdrplay_api_h.sdrplay_api_InvalidServiceVersion(), "Invalid Service Version"),
//Custom status codes
API_UNAVAILABLE(-2, "SDRplay API is not installed or it has an unsupported version"),
UNKNOWN(-1, "Unknown");
private int mValue;
private String mDescription;
Status(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Status code value
*/
public int getValue()
{
return mValue;
}
/**
* Indicates if this is a SUCCESS status.
*/
public boolean success()
{
return this == Status.SUCCESS;
}
public boolean fail()
{
return this != Status.SUCCESS;
}
/**
* Lookup the status from a return code
* @param value to lookup
* @return status or UKNOWN if the code is not recognized
*/
public static Status fromValue(int value)
{
for(Status status: Status.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNKNOWN;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,196 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
import java.util.EnumSet;
/**
* Update reason.
*
* These entries are used to notify the SDRplay API once settings are updated on the device.
*/
public enum UpdateReason
{
//Master Only mode
DEVICE_SAMPLE_RATE(sdrplay_api_h.sdrplay_api_Update_Dev_Fs(), "Sample Rate"),
DEVICE_PPM(sdrplay_api_h.sdrplay_api_Update_Dev_Ppm(), "PPM"),
DEVICE_SYNC_UPDATE(sdrplay_api_h.sdrplay_api_Update_Dev_SyncUpdate(), "Sync Update"),
DEVICE_RESET_FLAGS(sdrplay_api_h.sdrplay_api_Update_Dev_ResetFlags(), "Reset Flags"),
RSP1A_BIAS_T_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp1a_BiasTControl(), "RSP1A Bias-T Control"),
RSP1A_RF_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp1a_RfNotchControl(), "RSP1A RF Notch Control"),
RSP1A_RF_DAB_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp1a_RfDabNotchControl(), "RSP1A RF DAB Notch Control"),
RSP2_BIAS_T_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp2_BiasTControl(), "RSP2 Bias-T Control"),
RSP2_AM_PORT_SELECT(sdrplay_api_h.sdrplay_api_Update_Rsp2_AmPortSelect(), "RSP2 AM Port Select"),
RSP2_ANTENNA_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp2_AntennaControl(), "RSP2 Antenna Control"),
RSP2_RF_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp2_RfNotchControl(), "RSP2 RF Notch Control"),
RSP2_EXT_REF_CONTROL(sdrplay_api_h.sdrplay_api_Update_Rsp2_ExtRefControl(), "RSP2 External Reference Control"),
RSP_DUO_EXT_REF_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDuo_ExtRefControl(), "RSPduo External Reference Control"),
SPARE_1(sdrplay_api_h.sdrplay_api_Update_Master_Spare_1(), "Spare 1"),
SPARE_2(sdrplay_api_h.sdrplay_api_Update_Master_Spare_2(), "Spare 2"),
//Master and Slave mode
TUNER_GAIN_REDUCTION(sdrplay_api_h.sdrplay_api_Update_Tuner_Gr(), "Tuner Gain Reduction"),
TUNER_GAIN_REDUCTION_LIMITS(sdrplay_api_h.sdrplay_api_Update_Tuner_GrLimits(), "Tuner Gain Reduction Limits"),
TUNER_FREQUENCY_RF(sdrplay_api_h.sdrplay_api_Update_Tuner_Frf(), "Tuner Frequency RF"),
TUNER_BANDWIDTH_TYPE(sdrplay_api_h.sdrplay_api_Update_Tuner_BwType(), "Tuner Bandwidth Type"),
TUNER_IF_TYPE(sdrplay_api_h.sdrplay_api_Update_Tuner_IfType(), "Tuner IF Type"),
TUNER_DC_OFFSET(sdrplay_api_h.sdrplay_api_Update_Tuner_DcOffset(), "Tuner DC Offset"),
TUNER_LO_MODE(sdrplay_api_h.sdrplay_api_Update_Tuner_LoMode(), "Tuner LO Mode"),
CONTROL_DC_OFFSET_IQ_IMBALANCE(sdrplay_api_h.sdrplay_api_Update_Ctrl_DCoffsetIQimbalance(), "Control DC Offset IQ Imbalance"),
CONTROL_DECIMATION(sdrplay_api_h.sdrplay_api_Update_Ctrl_Decimation(), "Control Decimation"),
CONTROL_AGC(sdrplay_api_h.sdrplay_api_Update_Ctrl_Agc(), "Control AGC"),
CONTROL_ADSB_MODE(sdrplay_api_h.sdrplay_api_Update_Ctrl_AdsbMode(), "Control ADSB Mode"),
CONTROL_OVERLOAD_MESSAGE_ACK(sdrplay_api_h.sdrplay_api_Update_Ctrl_OverloadMsgAck(), "Control Overload Message Ack"),
RSP_DUO_BIAS_T_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDuo_BiasTControl(), "RSPduo Bias-T Control"),
RSP_DUO_AM_PORT_SELECT(sdrplay_api_h.sdrplay_api_Update_RspDuo_AmPortSelect(), "RSPduo AM Port Select"),
RSP_DUO_TUNER_1_AM_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDuo_Tuner1AmNotchControl(), "RSPduo Tuner 1 AM Notch Control"),
RSP_DUO_RF_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDuo_RfNotchControl(), "RSPduo RF Notch Control"),
RSP_DUO_RF_DAB_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDuo_RfDabNotchControl(), "RSPduo RF DAB Notch Control"),
//Extension 1
EXTENSION_RSP_DX_HDR_ENABLE(sdrplay_api_h.sdrplay_api_Update_RspDx_HdrEnable(), "RSPdx HDR Enable"),
EXTENSION_RSP_DX_BIAS_T_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDx_BiasTControl(), "RSPdx Bias-T Control"),
EXTENSION_RSP_DX_ANTENNA_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDx_AntennaControl(), "RSPdx Antenna Control"),
EXTENSION_RSP_DX_RF_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDx_RfNotchControl(), "RSPdx RF Notch Control"),
EXTENSION_RSP_DX_RF_DAB_NOTCH_CONTROL(sdrplay_api_h.sdrplay_api_Update_RspDx_RfDabNotchControl(), "RSPdx RF DAB Notch Control"),
EXTENSION_RSP_DX_HDR_BANDWIDTH(sdrplay_api_h.sdrplay_api_Update_RspDx_HdrBw(), "RSPdx HDR Bandwidth"),
EXTENSION_NONE(sdrplay_api_h.sdrplay_api_Update_Ext1_None(), "NONE"),
NONE(sdrplay_api_h.sdrplay_api_Update_None(), "NONE");
private int mValue;
private String mDescription;
UpdateReason(int value, String description)
{
mValue = value;
mDescription = description;
}
public static EnumSet<UpdateReason> EXTENSIONS = EnumSet.range(EXTENSION_RSP_DX_HDR_ENABLE, EXTENSION_NONE);
/**
* Many of the update reasons described in this enumeration are submitted asynchronously, since the API is
* non-blocking. However, the device event listener responses are limited to just three events: Frequency, Gain,
* and Sample Rate. This constant describes the three update reasons that correspond to the device events.
*/
public static EnumSet<UpdateReason> ASYNC_UPDATE_RESPONSES = EnumSet.of(DEVICE_SAMPLE_RATE, TUNER_FREQUENCY_RF, TUNER_GAIN_REDUCTION);
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Indicates if this is an extended update reason entry.
*/
public boolean isExtended()
{
return EXTENSIONS.contains(this);
}
/**
* Indicates if this update reason is one of the limited set of asynchronous update operation response types.
*/
public boolean isAsyncUpdateResponse()
{
return ASYNC_UPDATE_RESPONSES.contains(this);
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UNKNOWN if the code is not recognized
*/
public static UpdateReason fromValue(int value)
{
for(UpdateReason status: UpdateReason.values())
{
if(status.getValue() == value)
{
return status;
}
}
return NONE;
}
/**
* Calculates a combined logical OR value of the non-extended update reasons. Extended reason values will
* be ignored for this calculation.
*
* @param reasons to combine
* @return combined (logical OR) value.
*/
public static int getReasons(UpdateReason ... reasons)
{
int combined = UpdateReason.NONE.getValue();
for(UpdateReason reason: reasons)
{
if(!reason.isExtended())
{
combined += reason.getValue();
}
}
return combined;
}
/**
* Calculates a combined logical OR value of the extended update reasons. Non-extended reason values will
* be ignored for this calculation.
*
* @param reasons to combine
* @return combined (logical OR) value.
*/
public static int getExtendedReasons(UpdateReason ... reasons)
{
int combined = UpdateReason.EXTENSION_NONE.getValue();
for(UpdateReason reason: reasons)
{
if(reason.isExtended())
{
combined += reason.getValue();
}
}
return combined;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,99 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* SDRPlay API Versions
*/
public enum Version
{
UNKNOWN(0.0f, false),
V3_07(3.07f, true),
V3_08(3.08f, true),
V3_09(3.09f, true),
V3_10(3.10f, true),
V3_11(3.11f, true);
private float mValue;
private boolean mSupported;
private static final Logger mLog = LoggerFactory.getLogger(Version.class);
Version(float value, boolean supported)
{
mValue = value;
mSupported = supported;
}
/**
* Indicates if the API version is supported by the jsdrplay library
*/
public boolean isSupported()
{
return mSupported;
}
/**
* Indicates if this version is greater than or equal to the specified version.
* @param version to compare
* @return true if this version is greater than or equal to
*/
public boolean gte(Version version)
{
return this.ordinal() >= version.ordinal();
}
/**
* Numeric API version/value
*/
public float getVersion()
{
return mValue;
}
/**
* Lookup the version from the specified value.
* @param value to lookup
* @return version or UNKNOWN
*/
public static Version fromValue(float value)
{
for(Version version: values())
{
if(version.mValue == value)
{
return version;
}
}
mLog.warn("Unrecognized SDRplay API version [" + value + "]");
return UNKNOWN;
}
@Override
public String toString()
{
return String.valueOf(mValue);
}
}

View File

@@ -0,0 +1,227 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.async;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;
/**
* Asynchronous operation that implements the Future interface with utility methods for callback on completion, or
* converting to a synchronous (ie blocking) operation.
* @param <R> expected return type upon completion of the operation
*/
public class AsyncFuture<R> implements Future<R>
{
private R mResult;
private Throwable mError;
private boolean mCancelled;
private boolean mCompleted = false;
private ReentrantLock mLock = new ReentrantLock();
private IAsyncCallback mCallback;
/**
* Sets the result and completes this future.
* @param result to apply.
*/
public synchronized void setResult(R result)
{
if(mCompleted)
{
throw new IllegalStateException("Future is already completed.");
}
mResult = result;
finish();
}
/**
* Sets an error resulting from the operation and completes this future.
* @param error produced from the operation
*/
public synchronized void setError(Throwable error)
{
if(mCompleted)
{
throw new IllegalStateException("Future is already completed.");
}
mError = error;
finish();
}
/**
* (Optional) error produced from the operation.
*/
public Throwable getError()
{
return mError;
}
/**
* Indicates if this future had an error during the operation
*/
public boolean hasError()
{
return mError != null;
}
/**
* Cleanup task that completes the future and notifies an optional registered callback.
*/
private void finish()
{
mLock.lock();
try
{
mCompleted = true;
if(mCallback != null)
{
mCallback.complete(this);
mCallback = null;
}
}
finally
{
mLock.unlock();
}
notifyAll();
}
/**
* Signals a desire to cancel this future operation.
*
* Note: it is up to the implementer to monitor this cancel state.
* @param mayInterruptIfRunning not implemented.
* @return true always.
*/
@Override
public boolean cancel(boolean mayInterruptIfRunning)
{
mCancelled = true;
return true;
}
/**
* Indicates if this future has been cancelled.
*/
@Override
public boolean isCancelled()
{
return mCancelled;
}
/**
* Indicates if this future has completed.
*/
@Override
public boolean isDone()
{
return mCompleted;
}
/**
* Blocking call to wait indefinitely for the result of the operation.
* @return result of the operation
* @throws InterruptedException if the calling thread is interrupted while waiting
* @throws ExecutionException if there is an error produced from the operation
*/
@Override
public synchronized R get() throws InterruptedException, ExecutionException
{
while(!mCompleted)
{
wait();
}
if(mError != null)
{
throw new ExecutionException(mError);
}
return mResult;
}
/**
* Blocking call to synchronously get the result of the operation.
* @param timeout to wait
* @param unit for the timeout
* @return result once completed
* @throws InterruptedException if the calling thread is interrupted while waiting
* @throws ExecutionException if there is an error produced from the operation
* @throws TimeoutException if the timeout is exceeded while waiting.
*/
@Override
public synchronized R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
if(!mCompleted)
{
wait(unit.toMillis(timeout));
}
if(!mCompleted)
{
throw new TimeoutException("Get timeout [" + timeout + " " + unit + "] exceeded without completion");
}
if(mError != null)
{
throw new ExecutionException(mError);
}
return mResult;
}
/**
* Registers the callback to receive the result once the operation completes. If the operation is completed, the
* callback is immediately notified, otherwise the callback will be notified later.
* @param callback to be notified once the operation is completed.
*/
public synchronized void callback(IAsyncCallback callback)
{
if(mCallback != null)
{
throw new IllegalArgumentException("Callback has been registered - only one callback is supported.");
}
mLock.lock();
try
{
if(mCompleted)
{
callback.complete(this);
}
else
{
mCallback = callback;
}
}
finally
{
mLock.unlock();
}
}
}

View File

@@ -0,0 +1,100 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.async;
import io.github.dsheirer.source.tuner.sdrplay.api.Status;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
/**
* Asynchronous future for an SDRplay API update operation.
*/
public class AsyncUpdateFuture extends AsyncFuture<Status>
{
private TunerSelect mTunerSelect;
private UpdateReason mUpdateReason;
private UpdateReason mExpectedResponse;
private boolean mSubmitted;
/**
* Creates a to-be completed future where a successful update with return success or an unsuccessful update will
* return an exception.
* @param tunerSelect for the tuner to be updated
* @param updateReason of what is to be updated
* @param expectedResponse to be received to indicate the async operation is completed
*/
public AsyncUpdateFuture(TunerSelect tunerSelect, UpdateReason updateReason, UpdateReason expectedResponse)
{
mTunerSelect = tunerSelect;
mUpdateReason = updateReason;
mExpectedResponse = expectedResponse;
}
/**
* Tuner(s) for the update
*/
public TunerSelect getTunerSelect()
{
return mTunerSelect;
}
/**
* UpdateReason that is being updated
*/
public UpdateReason getUpdateReason()
{
return mUpdateReason;
}
/**
* Expected response to this update operation
*/
public UpdateReason getExpectedResponse()
{
return mExpectedResponse;
}
/**
* Flag to indicate if this update has been submitted and is currently awaiting results.
*/
public boolean isSubmitted()
{
return mSubmitted;
}
/**
* Sets flag to indicate that this update has been submitted.
*/
public void setSubmitted(boolean submitted)
{
mSubmitted = submitted;
}
/**
* Indicates if the completed async operation matches this submitted async update future
* @param completedAsyncUpdate to compare
* @return true if there is a match
*/
public boolean matches(CompletedAsyncUpdate completedAsyncUpdate)
{
return getTunerSelect().equals(completedAsyncUpdate.getTunerSelect()) &&
getExpectedResponse().equals(completedAsyncUpdate.getUpdateReason());
}
}

View File

@@ -0,0 +1,57 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.async;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
/**
* Completed asynchronous update operation
*/
public class CompletedAsyncUpdate
{
private TunerSelect mTunerSelect;
private UpdateReason mUpdateReason;
/**
* Creates a completed update.
*/
public CompletedAsyncUpdate(TunerSelect tunerSelect, UpdateReason updateReason)
{
mTunerSelect = tunerSelect;
mUpdateReason = updateReason;
}
/**
* Tuner(s) for the update
*/
public TunerSelect getTunerSelect()
{
return mTunerSelect;
}
/**
* UpdateReason that is being updated
*/
public UpdateReason getUpdateReason()
{
return mUpdateReason;
}
}

View File

@@ -0,0 +1,32 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.async;
/**
* Callback interface to be notified when an async future has completed or has resulted in an error
*/
public interface IAsyncCallback
{
/**
* Callback method once the future is completed or produces an error.
* @param future that is being monitored
*/
void complete(AsyncFuture future);
}

View File

@@ -0,0 +1,127 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_CallbackFnsT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_EventCallback_t;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_StreamCallback_t;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
/**
* Callback functions (sdrplay_api_CallbackFnsT) factory
*/
public class CallbackFunctions
{
private DeviceEventAdapter mDeviceEventAdapter;
private StreamCallbackAdapter mStreamACallbackAdapter;
private StreamCallbackAdapter mStreamBCallbackAdapter;
private MemorySegment mCallbackFunctionsMemorySegment;
/**
* Constructs a callback functions for single-tuner use.
* @param memorySession for native memory allocation
* @param deviceEventListener for device events
* @param streamListener for streaming samples
* @param streamCallbackListener for streaming events
*/
public CallbackFunctions(MemorySession memorySession, IDeviceEventListener deviceEventListener,
IStreamListener streamListener, IStreamCallbackListener streamCallbackListener)
{
//Create the event callback function
mDeviceEventAdapter = new DeviceEventAdapter(memorySession, deviceEventListener);
MemorySegment eventFunction = sdrplay_api_EventCallback_t.allocate(mDeviceEventAdapter, memorySession);
//Create the stream A callback function
mStreamACallbackAdapter = new StreamCallbackAdapter(memorySession, streamListener, streamCallbackListener);
MemorySegment streamAFunction = sdrplay_api_StreamCallback_t.allocate(mStreamACallbackAdapter, memorySession);
//Create the callback functions union and populate the callback functions
mCallbackFunctionsMemorySegment = sdrplay_api_CallbackFnsT.allocate(memorySession);
sdrplay_api_CallbackFnsT.EventCbFn$set(mCallbackFunctionsMemorySegment, eventFunction.address());
sdrplay_api_CallbackFnsT.StreamACbFn$set(mCallbackFunctionsMemorySegment, streamAFunction.address());
}
/**
* Constructs a callback functions for dual-tuner use.
* @param memorySession for native memory allocation
* @param deviceEventListener for device events
* @param streamAListener for streaming samples from the master tuner
* @param streamBListener for streaming samples from the slave tuner
* @param streamCallbackListener for streaming events
*/
public CallbackFunctions(MemorySession memorySession, IDeviceEventListener deviceEventListener,
IStreamListener streamAListener, IStreamListener streamBListener,
IStreamCallbackListener streamCallbackListener)
{
//Create the event callback function
mDeviceEventAdapter = new DeviceEventAdapter(memorySession, deviceEventListener);
MemorySegment eventFunction = sdrplay_api_EventCallback_t.allocate(mDeviceEventAdapter, memorySession);
//Create the stream A callback function
mStreamACallbackAdapter = new StreamCallbackAdapter(memorySession, streamAListener, streamCallbackListener);
MemorySegment streamAFunction = sdrplay_api_StreamCallback_t.allocate(mStreamACallbackAdapter, memorySession);
//Create the stream B callback function
mStreamBCallbackAdapter = new StreamCallbackAdapter(memorySession, streamBListener, streamCallbackListener);
MemorySegment streamBFunction = sdrplay_api_StreamCallback_t.allocate(mStreamBCallbackAdapter, memorySession);
//Create the callback functions union and populate the callback functions
mCallbackFunctionsMemorySegment = sdrplay_api_CallbackFnsT.allocate(memorySession);
sdrplay_api_CallbackFnsT.EventCbFn$set(mCallbackFunctionsMemorySegment, eventFunction.address());
sdrplay_api_CallbackFnsT.StreamACbFn$set(mCallbackFunctionsMemorySegment, streamAFunction.address());
sdrplay_api_CallbackFnsT.StreamBCbFn$set(mCallbackFunctionsMemorySegment, streamBFunction.address());
}
/**
* Foreign memory segment for the callback functions.
*/
public MemorySegment getCallbackFunctionsMemorySegment()
{
return mCallbackFunctionsMemorySegment;
}
/**
* Updates the device event listener
* @param listener to receive device events
*/
public void setDeviceEventListener(IDeviceEventListener listener)
{
mDeviceEventAdapter.setListener(listener);
}
/**
* Updates the stream A listener
* @param listener to receive samples for stream A
*/
public void setStreamAListener(IStreamListener listener)
{
mStreamACallbackAdapter.setListener(listener);
}
/**
* Updates the stream B listener
* @param listener to receive samples for stream B
*/
public void setStreamBListener(IStreamListener listener)
{
mStreamBCallbackAdapter.setListener(listener);
}
}

View File

@@ -0,0 +1,111 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.EventParametersFactory;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.EventType;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_EventCallback_t;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_EventParamsT;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Adapter for Device Event callbacks. Implements foreign interface and transfers foreign memory event details to
* native Java and invokes the appropriate interface methods for an event listener.
*/
public class DeviceEventAdapter implements sdrplay_api_EventCallback_t
{
private static final Logger mLog = LoggerFactory.getLogger(DeviceEventAdapter.class);
private MemorySession mMemorySession;
private IDeviceEventListener mDeviceEventListener;
/**
* Constructs an instance.
* @param memorySession to use in creating foreign memory segments to access foreign structures.
* @param listener to receive translated device events.
*/
public DeviceEventAdapter(MemorySession memorySession, IDeviceEventListener listener)
{
if(memorySession == null)
{
throw new IllegalArgumentException("Resource scope must be non-null");
}
mMemorySession = memorySession;
setListener(listener);
}
/**
* Updates the device event listener
* @param listener to receive device events
*/
public void setListener(IDeviceEventListener listener)
{
if(listener == null)
{
throw new IllegalArgumentException("Device event listener must be non-null");
}
mDeviceEventListener = listener;
}
@Override
public void apply(int eventTypeId, int tunerSelectId, MemoryAddress eventParametersPointer,
MemoryAddress callbackContext)
{
MemorySegment memorySegment = sdrplay_api_EventParamsT.ofAddress(eventParametersPointer, mMemorySession);
EventType eventType = EventType.fromValue(eventTypeId);
TunerSelect tunerSelect = TunerSelect.fromValue(tunerSelectId);
switch(eventType)
{
case GAIN_CHANGE -> {
mDeviceEventListener.processGainChange(tunerSelect,
EventParametersFactory.createGainCallbackParameters(memorySegment));
}
case POWER_OVERLOAD_CHANGE -> {
mDeviceEventListener.processPowerOverload(tunerSelect,
EventParametersFactory.createPowerOverloadCallbackParameters(memorySegment));
}
case DEVICE_REMOVED -> {
mDeviceEventListener.processDeviceRemoval(tunerSelect);
}
case RSP_DUO_MODE_CHANGE -> {
mDeviceEventListener.processRspDuoModeChange(tunerSelect,
EventParametersFactory.createRspDuoModeCallbackParameters(memorySegment));
}
case UNKNOWN -> {
mLog.warn("Unknown device event callback ignored. Please contact the library developer as this may " +
"indicate a change to the SDRPlay API change. Tuner:" + tunerSelect + " Event Type ID:" +
eventTypeId);
mDeviceEventListener.processEvent(eventType, tunerSelect);
}
default -> {
throw new IllegalStateException("DeviceEventAdapter must be updated handle EventType." + eventType);
}
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.EventType;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.GainCallbackParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.PowerOverloadCallbackParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.event.RspDuoModeCallbackParameters;
/**
* Device event listener. Receives events for the device, impacting one or both (if equipped) tuners on the device.
*/
public interface IDeviceEventListener
{
/**
* Process a device event
* @param eventType identifies the type of event
* @param tunerSelect identifies which tuner(s) are included in the event (A, B, BOTH, or NEITHER)
*/
void processEvent(EventType eventType, TunerSelect tunerSelect);
/**
* Process a gain change event
* @param tunerSelect identifies which tuner(s) are included in the event (A, B, BOTH, or NEITHER)
* @param gainCallbackParameters containing event details
*/
void processGainChange(TunerSelect tunerSelect, GainCallbackParameters gainCallbackParameters);
/**
* Process a power overload event
* @param tunerSelect identifies which tuner(s) are included in the event (A, B, BOTH, or NEITHER)
* @param parameters containing event details
*/
void processPowerOverload(TunerSelect tunerSelect, PowerOverloadCallbackParameters parameters);
/**
* Process an RSP-Duo mode change event
* @param tunerSelect identifies which tuner(s) are included in the event (A, B, BOTH, or NEITHER)
* @param parameters containing event details
*/
void processRspDuoModeChange(TunerSelect tunerSelect, RspDuoModeCallbackParameters parameters);
/**
* Process a device removed (ie unplugged) event
* @param tunerSelect identifies which tuner(s) are included in the event (A, B, BOTH, or NEITHER)
*/
void processDeviceRemoval(TunerSelect tunerSelect);
}

View File

@@ -0,0 +1,32 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
public interface IStreamCallbackListener
{
/**
* Process stream callback parameters and reset value received over the stream callback interface.
* @param parameters to process
* @param reset value
*/
void process(TunerSelect tunerSelect, StreamCallbackParameters parameters, int reset);
}

View File

@@ -0,0 +1,45 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.device.TunerSelect;
/**
* Stream Listener interface.
*/
public interface IStreamListener
{
/**
* Process samples from a single stream of I/Q samples
* @param xi array of Inphase samples
* @param xq array of Quadrature samples
* @param streamCallbackParameters stream callback parameters
* @param reset indicates if a re-initialization has occurred within the API and that local buffering should be reset
*/
void processStream(short[] xi, short[] xq, StreamCallbackParameters streamCallbackParameters,
boolean reset);
/**
* Indicates which tuner this stream listener is for. Note: this is used to manage asynchronous Updates to ensure
* that submitted updates get correctly mapped and resolved in the Device update manager.
* @return
*/
TunerSelect getTunerSelect();
}

View File

@@ -0,0 +1,107 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_StreamCallback_t;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_StreamCbParamsT;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.ValueLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* I/Q sample stream callback adapter. Implements the native interface and transfers the native callback data to an
* implementation of the Java IStreamListener interface.
*/
public class StreamCallbackAdapter implements sdrplay_api_StreamCallback_t
{
private static final Logger mLog = LoggerFactory.getLogger(StreamCallbackAdapter.class);
private MemorySession mMemorySession;
private IStreamListener mStreamListener;
private IStreamCallbackListener mStreamCallbackListener;
/**
* Constructs an instance of the callback implementation
* @param memorySession for defining new foreign memory segments
* @param streamListener to receive transferred I/Q samples and event details
* @param listener to receive callback parameters
*/
public StreamCallbackAdapter(MemorySession memorySession, IStreamListener streamListener,
IStreamCallbackListener listener)
{
if(memorySession == null)
{
throw new IllegalArgumentException("Resource scope must be non-null");
}
mMemorySession = memorySession;
mStreamCallbackListener = listener;
setListener(streamListener);
}
/**
* Updates the listener for receiving samples
* @param listener to receive stream samples
*/
public void setListener(IStreamListener listener)
{
mStreamListener = listener;
}
/**
* Receives callback of foreign memory data, transfers it to Java, and passes to the listener.
* @param iSamplesPointer array foreign memory address
* @param qSamplesPointer array foreign memory address
* @param parametersPointer associated with the callback - foreign memory address
* @param sampleCount number of samples in each of the I and Q arrays
* @param reset 0 or 1, translated to a boolean
* @param deviceContext of the device that sourced the samples
*/
@Override
public void apply(MemoryAddress iSamplesPointer, MemoryAddress qSamplesPointer, MemoryAddress parametersPointer,
int sampleCount, int reset, MemoryAddress deviceContext)
{
if(mStreamListener != null || mStreamCallbackListener != null)
{
//Translate the callback parameters pointer to a memory segment and re-construct the parameters as a Java object
StreamCallbackParameters parameters = new StreamCallbackParameters(sdrplay_api_StreamCbParamsT
.ofAddress(parametersPointer, mMemorySession));
if(mStreamCallbackListener != null)
{
mStreamCallbackListener.process(mStreamListener.getTunerSelect(), parameters, reset);
}
if(mStreamListener != null)
{
//Allocate memory segments from I/Q pointers, transfer from native to JVM array, and send to listener
long arrayByteSize = ValueLayout.JAVA_SHORT.byteSize() * sampleCount;
MemorySegment iSamples = MemorySegment.ofAddress(iSamplesPointer, arrayByteSize, mMemorySession);
MemorySegment qSamples = MemorySegment.ofAddress(qSamplesPointer, arrayByteSize, mMemorySession);
short[] i = iSamples.toArray(ValueLayout.JAVA_SHORT);
short[] q = qSamples.toArray(ValueLayout.JAVA_SHORT);
mStreamListener.processStream(i, q, parameters, Flag.evaluate(reset));
}
}
}
}

View File

@@ -0,0 +1,88 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.callback;
import io.github.dsheirer.source.tuner.sdrplay.api.util.Flag;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_StreamCbParamsT;
import java.lang.foreign.MemorySegment;
/**
* Stream Callback Parameters structure (sdrplay_api_StreamCbParamsT)
*/
public class StreamCallbackParameters
{
private int mFirstSampleNumber;
private boolean mGainReductionChanged;
private boolean mRfFrequencyChanged;
private boolean mSampleRateChanged;
private long mNumberSamples;
/**
* Constructs an instance from the foreign memory segment
*/
public StreamCallbackParameters(MemorySegment memorySegment)
{
mFirstSampleNumber = sdrplay_api_StreamCbParamsT.firstSampleNum$get(memorySegment);
mGainReductionChanged = Flag.evaluate(sdrplay_api_StreamCbParamsT.grChanged$get(memorySegment));
mRfFrequencyChanged = Flag.evaluate(sdrplay_api_StreamCbParamsT.rfChanged$get(memorySegment));
mSampleRateChanged = Flag.evaluate(sdrplay_api_StreamCbParamsT.fsChanged$get(memorySegment));
mNumberSamples = sdrplay_api_StreamCbParamsT.numSamples$get(memorySegment);
}
/**
* First sample number
*/
public int getFirstSampleNumber()
{
return mFirstSampleNumber;
}
/**
* Indicates if gain reduction value has changed
*/
public boolean isGainReductionChanged()
{
return mGainReductionChanged;
}
/**
* Indicates if RF center frequency has changed
*/
public boolean isRfFrequencyChanged()
{
return mRfFrequencyChanged;
}
/**
* Indicates if sample rate has changed
*/
public boolean isSampleRateChanged()
{
return mSampleRateChanged;
}
/**
* Number of samples
*/
public long getNumberSamples()
{
return mNumberSamples;
}
}

View File

@@ -0,0 +1,84 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
/**
* Software decimation rates supported by the API for SDRPlay RSP devices
*/
public enum Decimate
{
X1(1, 16),
X2(2, 16),
X4(4, 17),
X8(8, 17),
X16(16, 18),
X32(32, 20);
private int mValue;
private int mSampleSize;
/**
* Constructs an instance
* @param value
* @param sampleSize in bits to represent effective dynamic range.
*/
Decimate(int value, int sampleSize)
{
mValue = value;
mSampleSize = sampleSize;
}
/**
* Decimation value.
* @return
*/
public int getValue()
{
return mValue;
}
/**
* Sample size in bits to represent effective dynamic range for the decimation value.
*/
public int getSampleSize()
{
return mSampleSize;
}
/**
* Indicates if software decimation is enabled.
* @return true for all values except X1.
*/
public boolean isEnabled()
{
return !this.equals(X1);
}
@Override
public String toString()
{
if(this.equals(X1))
{
return "None";
}
return "x" + getValue();
}
}

View File

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

View File

@@ -0,0 +1,164 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.Version;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DeviceT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SegmentAllocator;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Factory methods for creating new RSP Device instances
*/
public class DeviceFactory
{
private static final Logger mLog = LoggerFactory.getLogger(DeviceFactory.class);
/**
* Creates a foreign memory segment for a DeviceT array, appropriate for the specified version.
* @param version value
* @param segmentAllocator to allocate the foreign memory
* @return devices array
*/
public static MemorySegment createDeviceArray(Version version, SegmentAllocator segmentAllocator)
{
if(version.gte(Version.V3_08))
{
return sdrplay_api_DeviceT.allocateArray(sdrplay_api_h.SDRPLAY_MAX_DEVICES(), segmentAllocator);
}
else if(version == Version.V3_07)
{
return sdrplay_api_DeviceT.allocateArray(sdrplay_api_h.SDRPLAY_MAX_DEVICES(), segmentAllocator);
}
throw new IllegalArgumentException("Unrecognized version: " + version);
}
/**
* Parses device information from a list of device structures
* @param deviceStructs representing devices to parse
* @return a list of device infos
*/
public static List<DeviceInfo> parseDeviceInfos(List<IDeviceStruct> deviceStructs)
{
List<DeviceInfo> deviceInfos = new ArrayList<>();
for(IDeviceStruct deviceStruct: deviceStructs)
{
deviceInfos.add(new DeviceInfo(deviceStruct));
}
return deviceInfos;
}
/**
* Parses device information from a memory segment containing an array of device structures.
* @param version of the API
* @param devicesArray memory segment
* @param count of device structures in the devicesArray.
* @return a list of device infos
* @throws exception if version is unrecognized or unsupported
*/
public static List<IDeviceStruct> parseDeviceStructs(Version version, MemorySegment devicesArray, int count)
throws SDRPlayException
{
List<IDeviceStruct> deviceStructs = new ArrayList<>();
if(version.gte(Version.V3_08))
{
devicesArray.elements(sdrplay_api_DeviceT.$LAYOUT())
.limit(count).forEach(memorySegment ->
deviceStructs.add(DeviceFactory.createDeviceStruct(version, memorySegment)));
}
else if(version == Version.V3_07)
{
devicesArray.elements(sdrplay_api_DeviceT.$LAYOUT()).limit(count).forEach(memorySegment ->
{
deviceStructs.add(DeviceFactory.createDeviceStruct(version, memorySegment));
});
}
else
{
throw new SDRPlayException("Unrecognized version: " + version);
}
return deviceStructs;
}
/**
* Creates an SDRplay device from the foreign memory Device instance.
* @param sdrPlay for device callback support
* @param deviceMemorySegment instance for the device
* @return correctly typed device
*/
public static Device createDevice(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
switch(deviceStruct.getDeviceType())
{
case RSP1 -> {
return new Rsp1Device(sdrPlay, deviceStruct);
}
case RSP1A -> {
return new Rsp1aDevice(sdrPlay, deviceStruct);
}
case RSP2 -> {
return new Rsp2Device(sdrPlay, deviceStruct);
}
case RSPduo -> {
return new RspDuoDevice(sdrPlay, deviceStruct);
}
case RSPdx -> {
return new RspDxDevice(sdrPlay, deviceStruct);
}
default -> {
return new UnknownDevice(sdrPlay, deviceStruct);
}
}
}
/**
* Creates a device structure parser for the specified API version
* @param version to create
* @param deviceMemorySegment for the device
* @return device structure
*/
private static IDeviceStruct createDeviceStruct(Version version, MemorySegment deviceMemorySegment)
{
if(version == Version.V3_07)
{
return new DeviceStruct_v3_07(deviceMemorySegment);
}
else if(version.gte(Version.V3_08))
{
return new DeviceStruct_v3_08(deviceMemorySegment);
}
else
{
throw new IllegalArgumentException("Unsupported version: " + version);
}
}
}

View File

@@ -0,0 +1,140 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.DeviceSelectionMode;
import java.util.Objects;
import org.apache.commons.lang3.Validate;
/**
* RSP device information to support device selection.
*/
public class DeviceInfo
{
private DeviceSelectionMode mDeviceSelectionMode = DeviceSelectionMode.SINGLE_TUNER_1;
private DeviceType mDeviceType;
private String mSerialNumber;
/**
* Constructs an instance
* @param deviceType of the RSP device
* @param serialNumber for the device
*/
public DeviceInfo(DeviceType deviceType, String serialNumber)
{
Validate.notNull(deviceType, "Device type cannot be null");
Validate.notNull(serialNumber, "Device serial number cannot be null");
mDeviceType = deviceType;
mSerialNumber = serialNumber;
}
/**
* Alternate constructor where we get the parameters from a device structure.
* @param deviceStruct containing device type and serial number values.
*/
public DeviceInfo(IDeviceStruct deviceStruct)
{
this(deviceStruct.getDeviceType(), deviceStruct.getSerialNumber());
}
/**
* Device type for this RSP device
* @return type
*/
public DeviceType getDeviceType()
{
return mDeviceType;
}
/**
* Serial number for this RSP device
* @return serial number
*/
public String getSerialNumber()
{
return mSerialNumber;
}
/**
* Device selection mode for this RSP device
* @return device selection mode where single tuner 1 is default
*/
public DeviceSelectionMode getDeviceSelectionMode()
{
return mDeviceSelectionMode;
}
/**
* Sets the device selection mode. This should be left as default of single tuner 1 unless this device is an RSPduo.
* @param deviceSelectionMode to use for this device.
*/
public void setDeviceSelectionMode(DeviceSelectionMode deviceSelectionMode)
{
Validate.notNull(deviceSelectionMode, "Device selection mode cannot be null");
mDeviceSelectionMode = deviceSelectionMode;
}
/**
* Clones this instance
* @return deep copy.
*/
public DeviceInfo clone()
{
return new DeviceInfo(mDeviceType, mSerialNumber);
}
/**
* Indicates if this device type and serial number matches the details of the device structure.
* @param deviceStruct to compare
* @return true if the device type and serial number match.
*/
public boolean matches(IDeviceStruct deviceStruct)
{
return deviceStruct != null && getDeviceType().equals(deviceStruct.getDeviceType()) && getSerialNumber().equals(deviceStruct.getSerialNumber());
}
@Override
public String toString()
{
return "Device: " + getDeviceType() + " Serial Number: " + getSerialNumber() + " Selection Mode: " + getDeviceSelectionMode();
}
@Override
public boolean equals(Object o)
{
if(this == o)
{
return true;
}
if(o == null || getClass() != o.getClass())
{
return false;
}
DeviceInfo that = (DeviceInfo) o;
return mDeviceSelectionMode == that.mDeviceSelectionMode && mDeviceType == that.mDeviceType && mSerialNumber.equals(that.mSerialNumber);
}
@Override
public int hashCode()
{
return Objects.hash(mDeviceSelectionMode, mDeviceType, mSerialNumber);
}
}

View File

@@ -0,0 +1,99 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DeviceT;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
/**
* sdrplay_api_DeviceT structure parser for API version 3.07
*/
public class DeviceStruct_v3_07 implements IDeviceStruct
{
private MemorySegment mDeviceMemorySegment;
private DeviceType mDeviceType;
private String mSerialNumber;
/**
* Constructs an instance
* @param deviceMemorySegment of foreign memory
*/
public DeviceStruct_v3_07(MemorySegment deviceMemorySegment)
{
mDeviceMemorySegment = deviceMemorySegment;
mDeviceType = DeviceType.fromValue(0xFF & sdrplay_api_DeviceT.hwVer$get(mDeviceMemorySegment));
MemorySegment serialSegment = sdrplay_api_DeviceT.SerNo$slice(mDeviceMemorySegment);
mSerialNumber = serialSegment.getUtf8String(0);
}
@Override public MemorySegment getDeviceMemorySegment()
{
return mDeviceMemorySegment;
}
@Override public String getSerialNumber()
{
return mSerialNumber;
}
@Override public DeviceType getDeviceType()
{
return mDeviceType;
}
@Override public TunerSelect getTunerSelect()
{
return TunerSelect.fromValue(sdrplay_api_DeviceT.tuner$get(getDeviceMemorySegment()));
}
@Override public RspDuoMode getRspDuoMode()
{
return RspDuoMode.fromValue(sdrplay_api_DeviceT.rspDuoMode$get(getDeviceMemorySegment()));
}
@Override
public void setRspDuoMode(RspDuoMode mode)
{
sdrplay_api_DeviceT.rspDuoMode$set(getDeviceMemorySegment(), mode.getValue());
}
@Override public boolean isValid()
{
//Always returns true for version 3.07
return true;
}
@Override public double getRspDuoSampleFrequency()
{
return sdrplay_api_DeviceT.rspDuoSampleFreq$get(getDeviceMemorySegment());
}
@Override
public void setRspDuoSampleFrequency(double frequency)
{
sdrplay_api_DeviceT.rspDuoSampleFreq$set(getDeviceMemorySegment(), frequency);
}
@Override public MemoryAddress getDeviceHandle()
{
return sdrplay_api_DeviceT.dev$get(getDeviceMemorySegment());
}
}

View File

@@ -0,0 +1,99 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_08.sdrplay_api_DeviceT;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
/**
* sdrplay_api_DeviceT structure parser for API version 3.07
*/
public class DeviceStruct_v3_08 implements IDeviceStruct
{
private MemorySegment mDeviceMemorySegment;
private DeviceType mDeviceType;
private String mSerialNumber;
/**
* Constructs an instance
* @param deviceMemorySegment of foreign memory
*/
public DeviceStruct_v3_08(MemorySegment deviceMemorySegment)
{
mDeviceMemorySegment = deviceMemorySegment;
mDeviceType = DeviceType.fromValue(0xFF & sdrplay_api_DeviceT.hwVer$get(mDeviceMemorySegment));
MemorySegment serialSegment = sdrplay_api_DeviceT.SerNo$slice(mDeviceMemorySegment);
mSerialNumber = serialSegment.getUtf8String(0);
}
@Override public MemorySegment getDeviceMemorySegment()
{
return mDeviceMemorySegment;
}
@Override public String getSerialNumber()
{
return mSerialNumber;
}
@Override public DeviceType getDeviceType()
{
return mDeviceType;
}
@Override public TunerSelect getTunerSelect()
{
return TunerSelect.fromValue(sdrplay_api_DeviceT.tuner$get(getDeviceMemorySegment()));
}
@Override public RspDuoMode getRspDuoMode()
{
return RspDuoMode.fromValue(sdrplay_api_DeviceT.rspDuoMode$get(getDeviceMemorySegment()));
}
@Override
public void setRspDuoMode(RspDuoMode mode)
{
sdrplay_api_DeviceT.rspDuoMode$set(getDeviceMemorySegment(), mode.getValue());
}
@Override public boolean isValid()
{
//Always returns true for version 3.07
return true;
}
@Override public double getRspDuoSampleFrequency()
{
return sdrplay_api_DeviceT.rspDuoSampleFreq$get(getDeviceMemorySegment());
}
@Override
public void setRspDuoSampleFrequency(double frequency)
{
sdrplay_api_DeviceT.rspDuoSampleFreq$set(getDeviceMemorySegment(), frequency);
}
@Override public MemoryAddress getDeviceHandle()
{
return sdrplay_api_DeviceT.dev$get(getDeviceMemorySegment());
}
}

View File

@@ -0,0 +1,76 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* RSP Device type
*/
public enum DeviceType
{
RSP1(sdrplay_api_h.SDRPLAY_RSP1_ID(), "RSP1"),
RSP1A(sdrplay_api_h.SDRPLAY_RSP1A_ID(), "RSP1A"),
RSP2(sdrplay_api_h.SDRPLAY_RSP2_ID(), "RSP2"),
RSPduo(sdrplay_api_h.SDRPLAY_RSPduo_ID(), "RSPduo"),
RSPdx(sdrplay_api_h.SDRPLAY_RSPdx_ID(), "RSPdx"),
UNKNOWN(Integer.MIN_VALUE, "UNKNOWN");
private int mValue;
private String mDescription;
DeviceType(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UNKNOWN if the code is not recognized
*/
public static DeviceType fromValue(int value)
{
for(DeviceType status: DeviceType.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNKNOWN;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,81 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
/**
* Interface for parsing and accessing the fields of the sdrplay_api_DeviceT structure across
* various versions.
*/
public interface IDeviceStruct
{
/**
* Foreign memory segment for this device structure
*/
MemorySegment getDeviceMemorySegment();
/**
* Serial number of the device
*/
String getSerialNumber();
/**
* Indicates the device type, or model of RSP
*/
DeviceType getDeviceType();
/**
* Indicates single, dual, or master/slave mode for the tuner.
*/
TunerSelect getTunerSelect();
/**
* RSPduo mode
*/
RspDuoMode getRspDuoMode();
/**
* Sets the RSPduo mode
* @param mode to set
*/
void setRspDuoMode(RspDuoMode mode);
/**
* Indicates if the device is valid and ready for use (V3.08 and later)
*/
boolean isValid();
/**
* Sample frequency/rate for the RSPduo when in master/slave mode
*/
double getRspDuoSampleFrequency();
/**
* Sets the sample frequency/rate for the RSPduo when in master (only) mode.
*/
void setRspDuoSampleFrequency(double frequency);
/**
* Device handle. Note this is only available if the device has been selected.
*/
MemoryAddress getDeviceHandle();
}

View File

@@ -0,0 +1,61 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.Rsp1CompositeParameters;
/**
* RSP1 Device
*/
public class Rsp1Device extends Device<Rsp1CompositeParameters, Rsp1Tuner>
{
private Rsp1Tuner mTuner1;
/**
* Constructs an SDRPlay RSP1 device from the foreign memory segment
*
* @param sdrPlay api instance that created this device
* @param deviceStruct parser
*/
Rsp1Device(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
super(sdrPlay, deviceStruct);
}
@Override
public Rsp1Tuner getTuner() throws SDRPlayException
{
if(!isSelected())
{
throw new SDRPlayException("Device must be selected before accessing the tuner");
}
if(mTuner1 == null)
{
mTuner1 = new Rsp1Tuner(Rsp1Device.this, getAPI(), getTunerSelect(),
getCompositeParameters().getDeviceParameters(), getCompositeParameters().getTunerAParameters(),
getCompositeParameters().getControlAParameters());
}
return mTuner1;
}
}

View File

@@ -0,0 +1,46 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.Rsp1DeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp1TunerParameters;
/**
* RSP1 Tuner
*/
public class Rsp1Tuner extends RspTuner<Rsp1DeviceParameters, Rsp1TunerParameters>
{
/**
* Constructs an instance
* @param device parent for this tuner
* @param sdrplay api
* @param tunerSelect to specify which tuner
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public Rsp1Tuner(Device device, SDRplay sdrplay, TunerSelect tunerSelect, Rsp1DeviceParameters deviceParameters,
Rsp1TunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, tunerSelect, deviceParameters, tunerParameters, controlParameters);
}
}

View File

@@ -0,0 +1,61 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.Rsp1aCompositeParameters;
/**
* RSP1A Device
*/
public class Rsp1aDevice extends Device<Rsp1aCompositeParameters, Rsp1aTuner>
{
private Rsp1aTuner mTuner1;
/**
* Constructs an SDRPlay RSP1A device from the foreign memory segment
*
* @param sdrPlay api instance that created this device
* @param deviceStruct parser
*/
Rsp1aDevice(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
super(sdrPlay, deviceStruct);
}
@Override
public Rsp1aTuner getTuner() throws SDRPlayException
{
if(!isSelected())
{
throw new SDRPlayException("Device must be selected before accessing the tuner");
}
if(mTuner1 == null)
{
mTuner1 = new Rsp1aTuner(Rsp1aDevice.this, getAPI(), getTunerSelect(),
getCompositeParameters().getDeviceParameters(), getCompositeParameters().getTunerAParameters(),
getCompositeParameters().getControlAParameters());
}
return mTuner1;
}
}

View File

@@ -0,0 +1,105 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.Rsp1aDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp1aTunerParameters;
/**
* RSP1A Tuner
*/
public class Rsp1aTuner extends RspTuner<Rsp1aDeviceParameters, Rsp1aTunerParameters>
{
/**
* Constructs an instance
* @param device parent for this tuner
* @param sdrplay api
* @param tunerSelect to specify which tuner
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public Rsp1aTuner(Device device, SDRplay sdrplay, TunerSelect tunerSelect, Rsp1aDeviceParameters deviceParameters,
Rsp1aTunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, tunerSelect, deviceParameters, tunerParameters, controlParameters);
}
/**
* Indicates if the RF notch is enabled
*/
public boolean isRfNotch()
{
return getDeviceParameters().isRFNotch();
}
/**
* Enables or disables the RF notch
* @param enable setting
* @throws SDRPlayException if there is an error
*/
public void setRfNotch(boolean enable) throws SDRPlayException
{
getDeviceParameters().setRFNotch(enable);
update(UpdateReason.RSP1A_RF_NOTCH_CONTROL);
}
/**
* Indicates if the RF DAB notch is enabled
*/
public boolean isRfDabNotch()
{
return getDeviceParameters().isRfDabNotch();
}
/**
* Enables or disables the RF DAB notch
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setRfDabNotch(boolean enable) throws SDRPlayException
{
getDeviceParameters().setRfDabNotch(enable);
update(UpdateReason.RSP1A_RF_DAB_NOTCH_CONTROL);
}
/**
* Indicates if the Bias-T is enabled
*/
public boolean isBiasT()
{
return getTunerParameters().isBiasT();
}
/**
* Enables or disables the Bias-T
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setBiasT(boolean enable) throws SDRPlayException
{
getTunerParameters().setBiasT(enable);
update(UpdateReason.RSP1A_BIAS_T_CONTROL);
}
}

View File

@@ -0,0 +1,61 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.Rsp2CompositeParameters;
/**
* RSP2 Device
*/
public class Rsp2Device extends Device<Rsp2CompositeParameters, Rsp2Tuner>
{
private Rsp2Tuner mTuner1;
/**
* Constructs an SDRPlay RSP2 device from the foreign memory segment
*
* @param sdrPlay api instance that created this device
* @param deviceStruct parser
*/
Rsp2Device(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
super(sdrPlay, deviceStruct);
}
@Override
public Rsp2Tuner getTuner() throws SDRPlayException
{
if(!isSelected())
{
throw new SDRPlayException("Device must be selected before accessing the tuner");
}
if(mTuner1 == null)
{
mTuner1 = new Rsp2Tuner(Rsp2Device.this, getAPI(), getTunerSelect(),
getCompositeParameters().getDeviceParameters(), getCompositeParameters().getTunerAParameters(),
getCompositeParameters().getControlAParameters());
}
return mTuner1;
}
}

View File

@@ -0,0 +1,145 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.Rsp2DeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp2AmPort;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp2Antenna;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.Rsp2TunerParameters;
/**
* RSP2 Tuner
*/
public class Rsp2Tuner extends RspTuner<Rsp2DeviceParameters, Rsp2TunerParameters>
{
/**
* Constructs an instance
* @param device parent for this tuner
* @param sdrplay api
* @param tunerSelect to specify which tuner
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public Rsp2Tuner(Device device, SDRplay sdrplay, TunerSelect tunerSelect, Rsp2DeviceParameters deviceParameters,
Rsp2TunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, tunerSelect, deviceParameters, tunerParameters, controlParameters);
}
/**
* Indicates if the external reference output is enabled.
*/
public boolean isExternalReferenceOutput()
{
return getDeviceParameters().isExternalReferenceOutput();
}
/**
* Enables or disables the external reference output
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setExternalReferenceOutput(boolean enable) throws SDRPlayException
{
getDeviceParameters().setExternalReferenceOutput(enable);
update(UpdateReason.RSP2_EXT_REF_CONTROL);
}
/**
* Indicates if the Bias-T is enabled
*/
public boolean isBiasT()
{
return getTunerParameters().isBiasT();
}
/**
* Enables or disables the Bias-T
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setBiasT(boolean enable) throws SDRPlayException
{
getTunerParameters().setBiasT(enable);
update(UpdateReason.RSP2_BIAS_T_CONTROL);
}
/**
* Indicates if the RF notch is enabled
*/
public boolean isRfNotch()
{
return getTunerParameters().isRfNotch();
}
/**
* Enables or disables the RF notch
* @param enable setting
* @throws SDRPlayException if there is an error
*/
public void setRfNotch(boolean enable) throws SDRPlayException
{
getTunerParameters().setRfNotch(enable);
update(UpdateReason.RSP2_RF_NOTCH_CONTROL);
}
/**
* AM port selection
*/
public Rsp2AmPort getAmPort()
{
return getTunerParameters().getAmPort();
}
/**
* Sets the AM port
* @param port to select
* @throws SDRPlayException if there is an error
*/
public void setAmPort(Rsp2AmPort port) throws SDRPlayException
{
getTunerParameters().setAmPort(port);
update(UpdateReason.RSP2_AM_PORT_SELECT);
}
/**
* Antenna selection
*/
public Rsp2Antenna getAntenna()
{
return getTunerParameters().getAntenna();
}
/**
* Sets the antenna
* @param antenna to select
* @throws SDRPlayException if there is an error
*/
public void setAntenna(Rsp2Antenna antenna) throws SDRPlayException
{
getTunerParameters().setAntenna(antenna);
update(UpdateReason.RSP2_ANTENNA_CONTROL);
}
}

View File

@@ -0,0 +1,212 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.RspDuoCompositeParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.IfMode;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.LoMode;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DeviceT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* RSPduo Device
*/
public class RspDuoDevice extends Device<RspDuoCompositeParameters, RspDuoTuner>
{
private static final Logger mLog = LoggerFactory.getLogger(RspDuoDevice.class);
private RspDuoTuner mTuner;
/**
* Constructs an SDRPlay RSPduo device from the foreign memory segment
*
* @param sdrPlay api instance that created this device
* @param deviceStruct parser
*/
RspDuoDevice(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
super(sdrPlay, deviceStruct);
}
/**
* Tuner
* @return tuner
* @throws SDRPlayException if there is an error
*/
@Override
public RspDuoTuner getTuner() throws SDRPlayException
{
if(!isSelected())
{
throw new SDRPlayException("Device must be selected before accessing the tuner");
}
if(mTuner == null)
{
if(getTunerSelect().equals(TunerSelect.TUNER_1))
{
mTuner = new RspDuoTuner1(RspDuoDevice.this, getAPI(),
getCompositeParameters().getDeviceParameters(), getCompositeParameters().getTunerAParameters(),
getCompositeParameters().getControlAParameters());
}
else
{
mTuner = new RspDuoTuner2(RspDuoDevice.this, getAPI(),
getCompositeParameters().getDeviceParameters(), getCompositeParameters().getTunerBParameters(),
getCompositeParameters().getControlBParameters());
}
}
return mTuner;
}
/**
* Selected tuner(s).
*/
@Override
public TunerSelect getTunerSelect()
{
return TunerSelect.fromValue(sdrplay_api_DeviceT.tuner$get(getDeviceMemorySegment()));
}
/**
* Sets the selected tuner(s)
*/
public void setTunerSelect(TunerSelect tunerSelect)
{
sdrplay_api_DeviceT.tuner$set(getDeviceMemorySegment(), tunerSelect.getValue());
}
/**
* RSPduo mode
*/
public RspDuoMode getRspDuoMode()
{
return getDeviceStruct().getRspDuoMode();
}
/**
* Sets RSPduo mode. Note this must be set before selecting the device for use.
* @param mode to set
* @throws SDRPlayException if the device has already been selected
*/
public void setRspDuoMode(RspDuoMode mode) throws SDRPlayException
{
if(isSelected())
{
throw new SDRPlayException("RSPduo device is already selected. Mode can only be set/changed before the " +
"device is selected for use.");
}
getDeviceStruct().setRspDuoMode(mode);
}
/**
* Sample rate when in master/slave mode
*/
public double getRspDuoSampleFrequency()
{
return getDeviceStruct().getRspDuoSampleFrequency();
}
/**
* Sets the sample rate when the device is configured for master mode.
* @param frequency
*/
public void setRspDuoSampleFrequency(double frequency) throws SDRPlayException
{
if(!getRspDuoMode().equals(RspDuoMode.MASTER))
{
throw new SDRPlayException("This method can only be used to set the overall sample rate when the RSPduo " +
"device is configured for master mode.");
}
getDeviceStruct().setRspDuoSampleFrequency(frequency);
}
/**
* Sets the decimation factor for the final sample rate.
* @param decimation as an integer multiple of two (e.g. 1, 2, 4, 8)
* @throws SDRPlayException if there is an error while setting decimation
*/
@Override
public void setDecimation(Decimate decimation) throws SDRPlayException
{
if(getTunerSelect() == TunerSelect.TUNER_1)
{
getCompositeParameters().getControlAParameters().getDecimation().setDecimationFactor(decimation.getValue());
getCompositeParameters().getControlAParameters().getDecimation().setEnabled(decimation.isEnabled());
update(getTunerSelect(), UpdateReason.CONTROL_DECIMATION);
}
else if(getTunerSelect() == TunerSelect.TUNER_2)
{
getCompositeParameters().getControlBParameters().getDecimation().setDecimationFactor(decimation.getValue());
getCompositeParameters().getControlBParameters().getDecimation().setEnabled(decimation.isEnabled());
update(getTunerSelect(), UpdateReason.CONTROL_DECIMATION);
}
else if(getTunerSelect() == TunerSelect.TUNER_BOTH)
{
//Dual-synchronized tuner mode ... let the parent Device class set the value
super.setDecimation(decimation);
}
}
/**
* Sets the IF mode when tuner 2 is selected in single-tuner mode.
* @param ifMode to set
*/
public void setIfModeTuner2(IfMode ifMode)
{
getCompositeParameters().getTunerBParameters().setIfMode(ifMode);
}
/**
* Sets the LO mode when tuner 2 is selected in single-tuner mode.
* @param loMode to set
*/
public void setLoModeTuner2(LoMode loMode)
{
getCompositeParameters().getTunerBParameters().setLoMode(loMode);
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("SDRPplay Device").append("\n");
sb.append("\tType: " + getDeviceType()).append("\n");
sb.append("\tSerial Number: " + getSerialNumber()).append("\n");
sb.append("\tTuner: " + getTunerSelect()).append("\n");
sb.append("\tRSP Duo: " + getRspDuoMode()).append("\n");
sb.append("\tRSP Duo Sample Rate: " + getRspDuoSampleFrequency()).append("\n");
sb.append("\tSelected: " + isSelected());
if(hasCompositeParameters())
{
sb.append("\t").append(getCompositeParameters());
}
return sb.toString();
}
}

View File

@@ -0,0 +1,75 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* RSP-Duo Mode
*/
public enum RspDuoMode
{
SINGLE_TUNER(sdrplay_api_h.sdrplay_api_RspDuoMode_Single_Tuner(), "SINGLE TUNER"),
DUAL_TUNER(sdrplay_api_h.sdrplay_api_RspDuoMode_Dual_Tuner(), "DUAL TUNER"),
MASTER(sdrplay_api_h.sdrplay_api_RspDuoMode_Master(), "MASTER"),
SLAVE(sdrplay_api_h.sdrplay_api_RspDuoMode_Slave(), "SLAVE"),
UNKNOWN(sdrplay_api_h.sdrplay_api_RspDuoMode_Unknown(), "UNKNOWN");
private int mValue;
private String mDescription;
RspDuoMode(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UKNOWN if the code is not recognized
*/
public static RspDuoMode fromValue(int value)
{
for(RspDuoMode status: RspDuoMode.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNKNOWN;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,105 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.RspDuoDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDuoTunerParameters;
/**
* RSPduo Tuner
*/
public abstract class RspDuoTuner extends RspTuner<RspDuoDeviceParameters, RspDuoTunerParameters>
{
/**
* Constructs an instance
* @param device parent for this tuner
* @param sdrplay api
* @param tunerSelect to specify which tuner
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public RspDuoTuner(Device device, SDRplay sdrplay, TunerSelect tunerSelect, RspDuoDeviceParameters deviceParameters,
RspDuoTunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, tunerSelect, deviceParameters, tunerParameters, controlParameters);
}
/**
* Indicates if the RF notch is enabled
*/
public boolean isRFNotch()
{
return getTunerParameters().isRfNotch();
}
/**
* Enables or disables the RF notch
* @param enable setting
* @throws SDRPlayException if there is an error
*/
public void setRfNotch(boolean enable) throws SDRPlayException
{
getTunerParameters().setRfNotch(enable);
update(UpdateReason.RSP_DUO_RF_NOTCH_CONTROL);
}
/**
* Indicates if the RF DAB notch is enabled
*/
public boolean isRfDabNotch()
{
return getTunerParameters().isRfDabNotch();
}
/**
* Enables or disables the RF DAB notch
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setRfDabNotch(boolean enable) throws SDRPlayException
{
getTunerParameters().setRfDabNotch(enable);
update(UpdateReason.RSP_DUO_RF_DAB_NOTCH_CONTROL);
}
/**
* Indicates if the external reference output is enabled.
*/
public boolean isExternalReferenceOutput()
{
return getDeviceParameters().isExternalReferenceOutput();
}
/**
* Enables or disables the external reference output
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setExternalReferenceOutput(boolean enable) throws SDRPlayException
{
getDeviceParameters().setExternalReferenceOutput(enable);
update(UpdateReason.RSP_DUO_EXT_REF_CONTROL);
}
}

View File

@@ -0,0 +1,87 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.RspDuoDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDuoAmPort;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDuoTunerParameters;
/**
* RSPduo Tuner 1
*/
public class RspDuoTuner1 extends RspDuoTuner
{
/**
* Constructs an instance
*
* @param device parent for this tuner
* @param sdrplay api
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public RspDuoTuner1(Device device, SDRplay sdrplay, RspDuoDeviceParameters deviceParameters,
RspDuoTunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, TunerSelect.TUNER_1, deviceParameters, tunerParameters, controlParameters);
}
/**
* Indicates which AM port is selected
*/
public RspDuoAmPort getAmPort()
{
return getTunerParameters().getTuner1AmPort();
}
/**
* Selects the AM port to use
* @param port to use
* @throws SDRPlayException if there is an error
*/
public void setAmPort(RspDuoAmPort port) throws SDRPlayException
{
getTunerParameters().setTuner1AmPort(port);
update(UpdateReason.RSP_DUO_AM_PORT_SELECT);
}
/**
* Indicates if the AM notch is enabled
*/
public boolean isAmNotch()
{
return getTunerParameters().isTuner1AmNotch();
}
/**
* Enables or disables the AM notch
* @param enable for the notch
* @throws SDRPlayException if there is an error
*/
public void setAmNotch(boolean enable) throws SDRPlayException
{
getTunerParameters().setTuner1AmNotch(enable);
update(UpdateReason.RSP_DUO_TUNER_1_AM_NOTCH_CONTROL);
}
}

View File

@@ -0,0 +1,67 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.RspDuoDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDuoTunerParameters;
/**
* RSPduo Tuner 2
*/
public class RspDuoTuner2 extends RspDuoTuner
{
/**
* Constructs an instance
*
* @param device parent for this tuner
* @param sdrplay api
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public RspDuoTuner2(Device device, SDRplay sdrplay, RspDuoDeviceParameters deviceParameters,
RspDuoTunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, TunerSelect.TUNER_2, deviceParameters, tunerParameters, controlParameters);
}
/**
* Indicates if the Bias-T is enabled
*/
public boolean isBiasT()
{
return getTunerParameters().isBiasT();
}
/**
* Enables or disables the Bias-T
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setBiasT(boolean enable) throws SDRPlayException
{
getTunerParameters().setBiasT(enable);
update(UpdateReason.RSP_DUO_BIAS_T_CONTROL);
}
}

View File

@@ -0,0 +1,62 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite.RspDxCompositeParameters;
/**
* RSPdx Device
*/
public class RspDxDevice extends Device<RspDxCompositeParameters, RspDxTuner>
{
private RspDxTuner mTuner1;
/**
* Constructs an SDRPlay RSPdx device from the foreign memory segment
*
* @param sdrPlay api instance that created this device
* @param deviceStruct parser
*/
RspDxDevice(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
super(sdrPlay, deviceStruct);
}
@Override
public RspDxTuner getTuner() throws SDRPlayException
{
if(!isSelected())
{
throw new SDRPlayException("Device must be selected before accessing the tuner");
}
if(mTuner1 == null)
{
mTuner1 = new RspDxTuner(RspDxDevice.this, getAPI(), getTunerSelect(),
getCompositeParameters().getDeviceParameters(), getCompositeParameters().getTunerAParameters(),
getCompositeParameters().getControlAParameters());
}
return mTuner1;
}
}

View File

@@ -0,0 +1,164 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
import io.github.dsheirer.source.tuner.sdrplay.api.UpdateReason;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.RspDxDeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.HdrModeBandwidth;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDxAntenna;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.RspDxTunerParameters;
/**
* RSPdx Tuner
*/
public class RspDxTuner extends RspTuner<RspDxDeviceParameters, RspDxTunerParameters>
{
/**
* Constructs an instance
* @param device parent for this tuner
* @param sdrplay api
* @param tunerSelect to specify which tuner
* @param deviceParameters for this device
* @param tunerParameters for this tuner
* @param controlParameters for this device
*/
public RspDxTuner(Device device, SDRplay sdrplay, TunerSelect tunerSelect, RspDxDeviceParameters deviceParameters,
RspDxTunerParameters tunerParameters, ControlParameters controlParameters)
{
super(device, sdrplay, tunerSelect, deviceParameters, tunerParameters, controlParameters);
}
/**
* Indicates if HDR mode is enabled
*/
public boolean isHdrMode()
{
return getDeviceParameters().isHdr();
}
/**
* Enables or disables HDR mode
* @param enable mode
* @throws SDRPlayException if there is an error
*/
public void setHdrMode(boolean enable) throws SDRPlayException
{
getDeviceParameters().setHdr(enable);
update(UpdateReason.EXTENSION_RSP_DX_HDR_ENABLE);
}
/**
* HDR mode bandwidth
*/
public HdrModeBandwidth getHdrModeBandwidth()
{
return getTunerParameters().getHdrModeBandwidth();
}
/**
* Sets HDR mode bandwidth
* @param bandwidth to select
* @throws SDRPlayException if there is an error
*/
public void setHdrModeBandwidth(HdrModeBandwidth bandwidth) throws SDRPlayException
{
getTunerParameters().setHdrModeBandwidth(bandwidth);
update(UpdateReason.EXTENSION_RSP_DX_HDR_BANDWIDTH);
}
/**
* Indicates if the RF notch is enabled
*/
public boolean isRfNotch()
{
return getDeviceParameters().isRfNotch();
}
/**
* Enables or disables the RF notch
* @param enable setting
* @throws SDRPlayException if there is an error
*/
public void setRfNotch(boolean enable) throws SDRPlayException
{
getDeviceParameters().setRfNotch(enable);
update(UpdateReason.EXTENSION_RSP_DX_RF_NOTCH_CONTROL);
}
/**
* Indicates if the RF DAB notch is enabled
*/
public boolean isRfDabNotch()
{
return getDeviceParameters().isRfDabNotch();
}
/**
* Enables or disables the RF DAB notch
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setRfDabNotch(boolean enable) throws SDRPlayException
{
getDeviceParameters().setRfDabNotch(enable);
update(UpdateReason.EXTENSION_RSP_DX_RF_DAB_NOTCH_CONTROL);
}
/**
* Indicates if the Bias-T is enabled
*/
public boolean isBiasT()
{
return getDeviceParameters().isBiasT();
}
/**
* Enables or disables the Bias-T
* @param enable value
* @throws SDRPlayException if there is an error
*/
public void setBiasT(boolean enable) throws SDRPlayException
{
getDeviceParameters().setBiasT(enable);
update(UpdateReason.EXTENSION_RSP_DX_BIAS_T_CONTROL);
}
/**
* Antenna selection
*/
public RspDxAntenna getAntenna()
{
return getDeviceParameters().getRspDxAntenna();
}
/**
* Sets the antenna selection
* @param antenna to select
* @throws SDRPlayException if there is an error
*/
public void setAntenna(RspDxAntenna antenna) throws SDRPlayException
{
getDeviceParameters().setRspDxAntenna(antenna);
update(UpdateReason.EXTENSION_RSP_DX_ANTENNA_CONTROL);
}
}

View File

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

View File

@@ -0,0 +1,74 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* Tuner Select
*/
public enum TunerSelect
{
TUNER_1(sdrplay_api_h.sdrplay_api_Tuner_A(), "TUNER 1"),
TUNER_2(sdrplay_api_h.sdrplay_api_Tuner_B(), "TUNER 2"),
TUNER_BOTH(sdrplay_api_h.sdrplay_api_Tuner_Both(), "TUNER 1 & 2"),
NEITHER(sdrplay_api_h.sdrplay_api_Tuner_Neither(), "NEITHER");
private int mValue;
private String mDescription;
TunerSelect(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or NEITHER if the code is not recognized
*/
public static TunerSelect fromValue(int value)
{
for(TunerSelect status: TunerSelect.values())
{
if(status.getValue() == value)
{
return status;
}
}
return NEITHER;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,46 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.device;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayException;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRplay;
/**
* Unknown or Unrecognized SDRplay Device
*/
public class UnknownDevice extends Device
{
/**
* Constructs an Unknown SDRPlay device from the foreign memory segment
*
* @param sdrPlay api instance that created this device
* @param deviceStruct parser
*/
UnknownDevice(SDRplay sdrPlay, IDeviceStruct deviceStruct)
{
super(sdrPlay, deviceStruct);
}
@Override
public RspTuner getTuner() throws SDRPlayException
{
throw new SDRPlayException("Unrecognized device type. Cannot construct tuner");
}
}

View File

@@ -0,0 +1,76 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.error;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_h;
/**
* Debug Level
*/
public enum DebugLevel
{
DISABLE(sdrplay_api_h.sdrplay_api_DbgLvl_Disable(), "DISABLE"),
VERBOSE(sdrplay_api_h.sdrplay_api_DbgLvl_Verbose(), "VERBOSE"),
WARNING(sdrplay_api_h.sdrplay_api_DbgLvl_Warning(), "WARNING"),
ERROR(sdrplay_api_h.sdrplay_api_DbgLvl_Error(), "ERROR"),
MESSAGE(sdrplay_api_h.sdrplay_api_DbgLvl_Message(), "MESSAGE"),
UNKNOWN(-1, "UNKNOWN");
private int mValue;
private String mDescription;
DebugLevel(int value, String description)
{
mValue = value;
mDescription = description;
}
/**
* Numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Lookup the entry from a return code
* @param value to lookup
* @return entry or UNKNOWN if the code is not recognized
*/
public static DebugLevel fromValue(int value)
{
for(DebugLevel status: DebugLevel.values())
{
if(status.getValue() == value)
{
return status;
}
}
return UNKNOWN;
}
@Override
public String toString()
{
return mDescription;
}
}

View File

@@ -0,0 +1,77 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.error;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_ErrorInfoT;
import java.lang.foreign.MemorySegment;
/**
* Error Information structure (sdrplay_api_ErrorInfoT)
*/
public class ErrorInformation
{
private String mFile;
private String mFunction;
private int mLine;
private String mMessage;
/**
* Constructs an instance from the foreign memory segment
*/
public ErrorInformation(MemorySegment memorySegment)
{
mFile = sdrplay_api_ErrorInfoT.file$slice(memorySegment).getUtf8String(0);
mFunction = sdrplay_api_ErrorInfoT.function$slice(memorySegment).getUtf8String(0);
mLine = sdrplay_api_ErrorInfoT.line$get(memorySegment);
mMessage = sdrplay_api_ErrorInfoT.message$slice(memorySegment).getUtf8String(0);
}
public String getFile()
{
return mFile;
}
public String getFunction()
{
return mFunction;
}
public int getLine()
{
return mLine;
}
public String getMessage()
{
return mMessage;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Error Information:").append("\n");
sb.append("\t File: ").append(getFile()).append("\n");
sb.append("\tFunction: ").append(getFunction()).append("\n");
sb.append("\t Line: ").append(getLine()).append("\n");
sb.append("\t Message: ").append(getMessage()).append("\n");
return sb.toString();
}
}

View File

@@ -0,0 +1,108 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.sdrplay.api.parameter.composite;
import io.github.dsheirer.source.tuner.sdrplay.api.device.DeviceType;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.control.ControlParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.DeviceParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.device.DeviceParametersFactory;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.TunerParameters;
import io.github.dsheirer.source.tuner.sdrplay.api.parameter.tuner.TunerParametersFactory;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DevParamsT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_DeviceParamsT;
import io.github.dsheirer.source.tuner.sdrplay.api.v3_07.sdrplay_api_RxChannelParamsT;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
/**
* Composite Device Parameters structure (sdrplay_api_DeviceParamsT) providing access to the device parameters and
* the tuner 1 parameters. Tuner 2 parameters are only accessible via the RSPduo sub-class implementation.
*
* Note: sub-class implementations will constrain access to the appropriate sub-structures of the DeviceParamsT
* structure for each specific device.
*/
public class CompositeParameters<D extends DeviceParameters, T extends TunerParameters>
{
private D mDeviceParameters;
private T mTunerAParameters;
private ControlParameters mControlAParameters;
/**
* Constructs an instance from the foreign memory segment
*
* @param deviceType to create
* @param memorySegment for the composite structure in foreign memory
* @param memorySession for allocating additional memory segments for the sub-structures.
*/
public CompositeParameters(DeviceType deviceType, MemorySegment memorySegment, MemorySession memorySession)
{
MemoryAddress parametersMemoryAddress = sdrplay_api_DeviceParamsT.devParams$get(memorySegment);
MemorySegment parametersMemorySegment = sdrplay_api_DevParamsT.ofAddress(parametersMemoryAddress, memorySession);
mDeviceParameters = (D) DeviceParametersFactory.create(deviceType, parametersMemorySegment);
MemoryAddress memoryAddressRxA = sdrplay_api_DeviceParamsT.rxChannelA$get(memorySegment);
MemorySegment memorySegmentRxA = sdrplay_api_RxChannelParamsT.ofAddress(memoryAddressRxA, memorySession);
mTunerAParameters = (T) TunerParametersFactory.create(deviceType, memorySegmentRxA);
MemorySegment tunerAControlParametersMemorySegment = sdrplay_api_RxChannelParamsT.ctrlParams$slice(memorySegmentRxA);
mControlAParameters = new ControlParameters(tunerAControlParametersMemorySegment);
}
/**
* Device parameters
*/
public D getDeviceParameters()
{
return mDeviceParameters;
}
/**
* Tuner A Parameters.
*
* Note: this is normally mapped to tuner 1. In the RSPduo, this is mapped to Tuner 1 or Tuner 2, according to how
* the user has setup the TunerSelect.
*/
public T getTunerAParameters()
{
return mTunerAParameters;
}
/**
* Tuner A Control Parameters
*
* Note: this is normally mapped to tuner 1. In the RSPduo, this is mapped to Tuner 1 or Tuner 2, according to how
* the user has setup the TunerSelect.
*/
public ControlParameters getControlAParameters()
{
return mControlAParameters;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("Composite Parameters\n");
sb.append("\tDevice Parameters:\n").append(getDeviceParameters()).append("\n");
sb.append("\tTuner A Parameters:\n").append(getTunerAParameters()).append("\n");
return sb.toString();
}
}

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