-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSDRHardware.cpp
311 lines (270 loc) · 10.7 KB
/
SDRHardware.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
#include <stdio.h>
#include <cstdint>
#include <iostream>
#include <chrono>
#include <vector>
#include <boost/lockfree/spsc_queue.hpp>
#include "SDRHardware.h"
#include "global.h"
#include "FFTProcessor.h"
#include "ClientManager.h"
#include "sdrplay_api.h" // the SDRplay driver must be installed!
using namespace std::chrono;
// Constructor
SDRHardware::SDRHardware() : numDevs(0), deviceParams(nullptr), chParams(nullptr), err(sdrplay_api_Success), chosenDevice(nullptr), TUNED_FREQUENCY(14240000), SDR_SAMPLE_RATE(2400000) {
std::cout << "SDRHardware object created.\n";
}
// Destructor (cleans up the API)
SDRHardware::~SDRHardware() {
/* if (chosenDevice) {
sdrplay_api_Uninit(chosenDevice->dev);
sdrplay_api_ReleaseDevice(chosenDevice);
}
sdrplay_api_Close();*/
std::cout << "SDRHardware object destroyed and SDRplay API closed.\n";
if(resampler_2400to480) {
msresamp_crcf_destroy(resampler_2400to480);
resampler_2400to480 = nullptr;
}
}
// Singleton implementation
SDRHardware& SDRHardware::getInstance() {
static SDRHardware instance; // This creates the single instance of the class
return instance;
}
// Initializes the SDR hardware
bool SDRHardware::init() {
printf("Initialize SDRplay hardware\n");
// Create the fractional resampler 2400 to 480 kS/s
resampler_2400to480 = msresamp_crcf_create(r_2400to480, As_2400to480);
// Öffne die SDRplay API
if ((err = sdrplay_api_Open()) != sdrplay_api_Success) {
printf("sdrplay_api_Open failed: %s\n", sdrplay_api_GetErrorString(err));
return false;
}
printf("SDRplay API opened\n");
// Geräte scannen
sdrplay_api_GetDevices(devices, &numDevs, sizeof(devices) / sizeof(sdrplay_api_DeviceT));
// Überprüfen, ob ein Gerät verfügbar ist
if (numDevs == 0) {
printf("ERROR: No RSP devices available.\n");
return false;
}
printf("%d devices detected. devices[0].hwVer = %d\n",numDevs,devices[0].hwVer);
// Wähle das erste verfügbare Gerät (RSP1A oder RSP1B)
if (devices[0].hwVer == SDRPLAY_RSP1A_ID) {
chosenDevice = &devices[0];
printf("SDRPLAY_RSP1A_ID found\n");
}
else if (devices[0].hwVer == SDRPLAY_RSP1B_ID) {
chosenDevice = &devices[0];
printf("SDRPLAY_RSP1B_ID found\n");
} else {
printf("ERROR: RSP selected is not available.\n");
return false;
}
// Gerät zur Nutzung auswählen
sdrplay_api_SelectDevice(chosenDevice);
printf("device selected\n");
// Hole die Geräteparameter
sdrplay_api_GetDeviceParams(chosenDevice->dev, &deviceParams);
printf("device parameters read\n");
// Setze die Tunerparameter
printf("set tuner parameters\n");
chParams = deviceParams->rxChannelA;
deviceParams->rxChannelA->tunerParams.gain.gRdB = 20; // Example: 40 dB gain reduction
deviceParams->rxChannelA->tunerParams.gain.LNAstate = 1; // Example: LNA state
deviceParams->rxChannelA->tunerParams.gain.syncUpdate = 0; // Default: no sync update needed
deviceParams->rxChannelA->tunerParams.gain.minGr = sdrplay_api_NORMAL_MIN_GR; // Normal gain reduction
chParams->tunerParams.rfFreq.rfHz = TUNED_FREQUENCY;
chParams->tunerParams.bwType = sdrplay_api_BW_0_600; // 600 kHz
deviceParams->rxChannelA->tunerParams.ifType = sdrplay_api_IF_Zero; // output is in baseband
deviceParams->devParams->fsFreq.fsHz = 2400000.0; // sample rate 2.4 MS/s
deviceParams->rxChannelA->ctrlParams.agc.enable = sdrplay_api_AGC_100HZ;
deviceParams->rxChannelA->ctrlParams.agc.setPoint_dBfs = -30;
// Callbacks einrichten
sdrplay_api_CallbackFnsT cbFns;
cbFns.StreamACbFn = StreamACallback;
cbFns.EventCbFn = EventCallback;
// Gerät initialisieren und Stream starten
if ((err = sdrplay_api_Init(chosenDevice->dev, &cbFns, NULL)) != sdrplay_api_Success) {
printf("sdrplay_api_Init failed: %s\n", sdrplay_api_GetErrorString(err));
return false;
}
return true;
}
// Sets the band and updates the frequency
// this function is called from the clientManager which is another process
// therefor we use an atomic flag to signal that the band value is ready to read
void SDRHardware::setBand(float b) {
int numclients = ClientManager::getInstance().getNumberOfLoggedInClients();
if(numclients != 1) return;
band = b;
bandReady = true;
}
void SDRHardware::convertToLiquidDSPFormat(short *xi, short *xq, unsigned int numSamples, liquid_float_complex* output)
{
int didx = 0;
float div = 32768.0f;
for(unsigned int i=0; i<numSamples; i++)
{
output[didx].real = (float)xi[i] / div;
output[didx].imag = (float)xq[i] / div;
didx++;
}
}
void SDRHardware::StreamACallback(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext) {
if (reset) {
printf("StreamACallback: Reset detected, numSamples=%d\n", numSamples);
}
SDRHardware& instance = SDRHardware::getInstance();
// Allocate an array for complex samples using unique_ptr
std::unique_ptr<liquid_float_complex[]> complexSamples(new liquid_float_complex[numSamples]);
instance.convertToLiquidDSPFormat(xi, xq, numSamples, complexSamples.get()); // Use .get() to access raw pointer
// Downsample to 480 kS/s
unsigned int num_samples_out_480 = static_cast<unsigned int>(480.0f / 2400.0f * numSamples + 0.5f);
std::unique_ptr<liquid_float_complex[]> samples_480(new liquid_float_complex[num_samples_out_480]);
unsigned int num_output_samples_480;
msresamp_crcf_execute(instance.resampler_2400to480, complexSamples.get(), numSamples, samples_480.get(), &num_output_samples_480);
// Convert sample array to a vector just before pushing to FFT process
SampleData datavect;
datavect.sdata = std::vector<liquid_float_complex>(samples_480.get(), samples_480.get() + num_output_samples_480);
datavect.numSamples = num_output_samples_480;
// Push samples to the FFT process
FFTProcessor& fftinstance = FFTProcessor::getInstance();
fftinstance.pushFFTinputSamples(datavect);
// Also send samples to the Client Manager
ClientManager& CMinstance = ClientManager::getInstance();
CMinstance.enqueueRawSamples(datavect);
// No need for delete[] here; std::unique_ptr will automatically release memory when it goes out of scope
}
// Event callback function (static member function)
void SDRHardware::EventCallback(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tuner, sdrplay_api_EventParamsT *params, void *cbContext) {
if (eventId == sdrplay_api_GainChange) {
/*
// set LNAstate to keep this gRdB between 20 and 59)
printf("Baseband Gain Reduction (gRdB): %d\n", params->gainParams.gRdB);
printf("LNA Gain Reduction (lnaGRdB): %d\n", params->gainParams.lnaGRdB);
printf("Current Total Gain: %.2f dB\n", params->gainParams.currGain);
*/
}
}
float SDRHardware::getTuningFrequency() {
return (float)TUNED_FREQUENCY;
}
void SDRHardware::changeBand() {
if(!bandReady) return;
bandReady = false;
uint32_t offset = 240000; // Offset in Hz (uint32_t)
uint32_t freq = 0; // Calculated frequency in Hz (uint32_t)
switch (static_cast<int>(band)) {
case 630:
StartQRG = start_630m;
EndQRG = end_630m;
break;
case 160:
StartQRG = start_160m;
EndQRG = end_160m;
break;
case 80:
StartQRG = start_80m;
EndQRG = end_80m;
break;
case 60:
StartQRG = start_60m;
EndQRG = end_60m; // USB for 60m
break;
case 40:
StartQRG = start_40m;
EndQRG = end_40m;
break;
case 30:
StartQRG = start_30m;
EndQRG = end_30m; // USB for 30m (primarily CW and digital modes)
break;
case 20:
StartQRG = start_20m;
EndQRG = end_20m; // USB for 20m
break;
case 17:
StartQRG = start_17m;
EndQRG = end_17m; // USB for 17m
break;
case 15:
StartQRG = start_15m;
EndQRG = end_15m; // USB for 15m
break;
case 12:
StartQRG = start_12m;
EndQRG = end_12m; // USB for 12m
break;
case 11:
StartQRG = start_11m;
EndQRG = end_11m; // USB for 11m
break;
case 280:
StartQRG = start_10m_a;
EndQRG = end_10m_a;
break;
case 285:
StartQRG = start_10m_b;
EndQRG = end_10m_b;
break;
case 290:
StartQRG = start_10m_c;
EndQRG = end_10m_c;
break;
case 6:
StartQRG = start_6m;
EndQRG = end_6m; // USB for 6m
break;
case 4:
StartQRG = start_4m;
EndQRG = end_4m; // USB for 4m
break;
case 144: // 144-144.5 MHz
StartQRG = start_2m_a;
EndQRG = end_2m_a; // USB for 2m
break;
case 145: // 144.5-145 MHz
StartQRG = start_2m_b;
EndQRG = end_2m_b; // USB for 2m
break;
case 146: // 145-145.5 MHz
StartQRG = start_2m_c;
EndQRG = end_2m_c; // USB for 2m
break;
case 147: // 145.5-146 MHz
StartQRG = start_2m_d;
EndQRG = end_2m_d; // USB for 2m
break;
case 438: // 438.8-439.3 MHz
StartQRG = start_70cm_a;
EndQRG = end_70cm_a; // USB for 70cm
break;
case 70:
StartQRG = start_70cm;
EndQRG = end_70cm; // USB for 70cm
break;
case 446:
StartQRG = start_PMR446;
EndQRG = end_PMR446;
break;
default:
std::cout << "Unknown band" << std::endl;
return;
}
// make sure the bandwidth does not exceed 480kHz
EndQRG = std::min(EndQRG, StartQRG + 480000);
freq = StartQRG + offset;
TUNED_FREQUENCY = freq;
printf("set tuner to: %d\n",TUNED_FREQUENCY);
/*mir_sdr_ErrT ret = mir_sdr_SetRf((double)TUNED_FREQUENCY, 1, 0);
if(ret) printf("err; %d\n",ret);*/
deviceParams->rxChannelA->tunerParams.rfFreq.rfHz = (double)TUNED_FREQUENCY;
// Call sdrplay_api_Update to apply the new frequency
sdrplay_api_ErrT ret = sdrplay_api_Update(chosenDevice->dev, sdrplay_api_Tuner_A, sdrplay_api_Update_Tuner_Frf, sdrplay_api_Update_Ext1_None);
if (ret != sdrplay_api_Success) {
printf("Error: sdrplay_api_Update failed with code %d: %s\n", ret, sdrplay_api_GetErrorString(ret));
}
}