Skip to content

Commit f877354

Browse files
DSheirerDennis Sheirer
andauthored
DSheirer#1455 Add Airspy HF+/Discovery Tuner Support (DSheirer#1524)
* DSheirer#1455 Add support for airspy hf+/discovery tuners * DSheirer#1455 testing updates --------- Co-authored-by: Dennis Sheirer <[email protected]>
1 parent df3d3b5 commit f877354

21 files changed

+1870
-14
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ repositories {
5353
maven { url "https://jitpack.io" }
5454
}
5555

56-
version = '0.6.0-alpha5'
56+
version = '0.6.0-alpha6'
5757

5858
//Java 19 is required for this version of the Project Panama preview/incubator feature
5959
java {

src/main/java/io/github/dsheirer/buffer/DcCorrectionManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2022 Dennis Sheirer
3+
* Copyright (C) 2014-2023 Dennis Sheirer
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -84,7 +84,7 @@ public void adjust(float calculatedDc)
8484
{
8585
mDcCalculationsRemaining--;
8686
}
87-
//
87+
8888
// mLog.info("DC: " + mDecimalFormat.format(mAverageDc) +
8989
// " RES:" + mDecimalFormat.format(residualOffsetToRemove) +
9090
// " REM:" + mDcCalculationsRemaining);
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* *****************************************************************************
3+
* Copyright (C) 2014-2023 Dennis Sheirer
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>
17+
* ****************************************************************************
18+
*/
19+
20+
package io.github.dsheirer.buffer.airspy.hf;
21+
22+
import io.github.dsheirer.buffer.AbstractNativeBuffer;
23+
import io.github.dsheirer.sample.complex.ComplexSamples;
24+
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
25+
import java.util.Iterator;
26+
27+
/**
28+
* Native buffer implementation for Airspy HF+ & Discovery tuners.
29+
*/
30+
public class AirspyHfNativeBuffer extends AbstractNativeBuffer
31+
{
32+
public static final float SCALE = 1.0f / 32768.0f;
33+
private short[] mInterleavedSamples;
34+
private float mAverageDc;
35+
36+
/**
37+
* Constructs an instance.
38+
* @param timestamp of the first sample of the buffer
39+
* @param interleavedSamples pairs of 16-bit complex samples.
40+
*/
41+
public AirspyHfNativeBuffer(long timestamp, float samplesPerMillisecond, float averageDc, short[] interleavedSamples)
42+
{
43+
super(timestamp, samplesPerMillisecond);
44+
mInterleavedSamples = interleavedSamples;
45+
mAverageDc = averageDc;
46+
}
47+
48+
@Override
49+
public Iterator<ComplexSamples> iterator()
50+
{
51+
return new IteratorComplexSamples();
52+
}
53+
54+
@Override
55+
public Iterator<InterleavedComplexSamples> iteratorInterleaved()
56+
{
57+
return new IteratorInterleaved();
58+
}
59+
60+
@Override
61+
public int sampleCount()
62+
{
63+
return mInterleavedSamples.length / 2;
64+
}
65+
66+
/**
67+
* Scalar implementation of complex samples buffer iterator
68+
*/
69+
public class IteratorComplexSamples implements Iterator<ComplexSamples>
70+
{
71+
private boolean mHasNext = true;
72+
73+
@Override
74+
public boolean hasNext()
75+
{
76+
return mHasNext;
77+
}
78+
79+
@Override
80+
public ComplexSamples next()
81+
{
82+
int length = mInterleavedSamples.length / 2;
83+
float[] i = new float[length];
84+
float[] q = new float[length];
85+
86+
int index = 0;
87+
88+
for(int x = 0; x < mInterleavedSamples.length; x += 2)
89+
{
90+
index = x / 2;
91+
//Native ordering is in Q, I, Q, I ... reverse it to I, Q, I, Q
92+
i[index] = (mInterleavedSamples[x + 1] * SCALE) - mAverageDc;
93+
q[index] = (mInterleavedSamples[x] * SCALE) - mAverageDc;
94+
}
95+
96+
mHasNext = false;
97+
98+
return new ComplexSamples(i, q, getTimestamp());
99+
}
100+
}
101+
102+
/**
103+
* Scalar implementation of interleaved sample buffer iterator.
104+
*/
105+
public class IteratorInterleaved implements Iterator<InterleavedComplexSamples>
106+
{
107+
private boolean mHasNext = true;
108+
109+
@Override
110+
public boolean hasNext()
111+
{
112+
return mHasNext;
113+
}
114+
115+
@Override
116+
public InterleavedComplexSamples next()
117+
{
118+
float[] samples = new float[mInterleavedSamples.length];
119+
120+
for(int x = 0; x < mInterleavedSamples.length; x += 2)
121+
{
122+
//Native ordering is in Q, I, Q, I ... reverse it to I, Q, I, Q
123+
samples[x] = (mInterleavedSamples[x + 1] * SCALE) - mAverageDc;
124+
samples[x + 1] = (mInterleavedSamples[x] * SCALE) - mAverageDc;
125+
}
126+
127+
mHasNext = false;
128+
129+
return new InterleavedComplexSamples(samples, getTimestamp());
130+
}
131+
}
132+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* *****************************************************************************
3+
* Copyright (C) 2014-2023 Dennis Sheirer
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>
17+
* ****************************************************************************
18+
*/
19+
20+
package io.github.dsheirer.buffer.airspy.hf;
21+
22+
import io.github.dsheirer.buffer.AbstractNativeBufferFactory;
23+
import io.github.dsheirer.buffer.DcCorrectionManager;
24+
import io.github.dsheirer.buffer.INativeBuffer;
25+
import java.nio.ByteBuffer;
26+
import java.nio.ByteOrder;
27+
import java.nio.ShortBuffer;
28+
29+
/**
30+
* Airspy HF+ native buffer factory.
31+
*
32+
* Note: the tuner provides 1024 samples in each transfer where samples are 16-bit interleaved complex.
33+
*/
34+
public class AirspyHfNativeBufferFactory extends AbstractNativeBufferFactory
35+
{
36+
private DcCorrectionManager mDcCorrectionManager = new DcCorrectionManager();
37+
38+
/**
39+
* Constructs an instance
40+
*/
41+
public AirspyHfNativeBufferFactory()
42+
{
43+
}
44+
45+
/**
46+
* Converts the samples byte buffer into a native buffer and calculates DC offset
47+
* @param samples byte array copied from native memory
48+
* @param timestamp of the samples
49+
* @return constructed native buffer
50+
*/
51+
@Override
52+
public INativeBuffer getBuffer(ByteBuffer samples, long timestamp)
53+
{
54+
ShortBuffer shortBuffer = samples.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
55+
short[] converted = new short[shortBuffer.capacity()];
56+
shortBuffer.get(converted);
57+
58+
if(mDcCorrectionManager.shouldCalculateDc())
59+
{
60+
calculateDc(converted);
61+
}
62+
63+
return new AirspyHfNativeBuffer(timestamp, getSamplesPerMillisecond(), mDcCorrectionManager.getAverageDc(), converted);
64+
}
65+
66+
/**
67+
* Calculates the average DC in the sample stream so that it can be subtracted from the samples when the
68+
* native buffer is used.
69+
* @param samples containing DC offset
70+
*/
71+
private void calculateDc(short[] samples)
72+
{
73+
float dcAccumulator = 0;
74+
75+
for(short sample: samples)
76+
{
77+
dcAccumulator += sample;
78+
}
79+
80+
dcAccumulator /= samples.length;
81+
mDcCorrectionManager.adjust(dcAccumulator * AirspyHfNativeBuffer.SCALE);
82+
}
83+
}

src/main/java/io/github/dsheirer/source/tuner/TunerClass.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2022 Dennis Sheirer
3+
* Copyright (C) 2014-2023 Dennis Sheirer
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@
2626
public enum TunerClass
2727
{
2828
AIRSPY("Airspy"),
29+
AIRSPY_HF("Airspy HF+"),
2930
FUNCUBE_DONGLE_PRO("Funcube Dongle Pro" ),
3031
FUNCUBE_DONGLE_PRO_PLUS("Funcube Dongle Pro+" ),
3132
HACKRF("HackRF" ),
@@ -52,7 +53,7 @@ public String toString()
5253
return mDescription;
5354
}
5455

55-
public static final EnumSet<TunerClass> SUPPORTED_USB_TUNERS = EnumSet.of(AIRSPY, HACKRF, RTL2832,
56+
public static final EnumSet<TunerClass> SUPPORTED_USB_TUNERS = EnumSet.of(AIRSPY, AIRSPY_HF, HACKRF, RTL2832,
5657
FUNCUBE_DONGLE_PRO, FUNCUBE_DONGLE_PRO_PLUS);
5758

5859
public static final EnumSet<TunerClass> FUNCUBE_TUNERS = EnumSet.of(FUNCUBE_DONGLE_PRO, FUNCUBE_DONGLE_PRO_PLUS);
@@ -122,6 +123,8 @@ public static TunerClass lookup(short vendor, short product)
122123
return HACKRF;
123124
case 0x1D5060A1:
124125
return AIRSPY;
126+
case 0x03EB800C:
127+
return AIRSPY_HF;
125128
}
126129

127130
return TunerClass.UNKNOWN;

src/main/java/io/github/dsheirer/source/tuner/TunerFactory.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
import io.github.dsheirer.source.tuner.airspy.AirspyTunerConfiguration;
2929
import io.github.dsheirer.source.tuner.airspy.AirspyTunerController;
3030
import io.github.dsheirer.source.tuner.airspy.AirspyTunerEditor;
31+
import io.github.dsheirer.source.tuner.airspy.hf.AirspyHfTuner;
32+
import io.github.dsheirer.source.tuner.airspy.hf.AirspyHfTunerConfiguration;
33+
import io.github.dsheirer.source.tuner.airspy.hf.AirspyHfTunerController;
34+
import io.github.dsheirer.source.tuner.airspy.hf.AirspyHfTunerEditor;
3135
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
3236
import io.github.dsheirer.source.tuner.fcd.FCDTuner;
3337
import io.github.dsheirer.source.tuner.fcd.proV1.FCD1TunerConfiguration;
@@ -323,6 +327,8 @@ public static Tuner getUsbTuner(TunerClass tunerClass, String portAddress, int b
323327
{
324328
case AIRSPY:
325329
return new AirspyTuner(new AirspyTunerController(bus, portAddress, tunerErrorListener), tunerErrorListener, channelizerType);
330+
case AIRSPY_HF:
331+
return new AirspyHfTuner(new AirspyHfTunerController(bus, portAddress, tunerErrorListener), tunerErrorListener, channelizerType);
326332
case FUNCUBE_DONGLE_PRO:
327333
TargetDataLine tdl1 = MixerManager.getTunerTargetDataLine(MixerTunerType.FUNCUBE_DONGLE_PRO);
328334
if(tdl1 != null)
@@ -372,6 +378,8 @@ public static TunerConfiguration getTunerConfiguration(TunerType type, String un
372378
{
373379
switch(type)
374380
{
381+
case AIRSPY_HF_PLUS:
382+
return new AirspyHfTunerConfiguration(uniqueID);
375383
case AIRSPY_R820T:
376384
return new AirspyTunerConfiguration(uniqueID);
377385
case ELONICS_E4000:
@@ -415,6 +423,8 @@ public static TunerEditor getEditor(UserPreferences userPreferences, DiscoveredT
415423
{
416424
case AIRSPY:
417425
return new AirspyTunerEditor(userPreferences, tunerManager, discoveredTuner);
426+
case AIRSPY_HF:
427+
return new AirspyHfTunerEditor(userPreferences, tunerManager, discoveredTuner);
418428
case FUNCUBE_DONGLE_PRO:
419429
return new FCD1TunerEditor(userPreferences, tunerManager, discoveredTuner);
420430
case FUNCUBE_DONGLE_PRO_PLUS:

src/main/java/io/github/dsheirer/source/tuner/TunerType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2022 Dennis Sheirer
3+
* Copyright (C) 2014-2023 Dennis Sheirer
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@
2626
public enum TunerType
2727
{
2828
AIRSPY_R820T("R820T"),
29+
AIRSPY_HF_PLUS("HF+"),
2930
ELONICS_E4000("E4000"),
3031
FCI_FC2580("FC2580"),
3132
FITIPOWER_FC0012("FC0012"),

0 commit comments

Comments
 (0)