Skip to content

Commit

Permalink
Merge pull request #1 from neilharvey94044/additional-sdrplay-features
Browse files Browse the repository at this point in the history
Add additional device features
  • Loading branch information
Sammy1Am authored Feb 16, 2021
2 parents a548830 + 0ca8b8d commit 17347cd
Show file tree
Hide file tree
Showing 7 changed files with 445 additions and 42 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ A Java wrapper for the [SDRplay API v3](https://www.sdrplay.com/) using [JNR-FFI
* The Java-like wrapper will only expose limited functionality at first to the extent that I'm able to test it.
* I only have an RSP1, so it's possible some of the features that work for me may not work on other hardware.
* The JNR wrapper is largely complete except for some model-specifc features. The friendly Java API is less complete and only contains a few core controls, but should be sufficient for basic use.
* http://jnrproject.org/jnr-ffi/apidocs/index.html NDH: found these which may or may not be useful

### Modifications v0.7.0 Neil Harvey 2021
* Updated structs to cover all device parameters for all API supported SDRplay devices
* Provided methods for updating the following parameters:
* Automatic Gain Control (AGC)
* Decimation
* DC Offset
* Broadcast FM Notch (RSP1A only)
* Digital Audio Broadcast (DAB) Notch (RSP1A only)
* Bias-T (RSP1A only)

#### With Thanks To
The [SerCeMan/jnr-fuse](https://github.com/SerCeMan/jnr-fuse) project for being an excellent example of working, complex JNR code.
10 changes: 7 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ dependencies {
}

// Publishing Info
version = '0.6.0'
version = '0.7.0'

task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
Expand All @@ -40,6 +40,10 @@ def pomConfig = {
id "Sammy1Am"
name "Sam A"
}
developer {
id "neilharvey94044"
name "Neil Harvey"
}
}

scm {
Expand All @@ -52,7 +56,7 @@ publishing {
maven(MavenPublication) {
groupId = 'io.github.sammy1am'
artifactId = 'SDRplayJava'
version = '0.6.0'
version = '0.7.0'

from components.java
artifact sourcesJar {
Expand Down Expand Up @@ -90,4 +94,4 @@ bintray {
}
}

}
}
12 changes: 8 additions & 4 deletions src/main/java/io/github/sammy1am/sdrplay/SDRplayAPI.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.sammy1am.sdrplay;

import io.github.sammy1am.sdrplay.model.RSPDuo;
import io.github.sammy1am.sdrplay.model.RSP1A;
import io.github.sammy1am.sdrplay.jnr.SDRplayAPIJNR;
import io.github.sammy1am.sdrplay.jnr.SDRplayAPIJNR.ErrT;
import java.util.ArrayList;
Expand Down Expand Up @@ -64,11 +65,14 @@ public static List<SDRplayDevice> getDevices(int maximumDevices) {

for (int d=0;d<numDevices.intValue();d++) {
// Create a new SDRplayDevice using the native device and add it to the list
switch (devices[d].hwVer.byteValue()) {
switch ((int) devices[d].hwVer.byteValue() & 0xFF) {
//TODO Add device classes for other models
case 3:
returnDevices.add(new RSPDuo(devices[d]));
break;
case 255:
returnDevices.add(new RSP1A(devices[d]));
break;
case 1:
default:
returnDevices.add(new SDRplayDevice(devices[d]));
Expand All @@ -79,12 +83,12 @@ public static List<SDRplayDevice> getDevices(int maximumDevices) {
}

public static enum HWModel {
UNKNOWN(-1),
UNKNOWN(0),
RSP1(1),
RSP1A(255),
RSP2(2),
RSPduo(3),
RSPdx(4);
RSPDUO(3),
RSPDX(4);

private final int val;

Expand Down
152 changes: 139 additions & 13 deletions src/main/java/io/github/sammy1am/sdrplay/SDRplayDevice.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.github.sammy1am.sdrplay.jnr.CallbackFnsT.EventParamsT;
import io.github.sammy1am.sdrplay.jnr.CallbackFnsT.EventT;
import io.github.sammy1am.sdrplay.jnr.CallbackFnsT.StreamCbParamsT;
import io.github.sammy1am.sdrplay.jnr.ControlParamsT.AgcControlT;
import io.github.sammy1am.sdrplay.jnr.DeviceParamsT;
import io.github.sammy1am.sdrplay.jnr.SDRplayAPIJNR;
import io.github.sammy1am.sdrplay.jnr.SDRplayAPIJNR.DbgLvl_t;
Expand Down Expand Up @@ -82,13 +83,13 @@ public void call(EventT eventId, TunerSelectT tuner, EventParamsT params, Pointe
/** Has this device been selected. Used to optimize parameter retrieval,
* and make sure we're not trying anything fishy with an un-selected device.
*/
private boolean isSelected = false;
protected boolean isSelected = false;

/**
* Has this device been initialized. Used to determine if update() needs to be
* called after settings changes or not.
*/
private boolean isInitialized = false;
protected boolean isInitialized = false;

/**
* Specifies the number of LNA states available for this device. At time of coding
Expand All @@ -114,8 +115,8 @@ public String getSerialNumber() {
}

public HWModel getHWModel() {
return HWModel.valueOf((int)nativeDevice.hwVer.byteValue());
}
return HWModel.valueOf((int)nativeDevice.hwVer.byteValue() & 0xff);
}

public TunerSelectT getTunerSelect() {
return nativeDevice.tuner.get();
Expand Down Expand Up @@ -181,33 +182,46 @@ public byte getNumLNAStates() {
return this.NUM_LNA_STATES;
}

/*******************
/*
* DEVICE PARAMETERS
* *****************
* Methods to get and set device parameters. There are a lot of these, so
* the most used ones will be added first.
*/

private void doUpdate(ReasonForUpdateT reason) {
protected void doUpdate(ReasonForUpdateT reason) {
ApiException.checkErrorCode(JNRAPI.sdrplay_api_Update(nativeDevice.dev.get(),
TunerSelectT.Tuner_A, // TODO: assume TunerA here for now-- maybe get this from nativeDevice?
reason,
ReasonForUpdateExtension1T.Update_Ext1_None));
}

/**
*
* sdrplay_api_DevParamsT.sdrplay_api_FsFreqT.fsHz
* @return Sample rate in Hz
*/
public double getSampleRate() {
return nativeParams.devParams.get().fsFreq.fsHz.get();
}


public void setSampleRate(double newSampleRate) {
nativeParams.devParams.get().fsFreq.fsHz.set(newSampleRate);
if (isInitialized) doUpdate(ReasonForUpdateT.Update_Dev_Fs);
}

public void setSampleRateAndIF(double newSampleRate, Bw_MHzT newBwType, If_kHzT newIfType) {
nativeParams.devParams.get().fsFreq.fsHz.set(newSampleRate);
nativeParams.rxChannelA.get().tunerParams.bwType.set(newBwType);
nativeParams.rxChannelA.get().tunerParams.ifType.set(newIfType);
if (isInitialized) doUpdate(ReasonForUpdateT.Update_Custom_sdrtrunk_SampleRateChange);

}

/**
* sdrplay_api_DeviceParamsT.sdrplay_api_DevParamsT.ppm
* @return Parts Per Million correction
*/
public double getPPM() {
return nativeParams.devParams.get().ppm.get();
}
Expand All @@ -217,9 +231,13 @@ public void setPPM(double newPPM) {
if (isInitialized) doUpdate(ReasonForUpdateT.Update_Dev_Ppm);
}

// TODO: All of these assume TunerA, but for a dual tuner would need to specify
// Made create a Tuner object that Devices can contain up to two of??
// Assumes Tuner A for all following settings

/**
* sdrplay_api_TunerParamsT.bwType
* @return Intermediate Frequency Bandwidth
*
*/
public Bw_MHzT getBwType() {
return nativeParams.rxChannelA.get().tunerParams.bwType.get();
}
Expand All @@ -229,6 +247,12 @@ public void setBwType(Bw_MHzT newBwType) {
if (isInitialized) doUpdate(ReasonForUpdateT.Update_Tuner_BwType);
}

/**
* sdrplay_api_TunerParamsT.ifType
* An enum value from sdrplay_api_If_kHzT
*
* @return Intermediate Frequency Type (see sdrplay_api_If_kHzT enum for values)
*/
public If_kHzT getIfType() {
return nativeParams.rxChannelA.get().tunerParams.ifType.get();
}
Expand All @@ -238,15 +262,92 @@ public void setIfType(If_kHzT newIfType) {
if (isInitialized) doUpdate(ReasonForUpdateT.Update_Tuner_IfType);
}

/**
*
* @return Local Oscillator Mode
*/
public LoModeT getLoMode() {
return nativeParams.rxChannelA.get().tunerParams.loMode.get();
return nativeParams.rxChannelA.get().tunerParams.loMode.get();
}

public void setLoMode(LoModeT newLoMode) {
nativeParams.rxChannelA.get().tunerParams.loMode.set(newLoMode);
if (isInitialized) doUpdate(ReasonForUpdateT.Update_Tuner_LoMode);
nativeParams.rxChannelA.get().tunerParams.loMode.set(newLoMode);
if (isInitialized) doUpdate(ReasonForUpdateT.Update_Tuner_LoMode);
}

/**
* DC Offset
* @param enableDC enable or disable DC Offset
*/
public void setDcOffset(boolean enableDC) {
nativeParams.rxChannelA.get().ctrlParams.dcOffset.DCenable.set(enableDC ? 1: 0);
nativeParams.rxChannelA.get().ctrlParams.dcOffset.IQenable.set(enableDC ? 1: 0);

if(isInitialized) doUpdate(ReasonForUpdateT.Update_Ctrl_DCoffsetIQimbalance);
}

/**
* Override in model specific subclass
* @return FM Broadcast Notch state
*/
public boolean getRfNotch() {
return false;
}
public void setRfNotch(boolean rfNotch) {
//defaults to no operation
}

/**
* Override in model specific subclass
* @return Digital Audio Broadcast Notch state
*/
public boolean getDABNotch() {
return false;
}
public void setDABNotch(boolean dabNotch) {
//defaults to no operation
}

/**
* Override in model specific subclass
* @return BiasT - puts current on the antenna to power pre-amplifiers
*/
public boolean getBiasT() {
return false;
}
public void setBiasT(boolean biasT) {
//defaults to no operation
}

/**
* @return Automatic Gain Control
*/
public boolean getAGCEnabled() {
return nativeParams.rxChannelA.get().ctrlParams.agc.enable.get() != AgcControlT.AGC_DISABLE;
}

public void setAGCEnabled(boolean enabled) {
if(enabled) {
nativeParams.rxChannelA.get().ctrlParams.agc.enable.set(AgcControlT.AGC_50HZ);
nativeParams.rxChannelA.get().ctrlParams.agc.setPoint_dBfs.set(-30);
nativeParams.rxChannelA.get().ctrlParams.agc.attack_ms.set(500);
nativeParams.rxChannelA.get().ctrlParams.agc.decay_delay_ms.set(200);
nativeParams.rxChannelA.get().ctrlParams.agc.decay_threshold_dB.set(5);
nativeParams.rxChannelA.get().ctrlParams.agc.syncUpdate.set(0);
}
else {
nativeParams.rxChannelA.get().ctrlParams.agc.enable.set(AgcControlT.AGC_DISABLE);
}
if (isInitialized) doUpdate(ReasonForUpdateT.Update_Ctrl_Agc);

}

/**
* sdrplay_api_TunerParamsT.sdrplay_api_GainT.LNAstate
* Review tables in SDRplay API documentation for valid values
*
* @return Low Noise Amplifier Gain Reduction State
*/
public byte getLNAState() {
return nativeParams.rxChannelA.get().tunerParams.gain.LNAstate.byteValue();
}
Expand All @@ -256,15 +357,40 @@ public void setLNAState(byte newLNAState) {
if (isInitialized) doUpdate(ReasonForUpdateT.Update_Tuner_Gr);
}

/**
* sdrplay_api_TunerParamsT.sdrplay_api_RfFreqT.rfHz
* Tuned Radio Frequency - aka center frequency?
*
* @return Tuned Frequency
*/
public double getRfHz() {
return nativeParams.rxChannelA.get().tunerParams.rfFreq.rfHz.get();
}

public void setRfHz(double newRfHz) {
//System.out.printf("Setting Frequency: %fl", newRfHz);
nativeParams.rxChannelA.get().tunerParams.rfFreq.rfHz.set(newRfHz);
if (isInitialized) doUpdate(ReasonForUpdateT.Update_Tuner_Frf);
}


/**
* @return Decimation Factor
*/
public int getDecFactor() {
return nativeParams.rxChannelA.get().ctrlParams.decimation.decimationFactor.get();
}
public void setDecFactor(int newDecFactor) {
boolean sampleRateBelow5M = getSampleRate() <= 5_000_000;
nativeParams.rxChannelA.get().ctrlParams.decimation.decimationFactor.set((newDecFactor > 1) && sampleRateBelow5M ? newDecFactor : 0);
nativeParams.rxChannelA.get().ctrlParams.decimation.enable.set((newDecFactor > 1) && sampleRateBelow5M ? 1 : 0);
nativeParams.rxChannelA.get().ctrlParams.decimation.wideBandSignal.set(0);

if (isInitialized) doUpdate(ReasonForUpdateT.Update_Ctrl_Decimation);
}

/**
* Tells the SDRPlay device we have received its antenna overload callback
*/
public void acknowledgeOverload() {
if (isInitialized) doUpdate(ReasonForUpdateT.Update_Ctrl_OverloadMsgAck);
}
Expand Down
Loading

0 comments on commit 17347cd

Please sign in to comment.