1 /**
2 * ybladerf.cpp
3 * This file is part of the YATE Project http://YATE.null.ro
4 *
5 * BladeRF radio interface
6 *
7 * Yet Another Telephony Engine - a fully featured software PBX and IVR
8 * Copyright (C) 2015, 2016 Null Team
9 * Copyright (C) 2015, 2016 LEGBA Inc
10 *
11 * This software is distributed under multiple licenses;
12 * see the COPYING file in the main directory for licensing
13 * information for this specific distribution.
14 *
15 * This use of this software may be subject to additional restrictions.
16 * See the LEGAL file in the main directory for details.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 */
22
23 #include <yatephone.h>
24 #include <yateradio.h>
25 #include <yatemath.h>
26 #include <libusb-1.0/libusb.h>
27
28 #ifdef __MMX__
29 #include <mmintrin.h>
30 #endif
31
32 #ifndef M_PI_2
33 #define M_PI_2 (M_PI / 2)
34 #endif
35 #ifndef M_PI_4
36 #define M_PI_4 (M_PI / 4)
37 #endif
38
39 #ifdef LITTLE_ENDIAN
40 #define BRF_LITTLE_ENDIAN (true)
41 #else
42 #define BRF_LITTLE_ENDIAN (false)
43 #endif
44
45 #define BRF_MAX_FLOAT ((float)0xffffffff)
46
47 //#define DEBUG_LUSB_TRANSFER_CALLBACK // Debug libusb transfer callback
48 //#define DEBUGGER_DEVICE_METH // Instantiate a Debugger to trace some device methods
49 //#define DEBUG_DEVICE_TX // Special (verbose) TX debug
50 //#define DEBUG_DEVICE_RX // Special (verbose) RX debug
51 //#define DEBUG_DEVICE_AUTOCAL // Special (verbose) autocalibration debug
52
53 using namespace TelEngine;
54 namespace { // anonymous
55
56 class BrfLibUsbDevice; // A bladeRF device using libusb
57 class BrfInterface; // A bladeRF radio interface
58 class BrfModule; // The module
59
60 // GPIO
61 // Configure FPGA to send smaller buffers (USB 2)
62 #define BRF_GPIO_SMALL_DMA_XFER (1 << 7)
63
64 // SPI flash page size, in bytes
65 #define BRF_FLASH_PAGE_SIZE 256
66
67 #define SI5338_F_VCO (38400000UL * 66UL)
68
69 // Vendor commands
70 #define BRF_USB_CMD_QUERY_FPGA_STATUS 1
71 #define BRF_USB_CMD_BEGIN_PROG 2
72 #define BRF_USB_CMD_RF_RX 4
73 #define BRF_USB_CMD_RF_TX 5
74 #define BRF_USB_CMD_READ_CAL_CACHE 110
75
76 #define BRF_SAMPLERATE_MIN 80000u
77 #define BRF_SAMPLERATE_MAX 40000000 // Max supported by LMS6002D
78
79 #define MAX_SAMPLERATE_HIGH 4100000
80 #define MAX_SAMPLERATE_SUPER 40000000
81
82 // Frequency bounds
83 #define BRF_FREQUENCY_MIN 232500000u
84 #define BRF_FREQUENCY_MAX 3800000000u
85
86 // Frequency offset interval
87 #define BRF_FREQ_OFFS_DEF 128.0
88 #define BRF_FREQ_OFFS_MIN 64.0
89 #define BRF_FREQ_OFFS_MAX 192.0
90
91 #define BRF_MAX_DELAY_SUPER_SPEED_DEF 550
92 #define BRF_MAX_DELAY_HIGH_SPEED_DEF 750
93 #define BRF_BEST_DELAY_SUPER_SPEED_DEF 450
94 #define BRF_BEST_DELAY_HIGH_SPEED_DEF 600
95 #define BRF_KNOWN_DELAY_SUPER_SPEED_DEF 400
96 #define BRF_KNOWN_DELAY_HIGH_SPEED_DEF 500
97 #define BRF_SYSTEM_ACCURACY_DEF 300
98 #define BRF_ACCURACY_PPB_DEF 30
99
100 #define BRF_RXVGA1_GAIN_MIN 5
101 #define BRF_RXVGA1_GAIN_MAX 30
102 #define BRF_RXVGA1_GAIN_DEF 30
103 #define BRF_RXVGA2_GAIN_MIN 0
104 #define BRF_RXVGA2_GAIN_MAX 30
105 #define BRF_RXVGA2_GAIN_DEF 3
106 #define BRF_TXVGA1_GAIN_MIN -35
107 #define BRF_TXVGA1_GAIN_MAX -4
108 #define BRF_TXVGA1_GAIN_DEF -14
109 #define BRF_TXVGA2_GAIN_MIN 0
110 #define BRF_TXVGA2_GAIN_MAX 25
111 #define BRF_TXVGA2_GAIN_DEF 0
112
113 #define VCO_HIGH 0x02
114 #define VCO_NORM 0x00
115 #define VCO_LOW 0x01
116
117 #define MAKE_TOKEN_NAME_PREFIX(PREFIX,x) {#x, PREFIX##x}
118
brfIsLowBand(unsigned int hz)119 static inline bool brfIsLowBand(unsigned int hz)
120 {
121 return hz < 1500000000u;
122 }
123
124 #define BRF_ALTSET_INVALID -1 // Invalid value
125 #define BRF_ALTSET_IDLE 0 // Used for idle mode
126 #define BRF_ALTSET_RF_LINK 1 // Send and receive samples. Also used for
127 // sending commands to peripherals (VCTCXO, Si5338, LMS6002D)
128 #define BRF_ALTSET_SPI_FLASH 2 // Update the firmware on the board
129 #define BRF_ALTSET_FPGA 3 // FPGA operations
130 #define BRF_ALTSET_MIN BRF_ALTSET_IDLE
131 #define BRF_ALTSET_MAX BRF_ALTSET_FPGA
132 static const TokenDict s_altSetDict[] = {
133 MAKE_TOKEN_NAME_PREFIX(BRF_ALTSET_,INVALID),
134 MAKE_TOKEN_NAME_PREFIX(BRF_ALTSET_,IDLE),
135 MAKE_TOKEN_NAME_PREFIX(BRF_ALTSET_,RF_LINK),
136 MAKE_TOKEN_NAME_PREFIX(BRF_ALTSET_,SPI_FLASH),
137 MAKE_TOKEN_NAME_PREFIX(BRF_ALTSET_,FPGA),
138 {0,0}
139 };
altSetName(int val)140 static inline const char* altSetName(int val)
141 {
142 return lookup(val,s_altSetDict);
143 }
144
145 // USB endpoints
146 #define BRF_ENDP_TX_SAMPLES 0x01 // Endpoint for TX data samples
147 #define BRF_ENDP_TX_CTRL 0x02 // Endpoint for ctrl RF
148 #define BRF_ENDP_RX_SAMPLES 0x81 // Endpoint for RX data samples
149 #define BRF_ENDP_RX_CTRL 0x82 // Endpoint for ctrl RF
150
151 // DC calibrate modules
152 // Auto calibration order is given in LMS6002D calibration guide, Section 4.7
153 #define BRF_CALIBRATE_LPF_TUNING 0 // DC offset cancellation of LPF
154 #define BRF_CALIBRATE_LPF_BANDWIDTH 1 // LPF bandwidth tunning
155 #define BRF_CALIBRATE_TX_LPF 2 // DC offset cancellation of TX LPF
156 #define BRF_CALIBRATE_RX_LPF 3 // DC offset cancellation of RX LPF
157 #define BRF_CALIBRATE_RX_VGA2 4 // DC offset cancellation of RX VGA2
158 #define BRF_CALIBRATE_FIRST BRF_CALIBRATE_LPF_TUNING
159 #define BRF_CALIBRATE_LAST BRF_CALIBRATE_RX_VGA2
160 #define BRF_CALIBRATE_MAX_SUBMODULES 5
161 static const TokenDict s_calModuleDict[] = {
162 MAKE_TOKEN_NAME_PREFIX(BRF_CALIBRATE_,LPF_TUNING),
163 MAKE_TOKEN_NAME_PREFIX(BRF_CALIBRATE_,LPF_BANDWIDTH),
164 MAKE_TOKEN_NAME_PREFIX(BRF_CALIBRATE_,TX_LPF),
165 MAKE_TOKEN_NAME_PREFIX(BRF_CALIBRATE_,RX_LPF),
166 MAKE_TOKEN_NAME_PREFIX(BRF_CALIBRATE_,RX_VGA2),
167 {0,0}
168 };
calModName(int val)169 static inline const char* calModName(int val)
170 {
171 return lookup(val,s_calModuleDict);
172 }
173 static const char* s_calRxTxLpfNames[] = {"DC_I","DC_Q"};
174 static const char* s_calRxVga2Names[] = {"VGA2_DC_REF","VGA2A_DC_I","VGA2A_DC_Q","VGA2B_DC_I","VGA2B_DC_Q"};
175 struct BrfCalDesc
176 {
177 uint8_t clkEnMask;
178 uint8_t addr;
179 uint8_t subModules;
180 const char** subModName;
181 };
182 static const BrfCalDesc s_calModuleDesc[] = {
183 // BRF_CALIBRATE_LPF_TUNING
184 {0x20,0x00,1,0},
185 // BRF_CALIBRATE_LPF_BANDWIDTH
186 {0,0,1,0},
187 // BRF_CALIBRATE_TX_LPF
188 {0x02,0x30,2,s_calRxTxLpfNames},
189 // BRF_CALIBRATE_RX_LPF
190 {0x08,0x50,2,s_calRxTxLpfNames},
191 // BRF_CALIBRATE_RX_VGA2
192 {0x10,0x60,5,s_calRxVga2Names}
193 };
194
195 // Maximum values for Rx/Tx DC offset I and Q
196 #define BRF_RX_DC_OFFSET_MAX 63
197 #define BRF_TX_DC_OFFSET_MIN -128
198 #define BRF_TX_DC_OFFSET_MAX 127
decodeDCOffs(bool tx,uint8_t val)199 static inline int16_t decodeDCOffs(bool tx, uint8_t val)
200 {
201 if (tx) {
202 bool negative = ((val & 0x80) == 0);
203 return negative ? ((int16_t)val - 128) : (int16_t)(val & 0x7f);
204 }
205 bool negative = ((val & 0x40) != 0);
206 return negative ? -(int16_t)(val & 0x3f) : (int16_t)(val & 0x3f);
207 }
208
209 // Calculate Rx DC offset correction
210 #define BRF_RX_DC_OFFSET_ERROR 10
211 #define BRF_RX_DC_OFFSET_COEF 1.5
212 #define BRF_RX_DC_OFFSET_AVG_DAMPING 1024
213 #define BRF_RX_DC_OFFSET_DEF (BRF_RX_DC_OFFSET_ERROR * BRF_RX_DC_OFFSET_AVG_DAMPING)
brfRxDcOffset(double val)214 static inline double brfRxDcOffset(double val)
215 {
216 return (val * BRF_RX_DC_OFFSET_COEF + BRF_RX_DC_OFFSET_ERROR) *
217 BRF_RX_DC_OFFSET_AVG_DAMPING;
218 }
219
220 // FPGA correction
221 #define BRF_FPGA_CORR_MAX 4096
222
223 // libusb defaults
224 #define LUSB_SYNC_TIMEOUT 50 // Sync transfer timeout def val (in milliseconds)
225 #define LUSB_CTRL_TIMEOUT 500 // Control transfer timeout def val (in milliseconds)
226 #define LUSB_BULK_TIMEOUT 500 // Bulk transfer timeout def val (in milliseconds)
227
228 // libusb control transfer
229 #define LUSB_CTRLTRANS_IFACE_VENDOR (LIBUSB_RECIPIENT_INTERFACE | LIBUSB_REQUEST_TYPE_VENDOR)
230 #define LUSB_CTRLTRANS_IFACE_VENDOR_IN (LUSB_CTRLTRANS_IFACE_VENDOR | LIBUSB_ENDPOINT_IN)
231 #define LUSB_CTRLTRANS_DEV_VENDOR (LIBUSB_RECIPIENT_DEVICE | LIBUSB_REQUEST_TYPE_VENDOR)
232 #define LUSB_CTRLTRANS_DEV_VENDOR_IN (LUSB_CTRLTRANS_DEV_VENDOR | LIBUSB_ENDPOINT_IN)
233 #define LUSB_CTRLTRANS_DEV_VENDOR_OUT (LUSB_CTRLTRANS_DEV_VENDOR | LIBUSB_ENDPOINT_OUT)
234
235 // Board reference clock (in Hz)
236 static const uint64_t s_freqRefClock = 38400000;
237
bytes2samplesf(unsigned int bytes)238 static inline unsigned int bytes2samplesf(unsigned int bytes)
239 {
240 return bytes / (2 * sizeof(float));
241 }
242
samplesf2bytes(unsigned int samples)243 static inline unsigned int samplesf2bytes(unsigned int samples)
244 {
245 return samples * 2 * sizeof(float);
246 }
247
samplesi2bytes(unsigned int samples)248 static inline unsigned int samplesi2bytes(unsigned int samples)
249 {
250 return samples * 2 * sizeof(int16_t);
251 }
252
dirStr(int8_t dir)253 static inline const char* dirStr(int8_t dir)
254 {
255 return dir ? (dir > 0 ? "u" : "d") : "=";
256 }
257
encloseDashes(String & s,bool extra=false)258 static inline const char* encloseDashes(String& s, bool extra = false)
259 {
260 static const String s1 = "\r\n-----";
261 if (s)
262 s = s1 + (extra ? "\r\n" : "") + s + s1;
263 return s.safe();
264 }
265
266 #define BRF_ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
267
268 // Utility: check timeout or cancelled
checkCancelled(String * error=0)269 static inline unsigned int checkCancelled(String* error = 0)
270 {
271 if (!Thread::check(false))
272 return 0;
273 if (error)
274 *error = "Cancelled";
275 return RadioInterface::Cancelled;
276 }
277
getSampleLimit(const NamedList & p,double defVal=(double)2040/2047)278 static inline float getSampleLimit(const NamedList& p, double defVal = (double)2040 / 2047)
279 {
280 float limit = (float)p.getDoubleValue(YSTRING("sample_limit"),defVal);
281 return (limit < 0) ? -limit : ((limit <= 1.0F) ? limit : 1.0F);
282 }
283
onStr(bool on)284 static inline const char* onStr(bool on)
285 {
286 return on ? "on" : "off";
287 }
288
enableStr(bool on)289 static inline const char* enableStr(bool on)
290 {
291 return on ? "enable" : "disable";
292 }
293
enabledStr(bool on)294 static inline const char* enabledStr(bool on)
295 {
296 return on ? "Enabled" : "Disabled";
297 }
298
brfDir(bool tx)299 static inline const char* brfDir(bool tx)
300 {
301 return tx ? "TX" : "RX";
302 }
303
mixer(bool pre)304 static inline char mixer(bool pre)
305 {
306 return pre ? '1' : '2';
307 }
308
brfIQ(bool i)309 static inline char brfIQ(bool i)
310 {
311 return i ? 'I' : 'Q';
312 }
313
activeStr(bool on)314 static inline const char* activeStr(bool on)
315 {
316 return on ? "active" : "inactive";
317 }
318
dumpFloatG(String & buf,double val,const char * prefix=0,const char * suffix=0)319 static inline String& dumpFloatG(String& buf, double val, const char* prefix = 0,
320 const char* suffix = 0)
321 {
322 return buf.printf("%s%g%s",TelEngine::c_safe(prefix),val,TelEngine::c_safe(suffix));
323 }
324
getInterval(const String & s,int & iMin,int & iMax,int minDef=INT_MIN,int maxDef=INT_MAX)325 static inline void getInterval(const String& s, int& iMin, int& iMax,
326 int minDef = INT_MIN, int maxDef = INT_MAX)
327 {
328 int pos = s.find('_');
329 if (pos >= 0) {
330 iMin = s.substr(0,pos).toInteger(minDef);
331 iMax = s.substr(pos + 1).toInteger(maxDef);
332 }
333 else {
334 iMin = s.toInteger(minDef);
335 iMax = maxDef;
336 }
337 if (iMin > iMax)
338 iMin = iMax;
339 }
340
isInterval(int val,int iMin,int iMax,const String & interval)341 static inline bool isInterval(int val, int iMin, int iMax, const String& interval)
342 {
343 if (interval)
344 getInterval(interval,iMin,iMax,iMin,iMax);
345 return (iMin <= val) && (val <= iMax);
346 }
347
addIntervalInt(String & s,int minVal,int maxVal,const char * sep=" ")348 static inline String& addIntervalInt(String& s, int minVal, int maxVal, const char* sep = " ")
349 {
350 String tmp;
351 return s.append(tmp.printf("[%d..%d]",minVal,maxVal),sep);
352 }
353
retMsgError(NamedList & list,const char * what,const char * param=0)354 static inline bool retMsgError(NamedList& list, const char* what, const char* param = 0)
355 {
356 NamedString* ns = new NamedString("error",what);
357 if (!TelEngine::null(param))
358 *ns << " '" << param << "'";
359 list.setParam(ns);
360 return false;
361 }
362
retParamError(NamedList & list,const char * param)363 static inline bool retParamError(NamedList& list, const char* param)
364 {
365 if (list.getParam(param))
366 return retMsgError(list,"Missing parameter",param);
367 return retMsgError(list,"Invalid parameter",param);
368 }
369
retValFailure(NamedList & list,unsigned int code)370 static inline bool retValFailure(NamedList& list, unsigned int code)
371 {
372 return retMsgError(list,String(code) + " " + RadioInterface::errorName(code));
373 }
374
getFirstStr(String & dest,String & line)375 static inline bool getFirstStr(String& dest, String& line)
376 {
377 int pos = line.find(' ');
378 if (pos >= 0) {
379 dest = line.substr(0,pos);
380 line = line.substr(pos + 1);
381 }
382 else {
383 dest = line;
384 line.clear();
385 }
386 return !dest.null();
387 }
388
389 // Convert 4 bytes to version string (MSB -> LSB: patch.minor.major)
ver2str(String & dest,uint32_t ver)390 static inline void ver2str(String& dest, uint32_t ver)
391 {
392 dest << (uint8_t)ver << ".";
393 dest << (uint8_t)(ver >> 8) << ".";
394 uint16_t patch = (uint8_t)(ver >> 16) | (uint8_t)(ver >> 24);
395 dest << patch;
396 }
397
398 // Code is expecting this array to have 15 elements
399 #define BRF_FILTER_BW_COUNT 16
400 #define BRF_FILTER_BW_MIN 1500000u
401 #define BRF_FILTER_BW_MAX 28000000u
402 static const uint32_t s_bandSet[BRF_FILTER_BW_COUNT] = {
403 BRF_FILTER_BW_MIN, 1750000u, 2500000u, 2750000u, 3000000u,
404 3840000u, 5000000u, 5500000u, 6000000u, 7000000u,
405 8750000u, 10000000u,12000000u,14000000u,20000000u,
406 BRF_FILTER_BW_MAX
407 };
bw2index(unsigned int value)408 static inline uint8_t bw2index(unsigned int value)
409 {
410 uint8_t i = 0;
411 for (; i < (BRF_FILTER_BW_COUNT - 1) && value > s_bandSet[i]; i++)
412 ;
413 return i;
414 }
index2bw(uint8_t index)415 static inline unsigned int index2bw(uint8_t index)
416 {
417 return index < BRF_FILTER_BW_COUNT ? s_bandSet[index] : BRF_FILTER_BW_MAX;
418 }
419
420 #if 0
421 static uint32_t s_freqLimits[] = {
422 BRF_FREQUENCY_MIN, 285625000, 0x27,
423 285625000, 336875000, 0x2f,
424 336875000, 405000000, 0x37,
425 405000000, 465000000, 0x3f,
426 465000000, 571250000, 0x26,
427 571250000, 673750000, 0x2e,
428 673750000, 810000000, 0x36,
429 810000000, 930000000, 0x3e,
430 930000000, 1142500000, 0x25,
431 1142500000, 1347500000, 0x2d,
432 1347500000, 1620000000, 0x35,
433 1620000000, 1860000000, 0x3d,
434 1860000000u, 2285000000u, 0x24,
435 2285000000u, 2695000000u, 0x2c,
436 2695000000u, 3240000000u, 0x34,
437 3240000000u, BRF_FREQUENCY_MAX, 0x3c,
438 0,0,0
439 };
440 #else
441 static uint32_t s_freqLimits[] = {
442 BRF_FREQUENCY_MIN, 285625000, 0x27,
443 285625000, 336875000, 0x2f,
444 336875000, 405000000, 0x37,
445 405000000, 475000000, 0x3f,
446 475000000, 571250000, 0x26,
447 571250000, 673750000, 0x2e,
448 673750000, 810000000, 0x36,
449 810000000, 945000000, 0x3e,
450 945000000, 1142500000, 0x25,
451 1142500000, 1350000000, 0x2d,
452 1350000000, 1620000000, 0x35,
453 1620000000, 1890000000, 0x3d,
454 1890000000u, 2285000000u, 0x24,
455 2285000000u, 2695000000u, 0x2c,
456 2695000000u, 3240000000u, 0x34,
457 3240000000u, BRF_FREQUENCY_MAX, 0x3c,
458 0,0,0
459 };
460 #endif
461
462 struct BrfRationalRate
463 {
464 uint64_t integer;
465 uint64_t numerator;
466 uint64_t denominator;
467 };
468
469 struct Si5338MultiSynth
470 {
471 uint8_t index; // Multisynth to program (0-3)
472 uint16_t base; // Base address of the multisynth
473 BrfRationalRate requested; // Requested sample rates
474 BrfRationalRate actual; // Actual sample rates
475 uint8_t enable; // Enables for A and/or B outputs
476 uint32_t a, b, c, r; // f_out = fvco / (a + b/c) / r
477 uint32_t p1, p2, p3; // (a, b, c) in multisynth (p1, p2, p3) form
478 uint8_t regs[10]; // p1, p2, p3) in register form
479 };
480
481 static const uint8_t s_rxvga1_set[BRF_RXVGA1_GAIN_MAX + 1] = {
482 2, 2, 2, 2, 2, 2, 14, 26, 37, 47, 56, 63, 70, 76, 82, 87,
483 91, 95, 99, 102, 104, 107, 109, 111, 113, 114, 116, 117, 118, 119, 120,
484 };
485
486 static const uint8_t s_rxvga1_get[121] = {
487 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
488 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8,
489 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10,
490 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 13, 13,
491 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 17,
492 17, 17, 18, 18, 18, 18, 19, 19, 19, 20, 20, 21, 21, 22, 22, 22, 23, 24, 24,
493 25, 25, 26, 27, 28, 29, 30
494 };
495
496 // Init radio caps with default values
initRadioCaps(RadioCapability & caps)497 static void initRadioCaps(RadioCapability& caps)
498 {
499 caps.maxPorts = 1;
500 caps.currPorts = 1;
501 caps.maxTuneFreq = BRF_FREQUENCY_MAX;
502 caps.minTuneFreq = BRF_FREQUENCY_MIN;
503 caps.maxSampleRate = BRF_SAMPLERATE_MAX;
504 caps.minSampleRate = BRF_SAMPLERATE_MIN;
505 caps.maxFilterBandwidth = BRF_FILTER_BW_MAX;
506 caps.minFilterBandwidth = BRF_FILTER_BW_MIN;
507 }
508
509 // Utility macros (call methods)
510 #define BRF_FUNC_CALL_(result,func,cond,instr) { \
511 result = func; \
512 if (cond) { instr; } \
513 }
514 // Call a method, remember the first error
515 #define BRF_FUNC_CALL(func) BRF_FUNC_CALL_(unsigned int tmp,func,!status && tmp,status = tmp; error = 0)
516 #define BRF_FUNC_CALL_BREAK(func) BRF_FUNC_CALL_(status,func,status,break)
517 #define BRF_FUNC_CALL_RET(func) BRF_FUNC_CALL_(status,func,status,return status)
518
threadIdleIntervals(unsigned int ms)519 static unsigned int threadIdleIntervals(unsigned int ms)
520 {
521 return 1 + ms / Thread::idleMsec();
522 }
523
validFloatSample(float val)524 static inline bool validFloatSample(float val)
525 {
526 return (val >= -1.0F) && (val <= 1.0F);
527 }
528
setMinMax(float & minF,float & maxF,float val)529 static inline void setMinMax(float& minF, float& maxF, float val)
530 {
531 if (maxF < val)
532 maxF = val;
533 if (minF > val)
534 minF = val;
535 }
536
checkSampleLimit(const float * buf,unsigned int samples,float limit,String * error)537 static unsigned int checkSampleLimit(const float* buf, unsigned int samples, float limit,
538 String* error)
539 {
540 unsigned int n = 2 * samples;
541 for (unsigned int i = 0; i < n; ++i, ++buf)
542 if (*buf < -limit || *buf > limit) {
543 if (error)
544 error->printf("sample %c %f (at %u) out of range limit=%f",
545 brfIQ((i % 2) == 0),*buf,i / 2,limit);
546 return RadioInterface::Saturation;
547 }
548 return 0;
549 }
550
551 // Generate ComplexVector tone (exponential)
generateExpTone(ComplexVector & v,float omega,unsigned int len=0)552 static void generateExpTone(ComplexVector& v, float omega, unsigned int len = 0)
553 {
554 if (len)
555 v.resetStorage(len);
556 for (unsigned int i = 0; i < v.length(); ++i) {
557 Complex c(0,i * omega);
558 v[i] = c.exp();
559 }
560 }
561
replaceDumpParams(String & buf,NamedString * ns,bool addRunParams=false,NamedString * ns1=0,NamedString * ns2=0)562 static String& replaceDumpParams(String& buf, NamedString* ns,
563 bool addRunParams = false, NamedString* ns1 = 0, NamedString* ns2 = 0)
564 {
565 NamedList p("");
566 p.addParam("newline","\r\n");
567 p.addParam("tab","\t");
568 if (ns)
569 p.addParam(ns);
570 p.addParam("sec_now",String(Time::secNow()));
571 char c[256];
572 Debugger::formatTime(c,Debugger::TextSep);
573 p.addParam("time",c);
574 if (addRunParams)
575 p.copyParams(Engine::runParams());
576 if (ns1)
577 p.addParam(ns1);
578 if (ns2)
579 p.addParam(ns2);
580 p.replaceParams(buf);
581 return buf;
582 }
583
584 // Allocate a new String. Replace params from format, return the new string
replaceDumpParamsFmt(const String & fmt,NamedString * ns,bool addRunParams=false,NamedString * ns1=0,NamedString * ns2=0)585 static inline String* replaceDumpParamsFmt(const String& fmt, NamedString* ns,
586 bool addRunParams = false, NamedString* ns1 = 0, NamedString* ns2 = 0)
587 {
588 String* s = new String(fmt);
589 replaceDumpParams(*s,ns,addRunParams,ns1,ns2);
590 return s;
591 }
592
593 // Dump Complex vector to a NamedString
dumpNsData(const ComplexVector & v,const char * name="data")594 static inline NamedString* dumpNsData(const ComplexVector& v, const char* name = "data")
595 {
596 NamedString* ns = new NamedString(name);
597 v.dump(*ns,Math::dumpComplex," ","%f%+fj");
598 return ns;
599 }
600
601 // Dump float vector to a NamedString
dumpNsData(const FloatVector & v,const char * name="data")602 static inline NamedString* dumpNsData(const FloatVector& v, const char* name = "data")
603 {
604 NamedString* ns = new NamedString(name);
605 v.dump(*ns,Math::dumpFloat,",","%f");
606 return ns;
607 }
608
boolSetError(String & s,const char * e=0)609 static inline bool boolSetError(String& s, const char* e = 0)
610 {
611 s = e;
612 return false;
613 }
614
615 // Parse a comma separated list of float values to complex vector
parseVector(String & error,const String & str,ComplexVector & buf)616 static bool parseVector(String& error, const String& str, ComplexVector& buf)
617 {
618 if (!str)
619 return boolSetError(error,"empty");
620 ObjList* list = str.split(',');
621 unsigned int len = list->length();
622 if ((len < 2) || (len % 2) != 0) {
623 TelEngine::destruct(list);
624 return boolSetError(error,"invalid length");
625 }
626 buf.resetStorage(len / 2);
627 ObjList* o = list;
628 for (float* b = (float*)buf.data(); o; o = o->next(), b++) {
629 if (!o->get())
630 continue;
631 *b = (static_cast<String*>(o->get()))->toDouble();
632 if (!validFloatSample(*b))
633 break;
634 }
635 TelEngine::destruct(list);
636 if (!o)
637 return true;
638 buf.resetStorage(0);
639 return boolSetError(error,"invalid data range");
640 }
641
generateCircleQuarter(Complex * & c,float amplitude,float i,float q,unsigned int loops,float angle,float iSign,float qSign)642 static inline void generateCircleQuarter(Complex*& c, float amplitude, float i, float q,
643 unsigned int loops, float angle, float iSign, float qSign)
644 {
645 (c++)->set(i * amplitude,q * amplitude);
646 if (!loops)
647 return;
648 float angleStep = M_PI_2 / (loops + 1);
649 if (angle)
650 angleStep = -angleStep;
651 iSign *= amplitude;
652 qSign *= amplitude;
653 for (; loops; --loops, ++c) {
654 angle += angleStep;
655 c->set(iSign * ::cosf(angle),qSign * ::sinf(angle));
656 }
657 }
658
659 // Parse a complex numbers pattern
660 // forcePeriodic=true: Force lenExtend=false and lenRequired=true for periodic
661 // patterns (like 'circle')
662 // lenExtend=true: Extend destination buffer to be minimum 'len'. 'lenRequired' is ignored
663 // lenRequired=true: 'len' MUST be a multiple of generated vector's length
buildVector(String & error,const String & pattern,ComplexVector & vector,unsigned int len=0,bool forcePeriodic=true,bool lenExtend=true,bool lenRequired=false,unsigned int * pLen=0,float gain=1)664 static bool buildVector(String& error, const String& pattern, ComplexVector& vector,
665 unsigned int len = 0, bool forcePeriodic = true, bool lenExtend = true,
666 bool lenRequired = false, unsigned int* pLen = 0, float gain=1)
667 {
668 if (!pattern)
669 return boolSetError(error,"empty");
670 bool isPeriodic = false;
671 String p = pattern;
672 ComplexVector v;
673 // Check for circles
674 if (p.startSkip("circle",false)) {
675 unsigned int cLen = 4;
676 bool rev = false;
677 float div = 1;
678 if (!p || p == YSTRING("_reverse"))
679 // circle[_reverse]
680 rev = !p.null();
681 else if (p.startSkip("_div_",false)) {
682 // circle_div[_reverse]_{divisor}
683 rev = p.startSkip("reverse_",false);
684 if (!p)
685 return boolSetError(error);
686 div = p.toDouble();
687 }
688 else if (p.startSkip("_points_",false)) {
689 // circle_points[_reverse]_{value}[_div_{divisor}]
690 rev = p.startSkip("reverse_",false);
691 if (!p)
692 return boolSetError(error);
693 int pos = p.find('_');
694 if (pos < 0)
695 cLen = p.toInteger(0,0,0);
696 else {
697 // Expecting div
698 cLen = p.substr(0,pos).toInteger(0,0,0);
699 p = p.substr(pos + 1);
700 if (!(p.startSkip("div_",false) && p))
701 return boolSetError(error);
702 div = p.toDouble();
703 }
704 }
705 else
706 return boolSetError(error);
707 // Circle length MUST be a multiple of 4
708 if (!cLen || (cLen % 4) != 0)
709 return boolSetError(error,"invalid circle length");
710 if (div < 1)
711 return boolSetError(error,"invalid circle div");
712 v.resetStorage(cLen);
713 Complex* c = v.data();
714 float amplitude = gain / div;
715 float direction = rev ? -1 : 1;
716 unsigned int n = (cLen - 4) / 4;
717 generateCircleQuarter(c,amplitude,1,0,n,0,1,direction);
718 generateCircleQuarter(c,amplitude,0,direction,n,M_PI_2,-1,direction);
719 generateCircleQuarter(c,amplitude,-1,0,n,0,-1,-direction);
720 generateCircleQuarter(c,amplitude,0,-direction,n,M_PI_2,1,-direction);
721 isPeriodic = true;
722 }
723 else if (pattern == YSTRING("zero")) {
724 // Fill with 0
725 vector.resetStorage(len ? len : 1);
726 if (pLen)
727 *pLen = 1;
728 return true;
729 }
730 else if (p.startSkip("fill_",false)) {
731 // Fill with value: fill_{real}_{imag}
732 int pos = p.find('_');
733 if (pos < 1 || p.find('_',pos + 1) > 0)
734 return boolSetError(error);
735 float re = p.substr(0,pos).toDouble();
736 float im = p.substr(pos + 1).toDouble();
737 if (validFloatSample(re) && validFloatSample(im)) {
738 vector.resetStorage(len ? len : 1);
739 vector.fill(Complex(re,im));
740 if (pLen)
741 *pLen = 1;
742 return true;
743 }
744 return boolSetError(error,"invalid data range");
745 }
746 else if (!parseVector(error,pattern,v))
747 // Parse list of values
748 return false;
749 if (!v.length())
750 return boolSetError(error,"empty result");
751 if (pLen)
752 *pLen = v.length();
753 if (isPeriodic && forcePeriodic) {
754 lenExtend = false;
755 lenRequired = true;
756 }
757 // Try to extend data
758 if (!len || (len == v.length()) || !(lenExtend || lenRequired))
759 vector = v;
760 else {
761 if (lenExtend) {
762 if (len < v.length())
763 len = v.length();
764 unsigned int rest = len % v.length();
765 if (rest)
766 len += v.length() - rest;
767 }
768 else if ((len < v.length()) || ((len % v.length()) != 0))
769 return boolSetError(error,"required/actual length mismatch");
770 vector.resetStorage(len);
771 for (unsigned int i = 0; (i + v.length()) <= len; i += v.length())
772 vector.slice(i,v.length()).copy(v,v.length());
773 }
774 return true;
775 }
776
777 static int16_t s_sampleEnergize = 2047;
778
779 // Energize a number. Refer the input value to the requested energy
sampleScale(float value,float scale)780 static inline int16_t sampleScale(float value, float scale)
781 {
782 value *= scale;
783 return (int16_t)((value >= 0.0F) ? (value + 0.5F) : (value - 0.5F));
784 }
785
786 // len is number of complex samples (I&Q pairs)
energize(const float * samples,int16_t * dest,const float iScale,const float qScale,const unsigned len)787 static bool energize(const float* samples, int16_t* dest,
788 const float iScale, const float qScale, const unsigned len)
789 {
790 if (len % 2 != 0) {
791 Debug("bladerf",DebugFail,"Energize len %u must be a multiple of 2",len);
792 return false;
793 }
794 // len is number of complex pairs
795 // N is number of scalars
796 const unsigned N = len * 2;
797 #ifdef __MMX__
798 const float rescale = 32767.0 / s_sampleEnergize;
799 const float is2 = iScale * rescale;
800 const float qs2 = qScale * rescale;
801
802 // Intel intrinstics
803 int32_t i32[4];
804 const __m64* s32A = (__m64*) &i32[0];
805 const __m64* s32B = (__m64*) &i32[2];
806 for (unsigned i = 0; i < N; i += 4) {
807 // apply I/Q correction and scaling and convert samples to 32 bits
808 // gcc -O2/-O3 on intel uses cvttss2si or cvttps2dq depending on the processor
809 i32[0] = is2 * samples[i + 0];
810 i32[1] = qs2 * samples[i + 1];
811 i32[2] = is2 * samples[i + 2];
812 i32[3] = qs2 * samples[i + 3];
813 // saturate 32 bits to 16
814 // process 4 16-bit samples in a 64-bit block
815 __m64* d64 = (__m64*) &dest[i];
816 *d64 = _mm_packs_pi32(*s32A, *s32B);
817 }
818 // shift 16 bit down to 12 bits for BladeRF
819 // This has to be done after saturation.
820 for (unsigned i = 0; i < N; i++)
821 dest[i] = dest[i] >> 4;
822 #else
823 for (unsigned i = 0; i < N; i += 2) {
824 // scale and saturate
825 float iv = iScale * samples[i];
826 if (iv > 2047)
827 iv = 2047;
828 else if (iv < -2047)
829 iv = -2047;
830 float qv = qScale * samples[i + 1];
831 if (qv > 2047)
832 qv = 2047;
833 else if (qv < -2047)
834 qv = -2047;
835 // convert and save
836 dest[i] = iv;
837 dest[i + 1] = qv;
838 }
839 #endif
840 return true;
841 }
842
brfCopyTxData(int16_t * dest,const float * src,const unsigned samples,const float scaleI,int16_t maxI,const float scaleQ,int16_t maxQ,unsigned int & clamped,const long * ampTable=NULL)843 static inline void brfCopyTxData(int16_t* dest, const float* src, const unsigned samples,
844 const float scaleI, int16_t maxI, const float scaleQ, int16_t maxQ, unsigned int& clamped,
845 const long* ampTable=NULL)
846 {
847 // scale and convert to 12-bit integers
848 if (!energize(src, dest, scaleI, scaleQ, samples)) {
849 ::memset(dest,0,2 * samples * sizeof(int16_t));
850 return;
851 }
852 if (ampTable) {
853 int16_t *d1 = dest;
854 const int16_t *s1 = dest;
855 for (unsigned i = 0; i < samples; i++) {
856 // amplifier predistortion
857 // power of the sample, normalized to the energy scale
858 // this has a range of 0 .. (2*scale)-1
859 long xRe = *s1++;
860 long xIm = *s1++;
861 unsigned p = (xRe * xRe + xIm * xIm) >> 10; // 2 * (xRe*xRe + xIm*xIm)/2048
862 // get the correction factor, abs of 0..1
863 long corrRe = ampTable[p];
864 long corrIm = ampTable[p+1];
865 // apply the correction factor (complex multiplication), rescaled by 2048
866 *d1++ = (corrRe * xRe - corrIm * xIm) >> 11;
867 *d1++ = (corrRe * xIm + corrIm * xRe) >> 11;
868 }
869 }
870 if (htole16(0x1234) != 0x1234)
871 for (unsigned i = 0; i < samples; i++)
872 dest[i] = htole16(dest[i]);
873 }
874
875 class BrfDuration
876 {
877 public:
BrfDuration(uint64_t start=Time::now ())878 inline BrfDuration(uint64_t start = Time::now())
879 : m_start(start), m_durationUs(0)
880 {}
stop()881 inline void stop() {
882 if (!m_durationUs)
883 m_durationUs = Time::now() - m_start;
884 }
secStr()885 inline const char* secStr() {
886 stop();
887 m_str.printf("%u.%usec",(unsigned int)(m_durationUs / 1000000),
888 (unsigned int)(m_durationUs % 1000000) / 1000);
889 return m_str;
890 }
891
892 protected:
893 uint64_t m_start;
894 uint64_t m_durationUs;
895 String m_str;
896 };
897
898
899 class BrfDumpFile
900 {
901 public:
BrfDumpFile(const NamedList * p=0,const char * fName=0,bool createAlways=false)902 inline BrfDumpFile(const NamedList* p = 0, const char* fName = 0,
903 bool createAlways = false)
904 : m_dumpOk(0), m_dumpFail(0), m_tmpDumpOk(0), m_tmpDumpFail(0),
905 m_newFile(false) {
906 if (p)
907 init(*p,fName,createAlways);
908 }
~BrfDumpFile()909 ~BrfDumpFile()
910 { writeData(true); }
valid() const911 inline bool valid() const
912 { return m_file.valid(); }
fileName() const913 inline const String& fileName() const
914 { return m_fileName; }
file() const915 inline const File& file() const
916 { return m_file; }
dumpHeader()917 inline bool dumpHeader()
918 { return (m_newFile && valid()) ? !(m_newFile = false) : false; }
dumpOk() const919 inline bool dumpOk() const
920 { return m_tmpDumpOk != 0; }
dumpFail() const921 inline bool dumpFail() const
922 { return m_tmpDumpFail != 0; }
resetDumpOkFail()923 inline void resetDumpOkFail() {
924 m_tmpDumpOk = m_dumpOk;
925 m_tmpDumpFail = m_dumpFail;
926 }
append(String * s)927 inline void append(String* s) {
928 if (s && *s)
929 m_dump.append(s);
930 else
931 TelEngine::destruct(s);
932 }
appendFormatted(const FloatVector & data,const String & fmt)933 inline void appendFormatted(const FloatVector& data, const String& fmt)
934 { append(replaceDumpParamsFmt(fmt,dumpNsData(data))); }
appendFormatted(const ComplexVector & data,bool ok)935 inline void appendFormatted(const ComplexVector& data, bool ok) {
936 const String& fmt = ok ? m_dumpFmtOk : m_dumpFmtFail;
937 if (!fmt)
938 return;
939 append(replaceDumpParamsFmt(fmt,dumpNsData(data)));
940 int& what = ok ? m_tmpDumpOk : m_tmpDumpFail;
941 if (what > 0)
942 what--;
943 }
944 // Dump vector data if format parameter is present
dumpDataFmt(const ComplexVector & v,const NamedList & params,const String & fmtParam)945 inline void dumpDataFmt(const ComplexVector& v, const NamedList& params,
946 const String& fmtParam) {
947 const String& fmt = params[fmtParam];
948 if (fmt)
949 append(replaceDumpParamsFmt(fmt,dumpNsData(v)));
950 }
init(const NamedList & p,const char * fName,bool createAlways=false)951 inline bool init(const NamedList& p, const char* fName, bool createAlways = false) {
952 writeData(true);
953 if (TelEngine::null(fName))
954 fName = p[YSTRING("dump_file")];
955 if (TelEngine::null(fName))
956 return false;
957 m_fileName = fName;
958 replaceDumpParams(m_fileName,0,true);
959 m_newFile = false;
960 if (createAlways || !m_file.openPath(m_fileName,true)) {
961 if (!m_file.openPath(m_fileName,true,false,true,false,false,true,true))
962 return false;
963 m_newFile = true;
964 }
965 else if (m_file.seek(Stream::SeekEnd) < 0) {
966 m_file.terminate();
967 return false;
968 }
969 m_dumpFmtOk = p[YSTRING("dump_buf_ok_format")];
970 m_dumpFmtFail = p[YSTRING("dump_buf_fail_format")];
971 m_dumpOk = m_dumpFmtOk ? p.getIntValue(YSTRING("dump_buf_ok")) : 0;
972 m_dumpFail = m_dumpFmtFail ? p.getIntValue(YSTRING("dump_buf_fail")) : 0;
973 resetDumpOkFail();
974 return true;
975 }
writeData(bool finalize=false)976 inline void writeData(bool finalize = false) {
977 if (!valid())
978 return;
979 if (m_dump.skipNull()) {
980 String buf;
981 buf.append(m_dump);
982 m_dump.clear();
983 if (buf)
984 m_file.writeData(buf.c_str(),buf.length());
985 }
986 if (finalize)
987 m_file.terminate();
988 }
989
990 protected:
991 int m_dumpOk;
992 int m_dumpFail;
993 int m_tmpDumpOk;
994 int m_tmpDumpFail;
995 String m_dumpFmtOk;
996 String m_dumpFmtFail;
997 ObjList m_dump;
998 bool m_newFile;
999 File m_file;
1000 String m_fileName;
1001 };
1002
1003 class BrfPeripheral : public String
1004 {
1005 public:
BrfPeripheral(const char * name,uint8_t devId)1006 inline BrfPeripheral(const char* name, uint8_t devId)
1007 : String(name),
1008 m_devId(devId), m_tx(false), m_rx(false), m_haveTrackAddr(false),
1009 m_trackLevel(-1) {
1010 lowCase = name;
1011 lowCase.toLower();
1012 setTrack(false,false);
1013 }
devId() const1014 inline uint8_t devId() const
1015 { return m_devId; }
trackDir(bool tx) const1016 inline bool trackDir(bool tx) const
1017 { return tx ? m_tx : m_rx; }
haveTrackAddr() const1018 inline bool haveTrackAddr() const
1019 { return m_haveTrackAddr; }
trackLevel(int level=DebugAll) const1020 inline int trackLevel(int level = DebugAll) const
1021 { return (m_trackLevel >= 0) ? m_trackLevel : level; }
1022 void setTrack(bool tx, bool rx, const String& addr = String::empty(), int level = -1);
1023 // Check for addr track range, return first match addr or -1 if not found
isTrackRange(uint8_t addr,uint8_t len) const1024 inline int isTrackRange(uint8_t addr, uint8_t len) const {
1025 for (; addr < sizeof(m_trackAddr) && len; len--, addr++)
1026 if (m_trackAddr[addr])
1027 return addr;
1028 return -1;
1029 }
isTrackAddr(uint8_t addr) const1030 inline bool isTrackAddr(uint8_t addr) const
1031 { return addr < sizeof(m_trackAddr) && m_trackAddr[addr]; }
1032
1033 String lowCase;
1034
1035 protected:
1036 uint8_t m_devId; // Device id
1037 bool m_tx;
1038 bool m_rx;
1039 bool m_haveTrackAddr;
1040 uint8_t m_trackAddr[128];
1041 int m_trackLevel;
1042 };
1043
1044 // Device calibration data
1045 class BrfCalData
1046 {
1047 public:
BrfCalData(int mod)1048 inline BrfCalData(int mod) {
1049 ::memset(this,0,sizeof(BrfCalData));
1050 module = mod;
1051 desc = &s_calModuleDesc[module];
1052 }
modName() const1053 inline const char* modName() const
1054 { return calModName(module); }
1055 int module;
1056 const BrfCalDesc* desc;
1057 uint8_t clkEn;
1058 uint8_t inputMixer;
1059 uint8_t loOpt;
1060 uint8_t lnaGain;
1061 int rxVga1;
1062 int rxVga2;
1063 uint8_t rxVga2GainAB;
1064 // LPF_BANDWIDTH
1065 uint8_t txVGA2PwAmp;
1066 uint8_t txPPL;
1067 uint8_t enLPFCAL;
1068 uint8_t clkLPFCAL;
1069 uint8_t nInt;
1070 uint8_t nFrac1;
1071 uint8_t nFrac2;
1072 uint8_t nFrac3;
1073 };
1074
1075 // Thresholds used to adjust the number of internal buffers from sampling rate
1076 class BrfBufsThreshold
1077 {
1078 public:
BrfBufsThreshold()1079 inline BrfBufsThreshold()
1080 : sampleRate(0), bufferedSamples(0), txMinBufs(0)
1081 {}
1082 unsigned int sampleRate;
1083 unsigned int bufferedSamples;
1084 unsigned int txMinBufs;
1085
1086 static const char* init(DataBlock& db, const String& str, const RadioCapability& caps);
1087 static BrfBufsThreshold* findThres(DataBlock& db, unsigned int sampleRate);
1088 };
1089
1090 // libusb transfer
1091 class LusbTransfer : public Mutex
1092 {
1093 public:
LusbTransfer(BrfLibUsbDevice * dev=0)1094 inline LusbTransfer(BrfLibUsbDevice* dev = 0)
1095 : Mutex(false,"LusbTransfer"),
1096 device(dev), ep(255), transfer(0), status(0), m_running(false)
1097 {}
~LusbTransfer()1098 inline ~LusbTransfer()
1099 { reset(); }
running() const1100 inline bool running() const
1101 { return m_running; }
running(bool start)1102 inline void running(bool start) {
1103 m_running = start;
1104 if (m_running) {
1105 status = 0;
1106 error.clear();
1107 }
1108 }
alloc()1109 inline bool alloc() {
1110 if (transfer)
1111 return true;
1112 transfer = ::libusb_alloc_transfer(0);
1113 if (transfer)
1114 return true;
1115 error = "Failed to allocate libusb transfer";
1116 status = RadioInterface::Failure;
1117 return false;
1118 }
reset()1119 inline void reset() {
1120 cancel();
1121 if (transfer)
1122 ::libusb_free_transfer(transfer);
1123 transfer = 0;
1124 m_running = false;
1125 }
1126 // Fill bulk transfer. Allocate if not already done
1127 // Return true on success (change state to Init)
1128 bool fillBulk(uint8_t* data, unsigned int len, unsigned int tout);
1129 bool submit();
1130 unsigned int cancel(String* error = 0);
1131
1132 BrfLibUsbDevice* device;
1133 uint8_t ep;
1134 libusb_transfer* transfer;
1135 unsigned int status;
1136 String error;
1137 protected:
1138 bool m_running;
1139 };
1140
1141 // Holds RX/TX related data
1142 // Hold samples read/write related data
1143 class BrfDevDirState
1144 {
1145 public:
BrfDevDirState(bool tx)1146 inline BrfDevDirState(bool tx)
1147 : showDcOffsChange(0), showFpgaCorrChange(0), showPowerBalanceChange(0),
1148 rfEnabled(false), frequency(0), vga1(0), vga1Changed(false), vga2(0), lpf(0),
1149 dcOffsetI(0), dcOffsetQ(0), fpgaCorrPhase(0), fpgaCorrGain(0),
1150 powerBalance(0), lpfBw(0), sampleRate(0), m_timestamp(0),
1151 m_tx(tx)
1152 {}
BrfDevDirState(const BrfDevDirState & src)1153 inline BrfDevDirState(const BrfDevDirState& src)
1154 { *this = src; }
operator =(const BrfDevDirState & src)1155 inline BrfDevDirState& operator=(const BrfDevDirState& src) {
1156 ::memcpy(this,&src,sizeof(src));
1157 return *this;
1158 }
tx() const1159 inline bool tx() const
1160 { return m_tx; }
1161
1162 unsigned int showDcOffsChange; // Show DC offset changed debug message
1163 unsigned int showFpgaCorrChange; // Show FPGA PHASE/GAIN changed debug message
1164 unsigned int showPowerBalanceChange; // Show power balance changed debug message
1165 bool rfEnabled; // RF enabled flag
1166 unsigned int frequency; // Used frequency
1167 int vga1; // VGA1 gain
1168 bool vga1Changed; // VGA1 was set by us
1169 int vga2; // VGA2 gain
1170 int lpf; // LPF status
1171 int dcOffsetI; // Current I (in-phase) DC offset
1172 int dcOffsetQ; // Current Q (quadrature) DC offset
1173 int fpgaCorrPhase; // Current FPGA phase correction
1174 int fpgaCorrGain; // Current FPGA gain correction
1175 float powerBalance; // Current power balance
1176 unsigned int lpfBw; // LPF bandwidth
1177 unsigned int sampleRate; // Sampling rate
1178 uint64_t m_timestamp;
1179
1180 protected:
1181 bool m_tx; // Direction
1182 };
1183
1184 // Holds device data. May be used to backup and restore
1185 class BrfDevState
1186 {
1187 public:
BrfDevState(unsigned int chg=0,unsigned int txChg=0,unsigned int rxChg=0)1188 inline BrfDevState(unsigned int chg = 0, unsigned int txChg = 0,
1189 unsigned int rxChg = 0)
1190 : m_changed(chg), m_txChanged(txChg), m_rxChanged(rxChg),
1191 m_loopback(0), m_loopbackParams(""), m_txPatternGain(1), m_rxDcAuto(true),
1192 m_tx(true), m_rx(false)
1193 {}
BrfDevState(const BrfDevState & src,unsigned int chg=0,unsigned int txChg=0,unsigned int rxChg=0)1194 inline BrfDevState(const BrfDevState& src, unsigned int chg = 0,
1195 unsigned int txChg = 0, unsigned int rxChg = 0)
1196 : m_loopbackParams(""), m_tx(true), m_rx(false) {
1197 assign(src,false);
1198 setFlags(chg,txChg,rxChg);
1199 }
setFlags(unsigned int chg=0,unsigned int txChg=0,unsigned int rxChg=0)1200 inline void setFlags(unsigned int chg = 0, unsigned int txChg = 0,
1201 unsigned int rxChg = 0) {
1202 m_changed = chg;
1203 m_txChanged = txChg;
1204 m_rxChanged = rxChg;
1205 }
setLoopback(int lp,const NamedList & params)1206 inline void setLoopback(int lp, const NamedList& params) {
1207 m_loopback = lp;
1208 m_loopbackParams.clearParams();
1209 m_loopbackParams.copyParams(params);
1210 }
assign(const BrfDevState & src,bool flags=true)1211 inline BrfDevState& assign(const BrfDevState& src, bool flags = true) {
1212 if (flags)
1213 setFlags(src.m_changed,src.m_txChanged,src.m_rxChanged);
1214 else
1215 setFlags();
1216 setLoopback(src.m_loopback,src.m_loopbackParams);
1217 m_txPattern = src.m_txPattern;
1218 m_txPatternGain = src.m_txPatternGain;
1219 m_rxDcAuto = src.m_rxDcAuto;
1220 m_tx = src.m_tx;
1221 m_rx = src.m_rx;
1222 return *this;
1223 }
operator =(const BrfDevState & src)1224 inline BrfDevState& operator=(const BrfDevState& src)
1225 { return assign(src); }
1226
1227 unsigned int m_changed; // Changed flags
1228 unsigned int m_txChanged; // TX data changed flags
1229 unsigned int m_rxChanged; // RX data changed flags
1230 int m_loopback; // Current loopback
1231 NamedList m_loopbackParams; // Loopback params
1232 String m_txPattern; // Transmit pattern
1233 float m_txPatternGain; // Transmit pattern gain
1234 bool m_rxDcAuto; // Automatically adjust Rx DC offset
1235 BrfDevDirState m_tx;
1236 BrfDevDirState m_rx;
1237 };
1238
1239 class BrfFloatMinMax
1240 {
1241 public:
BrfFloatMinMax()1242 inline BrfFloatMinMax()
1243 : value(0), min(BRF_MAX_FLOAT), max(-BRF_MAX_FLOAT)
1244 {}
set(float val)1245 inline void set(float val) {
1246 value = val;
1247 setMinMax(min,max,val);
1248 }
reset(float val=0)1249 inline void reset(float val = 0) {
1250 value = val;
1251 min = BRF_MAX_FLOAT;
1252 max = -BRF_MAX_FLOAT;
1253 }
operator float()1254 inline operator float()
1255 { return value; }
1256
1257 float value;
1258 float min;
1259 float max;
1260 };
1261
1262 class BrfFloatAccum
1263 {
1264 public:
BrfFloatAccum()1265 inline BrfFloatAccum()
1266 : count(0)
1267 {}
append(float val)1268 inline void append(float val)
1269 { data[count++] = val; }
reset(unsigned int len)1270 inline void reset(unsigned int len) {
1271 data.resetStorage(len);
1272 count = 0;
1273 }
normalize()1274 inline void normalize()
1275 { data.resize(count); }
1276 FloatVector data;
1277 unsigned int count;
1278 };
1279
1280 struct BrfBbCalDataResult
1281 {
BrfBbCalDataResult__anonab15ebc50111::BrfBbCalDataResult1282 inline BrfBbCalDataResult()
1283 : status(0), cal(0), test(0), total(0),
1284 test_total(0), cal_test(0),testOk(false), calOk(false)
1285 {}
1286 unsigned int status;
1287 float cal;
1288 float test;
1289 float total;
1290 float test_total; // test / total
1291 float cal_test; // cal / test
1292 bool testOk;
1293 bool calOk;
1294 };
1295
1296 class BrfBbCalData
1297 {
1298 public:
BrfBbCalData(unsigned int nSamples,const NamedList & p)1299 inline BrfBbCalData(unsigned int nSamples, const NamedList& p)
1300 : m_stopOnRecvFail(0), m_repeatRxLoop(5),
1301 m_best(0), m_cal_test(0),
1302 m_prevCal(0), m_testOk(false), m_calOk(false), m_params(p),
1303 m_tx(true), m_rx(false),
1304 m_calFreq(0), m_calSampleRate(0),
1305 m_dcI(0), m_dcQ(0), m_phase(0), m_gain(0),
1306 m_buffer(nSamples), m_calTone(nSamples), m_testTone(nSamples),
1307 m_calToneOmega(0), m_testToneOmega(0) {
1308 prepareCalculate();
1309 m_stopOnRecvFail = p.getIntValue(YSTRING("recv_fail_stop"),1);
1310 m_repeatRxLoop = p.getIntValue(YSTRING("recv_fail_loops"),5,1,1000);
1311 }
prefix(bool dc) const1312 inline const String& prefix(bool dc) const {
1313 static const String s_dcPrefix = "dc_";
1314 static const String s_imbalancePrefix = "imbalance_";
1315 return dc ? s_dcPrefix : s_imbalancePrefix;
1316 }
omega(bool cal) const1317 inline float omega(bool cal) const
1318 { return cal ? m_calToneOmega : m_testToneOmega; }
buf() const1319 inline float* buf() const
1320 { return (float*)m_buffer.data(); }
samples() const1321 inline unsigned int samples() const
1322 { return m_buffer.length(); }
buffer()1323 inline ComplexVector& buffer()
1324 { return m_buffer; }
calTone() const1325 inline const ComplexVector& calTone() const
1326 { return m_calTone; }
testTone() const1327 inline const ComplexVector& testTone() const
1328 { return m_testTone; }
prepareCalculate()1329 inline void prepareCalculate() {
1330 m_best = BRF_MAX_FLOAT;
1331 m_prevCal = 0;
1332 m_cal.reset(-1);
1333 m_total.reset();
1334 m_test.reset();
1335 }
resetBuffer(unsigned int nSamples)1336 inline void resetBuffer(unsigned int nSamples)
1337 { resetOmega(m_calToneOmega,m_testToneOmega,nSamples); }
resetOmega(float calToneOmega,float testToneOmega,unsigned int nSamples=0)1338 inline void resetOmega(float calToneOmega, float testToneOmega, unsigned int nSamples = 0) {
1339 if (nSamples)
1340 m_buffer.resetStorage(nSamples);
1341 m_calToneOmega = calToneOmega;
1342 m_testToneOmega = testToneOmega;
1343 generateExpTone(m_calTone,calToneOmega,m_buffer.length());
1344 generateExpTone(m_testTone,testToneOmega,m_buffer.length());
1345 }
setResult(BrfBbCalDataResult & res)1346 inline void setResult(BrfBbCalDataResult& res) {
1347 m_prevCal = m_cal.value;
1348 m_cal.set(res.cal);
1349 m_test.set(res.test);
1350 m_total.set(res.total);
1351 m_cal_test = res.cal_test;
1352 m_test_total.set(res.test_total);
1353 m_calOk = res.calOk;
1354 m_testOk = res.testOk;
1355 }
calculate(BrfBbCalDataResult & res)1356 inline bool calculate(BrfBbCalDataResult& res) {
1357 const Complex* last = 0;
1358 const Complex* b = m_buffer.data(0,m_buffer.length(),last);
1359 const Complex* calTone = m_calTone.data();
1360 const Complex* testTone = m_testTone.data();
1361 Complex calSum;
1362 Complex testSum;
1363 res.total = 0;
1364 // Calculate calibrate/test energy using the narrow band integrator
1365 // Calculate total buffer energy (power)
1366 for (; b != last; ++b, ++calTone, ++testTone) {
1367 calSum += *calTone * *b;
1368 testSum += *testTone * *b;
1369 res.total += b->norm2();
1370 }
1371 res.cal = calSum.norm2() / samples();
1372 res.test = testSum.norm2() / samples();
1373 res.cal_test = res.test ? (res.cal / res.test) : -1;
1374 res.test_total = res.total ? (res.test / res.total) : -1;
1375 res.calOk = 0.0F <= res.cal_test && res.cal_test <= 0.001F;
1376 res.testOk = 0.5F < res.test_total && res.test_total <= 1.0F;
1377 #if 0
1378 res.test /= samples();
1379 res.total /= samples();
1380 #endif
1381 return res.testOk;
1382 }
dump(String & s,bool full)1383 inline String& dump(String& s, bool full) {
1384 float delta = 0;
1385 if (m_prevCal >= 0.0F)
1386 delta = m_cal.value - m_prevCal;
1387 const char* dir = dirStr(delta ? (delta > 0.0F ? 1 : -1) : 0);
1388 if (full)
1389 return s.printf(1024,"%s cal:%-10f test:%-10f total:%-10f "
1390 "test/total:%3s %.2f%% cal/test:%3s %.2f%%",
1391 dir,m_cal.value,m_test.value,m_total.value,
1392 (m_testOk ? "OK" : "BAD"),m_test_total.value * 100,
1393 (m_calOk ? "OK" : "BAD"),m_cal_test * 100);
1394 return s.printf(1024,"%s cal:%-10f delta=%-10f",dir,m_cal.value,delta);
1395 }
dump(String & s,const BrfBbCalDataResult & res)1396 inline String& dump(String& s, const BrfBbCalDataResult& res) {
1397 return s.printf(1024,"cal:%-10f test:%-10f total:%-10f "
1398 "test/total:%3s %.2f%% cal/test:%3s %.2f%%",
1399 res.cal,res.test,res.total,(res.testOk ? "OK" : "BAD"),
1400 res.test_total * 100,(res.calOk ? "OK" : "BAD"),res.cal_test * 100);
1401 }
param(bool dc,const char * name) const1402 inline const String& param(bool dc, const char* name) const
1403 { return m_params[prefix(dc) + name]; }
uintParam(bool dc,const char * name,unsigned int defVal=0,unsigned int minVal=0,unsigned int maxVal=(unsigned int)LLONG_MAX) const1404 inline unsigned int uintParam(bool dc, const char* name, unsigned int defVal = 0,
1405 unsigned int minVal = 0, unsigned int maxVal = (unsigned int)LLONG_MAX) const
1406 { return param(dc,name).toInt64(defVal,0,minVal,maxVal); }
intParam(bool dc,const char * name,int defVal=0,int minVal=INT_MIN,int maxVal=INT_MAX) const1407 inline int intParam(bool dc, const char* name, int defVal = 0,
1408 int minVal = INT_MIN, int maxVal = INT_MAX) const
1409 { return param(dc,name).toInteger(defVal,0,minVal,maxVal); }
boolParam(bool dc,const char * name,bool defVal=false) const1410 inline bool boolParam(bool dc, const char* name, bool defVal = false) const
1411 { return param(dc,name).toBoolean(defVal); }
1412 void initCal(BrfLibUsbDevice& dev, bool dc, String& fName);
1413 void finalizeCal(const String& result);
1414 void dumpCorrStart(unsigned int pass, int corr, int corrVal, int fixedCorr,
1415 int fixedCorrVal, unsigned int range, unsigned int step,
1416 int calValMin, int calValMax);
1417 void dumpCorrEnd(bool dc);
1418
1419 int m_stopOnRecvFail; // Stop on data recv wrong result
1420 unsigned int m_repeatRxLoop; // Repeat data read on wrong result
1421 float m_best;
1422 BrfFloatMinMax m_cal; // Calculated calibrating value
1423 BrfFloatMinMax m_total; // Calculated total value
1424 BrfFloatMinMax m_test; // Calculated test value
1425 BrfFloatMinMax m_test_total; // Calculated test/total value
1426 float m_cal_test; // cal / test
1427 float m_prevCal; // Previous calibrating value
1428 bool m_testOk;
1429 bool m_calOk;
1430 NamedList m_params; // Calibration parameters
1431 BrfFloatAccum m_calAccum;
1432 BrfFloatAccum m_testAccum;
1433 BrfFloatAccum m_totalAccum;
1434 BrfDumpFile m_dump;
1435
1436 // Initial state
1437 BrfDevDirState m_tx;
1438 BrfDevDirState m_rx;
1439 // Calibration params
1440 unsigned int m_calFreq;
1441 unsigned int m_calSampleRate;
1442 // Calibration results
1443 int m_dcI;
1444 int m_dcQ;
1445 int m_phase;
1446 int m_gain;
1447
1448 protected:
1449 ComplexVector m_buffer;
1450 ComplexVector m_calTone;
1451 ComplexVector m_testTone;
1452 float m_calToneOmega;
1453 float m_testToneOmega;
1454 };
1455
1456 // Holds RX/TX related data
1457 // Hold samples read/write related data
1458 class BrfDevIO
1459 {
1460 public:
BrfDevIO(bool tx)1461 inline BrfDevIO(bool tx)
1462 : showBuf(0), showBufData(true), checkTs(0), dontWarnTs(0), checkLimit(0),
1463 mutex(false,tx ? "BrfDevIoTx" : "BrfDevIoRx"),
1464 startTime(0), transferred(0),
1465 timestamp(0), lastTs(0), buffers(0), hdrLen(0), bufSamples(0),
1466 bufSamplesLen(0), crtBuf(0), crtBufSampOffs(0), newBuffer(true),
1467 dataDumpParams(""), dataDump(0), dataDumpFile(brfDir(tx)),
1468 upDumpParams(""), upDump(0), upDumpFile(String(brfDir(tx)) + "-APP"),
1469 captureMutex(false,tx ? "BrfCaptureTx" : "BrfCaptureRx"),
1470 captureSemaphore(1,tx ? "BrfCaptureTx" : "BrfCaptureRx",1),
1471 captureBuf(0), captureSamples(0),
1472 captureTs(0), captureOffset(0), captureStatus(0),
1473 m_tx(tx), m_bufEndianOk(BRF_LITTLE_ENDIAN)
1474 {}
tx() const1475 inline bool tx() const
1476 { return m_tx; }
resetSamplesBuffer(unsigned int nSamples,unsigned int hLen,unsigned int nBuffers=1)1477 void resetSamplesBuffer(unsigned int nSamples, unsigned int hLen,
1478 unsigned int nBuffers = 1) {
1479 bufSamples = nSamples;
1480 bufSamplesLen = samplesi2bytes(bufSamples);
1481 hdrLen = hLen;
1482 bufLen = hdrLen + bufSamplesLen;
1483 buffers = nBuffers ? nBuffers : 1;
1484 buffer.assign(0,buffers * bufLen);
1485 resetPosTime();
1486 }
resetPosTime()1487 inline void resetPosTime() {
1488 resetBufPos(m_tx);
1489 timestamp = 0;
1490 lastTs = 0;
1491 startTime = 0;
1492 transferred = 0;
1493 }
reset()1494 inline void reset()
1495 { resetPosTime(); }
advanceBuffer()1496 inline bool advanceBuffer() {
1497 if (crtBuf < buffers)
1498 setCrtBuf(crtBuf + 1);
1499 newBuffer = true;
1500 return crtBuf < buffers;
1501 }
bufStart(unsigned int index)1502 inline uint8_t* bufStart(unsigned int index)
1503 { return buffer.data(index * bufLen); }
samples(unsigned int index)1504 inline int16_t* samples(unsigned int index)
1505 { return (int16_t*)(bufStart(index) + hdrLen); }
samplesEOF(unsigned int index)1506 inline int16_t* samplesEOF(unsigned int index)
1507 { return (int16_t*)(bufStart(index) + bufLen); }
1508 // Retrieve a pointer to current buffer samples start (including offset)
1509 // and available samples number
crtBufSamples(unsigned int & avail)1510 inline int16_t* crtBufSamples(unsigned int& avail) {
1511 avail = bufSamples - crtBufSampOffs;
1512 return samples(crtBuf) + crtBufSampOffs * 2;
1513 }
bufTs(unsigned int index)1514 inline uint64_t bufTs(unsigned int index) {
1515 // Skip reserved
1516 uint32_t* u = (uint32_t*)(bufStart(index) + 4);
1517 // Get timestamp (LOW32 + HI32, little endian)
1518 uint64_t ts = le32toh((uint32_t)(*u++ >> 1));
1519 return ts | ((uint64_t)le32toh(*u) << 31);
1520 }
setBufTs(unsigned int index,uint64_t ts)1521 inline void setBufTs(unsigned int index, uint64_t ts) {
1522 uint32_t* u = (uint32_t*)(bufStart(index));
1523 *u++ = htole32(0xdeadbeef);
1524 *u++ = htole32((uint32_t)(ts << 1));
1525 *u++ = htole32((uint32_t)(ts >> 31));
1526 *u = htole32((uint32_t)-1);
1527 }
resetBufPos(bool start=true)1528 inline void resetBufPos(bool start = true) {
1529 #ifndef LITTLE_ENDIAN
1530 m_bufEndianOk = false;
1531 #endif
1532 setCrtBuf(start ? 0 : buffers);
1533 newBuffer = true;
1534 }
fixEndian()1535 inline void fixEndian() {
1536 #ifndef LITTLE_ENDIAN
1537 if (m_bufEndianOk)
1538 return;
1539 m_bufEndianOk = true;
1540 uint8_t* d = buffer.data(0);
1541 for (unsigned int i = 0; i < buffers; i++) {
1542 d += hdrLen;
1543 for (uint8_t* last = d + bufSamplesLen; d != last; d += 2) {
1544 uint8_t tmp = *d;
1545 *d = d[1];
1546 d[1] = tmp;
1547 }
1548 }
1549 #endif
1550 }
dumpInt16Samples(String & s,unsigned int index,unsigned int sampOffs=0,int nSamples=-1)1551 inline void dumpInt16Samples(String& s, unsigned int index, unsigned int sampOffs = 0,
1552 int nSamples = -1) {
1553 int16_t* p = samples(index) + sampOffs * 2;
1554 unsigned int n = bufSamples - sampOffs;
1555 if (nSamples > 0 && nSamples < (int)n)
1556 n = nSamples;
1557 for (int16_t* last = (p + n * 2); p != last; p += 2) {
1558 if (s)
1559 s << " ";
1560 s << p[0] << "," << p[1];
1561 }
1562 }
1563
1564 int showBuf; // Show buffers
1565 bool showBufData; // Display buffer data
1566 int checkTs; // Check IO buffers timestamp
1567 int dontWarnTs; // Don't warn on invalid buffer timestamp
1568 int checkLimit; // Check IO buffers sample limit
1569 Mutex mutex; // Protect data changes when needed
1570 uint64_t startTime; // Absolute time for start (first TX/RX)
1571 uint64_t transferred; // The number of samples transferred
1572 // TX/RX data
1573 uint64_t timestamp; // Last timestamp to/from device
1574 uint64_t lastTs; // Last buffer timestamp (used when checking)
1575 unsigned int buffers; // The number of buffers
1576 unsigned int hdrLen; // Header length in bytes
1577 unsigned int bufSamples; // Length of a single buffer in samples (without header)
1578 unsigned int bufSamplesLen; // Length of a single buffer in bytes (without header)
1579 unsigned int bufLen; // Length of a single buffer (in bytes)
1580 unsigned int crtBuf; // Current buffer
1581 unsigned int crtBufSampOffs; // Current buffer samples offset
1582 bool newBuffer; // New buffer to process
1583 DataBlock buffer; // I/O buffer
1584 BrfBufsThreshold firstBufsThres; // Initial samplerate/bufs data
1585 // File dump
1586 NamedList dataDumpParams;
1587 int dataDump;
1588 RadioDataFile dataDumpFile;
1589 NamedList upDumpParams;
1590 int upDump;
1591 RadioDataFile upDumpFile;
1592 // Capture
1593 Mutex captureMutex;
1594 Semaphore captureSemaphore;
1595 float* captureBuf;
1596 unsigned int captureSamples;
1597 uint64_t captureTs;
1598 unsigned int captureOffset;
1599 unsigned int captureStatus;
1600 String captureError;
1601
1602 protected:
1603 // Reset current buffer to start
setCrtBuf(unsigned int index=0)1604 inline void setCrtBuf(unsigned int index = 0) {
1605 crtBuf = index;
1606 crtBufSampOffs = 0;
1607 }
1608 bool m_tx;
1609 bool m_bufEndianOk;
1610 };
1611
1612 // Temporary change alt setting. Restore on destruction
1613 class BrfDevTmpAltSet
1614 {
1615 public:
BrfDevTmpAltSet(BrfLibUsbDevice * dev)1616 inline BrfDevTmpAltSet(BrfLibUsbDevice* dev)
1617 : m_device(dev), m_oper(0), m_tmpAltSet(BRF_ALTSET_INVALID)
1618 {}
BrfDevTmpAltSet(BrfLibUsbDevice * dev,int altSet,unsigned int & status,String * error,const char * oper)1619 inline BrfDevTmpAltSet(BrfLibUsbDevice* dev, int altSet,
1620 unsigned int& status, String* error, const char* oper)
1621 : m_device(dev), m_oper(0), m_tmpAltSet(BRF_ALTSET_INVALID)
1622 { status = set(altSet,error,oper); }
1623 // Temporary change to RF_LINK
BrfDevTmpAltSet(BrfLibUsbDevice * dev,unsigned int & status,String * error,const char * oper)1624 inline BrfDevTmpAltSet(BrfLibUsbDevice* dev, unsigned int& status, String* error,
1625 const char* oper)
1626 : m_device(dev), m_oper(0), m_tmpAltSet(BRF_ALTSET_INVALID)
1627 { status = set(BRF_ALTSET_RF_LINK,error,oper); }
~BrfDevTmpAltSet()1628 inline ~BrfDevTmpAltSet()
1629 { restore(); }
1630 unsigned int set(int altSet, String* error, const char* oper);
set(String * error,const char * oper)1631 inline unsigned int set(String* error, const char* oper)
1632 { return set(BRF_ALTSET_RF_LINK,error,oper); }
1633 unsigned int restore();
1634 private:
1635 BrfLibUsbDevice* m_device;
1636 const char* m_oper;
1637 int m_tmpAltSet;
1638 };
1639
1640
1641 /**
1642 * Clock discipline algorithm to sync the BladeRF's VCTCXO to local machine's clock.
1643 * It's intended to maintain (measure and correct) sampling rate drifts,
1644 * caused by equipment aging and factory faults, within a desired range.
1645 *
1646 * The accuracy of the measured drift is highly impacted by these factors:
1647 * - the drift of the local machine's clock against the real time
1648 * - the accuracy of pinning radio board samples to local machine timestamps
1649 * - the time allocated for measuring the average sampling rate (a.k.a. baseline)
1650 */
1651 class BrfVctcxoDiscipliner {
1652
1653 public:
1654 /// Create a discipliner with default settings, waiting to be activated and configured through control messages.
BrfVctcxoDiscipliner()1655 BrfVctcxoDiscipliner()
1656 : m_trimsLeft(0), m_confSampleRate(0), m_freqOffset(0), m_resumePoint(0),
1657 m_samples(0), m_timestamp(0), m_delay(0), m_bestDelay(0), m_maxDelay(0),
1658 m_knownDelay(0), m_systemAccuracy(BRF_SYSTEM_ACCURACY_DEF), m_accuracyPpb(BRF_ACCURACY_PPB_DEF),
1659 m_nextPinning(0), m_driftPpb(0), m_trace(false), m_dumpDelays(0)
1660 { }
1661
1662 /// Handle clock discipline commands
1663 bool onCmdFreqCal(Message& msg, bool start = true);
1664
1665 /// Postpone activity for the specified period and drop current data
1666 void postponeActivity(unsigned minutes, bool dropData = false);
1667
1668 /// Stop activity and drop gathered data
1669 void disableDiscipline(bool onCmd = false);
1670
1671 /**
1672 * Discipline the BladeRF's VCTCXO to local machine's clock
1673 * This method should be called when the BrfModule catches an engine.timer message
1674 * @param timestamp the call time in microseconds
1675 * @param drift a drift expressed in ppb, to be forcefully corrected
1676 */
1677 void trimVctcxo(uint64_t timestamp = Time::now(), int drift = 0);
1678
1679 protected:
1680 /// Update the baseline interval
1681 void scheduleNextPinning(uint16_t delay);
1682 /// Update parameters and drop current data if the configuration is outdated
1683 bool outdatedConfig();
1684 /// If it's missing, do the initial sample measurement
1685 bool init();
1686 /// Trim the VCTCXO based on the measured drift and dispatch a message with the new frequency offset
1687 bool processData(int drift);
1688 /// Compute the average radio sampling rate and return the drift (ppb) for the current interval
1689 int measureDrift(uint64_t& samples, uint64_t& timestamp, uint16_t& delay);
1690 /// Get the most accurate radio board sample measurement out of a given number
1691 void samplesAndTimestamp(uint64_t& samples, uint64_t& timestamp, uint16_t& delay,
1692 unsigned maxIter = 10);
1693 /// Convert microseconds to minutes (floor division)
usToMin(uint64_t us)1694 inline unsigned usToMin(uint64_t us)
1695 { return us / 60000000UL; }
1696 /// The BladeRF device associated with this object
1697 virtual BrfLibUsbDevice& dev() =0;
1698
1699 int m_trimsLeft; ///< number of scheduled clock trims, 0 toggles to idle, -1 toggles to always active
1700 unsigned m_confSampleRate; ///< configured sampling rate (Hz)
1701 float m_freqOffset; ///< frequency offset, as a number converted from VCTCXO's voltage to pass through a digital to analog converter
1702 uint64_t m_resumePoint; ///< when postponed, activity resumes after this timestamp (microsec)
1703 uint64_t m_samples; ///< initial pinning of radio board samples
1704 uint64_t m_timestamp; ///< initial pinning timestamp (microsec)
1705 uint16_t m_delay; ///< initial pinning duration (microsec)
1706 uint16_t m_bestDelay; ///< minimum pinning delay (microsec), used to identify highly accurate measurements
1707 uint16_t m_maxDelay; ///< maximum pinning delay (microsec), used to identify highly inaccurate measurements
1708 uint16_t m_knownDelay; ///< fixed, known pinning delay (microsec), used as reference for assuming delay variations
1709 uint16_t m_systemAccuracy; ///< overall accuracy of the sync mechanism (microsec)
1710 unsigned m_accuracyPpb; ///< accuracy of the sampling rate measurement, expressed in ppb
1711 uint64_t m_nextPinning; ///< final pinning of samples is scheduled after this timestamp (microsec)
1712 int m_driftPpb; ///< drift of the sampling rate, expressed in ppb
1713 bool m_trace; ///< this variable is used in test mode to display debug messages
1714 unsigned int m_dumpDelays; ///< number of delays to calculate and dump
1715 String m_delayStat; ///< store delays every few seconds, then dump it for analysis
1716
1717 static const float s_ppbPerUnit; ///< the unit of m_freqOffset expressed as ppb
1718 // 1.9 for max ppm range, expressed in ppb
1719 // 1.25 for voltage range conversion of 0.4 - 2.4V to 0 - 2.5V
1720 // 2 ** 8 for integer range of m_freqOffset
1721 };
1722
1723
1724 class BrfThread;
1725 class BrfSerialize;
1726
1727 class BrfLibUsbDevice : public GenObject, public BrfVctcxoDiscipliner
1728 {
1729 friend class BrfDevTmpAltSet;
1730 friend class BrfThread;
1731 friend class BrfModule;
1732 friend class BrfInterface;
1733 friend class BrfSerialize;
1734 friend class BrfDevState;
1735 friend class BrfBbCalData;
1736 friend class BrfVctcxoDiscipliner;
1737 public:
1738 enum UartDev {
1739 UartDevGPIO = 0,
1740 UartDevLMS,
1741 UartDevVCTCXO,
1742 UartDevSI5338,
1743 UartDevCount
1744 };
1745 enum Endpoint {
1746 EpSendSamples = 0,
1747 EpSendCtrl,
1748 EpReadSamples,
1749 EpReadCtrl,
1750 EpCount
1751 };
1752 // LNA selection
1753 enum LmsLna {
1754 LmsLnaNone = 0, // Disable all LNAs
1755 LmsLna1, // Enable LNA1 (300MHz - 2.8GHz)
1756 LmsLna2, // Enable LNA2 (1.5GHz - 3.8GHz)
1757 LmsLna3, // Enable LNA3 (Unused on the bladeRF)
1758 LmsLnaDetect,
1759 };
1760 // PA Selection
1761 enum LmsPa {
1762 LmsPaNone = 0, // All PAs disabled
1763 LmsPa1, // PA1 Enable (300MHz - 2.8GHz)
1764 LmsPa2, // PA2 Enable (1.5GHz - 3.8GHz)
1765 LmsPaAux, // AUX PA Enable (for RF Loopback)
1766 };
1767 // LNA gain values
1768 enum LnaGain {
1769 LnaGainUnhandled = 0,
1770 LnaGainBypass = 1,
1771 LnaGainMid = 2,
1772 LnaGainMax = 3,
1773 };
1774 // Correction types (LMS and FPGA). Keep them in the same order
1775 // (values are used as array index)
1776 enum CorrectionType {
1777 CorrLmsI = 0,
1778 CorrLmsQ,
1779 CorrFpgaPhase,
1780 CorrFpgaGain,
1781 CorrCount
1782 };
1783 // Loopback mode
1784 enum Loopback {
1785 LoopNone = 0, // Disabled
1786 LoopFirmware, // Firmware loopback
1787 LoopLpfToRxOut, // Baseband: TX LPF -> RX out
1788 LoopLpfToVga2, // Baseband: TX LPF -> RX VGA2
1789 LoopVga1ToVga2, // Baseband: TX VGA1 -> RX VGA2
1790 LoopLpfToLpf, // Baseband: TX LPF -> RX LPF
1791 LoopVga1ToLpf, // Baseband: TX VGA1 -> RX LPF
1792 LoopRfLna1, // RF: mixer after PA -> LNA1
1793 LoopRfLna2, // RF: mixer after PA -> LNA2
1794 LoopRfLna3, // RF: mixer after PA -> LNA3
1795 LoopUnknown
1796 };
1797 enum Lpf {
1798 LpfInvalid = 0,
1799 LpfDisabled = 1,
1800 LpfBypass,
1801 LpfNormal,
1802 };
1803 // Flags used to restore dev status
1804 enum StatusFlags {
1805 DevStatFreq = 0x00000001,
1806 DevStatVga1 = 0x00000002,
1807 DevStatVga2 = 0x00000004,
1808 DevStatLpf = 0x00000008,
1809 DevStatDcI = 0x00000010,
1810 DevStatDcQ = 0x00000020,
1811 DevStatLpfBw = 0x00000040,
1812 DevStatSampleRate = 0x00000080,
1813 DevStatFpgaPhase = 0x00000100,
1814 DevStatFpgaGain = 0x00000200,
1815 DevStatLoopback = 0x00000400,
1816 DevStatRxDcAuto = 0x00000800,
1817 DevStatTxPattern = 0x00001000,
1818 DevStatTs = 0x00002000,
1819 DevStatPowerBalance = 0x10000000,
1820 DevStatAbortOnFail = 0x80000000,
1821 DevStatVga = DevStatVga1 | DevStatVga2,
1822 DevStatDc = DevStatDcI | DevStatDcQ,
1823 DevStatFpga = DevStatFpgaPhase | DevStatFpgaGain,
1824 };
1825 // Calibration status
1826 enum CalStatus {
1827 Calibrate = 0, // Not calibrated (not done or failed)
1828 Calibrated, // Succesfully calibrated
1829 Calibrating, // Calibration in progress
1830 };
1831 ~BrfLibUsbDevice();
owner() const1832 inline BrfInterface* owner() const
1833 { return m_owner; }
handle() const1834 inline libusb_device_handle* handle() const
1835 { return m_devHandle; }
capabilities()1836 inline RadioCapability& capabilities()
1837 { return m_radioCaps; }
validPort(unsigned int port) const1838 inline bool validPort(unsigned int port) const
1839 { return port < m_radioCaps.currPorts; }
speed() const1840 inline int speed() const
1841 { return m_devSpeed; }
speedStr() const1842 inline const char* speedStr() const
1843 { return speedStr(speed()); }
bus() const1844 inline int bus() const
1845 { return m_devBus; }
addr() const1846 inline int addr() const
1847 { return m_devAddr; }
address() const1848 inline const String& address() const
1849 { return m_address; }
serial() const1850 inline const String& serial() const
1851 { return m_devSerial; }
fwVerStr() const1852 inline const String& fwVerStr() const
1853 { return m_devFwVerStr; }
fpgaFile() const1854 inline const String& fpgaFile() const
1855 { return m_devFpgaFile; }
fpgaMD5() const1856 inline const String& fpgaMD5() const
1857 { return m_devFpgaMD5; }
fpgaVerStr() const1858 inline const String& fpgaVerStr() const
1859 { return m_devFpgaVerStr; }
lmsVersion() const1860 inline const String& lmsVersion() const
1861 { return m_lmsVersion; }
exiting() const1862 inline bool exiting() const
1863 { return m_exiting; }
exiting(bool on)1864 inline void exiting(bool on)
1865 { m_exiting = on; }
closing() const1866 inline bool closing() const
1867 { return m_closing; }
cancelled(String * error=0)1868 inline unsigned int cancelled(String* error = 0) {
1869 if (exiting() || closing()) {
1870 if (error)
1871 *error = "Exiting";
1872 return RadioInterface::Cancelled;
1873 }
1874 return checkCancelled(error);
1875 }
showBuf(bool tx,int val,bool tsOnly)1876 inline int showBuf(bool tx, int val, bool tsOnly) {
1877 Lock lck(m_dbgMutex);
1878 getIO(tx).showBufData = !tsOnly;
1879 return (getIO(tx).showBuf = val);
1880 }
checkTs(bool tx,int val)1881 inline int checkTs(bool tx, int val) {
1882 Lock lck(m_dbgMutex);
1883 return (getIO(tx).checkTs = val);
1884 }
checkLimit(bool tx,int val)1885 inline int checkLimit(bool tx, int val) {
1886 Lock lck(m_dbgMutex);
1887 return (getIO(tx).checkLimit = val);
1888 }
showRxDCInfo(int val)1889 inline int showRxDCInfo(int val) {
1890 Lock lck(m_dbgMutex);
1891 return (m_rxShowDcInfo = val);
1892 }
bufSamples(bool tx)1893 inline unsigned int bufSamples(bool tx)
1894 { return getIO(tx).bufSamples; }
bufCount(bool tx)1895 inline unsigned int bufCount(bool tx)
1896 { return getIO(tx).buffers; }
totalSamples(bool tx)1897 inline unsigned int totalSamples(bool tx) {
1898 BrfDevIO& io = getIO(tx);
1899 return io.buffers * io.bufSamples;
1900 }
freqOffset() const1901 inline float freqOffset() const
1902 { return m_freqOffset; }
1903 // Open (on=false)/close RXOUTSW switch
setRxOut(bool on)1904 inline unsigned int setRxOut(bool on)
1905 { return writeLMS(0x09,on ? 0x80 : 0x00,0x80); }
1906 unsigned int setTxPattern(const String& pattern, float gain = 1.0F);
1907 void dumpStats(String& buf, const char* sep);
1908 void dumpTimestamps(String& buf, const char* sep);
1909 void dumpDev(String& buf, bool info, bool state, const char* sep,
1910 bool fromStatus = false, bool withHdr = true);
1911 void dumpBoardStatus(String& buf, const char* sep);
1912 unsigned int dumpPeripheral(uint8_t dev, uint8_t addr, uint8_t len, String* buf = 0);
1913 // Module reload
1914 void reLoad(const NamedList* params = 0);
1915 void setDataDump(int dir = 0, int level = 0, const NamedList* params = 0);
1916 // Open the device
1917 // Call the reset method in order to set the device to a known state
1918 unsigned int open(const NamedList& params, String& error);
1919 // Initialize operating parameters
1920 unsigned int initialize(const NamedList& params);
1921 // Check if parameters are set
1922 unsigned int isInitialized(bool tx, bool rx, String* error);
1923 // Close the device.
1924 void close();
1925 // Power on the radio
1926 // Enable timestamps, enable RF TX/RX
1927 unsigned int powerOn();
1928 // Send an array of samples waiting to be transmitted
1929 // samples: The number of I/Q samples (i.e. half buffer lengh)
1930 unsigned int syncTx(uint64_t ts, float* data, unsigned int samples,
1931 float* powerScale = 0, bool internal = false);
1932 // Receive data from the Rx interface of the bladeRF device
1933 // samples: The number of I/Q samples (i.e. half buffer lengh)
1934 unsigned int syncRx(uint64_t& ts, float* data, unsigned int& samples,
1935 String* error = 0, bool internal = false);
1936 // Capture data
1937 unsigned int capture(bool tx, float* buf, unsigned int samples, uint64_t& ts,
1938 String* error = 0);
1939 // Set the frequency on the Tx or Rx side
1940 unsigned int setFrequency(uint64_t hz, bool tx);
1941 // Retrieve frequency
1942 unsigned int getFrequency(uint32_t& hz, bool tx);
1943 // Set frequency offset
1944 unsigned int setFreqOffset(float offs, float* newVal = 0, bool stopAutoCal = true);
1945 // Get frequency offset
1946 unsigned int getFreqOffset(float& offs);
1947 // Set the LPF bandwidth for a specific module
1948 unsigned int setLpfBandwidth(uint32_t band, bool tx);
1949 // Get the LPF bandwidth for a specific module
1950 unsigned int getLpfBandwidth(uint32_t& band, bool tx);
1951 // LPF set/get
1952 unsigned int setLpf(int lpf, bool tx);
1953 unsigned int getLpf(int& lpf, bool tx);
1954 // Set the sample rate on a specific module
1955 unsigned int setSamplerate(uint32_t value, bool tx);
1956 // Get the sample rate on a specific module
1957 unsigned int getSamplerate(uint32_t& value, bool tx);
1958 // Set the pre-mixer gain on transmission (interval [-35..-4])
1959 // Set the post-mixer gain setting on transmission (interval: [0..25])
1960 unsigned int setTxVga(int vga, bool preMixer);
1961 // Set the post-mixer gain setting on transmission (interval: [0..25])
setTxVga1(int vga)1962 inline unsigned int setTxVga1(int vga)
1963 { return setTxVga(vga,true); }
setTxVga2(int vga)1964 inline unsigned int setTxVga2(int vga)
1965 { return setTxVga(vga,false); }
1966 // Retrieve the pre/post mixer gain setting on transmission
1967 unsigned int getTxVga(int& vga, bool preMixer);
getTxVga1(int & vga)1968 inline unsigned int getTxVga1(int& vga)
1969 { return getTxVga(vga,true); }
getTxVga2(int & vga)1970 inline unsigned int getTxVga2(int& vga)
1971 { return getTxVga(vga,false); }
1972 // Set TX power balance
1973 unsigned int setTxIQBalance(float value);
1974 // Enable or disable the pre/post mixer gain on the receive side
1975 unsigned int enableRxVga(bool on, bool preMixer);
enableRxVga1(bool on)1976 inline unsigned int enableRxVga1(bool on)
1977 { return enableRxVga(on,true); }
enableRxVga2(bool on)1978 inline unsigned int enableRxVga2(bool on)
1979 { return enableRxVga(on,false); }
1980 // Set the pre-mixer RX gain setting on the receive side (interval [5..30])
1981 // Set the post-mixer RX gain setting (interval [0..30])
1982 unsigned int setRxVga(int vga, bool preMixer);
setRxVga1(int vga)1983 inline unsigned int setRxVga1(int vga)
1984 { return setRxVga(vga,true); }
setRxVga2(int vga)1985 inline unsigned int setRxVga2(int vga)
1986 { return setRxVga(vga,false); }
1987 // Retrieve the pre/post mixer rx gain setting
1988 unsigned int getRxVga(int& vga, bool preMixer);
getRxVga1(int & vga)1989 inline unsigned int getRxVga1(int& vga)
1990 { return getRxVga(vga,true); }
getRxVga2(int & vga)1991 inline unsigned int getRxVga2(int& vga)
1992 { return getRxVga(vga,false); }
1993 // Set pre and post mixer value
1994 unsigned int setGain(bool tx, int val, int* newVal = 0);
1995 // Run check / calibration procedure
1996 unsigned int calibrate(bool sync = true, const NamedList& params = NamedList::empty(),
1997 String* error = 0, bool fromInit = false);
1998 // Set Tx/Rx DC I/Q offset correction
1999 unsigned int setDcOffset(bool tx, bool i, int16_t value);
2000 // Retrieve Tx/Rx DC I/Q offset correction
2001 unsigned int getDcOffset(bool tx, bool i, int16_t& value);
2002 // Set/Get FPGA correction
2003 unsigned int setFpgaCorr(bool tx, int corr, int16_t value);
2004 unsigned int getFpgaCorr(bool tx, int corr, int16_t& value);
2005 // Retrieve TX/RX timestamp
2006 unsigned int getTimestamp(bool tx, uint64_t& ts);
2007 // Retrieve TX radio timestamp (samples) with the current timestamp from the local machine
2008 unsigned int samplesAndTimestamp(uint64_t& samples, uint64_t& timestamp, uint16_t& delay,
2009 String* serializeErr);
2010 // Write LMS register(s)
2011 unsigned int writeLMS(uint8_t addr, uint8_t value, uint8_t* rst = 0,
2012 String* error = 0, bool internal = false);
writeLMS(uint8_t addr,uint8_t value,uint8_t rst,String * error=0,bool internal=false)2013 unsigned int writeLMS(uint8_t addr, uint8_t value, uint8_t rst,
2014 String* error = 0, bool internal = false)
2015 { return writeLMS(addr,value,&rst,error,internal); }
2016 unsigned int writeLMS(const String& str, String* error = 0, bool internal = false);
2017 // Read LMS register(s)
2018 unsigned int readLMS(uint8_t addr, uint8_t& value, String* error = 0,
2019 bool internal = false);
2020 unsigned int readLMS(String& dest, const String* read, bool readIsInterleaved,
2021 String* error = 0, bool internal = false);
2022 // Check LMS registers
2023 unsigned int checkLMS(const String& what, String* error = 0, bool internal = false);
2024 // Enable or disable loopback
2025 unsigned int setLoopback(const char* name = 0,
2026 const NamedList& params = NamedList::empty());
2027 // Set parameter(s)
2028 unsigned int setParam(const String& param, const String& value,
2029 const NamedList& params = NamedList::empty());
2030 // Utility: run device send data
2031 void runSend(BrfThread* th);
2032 // Utility: run device recv data
2033 void runRecv(BrfThread* th);
2034 // Build notification message
2035 Message* buildNotify(const char* status = 0);
notifyFreqOffs()2036 inline void notifyFreqOffs() {
2037 Message* m = buildNotify();
2038 m->addParam("RadioFrequencyOffset",String(m_freqOffset));
2039 Engine::enqueue(m);
2040 }
2041 // Release data
2042 virtual void destruct();
2043 // Utilities
speedStr(int speed)2044 static const char* speedStr(int speed) {
2045 switch (speed) {
2046 case LIBUSB_SPEED_SUPER:
2047 return "SUPER";
2048 case LIBUSB_SPEED_HIGH:
2049 return "HIGH";
2050 }
2051 return "Unknown";
2052 }
2053 static uint64_t reduceFurther(uint64_t v1, uint64_t v2);
2054 static void reduceRational(BrfRationalRate& rate);
rationalDouble(BrfRationalRate & rate)2055 static inline void rationalDouble(BrfRationalRate& rate) {
2056 rate.integer *= 2;
2057 rate.numerator *= 2;
2058 reduceRational(rate);
2059 }
2060 static void calcSrate(Si5338MultiSynth& synth, BrfRationalRate& rate);
2061 static unsigned int calcMultiSynth(Si5338MultiSynth& synth,
2062 BrfRationalRate& rate, String* error = 0);
2063 static void packRegs(Si5338MultiSynth& synth);
2064 static void unpackRegs(Si5338MultiSynth& synth);
2065 // Set error string
setError(unsigned int code,String * buf,const char * error,const char * prefix=0)2066 static inline unsigned int setError(unsigned int code, String* buf,
2067 const char* error, const char* prefix = 0) {
2068 if (!(buf && code))
2069 return code;
2070 String tmp = prefix;
2071 tmp.append((error && *error) ? error : RadioInterface::errorName(code)," - ");
2072 buf->append(tmp," - ");
2073 return code;
2074 }
setErrorFail(String * buf,const char * error,const char * prefix=0)2075 static inline unsigned int setErrorFail(String* buf, const char* error,
2076 const char* prefix = 0)
2077 { return setError(RadioInterface::Failure,buf,error,prefix); }
setErrorTimeout(String * buf,const char * error,const char * prefix=0)2078 static inline unsigned int setErrorTimeout(String* buf, const char* error,
2079 const char* prefix = 0)
2080 { return setError(RadioInterface::Timeout,buf,error,prefix); }
setErrorNotInit(String * buf,const char * error="not initialized",const char * prefix=0)2081 static inline unsigned int setErrorNotInit(String* buf,
2082 const char* error = "not initialized", const char* prefix = 0)
2083 { return setError(RadioInterface::NotInitialized,buf,error,prefix); }
setUnkValue(String & buf,const char * unsupp=0,const char * invalid=0)2084 static inline unsigned int setUnkValue(String& buf, const char* unsupp = 0,
2085 const char* invalid = 0) {
2086 if (unsupp)
2087 buf << "Unsupported " << unsupp;
2088 else if (invalid)
2089 buf << "Invalid " << invalid;
2090 else
2091 buf << "Unknown value";
2092 return RadioInterface::OutOfRange;
2093 }
setUnhandled(String & buf,int val,const char * what=0)2094 static inline unsigned int setUnhandled(String& buf, int val, const char* what = 0) {
2095 buf << "Unhandled";
2096 buf.append(what," ");
2097 buf << val;
2098 return RadioInterface::OutOfRange;
2099 }
2100 // Print libusb error
appendLusbError(String & buf,int code,const char * prefix=0)2101 static inline String& appendLusbError(String& buf, int code, const char* prefix = 0) {
2102 buf << prefix << "(" << code << " '" << ::libusb_error_name(code) << "')";
2103 return buf;
2104 }
2105 static unsigned int lusb2ifaceError(int code);
2106 // Utility: check libusb result against LIBUSB_SUCCESS
2107 // Print libusb result to string on failure and return radio iface code
lusbCheckSuccess(int code,String * error,const char * prefix=0)2108 static inline unsigned int lusbCheckSuccess(int code, String* error,
2109 const char* prefix = 0) {
2110 if (code == LIBUSB_TRANSFER_COMPLETED || code == LIBUSB_SUCCESS)
2111 return 0;
2112 if (error)
2113 appendLusbError(*error,code,prefix);
2114 return lusb2ifaceError(code);
2115 }
2116 // Retrieve UART addr for FPGA correction
fpgaCorrAddr(bool tx,bool phase)2117 static inline uint8_t fpgaCorrAddr(bool tx, bool phase) {
2118 if (phase)
2119 return tx ? 10 : 6;
2120 return tx ? 8 : 4;
2121 }
2122 // Retrieve LMS addr for I/Q correction
lmsCorrIQAddr(bool tx,bool i)2123 static inline uint8_t lmsCorrIQAddr(bool tx, bool i) {
2124 if (tx)
2125 return i ? 0x42 : 0x43;
2126 return i ? 0x71 : 0x72;
2127 }
2128 // Retrieve LMS addr for TX/RX VGA 1/2
lmsVgaAddr(bool tx,bool preMixer)2129 static inline uint8_t lmsVgaAddr(bool tx, bool preMixer) {
2130 if (tx)
2131 return preMixer ? 0x41 : 0x45;
2132 return preMixer ? 0x76 : 0x65;
2133 }
2134 // Retrieve LMS LPF base address
lmsLpfAddr(bool tx)2135 static inline uint8_t lmsLpfAddr(bool tx)
2136 { return tx ? 0x34 : 0x54; }
2137 // Retrieve LMS PLL freq config addr
lmsFreqAddr(bool tx)2138 static inline uint8_t lmsFreqAddr(bool tx)
2139 { return tx ? 0x10 : 0x20; }
2140
2141 protected:
dev()2142 virtual BrfLibUsbDevice& dev()
2143 { return *this; }
2144
2145 private:
2146 BrfLibUsbDevice(BrfInterface* owner);
2147 void doClose();
resetTimestamps(bool tx)2148 inline void resetTimestamps(bool tx) {
2149 getIO(tx).reset();
2150 if (!tx) {
2151 m_rxTimestamp = 0;
2152 m_rxResyncCandidate = 0;
2153 }
2154 }
2155 // Batch state update
2156 unsigned int setState(BrfDevState& state, String* error = 0);
2157 // Request changes (synchronous TX). Wait for change
setStateSyncTx(unsigned int flags=0,String * error=0,bool fatal=true)2158 inline unsigned int setStateSyncTx(unsigned int flags = 0, String* error = 0,
2159 bool fatal = true) {
2160 m_syncTxState.setFlags(fatal ? DevStatAbortOnFail : 0,flags);
2161 return setStateSync(error);
2162 }
setStateSyncRx(unsigned int flags=0,String * error=0,bool fatal=true)2163 inline unsigned int setStateSyncRx(unsigned int flags = 0, String* error = 0,
2164 bool fatal = true) {
2165 m_syncTxState.setFlags(fatal ? DevStatAbortOnFail : 0,0,flags);
2166 return setStateSync(error);
2167 }
setStateSyncLoopback(int lp,const NamedList & params,String * error=0)2168 inline unsigned int setStateSyncLoopback(int lp, const NamedList& params,
2169 String* error = 0) {
2170 m_syncTxState.setFlags(DevStatLoopback);
2171 m_syncTxState.setLoopback(lp,params);
2172 return setStateSync(error);
2173 }
2174 unsigned int setStateSync(String* error = 0);
2175 void internalDumpDev(String& buf, bool info, bool state, const char* sep,
2176 bool internal, bool fromStatus = false, bool withHdr = true);
2177 unsigned int internalPowerOn(bool rfLink, bool tx = true, bool rx = true,
2178 String* error = 0);
2179 // Send an array of samples waiting to be transmitted
2180 // samples: The number of I/Q samples (i.e. half buffer lengh)
2181 unsigned int send(uint64_t ts, float* data, unsigned int samples,
2182 float* powerScale = 0);
2183 void sendTxPatternChanged();
2184 void sendCopyTxPattern(int16_t* buf, unsigned int avail,
2185 float scaleI, int16_t maxI, float scaleQ, int16_t maxQ, unsigned int& clamped,
2186 const long* ampTable);
2187 unsigned int recv(uint64_t& ts, float* data, unsigned int& samples,
2188 String* error = 0);
2189 void captureHandle(BrfDevIO& io, const float* buf, unsigned int samples, uint64_t ts,
2190 unsigned int status, const String* error);
2191 unsigned int internalSetSampleRate(bool tx, uint32_t value, String* error = 0);
internalSetSampleRateBoth(uint32_t value,String * error=0)2192 inline unsigned int internalSetSampleRateBoth(uint32_t value, String* error = 0) {
2193 unsigned int status = internalSetSampleRate(true,value,error);
2194 return status ? status : internalSetSampleRate(false,value,error);
2195 }
2196 // Update FPGA (load, get version)
2197 unsigned int updateFpga(const NamedList& params);
2198 unsigned int internalSetFpgaCorr(bool tx, int corr, int16_t value,
2199 String* error = 0, int clampLevel = DebugNote);
2200 unsigned int internalGetFpgaCorr(bool tx, int corr, int16_t* value = 0,
2201 String* error = 0);
2202 unsigned int internalSetTxVga(int vga, bool preMixer, String* error = 0);
2203 unsigned int internalGetTxVga(int* vga, bool preMixer, String* error = 0);
2204 // Enable or disable the pre/post mixer gain on the receive side
2205 unsigned int internalEnableRxVga(bool on, bool preMixer, String* error = 0);
2206 unsigned int internalSetRxVga(int vga, bool preMixer, String* error = 0);
2207 unsigned int internalGetRxVga(int* vga, bool preMixer, String* error = 0);
internalRxVga(bool read,int & vga,bool preMixer,String * error=0)2208 inline unsigned int internalRxVga(bool read, int& vga, bool preMixer,
2209 String* error = 0) {
2210 if (read)
2211 return internalGetRxVga(&vga,preMixer,error);
2212 return internalSetRxVga(vga,preMixer,error);
2213 }
internalSetVga(bool tx,int vga,bool preMixer,String * error=0)2214 inline unsigned int internalSetVga(bool tx, int vga, bool preMixer,
2215 String* error = 0) {
2216 if (tx)
2217 return internalSetTxVga(vga,preMixer,error);
2218 return internalSetRxVga(vga,preMixer,error);
2219 }
2220 unsigned int internalSetGain(bool tx, int val, int* newVal = 0, String* error = 0);
2221 unsigned int internalSetTxIQBalance(bool newGain, float newBalance = 0,
2222 const char* param = 0);
2223 unsigned int setGainExp(float breakpoint, float max);
2224 unsigned int setPhaseExp(float breakpoint, float max);
internalSetCorrectionIQ(bool tx,int I,int Q,String * error=0)2225 inline unsigned int internalSetCorrectionIQ(bool tx, int I, int Q,
2226 String* error = 0) {
2227 unsigned int status = internalSetDcOffset(tx,true,I,error);
2228 return !status ? internalSetDcOffset(tx,false,Q,error) : status;
2229 }
internalSetDcCorr(int txI,int txQ,int rxI,int rxQ,String * error=0)2230 inline unsigned int internalSetDcCorr(int txI, int txQ, int rxI, int rxQ,
2231 String* error = 0) {
2232 unsigned int status = 0;
2233 BRF_FUNC_CALL(internalSetCorrectionIQ(true,txI,txQ,error));
2234 BRF_FUNC_CALL(internalSetCorrectionIQ(false,rxI,rxQ,error));
2235 return status;
2236 }
2237 unsigned int internalSetFreqOffs(float val, float* newVal, String* error = 0);
2238 unsigned int internalSetFrequency(bool tx, uint64_t val, String* error = 0);
2239 unsigned int internalGetFrequency(bool tx, uint32_t* hz = 0, String* error = 0);
2240 // Retrieve TX/RX timestamp
2241 unsigned int internalGetTimestamp(bool tx, uint64_t& ts, String* error = 0);
2242 // Retrieve and set frequency
restoreFreq(bool tx,String * error=0)2243 inline unsigned int restoreFreq(bool tx, String* error = 0) {
2244 uint32_t hz = 0;
2245 unsigned int status = internalGetFrequency(tx,&hz,error);
2246 return status == 0 ? internalSetFrequency(tx,hz,error) : status;
2247 }
2248 // Alt interface setting change
2249 unsigned int lusbSetAltInterface(int altSetting, String* error = 0);
2250 // Wrapper for libusb_control_transfer
2251 unsigned int lusbCtrlTransfer(uint8_t reqType, int8_t request, uint16_t value,
2252 uint16_t index, uint8_t* data, uint16_t len, String* error = 0,
2253 unsigned int tout = 0);
2254 // Wrapper for libusb synchronous bulk transfer
2255 unsigned int lusbBulkTransfer(uint8_t endpoint, uint8_t* data, unsigned int len,
2256 unsigned int* transferred = 0, String* error = 0, unsigned int tout = 0);
2257 // Make an async usb transfer
2258 unsigned int syncTransfer(int ep, uint8_t* data, unsigned int len, String* error = 0);
2259 // Select amplifier (PA/LNA) from low/high frequency
selectPaLna(bool tx,bool lowBand,String * error)2260 inline unsigned int selectPaLna(bool tx, bool lowBand, String* error) {
2261 if (tx)
2262 return paSelect(lowBand,error);
2263 return lnaSelect(lowBand ? LmsLna1 : LmsLna2,error);
2264 }
2265 // Read the value of a specific GPIO register
2266 unsigned int gpioRead(uint8_t addr, uint32_t& value, uint8_t len, String* error = 0,
2267 const char* loc = 0);
2268 // Write a value to a specific GPIO register
2269 unsigned int gpioWrite(uint8_t addr, uint32_t value, uint8_t len, String* error = 0,
2270 const char* loc = 0);
2271 // Read the lms configuration
lmsRead(uint8_t addr,uint8_t & data,String * error=0,const char * loc=0)2272 inline unsigned int lmsRead(uint8_t addr, uint8_t& data, String* error = 0,
2273 const char* loc = 0)
2274 { return accessPeripheralRead(UartDevLMS,addr,data,error,loc); }
lmsRead2(uint8_t addr1,uint8_t & data1,uint8_t addr2,uint8_t & data2,String * error=0,const char * loc=0)2275 inline unsigned int lmsRead2(uint8_t addr1, uint8_t& data1,
2276 uint8_t addr2, uint8_t& data2, String* error = 0, const char* loc = 0) {
2277 unsigned int status = lmsRead(addr1,data1,error,loc);
2278 return status == 0 ? lmsRead(addr2,data2,error,loc) : status;
2279 }
2280 // Write the lms configuration
2281 unsigned int lmsWrite(const String& str, bool updStat, String* error = 0);
2282 // Read the lms configuration
2283 // Read all if 'read' is null
2284 // 'read' non null: set 'readIsInterleaved' to true if 'read' is addr/value interleaved
2285 unsigned int lmsRead(String& dest, const String* read,
2286 bool readIsInterleaved, String* error = 0);
2287 // Check LMS registers
2288 unsigned int lmsCheck(const String& what, String* error = 0);
lmsWrite(uint8_t addr,uint8_t data,String * error=0,const char * loc=0)2289 inline unsigned int lmsWrite(uint8_t addr, uint8_t data, String* error = 0,
2290 const char* loc = 0)
2291 { return accessPeripheralWrite(UartDevLMS,addr,data,error,loc); }
lmsWrite2(uint8_t addr1,uint8_t data1,uint8_t addr2,uint8_t data2,String * error=0,const char * loc=0)2292 inline unsigned int lmsWrite2(uint8_t addr1, uint8_t data1,
2293 uint8_t addr2, uint8_t data2, String* error = 0, const char* loc = 0) {
2294 unsigned int status = lmsWrite(addr1,data1,error,loc);
2295 return status == 0 ? lmsWrite(addr2,data2,error,loc) : status;
2296 }
lms(bool read,uint8_t addr,uint8_t & data,String * error=0,const char * loc=0)2297 inline unsigned int lms(bool read, uint8_t addr, uint8_t& data,
2298 String* error = 0, const char* loc = 0) {
2299 if (read)
2300 return lmsRead(addr,data,error,loc);
2301 return lmsWrite(addr,data,error,loc);
2302 }
2303 // Read address from LMS, clear mask, set val (using OR) and write it back
lmsSet(uint8_t addr,uint8_t val,uint8_t clearMask,String * error=0)2304 inline unsigned int lmsSet(uint8_t addr, uint8_t val, uint8_t clearMask,
2305 String* error = 0) {
2306 uint8_t data = 0;
2307 unsigned int status = lmsRead(addr,data,error);
2308 return status ? status : lmsWrite(addr,(data & ~clearMask) | val,error);
2309 }
2310 // Read address from LMS, set val (using OR) and write it back
lmsSet(uint8_t addr,uint8_t val,String * error=0)2311 inline unsigned int lmsSet(uint8_t addr, uint8_t val, String* error = 0) {
2312 uint8_t data = 0;
2313 unsigned int status = lmsRead(addr,data,error);
2314 return status ? status : lmsWrite(addr,data | val,error);
2315 }
2316 // Read address from LMS, clear mask and write it back
lmsReset(uint8_t addr,uint8_t clearMask,String * error=0)2317 inline unsigned int lmsReset(uint8_t addr, uint8_t clearMask, String* error = 0) {
2318 uint8_t data = 0;
2319 unsigned int status = lmsRead(addr,data,error);
2320 return status ? status : lmsWrite(addr,(data & ~clearMask),error);
2321 }
2322 // Reset LMS addr using mask. Optionally set a value
lmsChange(uint8_t addr,uint8_t * maskReset,uint8_t * maskSet,String * error)2323 inline unsigned int lmsChange(uint8_t addr, uint8_t* maskReset, uint8_t* maskSet,
2324 String* error) {
2325 if (maskReset && maskSet)
2326 return lmsSet(addr,*maskSet,*maskReset,error);
2327 if (maskReset)
2328 return lmsReset(addr,*maskReset,error);
2329 return maskSet ? lmsSet(addr,*maskSet,error) : 0;
2330 }
lmsChangeMask(uint8_t addr,uint8_t mask,bool set,String * error)2331 inline unsigned int lmsChangeMask(uint8_t addr, uint8_t mask, bool set,
2332 String* error)
2333 { return lmsChange(addr,set ? 0 : &mask,set ? &mask : 0,error); }
2334 // LNA
2335 unsigned int lnaSelect(int lna, String* error = 0);
2336 unsigned int lnaEnable(bool on, String* error = 0);
2337 unsigned int lnaGainSet(uint8_t value, String* error = 0);
2338 unsigned int lnaGainGet(uint8_t& value, String* error = 0);
lnaGain(bool read,uint8_t & value,String * error=0)2339 inline unsigned int lnaGain(bool read, uint8_t& value, String* error = 0) {
2340 if (read)
2341 return lnaGainGet(value,error);
2342 return lnaGainSet(value,error);
2343 }
2344 // LPF set/get
2345 unsigned int internalSetLpfBandwidth(bool tx, uint32_t band, String* error = 0);
internalSetLpfBandwidthBoth(uint32_t band,String * error=0)2346 inline unsigned int internalSetLpfBandwidthBoth(uint32_t band, String* error = 0) {
2347 unsigned int status = internalSetLpfBandwidth(true,band,error);
2348 if (!status)
2349 status = internalSetLpfBandwidth(false,band,error);
2350 return status;
2351 }
2352 unsigned int internalSetLpf(bool tx, int lpf, String* error = 0);
2353 unsigned int internalGetLpf(bool tx, int* lpf, String* error = 0);
2354 // Fill the m_list member of the class
2355 unsigned int updateDeviceList(String* error = 0);
clearDeviceList()2356 inline void clearDeviceList() {
2357 if (!m_list)
2358 return;
2359 ::libusb_free_device_list(m_list,1);
2360 m_dev = 0;
2361 m_list = 0;
2362 m_listCount = 0;
2363 }
2364 // Enable/disable RF and sample circulation on both RX and TX sides
enableRfBoth(bool on,bool frontEndOnly,String * error=0)2365 inline unsigned int enableRfBoth(bool on, bool frontEndOnly, String* error = 0) {
2366 unsigned int status = enableRf(true,on,frontEndOnly,error);
2367 if (status == 0)
2368 return enableRf(false,on,frontEndOnly,error);
2369 return status;
2370 }
enableRfFpgaBoth(bool on,String * error=0)2371 inline unsigned int enableRfFpgaBoth(bool on, String* error = 0) {
2372 unsigned int status = enableRfFpga(true,on,error);
2373 if (status == 0)
2374 return enableRfFpga(false,on,error);
2375 return status;
2376 }
2377 unsigned int enableRf(bool tx, bool on, bool frontEndOnly = false, String* error = 0);
2378 unsigned int enableRfFpga(bool tx, bool on, String* error = 0);
2379 // Check if fpga is loaded
2380 // Return NoError/NotInitialized (result OK) or other error on failure
2381 unsigned int checkFpga();
2382 // Restore device after loading the FPGA
2383 unsigned int restoreAfterFpgaLoad(String* error = 0);
2384 // Change some LMS registers default value on open
2385 unsigned int openChangeLms(const NamedList& params, String* error = 0);
2386 // Reset the Usb interface using an ioctl call
2387 unsigned int resetUsb(String* error = 0);
2388 // Set the VCTCXO configuration to the correct value
2389 unsigned int tuneVcocap(uint8_t addr, String* error = 0);
2390 // Send requests to the bladeRF device regarding the FPGA image configuration.
2391 unsigned int vendorCommand(uint8_t cmd, uint8_t endpoint, uint8_t* data, uint16_t len,
2392 String* error = 0);
vendorCommand(uint8_t cmd,uint8_t endpoint,int32_t & data,String * error=0)2393 inline unsigned int vendorCommand(uint8_t cmd, uint8_t endpoint, int32_t& data,
2394 String* error = 0)
2395 { return vendorCommand(cmd,endpoint,(uint8_t*)&data,sizeof(data),error); }
vendorCommand0_4(uint8_t cmd,uint8_t endpoint,String * error=0)2396 inline unsigned int vendorCommand0_4(uint8_t cmd, uint8_t endpoint, String* error = 0) {
2397 uint32_t dummy = 0;
2398 return vendorCommand(cmd,endpoint,(uint8_t*)&dummy,4,error);
2399 }
2400 // Access the bladeRF board in order to transmit data
2401 unsigned int accessPeripheral(uint8_t dev, bool tx, uint8_t addr,
2402 uint8_t* data, String* error = 0, uint8_t len = 1, const char* loc = 0);
accessPeripheralWrite(uint8_t dev,uint8_t addr,uint8_t data,String * error=0,const char * loc=0)2403 inline unsigned int accessPeripheralWrite(uint8_t dev, uint8_t addr, uint8_t data,
2404 String* error = 0, const char* loc = 0)
2405 { return accessPeripheral(dev,true,addr,&data,error,1,loc); }
accessPeripheralRead(uint8_t dev,uint8_t addr,uint8_t & data,String * error=0,const char * loc=0)2406 inline unsigned int accessPeripheralRead(uint8_t dev, uint8_t addr, uint8_t& data,
2407 String* error = 0, const char* loc = 0)
2408 { return accessPeripheral(dev,false,addr,&data,error,1,loc); }
setSi5338(uint8_t addr,uint8_t data,String * error=0)2409 inline unsigned int setSi5338(uint8_t addr, uint8_t data, String* error = 0)
2410 { return accessPeripheralWrite(UartDevSI5338,addr,data,error); }
getSi5338(uint8_t addr,uint8_t & data,String * error=0)2411 inline unsigned int getSi5338(uint8_t addr, uint8_t& data, String* error = 0)
2412 { return accessPeripheralRead(UartDevSI5338,addr,data,error); }
2413 unsigned int internalSetDcOffset(bool tx, bool i, int16_t value, String* error = 0);
2414 unsigned int internalGetDcOffset(bool tx, bool i, int16_t* value, String* error = 0);
2415 unsigned int enableTimestamps(bool on = true, String* error = 0);
2416 unsigned int updateStatus(String* error = 0);
paSelect(bool lowBand,String * error=0)2417 inline unsigned int paSelect(bool lowBand, String* error = 0)
2418 { return paSelect(lowBand ? LmsPa1 : LmsPa2,error); }
2419 unsigned int paSelect(int pa, String* error = 0);
2420 int64_t clampInt(int64_t val, int64_t minVal, int64_t maxVal, const char* what = 0,
2421 int level = DebugNote);
clampIntParam(const NamedList & params,const String & param,int64_t defVal,int64_t minVal,int64_t maxVal,int level=DebugConf)2422 inline int64_t clampIntParam(const NamedList& params, const String& param,
2423 int64_t defVal, int64_t minVal, int64_t maxVal, int level = DebugConf)
2424 { return clampInt(params.getInt64Value(param,defVal),minVal,maxVal,param,level); }
2425 float clampFloat(float val, float minVal, float maxVal, const char* what = 0,
2426 int level = DebugNote);
clampFloatParam(const NamedList & params,const String & param,float defVal,float minVal,float maxVal,int level=DebugConf)2427 inline float clampFloatParam(const NamedList& params, const String& param,
2428 float defVal, float minVal, float maxVal, int level = DebugConf)
2429 { return clampFloat(params.getDoubleValue(param,defVal),minVal,maxVal,param,level); }
2430 unsigned int openDevice(bool claim, String* error = 0);
2431 void closeDevice();
2432 void closeUsbDev();
2433 void getDevStrDesc(String& data, uint8_t index, const char* what);
2434 // Read pages from device using contrt to 0 (from -35)ol transfer
2435 unsigned int ctrlTransferReadPage(uint8_t request, DataBlock& buf, String* error = 0);
2436 // Read calibration cache page from device
2437 unsigned int readCalCache(String* error = 0);
2438 // Retrieve a filed from a buffer of elements
2439 // Buffer format: 1 byte length + data + 2 bytes CRC16
2440 // Return error string on failure
2441 const char* getBufField(String& value, const char* field);
2442 // Read calibration cache field
2443 unsigned int getCalField(String& value, const String& name,
2444 const char* desc = 0, String* error = 0);
2445 String& dumpCalCache(String& dest);
2446 // Update speed related data
2447 unsigned int updateSpeed(const NamedList& params, String* error = 0);
2448 // Set I/O buffers
2449 void initBuffers(bool* txSet, unsigned int totalSamples, unsigned int txMinSend);
2450 // Compute Rx avg values, autocorrect offsets if configured
2451 void computeRx(uint64_t ts);
2452 // Check io timestamps
2453 void ioBufCheckTs(bool tx, unsigned int nBufs = 0);
2454 void setIoDontWarnTs(bool tx);
2455 // Check io samples limit
2456 void ioBufCheckLimit(bool tx, unsigned int nBufs = 0);
2457 // Alter data
2458 void updateAlterData(const NamedList& params);
2459 void rxAlterData(bool first);
2460 // Calibration utilities
2461 void dumpState(String& s, const NamedList& data, bool lockPub, bool force = false);
2462 unsigned int calibrateAuto(String* error);
2463 unsigned int calBackupRestore(BrfCalData& bak, bool backup, String* error);
2464 unsigned int calInitFinal(BrfCalData& bak, bool init, String* error);
2465 unsigned int dcCalProcPrepare(const BrfCalData& bak, uint8_t subMod, String& error);
2466 unsigned int dcCalProc(const BrfCalData& bak, uint8_t subMod, uint8_t dcCnt,
2467 uint8_t& dcReg, String& error);
2468 unsigned int dcCalProcPost(const BrfCalData& bak, uint8_t subMod, uint8_t dcReg,
2469 String& error);
2470 unsigned int calLPFBandwidth(const BrfCalData& bak, uint8_t subMod, uint8_t dcCnt,
2471 uint8_t& dcReg, String& error);
2472 unsigned int calibrateBbCorrection(BrfBbCalData& data, int corr, int range, int step,
2473 int pass, String* error);
2474 unsigned int prepareCalibrateBb(BrfBbCalData& data, bool dc, String* error);
2475 unsigned int calibrateBb(BrfBbCalData& data, bool dc, String* error);
2476 unsigned int calibrateBaseband(String* error);
2477 // amplifier linearization
2478 ComplexVector sweepPower(float startdB, float stopdB, float stepdB);
2479 unsigned int findGainExpParams(const ComplexVector& sweep, float startSweep, float stepSweep);
2480 unsigned int findPhaseExpParams(const ComplexVector& swee, float startSweep, float stepSweepp);
2481 unsigned int calculateAmpTable();
2482 //
2483 unsigned int loopbackCheck(String* error);
2484 unsigned int testVga(const char* loc, bool tx, bool preMixer, float omega = 0,
2485 String* error = 0);
testVgaCheck(const NamedList & p,const char * loc,float omega,String * error,const String & prefix=String::empty ())2486 inline unsigned int testVgaCheck(const NamedList& p, const char* loc,
2487 float omega, String* error, const String& prefix = String::empty()) {
2488 unsigned int status = 0;
2489 #define BRF_TEST_VGA(param,tx,preMixer) \
2490 if (!status && p.getBoolValue(prefix + param)) \
2491 status = testVga(loc,tx,preMixer,omega,error);
2492 BRF_TEST_VGA("test_tx_vga1",true,true);
2493 BRF_TEST_VGA("test_tx_vga2",true,false);
2494 BRF_TEST_VGA("test_rx_vga1",false,true);
2495 BRF_TEST_VGA("test_rx_vga2",false,false);
2496 #undef BRF_TEST_VGA
2497 return status;
2498 }
2499 // Set error string or put a debug message
2500 unsigned int showError(unsigned int code, const char* error, const char* prefix,
2501 String* buf, int level = DebugNote);
2502 void printIOBuffer(bool tx, const char* loc, int index = -1, unsigned int nBufs = 0);
2503 void dumpIOBuffer(BrfDevIO& io, unsigned int nBufs);
2504 void updateIODump(BrfDevIO& io);
getIO(bool tx)2505 inline BrfDevIO& getIO(bool tx)
2506 { return tx ? m_txIO : m_rxIO; }
getDirState(bool tx)2507 inline BrfDevDirState& getDirState(bool tx)
2508 { return tx ? m_state.m_tx : m_state.m_rx; }
checkDbgInt(int & val,unsigned int step=1)2509 inline unsigned int checkDbgInt(int& val, unsigned int step = 1) {
2510 if (!(val && step))
2511 return 0;
2512 Lock lck(m_dbgMutex);
2513 if (val < 0)
2514 return step;
2515 if (val >= (int)step)
2516 val -= step;
2517 else {
2518 step = val;
2519 val = 0;
2520 }
2521 return step;
2522 }
2523 // Enable or disable loopback
2524 unsigned int internalSetLoopback(int mode = 0,
2525 const NamedList& params = NamedList::empty(), String* error = 0);
2526 unsigned int setLoopbackPath(int mode, String& error);
2527 void dumpLoopbackStatus(String* dest = 0);
2528 void dumpLmsModulesStatus(String* dest = 0);
2529 unsigned int internalDumpPeripheral(uint8_t dev, uint8_t addr, uint8_t len,
2530 String* buf, uint8_t lineLen);
decodeLpf(uint8_t reg1,uint8_t reg2) const2531 inline int decodeLpf(uint8_t reg1, uint8_t reg2) const {
2532 int on = reg1 & (1 << 1);
2533 int bypass = reg2 & (1 << 6);
2534 if (on)
2535 return bypass ? LpfInvalid : LpfNormal;
2536 return bypass ? LpfBypass : LpfDisabled;
2537 }
2538 // Set RXVGA2 DECODE bit (LMS addr 0x64 bit 0)
2539 // 0(true): Decode control signals
2540 // 1(false): Use control signal from test mode registers
setRxVga2Decode(bool on,String * error)2541 inline unsigned int setRxVga2Decode(bool on, String* error)
2542 { return on ? lmsReset(0x64,0x01,error) : lmsSet(0x64,0x01,error); }
setRxDcAuto(bool value)2543 inline bool setRxDcAuto(bool value) {
2544 if (m_state.m_rxDcAuto != value)
2545 return !(m_state.m_rxDcAuto = value);
2546 return m_state.m_rxDcAuto;
2547 }
getRxSamples(const NamedList & p,const char * name="samples")2548 inline unsigned int getRxSamples(const NamedList& p, const char* name = "samples") {
2549 unsigned int n = p.getIntValue(name,totalSamples(false),0);
2550 if (n < 1000)
2551 return 1000;
2552 if ((n % 4) == 0)
2553 return n;
2554 return n + 4 - (n % 4);
2555 }
2556 // Start internal threads
2557 unsigned int startCalibrateThreads(String* error,
2558 const NamedList& params = NamedList::empty());
2559 // Pause/resume I/O internal threads pause
2560 unsigned int calThreadsPause(bool on, String* error = 0);
2561 // Stop internal threads
2562 void stopThreads();
checkDev(const char * loc)2563 inline unsigned int checkDev(const char* loc) {
2564 return m_devHandle ? 0 :
2565 showError(RadioInterface::NotInitialized,"not open",loc,0,DebugCrit);
2566 }
checkCalStatus(const char * loc)2567 inline unsigned int checkCalStatus(const char* loc) {
2568 return (Calibrating != m_calibrateStatus) ? 0 :
2569 showError(RadioInterface::NotCalibrated,"calibrating",loc,0,DebugCrit);
2570 }
checkPubFuncEntry(bool internal,const char * loc)2571 inline unsigned int checkPubFuncEntry(bool internal, const char* loc) {
2572 unsigned int status = 0;
2573 BRF_FUNC_CALL_RET(checkDev(loc));
2574 if (!internal)
2575 { BRF_FUNC_CALL_RET(checkCalStatus(loc)); }
2576 return 0;
2577 }
2578 unsigned int waitCancel(const char* loc, const char* reason, String* error);
2579 // Apply parameters from start notification message
2580 unsigned int applyStartParams(const NamedList& params, String* error);
2581
2582 BrfInterface* m_owner; // The interface owning the device
2583 String m_serial; // Serial number of device to use
2584 bool m_initialized; // Initialized flag
2585 bool m_exiting; // Exiting flag
2586 bool m_closing; // Closing flag
2587 bool m_closingDevice; // Closing device flag
2588 bool m_notifyOff; // Notify power off
2589 Mutex m_dbgMutex;
2590 // libusb
2591 libusb_context* m_context; // libusb context
2592 libusb_device** m_list; // List of devices
2593 unsigned int m_listCount; // Device list length
2594 libusb_device_handle* m_devHandle; // Device handle
2595 libusb_device* m_dev; // Pointer to used device (in m_list)
2596 // Device info
2597 RadioCapability m_radioCaps;
2598 int m_devBus; // Device bus
2599 int m_devAddr; // Device address
2600 int m_devSpeed; // Device speed
2601 String m_address; // Device address
2602 String m_devSerial; // Device serial number
2603 String m_devFwVerStr; // Device firmware version string
2604 String m_devFpgaVerStr; // Device FPGA version string
2605 String m_devFpgaFile; // Device FPGA file (nul if not loaded)
2606 String m_devFpgaMD5; // FPGA MD5
2607 String m_lmsVersion; // LMS chip version
2608 uint16_t m_ctrlTransferPage; // Control transfer page size
2609 DataBlock m_calCache;
2610 //
2611 unsigned int m_syncTout; // Sync transfer timeout (in milliseconds)
2612 Semaphore m_syncSemaphore;
2613 unsigned int m_ctrlTout; // Control transfer timeout (in milliseconds)
2614 unsigned int m_bulkTout; // Bulk transfer timeout (in milliseconds)
2615 int m_altSetting;
2616 int m_rxShowDcInfo; // Output Rx DC info
2617 int m_rxDcOffsetMax; // Rx DC offset correction
2618 int m_rxDcAvgI; // Current average for I (in-phase) DC RX offset
2619 int m_rxDcAvgQ; // Current average for Q (quadrature) DC RX offset
2620 float m_freqOffset; // Master clock frequency adjustment
2621 bool m_txGainCorrSoftware; // Use software TX GAIN correction
2622 BrfDevIO m_txIO;
2623 BrfDevIO m_rxIO;
2624 DataBlock m_bufThres; // Thresholds for used buffers adjustment (BrfBufsThreshold)
2625 LusbTransfer m_usbTransfer[EpCount]; // List of USB transfers
2626 BrfDevState m_state; // State data used for current operation and backup / restore
2627 bool m_syncTxStateSet; //
2628 unsigned int m_syncTxStateCode; //
2629 String m_syncTxStateError; //
2630 BrfDevState m_syncTxState; // Data used to sync set state in send method
2631 uint64_t m_rxTimestamp; // RX timestamp
2632 uint64_t m_rxResyncCandidate; // RX: timestamp resync value
2633 unsigned int m_rxTsPastIntervalMs; // RX: allowed timestamp in the past interval in 1 read operation
2634 unsigned int m_rxTsPastSamples; // RX: How many samples in the past to allow in 1 read operation
2635 float m_warnClamped; // TX: Warn clamped threshold (percent)
2636 unsigned int m_minBufsSend; // Minimum buffers to send
2637 unsigned int m_silenceTimeMs; // Silence timestamp related debug messages (in millseconds)
2638 uint64_t m_silenceTs; // Silence timestamp related debug messages
2639 // TX power scale
2640 float m_txPowerBalance;
2641 bool m_txPowerBalanceChanged;
2642 float m_txPowerScaleI;
2643 float m_txPowerScaleQ;
2644 float m_wrPowerScaleI;
2645 float m_wrPowerScaleQ;
2646 int16_t m_wrMaxI;
2647 int16_t m_wrMaxQ;
2648 // amp linearization
2649 float m_gainExpBreak; // amp linearization gain exapansion breakpoint, dB power scale
2650 float m_gainExpSlope; // amp linearization gain exapansion slope, dB power gain
2651 float m_phaseExpBreak; // amp linearization phase expansion breakpoint, dB power scale
2652 float m_phaseExpSlope; // amp linearization phase expanaion slope, radians per power unit
2653 // The parameters above are used to generate this table
2654 long m_ampTable[2*2*2048]; // amp linearization table, complex pairs indexed in normalized power units
2655 bool m_ampTableUse;
2656 // Alter data
2657 NamedList m_rxAlterDataParams;
2658 bool m_rxAlterData;
2659 int16_t m_rxAlterIncrement;
2660 String m_rxAlterTsJumpPatern; // Pattern used to alter rx timestamps (kept to check changes)
2661 bool m_rxAlterTsJumpSingle; // Stop altering ts after first pass
2662 DataBlock m_rxAlterTsJump; // Values to alter rx timestamps
2663 unsigned int m_rxAlterTsJumpPos; // Current position in rx alter timestamps
2664 bool m_txPatternChanged;
2665 ComplexVector m_txPattern;
2666 ComplexVector m_txPatternBuffer;
2667 unsigned int m_txPatternBufPos;
2668 // Check & calibration
2669 bool m_calLms; // Run LMS auto cal
2670 int m_calibrateStatus;
2671 int m_calibrateStop;
2672 NamedList m_calibration; // Calibration parameters
2673 String m_devCheckFile;
2674 String m_bbCalDcFile;
2675 String m_bbCalImbalanceFile;
2676 BrfThread* m_calThread;
2677 BrfThread* m_sendThread;
2678 BrfThread* m_recvThread;
2679 Semaphore m_internalIoSemaphore;
2680 uint64_t m_internalIoTimestamp;
2681 unsigned int m_internalIoTxRate;
2682 unsigned int m_internalIoRxRate;
2683 bool m_internalIoRateChanged;
2684 Mutex m_threadMutex;
2685 };
2686
2687 // Initialize data used to wait for interface Tx busy
2688 // Clear the flag when destroyed
2689 class BrfSerialize
2690 {
2691 public:
BrfSerialize(BrfLibUsbDevice * dev,bool tx,bool waitNow=true)2692 inline BrfSerialize(BrfLibUsbDevice* dev, bool tx, bool waitNow = true)
2693 : status(0), m_device(dev), m_io(m_device->getIO(tx)), m_lock(0) {
2694 if (waitNow)
2695 wait();
2696 }
~BrfSerialize()2697 inline ~BrfSerialize()
2698 { drop(); }
drop()2699 inline void drop()
2700 { m_lock.drop(); }
devLocked() const2701 inline bool devLocked() const
2702 { return m_io.mutex.locked(); }
wait(String * error=0,long maxwait=-1)2703 inline unsigned int wait(String* error = 0, long maxwait = -1) {
2704 if (m_lock.acquire(m_io.mutex,maxwait)) {
2705 if ((status = m_device->cancelled(error)) != 0)
2706 drop();
2707 }
2708 else
2709 status = m_device->showError(RadioInterface::Failure,
2710 "Failed to serialize",brfDir(m_io.tx()),error,DebugWarn);
2711 return status;
2712 }
2713 unsigned int status;
2714 protected:
2715 BrfLibUsbDevice* m_device;
2716 BrfDevIO& m_io;
2717 Lock m_lock;
2718 };
2719
2720 class BrfInterface : public RadioInterface
2721 {
2722 YCLASS(BrfInterface,RadioInterface)
2723 friend class BrfModule;
2724 public:
2725 ~BrfInterface();
device() const2726 inline BrfLibUsbDevice* device() const
2727 { return m_dev; }
isDevice(void * dev) const2728 inline bool isDevice(void* dev) const
2729 { return m_dev && m_dev == (BrfLibUsbDevice*)dev; }
2730 // Module reload
reLoad()2731 inline void reLoad() {
2732 if (m_dev)
2733 m_dev->reLoad();
2734 }
setPending(unsigned int oper,unsigned int code=Pending)2735 inline void setPending(unsigned int oper, unsigned int code = Pending)
2736 { RadioInterface::setPending(oper,code); }
2737 void notifyError(unsigned int status, const char* str, const char* oper);
2738 virtual unsigned int initialize(const NamedList& params = NamedList::empty());
2739 virtual unsigned int setParams(NamedList& params, bool shareFate = true);
setDataDump(int dir=0,int level=0,const NamedList * params=0)2740 virtual unsigned int setDataDump(int dir = 0, int level = 0,
2741 const NamedList* params = 0) {
2742 if (!m_dev)
2743 return Failure;
2744 m_dev->setDataDump(dir,level,params);
2745 return 0;
2746 }
2747 virtual unsigned int send(uint64_t when, float* samples, unsigned size,
2748 float* powerScale = 0);
2749 virtual unsigned int recv(uint64_t& when, float* samples, unsigned& size);
2750 unsigned int setFrequency(uint64_t hz, bool tx);
2751 unsigned int getFrequency(uint64_t& hz, bool tx) const;
setTxFreq(uint64_t hz)2752 virtual unsigned int setTxFreq(uint64_t hz)
2753 { return setFrequency(hz,true); }
getTxFreq(uint64_t & hz) const2754 virtual unsigned int getTxFreq(uint64_t& hz) const
2755 { return getFrequency(hz,true); }
setRxFreq(uint64_t hz)2756 virtual unsigned int setRxFreq(uint64_t hz)
2757 { return setFrequency(hz,false); }
getRxFreq(uint64_t & hz) const2758 virtual unsigned int getRxFreq(uint64_t& hz) const
2759 { return getFrequency(hz,false); }
setFreqOffset(float offs,float * newVal=0)2760 virtual unsigned int setFreqOffset(float offs, float* newVal = 0)
2761 { return m_dev->setFreqOffset(offs,newVal); }
2762 virtual unsigned int setSampleRate(uint64_t hz);
2763 virtual unsigned int getSampleRate(uint64_t& hz) const;
2764 virtual unsigned int setFilter(uint64_t hz);
2765 virtual unsigned int getFilterWidth(uint64_t& hz) const;
2766 unsigned int setRxGain(int val, unsigned port, bool preMixer);
setRxGain1(int val,unsigned port)2767 virtual unsigned int setRxGain1(int val, unsigned port)
2768 { return setRxGain(val,port,true); }
setRxGain2(int val,unsigned port)2769 virtual unsigned int setRxGain2(int val, unsigned port)
2770 { return setRxGain(val,port,false); }
2771 unsigned int setTxGain(int val, unsigned port, bool preMixer);
setTxGain1(int val,unsigned port)2772 virtual unsigned int setTxGain1(int val, unsigned port)
2773 { return setTxGain(val,port,true); }
setTxGain2(int val,unsigned port)2774 virtual unsigned int setTxGain2(int val, unsigned port)
2775 { return setTxGain(val,port,false); }
getTxTime(uint64_t & time) const2776 virtual unsigned int getTxTime(uint64_t& time) const
2777 { return m_dev->getTimestamp(true,time); }
getRxTime(uint64_t & time) const2778 virtual unsigned int getRxTime(uint64_t& time) const
2779 { return m_dev->getTimestamp(false,time); }
setTxPower(const unsigned dBm)2780 virtual unsigned int setTxPower(const unsigned dBm)
2781 { return setTxGain2(dBm,0); }
setPorts(unsigned ports)2782 virtual unsigned int setPorts(unsigned ports) {
2783 if (ports == m_radioCaps->currPorts)
2784 return 0;
2785 return ports ? NotSupported : OutOfRange;
2786 }
2787 // Set pre and post mixer value
2788 unsigned int setGain(bool tx, int val, unsigned int port,
2789 int* newValue = 0) const;
status(int port=-1) const2790 virtual unsigned status(int port = -1) const
2791 { return (m_totalErr & FatalErrorMask); }
setLoopback(const char * name=0)2792 virtual unsigned int setLoopback(const char* name = 0)
2793 { return m_dev ? m_dev->setLoopback(name) : NotInitialized; }
calibrate()2794 virtual unsigned int calibrate()
2795 { return m_dev->calibrate(); }
2796 virtual void completeDevInfo(NamedList& p, bool full = false, bool retData = false);
2797
2798 protected:
2799 BrfInterface(const char* name);
2800 // Method to call after creation to init the interface
2801 unsigned int init(const NamedList& params, String& error);
2802 virtual void destroyed();
2803
2804 private:
2805 BrfLibUsbDevice* m_dev; // Used device
2806 };
2807
2808
2809 class BrfThread : public Thread
2810 {
2811 public:
2812 enum Type {
2813 Unknown = 0,
2814 DevCalibrate,
2815 DevSend,
2816 DevRecv,
2817 };
2818 // Device thread
2819 BrfThread(BrfLibUsbDevice* dev, int type, const NamedList& p = NamedList::empty(),
2820 const char* name = 0, Thread::Priority prio = Thread::Normal);
~BrfThread()2821 ~BrfThread()
2822 { notify(); }
name() const2823 inline const char* name() const
2824 { return m_params; }
ifc() const2825 inline BrfInterface* ifc() const
2826 { return (m_device ? m_device->owner() : 0); }
cleanup()2827 virtual void cleanup()
2828 { notify(); }
isPaused() const2829 inline bool isPaused() const
2830 { return m_paused; }
2831 // I/O pause check. Update timestamp on resume
2832 // This method is expected to be called from run()
paused(bool tx,uint64_t & ts,unsigned int & status)2833 inline bool paused(bool tx, uint64_t& ts, unsigned int& status) {
2834 if (!m_pauseToggle)
2835 return m_paused;
2836 m_paused = !m_paused;
2837 if (m_paused)
2838 status = 0;
2839 else if (m_device)
2840 status = m_device->getTimestamp(tx,ts);
2841 else
2842 status = RadioInterface::NotInitialized;
2843 bool failed = (status && status != RadioInterface::Cancelled);
2844 Debug(ifc(),failed ? DebugNote : DebugAll,"%s %s at ts=" FMT64U " [%p]",
2845 name(),(m_paused ? "paused" : "resume"),ts,ifc());
2846 m_pauseToggle = false;
2847 return m_paused;
2848 }
2849 // Start this thread. Delete object on failure and return 0
2850 BrfThread* start();
2851 // Pause / resume a thread
2852 static inline unsigned int pauseToggle(BrfThread*& th, Mutex* mtx, bool on,
2853 String* error = 0);
pause(BrfThread * & th,Mutex * mtx,String * error=0)2854 static inline unsigned int pause(BrfThread*& th, Mutex* mtx, String* error = 0)
2855 { return pauseToggle(th,mtx,true,error); }
resume(BrfThread * & th,Mutex * mtx,String * error=0)2856 static inline unsigned int resume(BrfThread*& th, Mutex* mtx, String* error = 0)
2857 { return pauseToggle(th,mtx,false,error); }
2858 // Stop thread
2859 static void cancelThread(BrfThread*& th, Mutex* mtx, unsigned int waitMs,
2860 DebugEnabler* dbg, void* ptr);
2861
2862 protected:
2863 virtual void run();
2864 void notify();
2865
2866 int m_type;
2867 NamedList m_params;
2868 BrfLibUsbDevice* m_device;
2869 bool m_paused;
2870 bool m_pauseToggle;
2871 const char* m_priority;
2872 };
2873
2874 class BrfModule : public Module
2875 {
2876 friend class BrfInterface;
2877 public:
2878 enum Relay {
2879 RadioCreate = Private,
2880 };
2881 BrfModule();
2882 ~BrfModule();
2883 bool findIfaceByDevice(RefPointer<BrfInterface>& iface, void* dev);
findIface(RefPointer<BrfInterface> & iface,const String & n)2884 inline bool findIface(RefPointer<BrfInterface>& iface, const String& n) {
2885 Lock lck(this);
2886 ObjList* o = m_ifaces.find(n);
2887 if (o)
2888 iface = static_cast<BrfInterface*>(o->get());
2889 return iface != 0;
2890 }
2891
2892 protected:
2893 virtual void initialize();
2894 virtual bool received(Message& msg, int id);
2895 virtual void statusModule(String& str);
2896 virtual void statusParams(String& str);
2897 virtual void statusDetail(String& str);
2898 virtual bool commandComplete(Message& msg, const String& partLine,
2899 const String& partWord);
2900 bool createIface(NamedList& params);
2901 void completeIfaces(String& dest, const String& partWord);
2902 bool onCmdControl(BrfInterface* ifc, Message& msg);
2903 bool onCmdStatus(String& retVal, String& line);
2904 bool onCmdGain(BrfInterface* ifc, Message& msg, int tx = -1, bool preMixer = true);
2905 bool onCmdCorrection(BrfInterface* ifc, Message& msg, int tx = -1, int corr = 0);
2906 bool onCmdLmsWrite(BrfInterface* ifc, Message& msg);
2907 bool onCmdBufOutput(BrfInterface* ifc, Message& msg);
2908 bool onCmdShow(BrfInterface* ifc, Message& msg, const String& what = String::empty());
2909 bool onCmdFreqOffs(BrfInterface* ifc, Message& msg);
2910 bool onCmdFreqCal(BrfInterface* ifc, Message& msg, bool start = true);
2911 void setDebugPeripheral(const NamedList& list);
2912 void setSampleEnergize(const String& value);
waitDisciplineFree()2913 inline bool waitDisciplineFree() {
2914 do {
2915 Lock lck(this);
2916 if (!m_disciplineBusy) {
2917 m_disciplineBusy = true;
2918 return true;
2919 }
2920 lck.drop();
2921 Thread::idle();
2922 }
2923 while (!Thread::check(false));
2924 return false;
2925 }
2926
2927 unsigned int m_ifaceId;
2928 ObjList m_ifaces;
2929 bool m_disciplineBusy; ///< flag used to serialize the VCTCXO discipliner
2930 unsigned m_lastDiscipline; ///< the timestamp (sec) of the last call on the discipliner
2931 };
2932
2933 static bool s_usbContextInit = false; // USB library init flag
2934 const float BrfVctcxoDiscipliner::s_ppbPerUnit = 19000 * 1.25 / 256;
2935 INIT_PLUGIN(BrfModule);
2936 static Configuration s_cfg; // Configuration file (protected by plugin mutex)
2937 static const String s_modCmds[] = {"help",""};
2938 static const String s_ifcCmds[] = {
2939 "txgain1", "txgain2", "rxgain1", "rxgain2",
2940 "txdci", "txdcq", "txfpgaphase", "txfpgagain",
2941 "rxdci", "rxdcq", "rxfpgaphase", "rxfpgagain",
2942 "showstatus", "showboardstatus", "showstatistics", "showtimestamps", "showlms",
2943 "vgagain","correction","lmswrite",
2944 "bufoutput","rxdcoutput","txpattern","show",
2945 "cal_stop", "cal_abort",
2946 "balance",
2947 "gainexp", "phaseexp",
2948 "freqoffs", "freqcalstart", "freqcalstop",
2949 ""};
2950 // libusb
2951 static unsigned int s_lusbSyncTransferTout = LUSB_SYNC_TIMEOUT; // Sync transfer timeout def val (in milliseconds)
2952 static unsigned int s_lusbCtrlTransferTout = LUSB_CTRL_TIMEOUT; // Control transfer timeout def val (in milliseconds)
2953 static unsigned int s_lusbBulkTransferTout = LUSB_BULK_TIMEOUT; // Bulk transfer timeout def val (in milliseconds)
2954
2955 static BrfPeripheral s_uartDev[BrfLibUsbDevice::UartDevCount] = {
2956 BrfPeripheral("GPIO",0x00),
2957 BrfPeripheral("LMS",0x10),
2958 BrfPeripheral("VCTCXO",0x20),
2959 BrfPeripheral("SI5338",0x30)
2960 };
2961
2962 static const TokenDict s_usbEndpoint[] = {
2963 {"SEND_SAMPLES", BrfLibUsbDevice::EpSendSamples},
2964 {"SEND_CTRL", BrfLibUsbDevice::EpSendCtrl},
2965 {"READ_SAMPLES", BrfLibUsbDevice::EpReadSamples},
2966 {"READ-CTRL", BrfLibUsbDevice::EpReadCtrl},
2967 {0,0}
2968 };
2969
2970 static const TokenDict s_loopback[] = {
2971 {"firmware", BrfLibUsbDevice::LoopFirmware},
2972 {"lpf-to-rxout", BrfLibUsbDevice::LoopLpfToRxOut},
2973 {"lpf-to-vga2", BrfLibUsbDevice::LoopLpfToVga2},
2974 {"vga1-to-vga2", BrfLibUsbDevice::LoopVga1ToVga2},
2975 {"lpf-to-lpf", BrfLibUsbDevice::LoopLpfToLpf},
2976 {"vga1-to-lpf", BrfLibUsbDevice::LoopVga1ToLpf},
2977 {"pa-to-lna1", BrfLibUsbDevice::LoopRfLna1},
2978 {"pa-to-lna2", BrfLibUsbDevice::LoopRfLna2},
2979 {"pa-to-lna3", BrfLibUsbDevice::LoopRfLna3},
2980 {"none", BrfLibUsbDevice::LoopNone},
2981 {0,0}
2982 };
2983 static const TokenDict s_pa[] = {
2984 {"AUXPA", BrfLibUsbDevice::LmsPaAux},
2985 {"PA1", BrfLibUsbDevice::LmsPa1},
2986 {"PA2", BrfLibUsbDevice::LmsPa2},
2987 {0,0}
2988 };
2989 static const TokenDict s_lpf[] = {
2990 {"disabled", BrfLibUsbDevice::LpfDisabled},
2991 {"bypassed", BrfLibUsbDevice::LpfBypass},
2992 {"normal", BrfLibUsbDevice::LpfNormal},
2993 {0,0}
2994 };
2995 static const TokenDict s_lnaGain[] = {
2996 {"BYPASS", BrfLibUsbDevice::LnaGainBypass},
2997 {"MID", BrfLibUsbDevice::LnaGainMid},
2998 {"MAX", BrfLibUsbDevice::LnaGainMax},
2999 {"Unhandled", BrfLibUsbDevice::LnaGainUnhandled},
3000 {0,0}
3001 };
3002 static const TokenDict s_corr[] = {
3003 {"I", BrfLibUsbDevice::CorrLmsI},
3004 {"Q", BrfLibUsbDevice::CorrLmsQ},
3005 {"PHASE", BrfLibUsbDevice::CorrFpgaPhase},
3006 {"GAIN", BrfLibUsbDevice::CorrFpgaGain},
3007 {0,0}
3008 };
3009
completeStrList(String & dest,const String & partWord,const String * ptr)3010 static bool completeStrList(String& dest, const String& partWord, const String* ptr)
3011 {
3012 if (!ptr)
3013 return false;
3014 while (*ptr)
3015 Module::itemComplete(dest,*ptr++,partWord);
3016 return false;
3017 }
3018
loadCfg(Configuration * cfg=0,bool warn=true)3019 static inline void loadCfg(Configuration* cfg = 0, bool warn = true)
3020 {
3021 if (!cfg)
3022 cfg = &s_cfg;
3023 *cfg = Engine::configFile("ybladerf");
3024 cfg->load(warn);
3025 }
3026
lusbSetDebugLevel(int level=-1)3027 static void lusbSetDebugLevel(int level = -1)
3028 {
3029 // No lock needed: this function is called from plugin init (loads the config) or
3030 // context init (locks the plugin)
3031 if (!s_usbContextInit)
3032 return;
3033 if (level < 0) {
3034 String* l = s_cfg.getKey(YSTRING("libusb"),YSTRING("debug_level"));
3035 ::libusb_set_debug(0,l ? l->toInteger(0,0,0) : 0);
3036 }
3037 else
3038 ::libusb_set_debug(0,level);
3039 }
3040
3041 // libusb transfer stream callback
lusbTransferCb(libusb_transfer * transfer)3042 static void lusbTransferCb(libusb_transfer* transfer)
3043 {
3044 if (!transfer) {
3045 DDebug(&__plugin,DebugWarn,"lusbTransferCb() called with NULL transfer");
3046 return;
3047 }
3048 LusbTransfer* t = (LusbTransfer*)(transfer->user_data);
3049 #ifdef DEBUG_LUSB_TRANSFER_CALLBACK
3050 int level = DebugAll;
3051 if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
3052 level = DebugNote;
3053 if (!__plugin.debugAt(level))
3054 return;
3055 RefPointer<BrfInterface> ifc;
3056 String ifcInfo;
3057 if (t && __plugin.findIfaceByDevice(ifc,t->device)) {
3058 ifcInfo.printf("(%p %s)",(BrfInterface*)ifc,ifc->debugName());
3059 ifc = 0;
3060 }
3061 String x;
3062 String tmp;
3063 x << "\r\ninterface=" << ifcInfo.safe("not found");
3064 x << tmp.printf("\r\nhandle=%p",transfer->dev_handle);
3065 x << tmp.printf("\r\nuser_data=%p",transfer->user_data);
3066 x << tmp.printf("\r\nflags=0x%x",transfer->flags);
3067 x << "\r\ntype=";
3068 switch (transfer->type) {
3069 case LIBUSB_TRANSFER_TYPE_CONTROL:
3070 x << "CONTROL";
3071 break;
3072 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
3073 x << "ISOCHRONOUS";
3074 break;
3075 case LIBUSB_TRANSFER_TYPE_BULK:
3076 x << "BULK";
3077 break;
3078 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
3079 x << "INTERRUPT";
3080 break;
3081 //case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
3082 // x << "STREAM";
3083 // break;
3084 default:
3085 x << (unsigned int)(transfer->type);
3086 }
3087 String endp;
3088 switch (transfer->endpoint) {
3089 case BRF_ENDP_TX_SAMPLES:
3090 endp = lookup(BrfLibUsbDevice::EpSendSamples,s_usbEndpoint);
3091 break;
3092 case BRF_ENDP_TX_CTRL:
3093 endp = lookup(BrfLibUsbDevice::EpSendCtrl,s_usbEndpoint);
3094 break;
3095 case BRF_ENDP_RX_SAMPLES:
3096 endp = lookup(BrfLibUsbDevice::EpReadSamples,s_usbEndpoint);
3097 break;
3098 case BRF_ENDP_RX_CTRL:
3099 endp = lookup(BrfLibUsbDevice::EpReadCtrl,s_usbEndpoint);
3100 break;
3101 default:
3102 endp.printf("0x%x",transfer->endpoint);
3103 }
3104 x << "\r\nendpoint=" << endp;
3105 x << "\r\ntimeout=" << transfer->timeout << "ms";
3106 BrfLibUsbDevice::appendLusbError(x,transfer->status,"\r\nstatus=");
3107 x << "\r\ncurrent_buffer_len=" << transfer->length;
3108 x << "\r\ntransferred=" << transfer->actual_length;
3109 Debug(&__plugin,level,"lusbTransferCb(%p)%s",transfer,encloseDashes(x));
3110 #endif
3111 if (!t)
3112 return;
3113 Lock lck(t);
3114 if (transfer->status == LIBUSB_TRANSFER_COMPLETED &&
3115 transfer->length != transfer->actual_length) {
3116 t->status = RadioInterface::HardwareIOError;
3117 t->error.printf("Incomplete transfer %u/%u",transfer->actual_length,transfer->length);
3118 }
3119 else
3120 t->status = BrfLibUsbDevice::lusbCheckSuccess(transfer->status,&t->error);
3121 t->running(false);
3122 }
3123
3124
3125 //
3126 // BrfPeripheral
3127 //
setTrack(bool tx,bool rx,const String & addr,int level)3128 void BrfPeripheral::setTrack(bool tx, bool rx, const String& addr, int level)
3129 {
3130 bool changed = m_tx != tx || m_rx != rx;
3131 String oldTrackAddr;
3132 if (m_haveTrackAddr)
3133 oldTrackAddr.hexify(m_trackAddr,sizeof(m_trackAddr));
3134 m_tx = tx;
3135 m_rx = rx;
3136 m_trackLevel = level;
3137 m_haveTrackAddr = false;
3138 ::memset(m_trackAddr,0,sizeof(m_trackAddr));
3139 if ((m_tx || m_rx) && addr && addr != oldTrackAddr) {
3140 DataBlock tmp;
3141 if (tmp.unHexify(addr)) {
3142 uint8_t* d = tmp.data(0);
3143 for (unsigned int i = 0; i < tmp.length(); i++, d++) {
3144 if (*d < 128) {
3145 m_trackAddr[*d] = 1;
3146 m_haveTrackAddr = true;
3147 }
3148 else
3149 Debug(&__plugin,DebugConf,
3150 "Ignoring invalid track address 0x%x for peripheral '%s'",*d,c_str());
3151 }
3152 }
3153 else
3154 Debug(&__plugin,DebugConf,
3155 "Ignoring invalid track addresses for peripheral '%s'",c_str());
3156 }
3157 String newTrackAddr;
3158 if (m_haveTrackAddr) {
3159 newTrackAddr.hexify(m_trackAddr,sizeof(m_trackAddr));
3160 changed = (newTrackAddr != oldTrackAddr);
3161 }
3162 else if (oldTrackAddr)
3163 changed = true;
3164 if (!changed)
3165 return;
3166 String state;
3167 if (m_tx || m_rx) {
3168 String ta;
3169 if (m_haveTrackAddr) {
3170 String tmp;
3171 for (uint8_t i = 0; i < BRF_ARRAY_LEN(m_trackAddr); i++)
3172 if (m_trackAddr[i])
3173 ta.append(tmp.hexify(&i,1)," ");
3174 }
3175 Debug(&__plugin,DebugAll,
3176 "%s peripheral debug changed: tx=%s rx=%s tracked_addr=%s level=%d",
3177 c_str(),String::boolText(m_tx),String::boolText(m_rx),ta.safe(),level);
3178 }
3179 else
3180 Debug(&__plugin,DebugAll,"%s peripheral debug is disabled",c_str());
3181 }
3182
3183
3184 //
3185 // BrfBufsThreshold
3186 //
init(DataBlock & db,const String & str,const RadioCapability & caps)3187 const char* BrfBufsThreshold::init(DataBlock& db, const String& str,
3188 const RadioCapability& caps)
3189 {
3190 db.clear();
3191 if (!str)
3192 return 0;
3193 ObjList* list = str.split(',',false);
3194 unsigned int n = list->count();
3195 const char* result = 0;
3196 if (!n) {
3197 TelEngine::destruct(list);
3198 return 0;
3199 }
3200 db.assign(0,n * sizeof(BrfBufsThreshold));
3201 BrfBufsThreshold* t = (BrfBufsThreshold*)db.data(0);
3202 unsigned int i = 0;
3203 for (ObjList* o = list->skipNull(); o; o = o->skipNext(), ++i) {
3204 String& s = *static_cast<String*>(o->get());
3205 int pos1 = s.find('/');
3206 if (pos1 < 0) {
3207 result = "invalid format";
3208 break;
3209 }
3210 int64_t sRate = s.substr(0,pos1).trimBlanks().toInt64();
3211 int64_t bSamples = 0;
3212 int txMinBufs = 0;
3213 int pos2 = s.find('/',pos1 + 1);
3214 if (pos2 > pos1) {
3215 String tmp = s.substr(pos2 + 1).trimBlanks();
3216 if (tmp)
3217 txMinBufs = tmp.toInteger(-1);
3218 bSamples = s.substr(pos1 + 1,pos2 - pos1 - 1).trimBlanks().toInt64(-1);
3219 }
3220 else
3221 bSamples = s.substr(pos1 + 1).trimBlanks().toInt64(-1);
3222 XDebug(&__plugin,DebugAll,"BrfBufsThreshold::init() %u/%u '%s' -> " FMT64 "/" FMT64 "/%d",
3223 i + 1,n,s.c_str(),sRate,bSamples,txMinBufs);
3224 if (sRate < caps.minSampleRate || sRate > caps.maxSampleRate)
3225 result = "samplerate out of range";
3226 else if (bSamples <= 0 || bSamples > 0xffffffff)
3227 result = "invalid buffered_samples";
3228 else if (txMinBufs < 0)
3229 result = "invalid tx_min_buffers";
3230 else {
3231 t[i].sampleRate = sRate;
3232 t[i].bufferedSamples = bSamples;
3233 t[i].txMinBufs = txMinBufs;
3234 if (!i || t[i].sampleRate > t[i - 1].sampleRate ||
3235 t[i].bufferedSamples > t[i - 1].bufferedSamples)
3236 continue;
3237 result = "not in ascending order";
3238 }
3239 break;
3240 }
3241 TelEngine::destruct(list);
3242 if (result) {
3243 db.clear();
3244 return result;
3245 }
3246 #ifdef XDEBUG
3247 String s;
3248 for (i = 0; i < n; i++, t++)
3249 s << "\r\n" << t->sampleRate << "\t" << t->bufferedSamples << "\t" << t->txMinBufs;
3250 Output("Got %u BrfBufsThreshold:%s",n,encloseDashes(s));
3251 #endif
3252 return 0;
3253 }
3254
findThres(DataBlock & db,unsigned int sampleRate)3255 BrfBufsThreshold* BrfBufsThreshold::findThres(DataBlock& db, unsigned int sampleRate)
3256 {
3257 if (!(db.length() && sampleRate))
3258 return 0;
3259 unsigned int n = db.length() / sizeof(BrfBufsThreshold);
3260 BrfBufsThreshold* t = (BrfBufsThreshold*)db.data(0);
3261 for (unsigned int i = 0; i < n; i++, t++) {
3262 if (t->sampleRate <= sampleRate) {
3263 // Last entry or less than next one: return it
3264 if (i == n - 1 || sampleRate < t[1].sampleRate)
3265 return t;
3266 continue;
3267 }
3268 }
3269 return 0;
3270 }
3271
3272
3273 //
3274 // LusbTransfer
3275 //
fillBulk(uint8_t * data,unsigned int len,unsigned int tout)3276 bool LusbTransfer::fillBulk(uint8_t* data, unsigned int len, unsigned int tout)
3277 {
3278 if (!alloc())
3279 return false;
3280 ::libusb_fill_bulk_transfer(transfer,device->handle(),ep,data,len,lusbTransferCb,
3281 this,tout);
3282 return true;
3283 }
3284
submit()3285 bool LusbTransfer::submit()
3286 {
3287 status = BrfLibUsbDevice::lusbCheckSuccess(::libusb_submit_transfer(transfer),
3288 &error,"libusb_submit_transfer() failed ");
3289 return status == 0;
3290 }
3291
cancel(String * error)3292 unsigned int LusbTransfer::cancel(String* error)
3293 {
3294 if (!transfer)
3295 return 0;
3296 int code = ::libusb_cancel_transfer(transfer);
3297 if (code == LIBUSB_SUCCESS)
3298 return 0;
3299 m_running = false;
3300 if (code == LIBUSB_ERROR_NOT_FOUND)
3301 return 0;
3302 return BrfLibUsbDevice::lusbCheckSuccess(code,error,
3303 "libusb_cancel_transfer() failed ");
3304 }
3305
3306
3307 //
3308 // BrfBbCalData
3309 //
initCal(BrfLibUsbDevice & dev,bool dc,String & fName)3310 void BrfBbCalData::initCal(BrfLibUsbDevice& dev, bool dc, String& fName)
3311 {
3312 if (!fName)
3313 fName = param(dc,"file_dump");
3314 if (fName) {
3315 replaceDumpParams(fName,0,true);
3316 if (m_dump.init(m_params,fName)) {
3317 if (m_dump.dumpHeader()) {
3318 const String& fmt = param(dc,"header_format");
3319 NamedString* ns = new NamedString("data");
3320 dev.dumpState(*ns,m_params,true,true);
3321 *ns <<
3322 "\r\n\r\nOmega_Error: " << omega(true) <<
3323 "\r\nOmega_Test: " << omega(false);
3324 String* s = new String(fmt.safe("TIME: ${time}${newline}${data}"));
3325 replaceDumpParams(*s,ns);
3326 m_dump.append(s);
3327 }
3328 m_dump.dumpDataFmt(calTone(),m_params,"dump_filter_cal");
3329 m_dump.dumpDataFmt(testTone(),m_params,"dump_filter_test");
3330 }
3331 }
3332 else
3333 m_dump.writeData(true);
3334
3335 unsigned int n = uintParam(dc,"dump_tone");
3336 if (n) {
3337 String cS, tS;
3338 if (n > calTone().length())
3339 n = calTone().length();
3340 calTone().head(n).dump(cS,Math::dumpComplex," ","%.2f,%.2f");
3341 testTone().head(n).dump(tS,Math::dumpComplex," ","%.2f,%.2f");
3342 Output("Omega cal=%f test=%f\r\nCAL: %s\r\nTEST: %s",omega(true),omega(false),
3343 cS.safe(),tS.safe());
3344 }
3345 }
3346
finalizeCal(const String & result)3347 void BrfBbCalData::finalizeCal(const String& result)
3348 {
3349 if (m_dump.valid()) {
3350 const String& fmt = m_params[YSTRING("dump_result_format")];
3351 if (fmt) {
3352 NamedString* ns = new NamedString("data",result.safe("FAILURE"));
3353 m_dump.append(replaceDumpParamsFmt(fmt,ns));
3354 }
3355 }
3356 }
3357
dumpCorrStart(unsigned int pass,int corr,int corrVal,int fixedCorr,int fixedCorrVal,unsigned int range,unsigned int step,int calValMin,int calValMax)3358 void BrfBbCalData::dumpCorrStart(unsigned int pass, int corr, int corrVal, int fixedCorr,
3359 int fixedCorrVal, unsigned int range, unsigned int step,
3360 int calValMin, int calValMax)
3361 {
3362 const String& fmt = m_params[YSTRING("dump_pass_info_start")];
3363 if (fmt) {
3364 String* s = 0;
3365 if (fmt != YSTRING("-"))
3366 s = new String(fmt);
3367 else
3368 s = new String("${newline}${newline}${data}");
3369 NamedString* ns = new NamedString("data");
3370 ns->printf(1024,"Pass #%u calibrating %s (crt: %d) %s=%d "
3371 "samples=%u range=%d step=%d interval=[%d..%d]",
3372 pass,lookup(corr,s_corr),corrVal,lookup(fixedCorr,s_corr),fixedCorrVal,
3373 samples(),range,step,calValMin,calValMax);
3374 replaceDumpParams(*s,ns);
3375 m_dump.append(s);
3376 }
3377 unsigned int n = 0;
3378 if (m_params[YSTRING("dump_accumulate_format")])
3379 n = range * 2 + 1;
3380 m_calAccum.reset(n);
3381 m_testAccum.reset(n);
3382 m_totalAccum.reset(n);
3383 }
3384
dumpCorrEnd(bool dc)3385 void BrfBbCalData::dumpCorrEnd(bool dc)
3386 {
3387 if (m_calAccum.data.length()) {
3388 const String& accum = m_params[YSTRING("dump_accumulate_format")];
3389 if (accum) {
3390 m_calAccum.normalize();
3391 m_testAccum.normalize();
3392 m_totalAccum.normalize();
3393 String* s = new String(accum);
3394 replaceDumpParams(*s,dumpNsData(m_calAccum.data,"data_cal"),false,
3395 dumpNsData(m_testAccum.data,"data_test"),
3396 dumpNsData(m_totalAccum.data,"data_total"));
3397 m_dump.append(s);
3398 }
3399 }
3400 const String& fmt = m_params[YSTRING("dump_pass_info_end")];
3401 if (fmt) {
3402 String* s = 0;
3403 if (fmt != YSTRING("-"))
3404 s = new String(fmt);
3405 else
3406 s = new String("${newline}${data}");
3407 NamedString* ns = new NamedString("data");
3408 ns->printf(1024,"Result: %d/%d Min/Max: cal=%f/%f test=%f/%f total=%f/%f",
3409 (dc ? m_dcI : m_phase),(dc ? m_dcQ : m_gain),m_cal.min,m_cal.max,
3410 m_test.min,m_test.max,m_total.min,m_total.max);
3411 replaceDumpParams(*s,ns);
3412 m_dump.append(s);
3413 }
3414 }
3415
3416
3417 //
3418 // BrfDevTmpAltSet
3419 // Temporary change alt setting. Restore on destruction
3420 //
set(int altSet,String * error,const char * oper)3421 unsigned int BrfDevTmpAltSet::set(int altSet, String* error, const char* oper)
3422 {
3423 restore();
3424 if (!m_device || m_device->m_altSetting == altSet)
3425 return 0;
3426 unsigned int status = m_device->lusbSetAltInterface(altSet,error);
3427 if (status)
3428 return status;
3429 m_oper = oper;
3430 m_tmpAltSet = altSet;
3431 DDebug(m_device->owner(),DebugAll,
3432 "Temporary changed alt interface to %s for '%s' [%p]",
3433 altSetName(m_tmpAltSet),m_oper,m_device->owner());
3434 return 0;
3435 }
3436
restore()3437 unsigned int BrfDevTmpAltSet::restore()
3438 {
3439 if (m_tmpAltSet == BRF_ALTSET_INVALID)
3440 return 0;
3441 String e;
3442 unsigned int status = m_device->lusbSetAltInterface(m_tmpAltSet,&e);
3443 if (status == 0)
3444 DDebug(m_device->owner(),DebugAll,
3445 "Restored alt interface to %s after '%s' [%p]",
3446 altSetName(m_tmpAltSet),m_oper,m_device->owner());
3447 else
3448 Debug(m_device->owner(),DebugCrit,
3449 "Failed to restore alt interface after '%s': %s [%p]",
3450 m_oper,e.c_str(),m_device->owner());
3451 m_tmpAltSet = BRF_ALTSET_INVALID;
3452 return status;
3453 }
3454
3455 //
3456 // BrfVctcxoDiscipliner
3457 //
onCmdFreqCal(Message & msg,bool start)3458 bool BrfVctcxoDiscipliner::onCmdFreqCal(Message& msg, bool start)
3459 {
3460 if (start) {
3461 if (!m_trimsLeft) {
3462 Debug(dev().owner(),DebugNote,"Frequency calibration is starting [%p]",dev().owner());
3463 m_trimsLeft = -1;
3464 }
3465 const NamedString* s = msg.getParam(YSTRING("system_accuracy"));
3466 if (s) {
3467 int us = s->toInteger(-1,0,0,2000);
3468 if (us >= 0) {
3469 if (us != (int)m_systemAccuracy) {
3470 postponeActivity(1,true);
3471 m_systemAccuracy = us;
3472 scheduleNextPinning(m_delay);
3473 }
3474 }
3475 else
3476 Debug(dev().owner(),DebugNote,"VCTCXO discipliner: ignoring invalid %s='%s' [%p]",
3477 s->name().c_str(),s->c_str(),dev().owner());
3478 }
3479 s = msg.getParam(YSTRING("count"));
3480 if (s) {
3481 int count = s->toInteger();
3482 if (count >= 0)
3483 m_trimsLeft = (count) ? count : -1;
3484 else
3485 Debug(dev().owner(),DebugNote,"VCTCXO discipliner: ignoring invalid %s='%s' [%p]",
3486 s->name().c_str(),s->c_str(),dev().owner());
3487 }
3488 }
3489 else if (!m_trimsLeft) {
3490 msg.retValue() << "frequency calibration is currently disabled";
3491 return true;
3492 }
3493 // return current parameters
3494 if (m_trimsLeft > 0)
3495 msg.retValue() << "count=" << m_trimsLeft << " ";
3496 uint64_t usec = Time::now();
3497 unsigned int last = (!m_samples ? 0 : usToMin(m_nextPinning - m_timestamp));
3498 unsigned int remains = (!m_samples ? 0 : usToMin(m_nextPinning - usec));
3499 msg.retValue() << "measurement_interval=" << last << "min (" << remains <<
3500 "min left) system_accuracy=" << m_systemAccuracy << "us measurement_accuracy=" <<
3501 m_accuracyPpb << "ppb freqoffs=" << dev().m_freqOffset;
3502 if (m_resumePoint > usec)
3503 msg.retValue() << " (idling for " << usToMin(m_resumePoint - usec) << "min)";
3504 else if (!start && m_samples) {
3505 uint64_t samples = 0, timestamp = 0;
3506 uint16_t delay = 0;
3507 int ppb = measureDrift(samples,timestamp,delay);
3508 if (samples) {
3509 String str;
3510 msg.retValue() << (str.printf(" (current drift: ppb=%d interval=%gmin delay=%uus",
3511 ppb,(timestamp - m_timestamp) / 60.0e6F,delay));
3512 }
3513 else
3514 msg.retValue() << " (drift measurement failed)";
3515 }
3516 return true;
3517 }
3518
postponeActivity(unsigned minutes,bool dropData)3519 void BrfVctcxoDiscipliner::postponeActivity(unsigned minutes, bool dropData)
3520 {
3521 if (minutes) {
3522 m_resumePoint = usToMin(minutes) + Time::now();
3523 if (m_trace)
3524 Debug(dev().owner(),DebugInfo,"VCTCXO discipliner: postpone %u min [%p]",minutes,dev().owner());
3525 }
3526 if (dropData && m_samples) {
3527 m_samples = 0;
3528 if (m_trace)
3529 Debug(dev().owner(),DebugInfo,"VCTCXO discipliner: dropping current data [%p]",dev().owner());
3530 }
3531 }
3532
disableDiscipline(bool onCmd)3533 void BrfVctcxoDiscipliner::disableDiscipline(bool onCmd)
3534 {
3535 if (!m_trimsLeft)
3536 return;
3537 m_trimsLeft = 0;
3538 postponeActivity(0,true);
3539 Debug(dev().owner(),DebugNote,"Frequency calibration is stopping (%s) [%p]",
3540 onCmd ? "changed by command" : "disabled",dev().owner());
3541 if (onCmd)
3542 dev().notifyFreqOffs();
3543 }
3544
trimVctcxo(uint64_t timestamp,int drift)3545 void BrfVctcxoDiscipliner::trimVctcxo(uint64_t timestamp, int drift)
3546 {
3547 // process a previously measured drift or as forced input
3548 if (processData(drift ? drift : m_driftPpb))
3549 return;
3550 // minimize activity until all prerequisites are met
3551 if (!m_trimsLeft || outdatedConfig() || m_resumePoint > timestamp || init())
3552 return;
3553 // Dump delays ?
3554 if (m_dumpDelays) {
3555 uint64_t samples = 0;
3556 uint64_t timestamp = 0;
3557 uint16_t delay = 0;
3558 String err;
3559 Thread::yield();
3560 dev().samplesAndTimestamp(samples,timestamp,delay,&err);
3561 if (samples) {
3562 bool dump = (m_dumpDelays == 1);
3563 m_dumpDelays--;
3564 m_delayStat.append(String(delay)," ");
3565 if (dump) {
3566 Output("VCTCXO discipliner delays: %s",m_delayStat.c_str());
3567 m_delayStat.clear();
3568 }
3569 }
3570 }
3571 // wait the passing of the baseline interval before trying to determine the current drift
3572 if (m_nextPinning > timestamp)
3573 return;
3574 uint64_t samples = 0;
3575 uint16_t delay = 0;
3576 m_driftPpb = measureDrift(samples,timestamp,delay);
3577 // update the baseline interval if the measurement is valid
3578 if (!samples)
3579 return;
3580 scheduleNextPinning(delay);
3581 // drop the measured drift if the measurement isn't accurate
3582 if (m_nextPinning > timestamp) {
3583 if (m_trace)
3584 Debug(dev().owner(),DebugInfo,
3585 "VCTCXO discipliner: inaccurate measurement rescheduled in %umin [%p]",
3586 usToMin(m_nextPinning - Time::now()),dev().owner());
3587 m_driftPpb = 0;
3588 return;
3589 }
3590 // replace the initial measurement
3591 m_samples = samples;
3592 m_timestamp = timestamp;
3593 m_delay = delay;
3594 }
3595
scheduleNextPinning(uint16_t delay)3596 void BrfVctcxoDiscipliner::scheduleNextPinning(uint16_t delay)
3597 {
3598 m_nextPinning = m_systemAccuracy;
3599 if (m_delay > m_knownDelay)
3600 m_nextPinning += m_delay - m_knownDelay;
3601 if (delay > m_knownDelay)
3602 m_nextPinning += delay - m_knownDelay;
3603 m_nextPinning *= 1000000000UL / m_accuracyPpb;
3604 m_nextPinning += m_timestamp;
3605 if (m_trace)
3606 Debug(dev().owner(),DebugInfo,
3607 "VCTCXO discipliner: scheduled next pinning at %f (%umin) system_accuracy=%u "
3608 "accuracy_ppb=%u delay(initial/current/known)=%u/%u/%u [%p]",
3609 1.0e-6 * m_nextPinning,usToMin(m_nextPinning - m_timestamp),
3610 m_systemAccuracy,m_accuracyPpb,m_delay,delay,m_knownDelay,dev().owner());
3611 }
3612
outdatedConfig()3613 bool BrfVctcxoDiscipliner::outdatedConfig()
3614 {
3615 // check if current configuration is already valid
3616 if (dev().getDirState(true).rfEnabled
3617 && dev().m_calibrateStatus != BrfLibUsbDevice::Calibrating
3618 && dev().m_freqOffset == m_freqOffset
3619 && dev().getDirState(true).sampleRate == m_confSampleRate
3620 && m_confSampleRate)
3621 return false;
3622 if (m_freqOffset != dev().m_freqOffset) {
3623 if (m_trace && m_freqOffset)
3624 Debug(dev().owner(),DebugInfo,
3625 "VCTCXO discipliner: voltageDAC changed %g -> %g [%p]",
3626 m_freqOffset,dev().m_freqOffset,dev().owner());
3627 m_freqOffset = dev().m_freqOffset;
3628 }
3629 if (m_confSampleRate != dev().getDirState(true).sampleRate) {
3630 if (m_trace && m_confSampleRate)
3631 Debug(dev().owner(),DebugInfo,
3632 "VCTCXO discipliner: configSampleRate changed %u -> %u [%p]",
3633 m_confSampleRate,dev().getDirState(true).sampleRate,dev().owner());
3634 m_confSampleRate = dev().getDirState(true).sampleRate;
3635 }
3636 postponeActivity(3,true);
3637 return true;
3638 }
3639
init()3640 bool BrfVctcxoDiscipliner::init()
3641 {
3642 if (!m_samples) {
3643 samplesAndTimestamp(m_samples,m_timestamp,m_delay,20);
3644 scheduleNextPinning(m_delay);
3645 return true;
3646 }
3647 return false;
3648 }
3649
processData(int drift)3650 bool BrfVctcxoDiscipliner::processData(int drift)
3651 {
3652 if (!drift)
3653 return false;
3654 if (m_driftPpb && drift != m_driftPpb) {
3655 Debug(dev().owner(),DebugNote,
3656 "VCTCXO discipliner: dropping last measured drift %dppb [%p]",
3657 m_driftPpb,dev().owner());
3658 m_driftPpb = 0;
3659 }
3660 // transform the drift in voltageDAC units used for trimming the VCTCXO
3661 float trimDAC = -drift / s_ppbPerUnit;
3662 // limit the change in voltage (trimDAC = +/-10 => approx. +/-0.1V)
3663 const int limit = 12; // arbitrary
3664 if (trimDAC < -limit || trimDAC > limit) // clamp
3665 trimDAC = (trimDAC > limit) ? limit : -limit;
3666 float newOffs = dev().m_freqOffset + trimDAC;
3667 if (m_trace)
3668 Debug(dev().owner(),(!m_driftPpb) ? DebugInfo : DebugNote,
3669 "VCTCXO discipliner: changing FrequencyOffset %g -> %g drift=%dppb [%p]",
3670 dev().m_freqOffset,newOffs,drift,dev().owner());
3671 // trim the VCTCXO
3672 unsigned status = dev().setFreqOffset(newOffs,0,false);
3673 if (status) {
3674 // postpone activity for a minute to avoid a flood of debug messages
3675 postponeActivity(1);
3676 XDebug(dev().owner(),DebugNote,
3677 "VCTCXO discipliner: failed to set FrequencyOffset to %g status=%u %s [%p]",
3678 newOffs,status,RadioInterface::errorName(status),dev().owner());
3679 return true;
3680 }
3681 postponeActivity(1,true);
3682 // no more actions to be done if this was a forced drift correction
3683 if (!m_driftPpb)
3684 return true;
3685 // enqueue a feedback message with the adjusted frequency offset
3686 dev().notifyFreqOffs();
3687 // clear the pending drift
3688 m_driftPpb = 0;
3689 // decrease the number of scheduled trims, unless toggled on (-1)
3690 if (m_trimsLeft > 0) {
3691 m_trimsLeft--;
3692 if (!m_trimsLeft)
3693 Debug(dev().owner(),DebugNote,
3694 "Frequency calibration is stopping (count=0) [%p]",dev().owner());
3695 else if (m_trace)
3696 Debug(dev().owner(),DebugInfo,"VCTCXO discipliner: %d trims left [%p]",
3697 m_trimsLeft,dev().owner());
3698 }
3699 return true;
3700 }
3701
measureDrift(uint64_t & samples,uint64_t & timestamp,uint16_t & delay)3702 int BrfVctcxoDiscipliner::measureDrift(uint64_t& samples, uint64_t& timestamp, uint16_t& delay)
3703 {
3704 samplesAndTimestamp(samples,timestamp,delay);
3705 // revoke the measurement results for invalid samples or timestamp
3706 if (samples < m_samples || timestamp < m_timestamp)
3707 samples = 0;
3708 if (!samples) {
3709 XDebug(dev().owner(),DebugInfo,"VCTCXO discipliner: invalid sample to timestamp pinning,"
3710 " failed to measure drift [%p]",dev().owner());
3711 return 0;
3712 }
3713 // compute the average sample rate for the current interval,
3714 // expressed in Hz (the microsec timestamp gets converted to sec)
3715 double sampleRate = (double)(samples - m_samples) / (1.0e-6 * (timestamp - m_timestamp));
3716 int drift = 1.0e9 * (sampleRate / m_confSampleRate - 1);
3717 if (m_trace)
3718 Debug(dev().owner(),DebugInfo,"VCTCXO discipliner: measured drift=%dppb sampleRate "
3719 "current=%f configured=%u deltaSamples=" FMT64U " deltaTs=" FMT64U " [%p]",
3720 drift,sampleRate,m_confSampleRate,samples - m_samples,timestamp - m_timestamp,dev().owner());
3721 return drift;
3722 }
3723
samplesAndTimestamp(uint64_t & samples,uint64_t & timestamp,uint16_t & delay,unsigned maxIter)3724 void BrfVctcxoDiscipliner::samplesAndTimestamp(uint64_t& samples, uint64_t& timestamp,
3725 uint16_t& delay, unsigned maxIter)
3726 {
3727 static unsigned int s_stop = RadioInterface::NotInitialized | RadioInterface::NotCalibrated |
3728 RadioInterface::Cancelled;
3729 samples = 0;
3730 delay = m_maxDelay + 1;
3731 unsigned timeouts = 0;
3732 unsigned i = 0;
3733 for (; i < maxIter; i++) {
3734 uint64_t tempSamples = 0;
3735 uint64_t tempTs = 0;
3736 uint16_t tempDelay = 0;
3737 String serializeErr;
3738 Thread::yield();
3739 unsigned status = dev().samplesAndTimestamp(tempSamples,tempTs,tempDelay,&serializeErr);
3740 if (status) {
3741 if (0 != (status & s_stop)) {
3742 postponeActivity(1);
3743 return;
3744 }
3745 if (status == RadioInterface::Failure && serializeErr)
3746 timeouts++;
3747 else if (status & RadioInterface::FatalErrorMask) {
3748 disableDiscipline();
3749 return;
3750 }
3751 }
3752 // drop invalid and imprecise measurements
3753 if (!tempSamples || tempDelay > delay)
3754 continue;
3755 // higher accuracy measurement
3756 delay = tempDelay;
3757 samples = tempSamples;
3758 timestamp = tempTs;
3759 if (delay < m_knownDelay) {
3760 if (m_trace)
3761 Debug(dev().owner(),DebugInfo,"VCTCXO discipliner: known delay changed %u -> %u [%p]",
3762 m_knownDelay,delay * 19 / 20,dev().owner());
3763 m_knownDelay = delay * 19 / 20;
3764 scheduleNextPinning(m_delay);
3765 }
3766 // optimal measurement
3767 if (delay < m_bestDelay)
3768 break;
3769 }
3770 if (m_trace)
3771 Debug(dev().owner(),(delay < m_maxDelay) ? DebugInfo : DebugNote,
3772 "VCTCXO discipliner: got samples=" FMT64U " timestamp=%f delay=%u "
3773 "(max=%u best=%u known=%u) iteration %u/%u timeouts=%u [%p]",
3774 samples,1.0e-6 * timestamp,delay,m_maxDelay,m_bestDelay,
3775 m_knownDelay,i,maxIter,timeouts,dev().owner());
3776 }
3777
3778
3779 //
3780 // BrfLibUsbDevice
3781 //
3782 #define BRF_TX_SERIALIZE_(waitNow,instr) \
3783 BrfSerialize txSerialize(this,true,waitNow); \
3784 if (txSerialize.status) \
3785 instr
3786 #define BRF_TX_SERIALIZE BRF_TX_SERIALIZE_(true,return txSerialize.status)
3787 #define BRF_TX_SERIALIZE_CHECK_DEV(loc) \
3788 BRF_TX_SERIALIZE_(true,return txSerialize.status); \
3789 txSerialize.status = checkDev(loc); \
3790 if (txSerialize.status) \
3791 return txSerialize.status;
3792 #define BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(internal,loc) \
3793 BRF_TX_SERIALIZE; \
3794 txSerialize.status = checkPubFuncEntry(internal,loc); \
3795 if (txSerialize.status) \
3796 return txSerialize.status;
3797 #define BRF_TX_SERIALIZE_NONE BRF_TX_SERIALIZE_(true,return)
3798
3799 #define BRF_RX_SERIALIZE_(waitNow,instr) \
3800 BrfSerialize rxSerialize(this,false,waitNow); \
3801 if (rxSerialize.status) \
3802 instr
3803 #define BRF_RX_SERIALIZE BRF_RX_SERIALIZE_(true,return rxSerialize.status)
3804 #define BRF_RX_SERIALIZE_CHECK_PUB_ENTRY(internal,loc) \
3805 BRF_RX_SERIALIZE; \
3806 rxSerialize.status = checkPubFuncEntry(internal,loc); \
3807 if (rxSerialize.status) \
3808 return rxSerialize.status;
3809 #define BRF_RX_SERIALIZE_NONE BRF_RX_SERIALIZE_(true,return)
3810
BrfLibUsbDevice(BrfInterface * owner)3811 BrfLibUsbDevice::BrfLibUsbDevice(BrfInterface* owner)
3812 : m_owner(owner),
3813 m_initialized(false),
3814 m_exiting(false),
3815 m_closing(false),
3816 m_closingDevice(false),
3817 m_notifyOff(false),
3818 m_dbgMutex(false,"BrfDevDbg"),
3819 m_context(0),
3820 m_list(0),
3821 m_listCount(0),
3822 m_devHandle(0),
3823 m_dev(0),
3824 m_devBus(-1),
3825 m_devAddr(-1),
3826 m_devSpeed(LIBUSB_SPEED_HIGH),
3827 m_ctrlTransferPage(0),
3828 m_syncTout(s_lusbSyncTransferTout),
3829 m_syncSemaphore(1,"BrfSync",1),
3830 m_ctrlTout(s_lusbCtrlTransferTout),
3831 m_bulkTout(s_lusbBulkTransferTout),
3832 m_altSetting(BRF_ALTSET_INVALID),
3833 m_rxShowDcInfo(0),
3834 m_rxDcOffsetMax(BRF_RX_DC_OFFSET_DEF),
3835 m_rxDcAvgI(0),
3836 m_rxDcAvgQ(0),
3837 m_freqOffset(BRF_FREQ_OFFS_DEF),
3838 m_txGainCorrSoftware(true),
3839 m_txIO(true),
3840 m_rxIO(false),
3841 m_syncTxStateSet(false),
3842 m_syncTxStateCode(0),
3843 m_rxTimestamp(0),
3844 m_rxResyncCandidate(0),
3845 m_rxTsPastIntervalMs(200),
3846 m_rxTsPastSamples(0),
3847 m_warnClamped(0),
3848 m_minBufsSend(1),
3849 m_silenceTimeMs(0),
3850 m_silenceTs(0),
3851 m_txPowerBalance(1),
3852 m_txPowerBalanceChanged(false),
3853 m_txPowerScaleI(1),
3854 m_txPowerScaleQ(1),
3855 m_wrPowerScaleI(s_sampleEnergize),
3856 m_wrPowerScaleQ(s_sampleEnergize),
3857 m_wrMaxI(s_sampleEnergize),
3858 m_wrMaxQ(s_sampleEnergize),
3859 m_gainExpBreak(0),
3860 m_gainExpSlope(0),
3861 m_phaseExpBreak(0),
3862 m_phaseExpSlope(0),
3863 m_ampTableUse(false),
3864 m_rxAlterDataParams(""),
3865 m_rxAlterData(false),
3866 m_rxAlterIncrement(0),
3867 m_rxAlterTsJumpSingle(true),
3868 m_rxAlterTsJumpPos(0),
3869 m_txPatternChanged(false),
3870 m_txPatternBufPos(0),
3871 m_calLms(false),
3872 m_calibrateStatus(0),
3873 m_calibrateStop(0),
3874 m_calibration(""),
3875 m_calThread(0),
3876 m_sendThread(0),
3877 m_recvThread(0),
3878 m_internalIoSemaphore(1,"BrfDevSyncThreads",1),
3879 m_internalIoTimestamp(0),
3880 m_internalIoTxRate(0),
3881 m_internalIoRxRate(0),
3882 m_internalIoRateChanged(false),
3883 m_threadMutex("BrfDevInternalThread")
3884 {
3885 DDebug(&__plugin,DebugAll,"BrfLibUsbDevice(%p) [%p]",m_owner,this);
3886 m_usbTransfer[EpSendSamples].device = this;
3887 m_usbTransfer[EpSendSamples].ep = BRF_ENDP_TX_SAMPLES;
3888 m_usbTransfer[EpSendCtrl].device = this;
3889 m_usbTransfer[EpSendCtrl].ep = BRF_ENDP_TX_CTRL;
3890 m_usbTransfer[EpReadSamples].device = this;
3891 m_usbTransfer[EpReadSamples].ep = BRF_ENDP_RX_SAMPLES;
3892 m_usbTransfer[EpReadCtrl].device = this;
3893 m_usbTransfer[EpReadCtrl].ep = BRF_ENDP_RX_CTRL;
3894 m_state.m_rx.vga1 = BRF_RXVGA1_GAIN_MAX + 1;
3895 m_state.m_rx.dcOffsetI = BRF_RX_DC_OFFSET_MAX + 1;
3896 m_state.m_rx.dcOffsetQ = BRF_RX_DC_OFFSET_MAX + 1;
3897 m_state.m_tx.vga1 = BRF_TXVGA1_GAIN_MIN - 1;
3898 m_state.m_tx.vga2 = BRF_TXVGA2_GAIN_MIN - 1;
3899 m_state.m_tx.dcOffsetI = BRF_RX_DC_OFFSET_MAX + 1;
3900 m_state.m_tx.dcOffsetQ = BRF_RX_DC_OFFSET_MAX + 1;
3901 initRadioCaps(m_radioCaps);
3902 }
3903
~BrfLibUsbDevice()3904 BrfLibUsbDevice::~BrfLibUsbDevice()
3905 {
3906 DDebug(&__plugin,DebugAll,"~BrfLibUsbDevice(%p) [%p]",m_owner,this);
3907 doClose();
3908 }
3909
setTxPattern(const String & pattern,float gain)3910 unsigned int BrfLibUsbDevice::setTxPattern(const String& pattern, float gain)
3911 {
3912 Lock lck(m_dbgMutex);
3913 if (m_state.m_txPattern == pattern && m_state.m_txPatternGain == gain)
3914 return 0;
3915 ComplexVector buf;
3916 unsigned int status = 0;
3917 String e;
3918 unsigned int pLen = 0;
3919 if (pattern &&
3920 !buildVector(e,pattern,buf,totalSamples(true),false,true,false,&pLen,gain)) {
3921 Debug(m_owner,DebugNote,"Invalid tx pattern '%s': %s [%p]",
3922 pattern.c_str(),e.c_str(),m_owner);
3923 status = RadioInterface::Failure;
3924 }
3925 if (!status && buf.length()) {
3926 m_txPattern = buf;
3927 m_state.m_txPattern = pattern;
3928 m_state.m_txPatternGain = gain;
3929 if (m_owner && m_owner->debugAt(DebugNote)) {
3930 String s;
3931 if (!pLen)
3932 pLen = m_txPattern.length();
3933 if (pLen > 30)
3934 pLen = 30;
3935 m_txPattern.head(pLen).dump(s,Math::dumpComplex," ","%g,%g");
3936 if (s.startsWith(m_state.m_txPattern))
3937 s.clear();
3938 else
3939 s.printf(1024,"HEAD[%u]: %s",pLen,s.c_str());
3940 Debug(m_owner,DebugInfo,"TX pattern set to '%s' gain=%.3f len=%u [%p]%s",
3941 m_state.m_txPattern.substr(0,100).c_str(),m_state.m_txPatternGain,
3942 m_txPattern.length(),m_owner,encloseDashes(s,true));
3943 }
3944 }
3945 else {
3946 if (m_state.m_txPattern)
3947 Debug(m_owner,DebugInfo,"TX pattern cleared [%p]",m_owner);
3948 m_txPattern.resetStorage(0);
3949 m_state.m_txPattern.clear();
3950 m_state.m_txPatternGain = 1;
3951 }
3952 m_txPatternChanged = true;
3953 return status;
3954 }
3955
dumpIOAvg(String & buf,BrfDevIO & io,uint64_t now)3956 static inline String& dumpIOAvg(String& buf, BrfDevIO& io, uint64_t now)
3957 {
3958 if (io.startTime && io.transferred) {
3959 unsigned int sec = (unsigned int)((now - io.startTime) / 1000000);
3960 if (sec) {
3961 buf = io.transferred / sec;
3962 return (buf << " samples/sec");
3963 }
3964 }
3965 return (buf = "-");
3966 }
3967
dumpStats(String & buf,const char * sep)3968 void BrfLibUsbDevice::dumpStats(String& buf, const char* sep)
3969 {
3970 BRF_RX_SERIALIZE_NONE;
3971 BRF_TX_SERIALIZE_NONE;
3972 String s;
3973 uint64_t now = Time::now();
3974 buf.append("TxTS=",sep) << m_txIO.timestamp;
3975 buf << sep << "RxTS=" << m_rxIO.timestamp;
3976 buf << sep << "TxAvg=" << dumpIOAvg(s,m_txIO,now);
3977 buf << sep << "RxAvg=" << dumpIOAvg(s,m_rxIO,now);
3978 }
3979
buildTimestampReport(String & buf,bool tx,uint64_t our,uint64_t board,unsigned int code,bool app=true)3980 static inline void buildTimestampReport(String& buf, bool tx, uint64_t our, uint64_t board,
3981 unsigned int code, bool app = true)
3982 {
3983 if (!code) {
3984 const char* what = app ? "app" : "crt";
3985 int64_t delta = (int64_t)(our - board);
3986 buf.printf("%s: %s=" FMT64U "\tboard=" FMT64U "\tdelta=" FMT64 "\t%s_position: %s",
3987 brfDir(tx),what,our,board,delta,what,(delta < 0 ? "past" : "future"));
3988 }
3989 else
3990 buf << brfDir(tx) << ": failure - " << RadioInterface::errorName(code);
3991 }
3992
dumpTimestamps(String & buf,const char * sep)3993 void BrfLibUsbDevice::dumpTimestamps(String& buf, const char* sep)
3994 {
3995 BRF_TX_SERIALIZE_NONE;
3996 uint64_t tsTx = 0;
3997 uint64_t ourTx = m_txIO.lastTs;
3998 unsigned int codeTx = internalGetTimestamp(true,tsTx);
3999 txSerialize.drop();
4000 BRF_RX_SERIALIZE_NONE;
4001 uint64_t tsRx = 0;
4002 uint64_t ourRx = m_rxIO.timestamp;
4003 unsigned int codeRx = internalGetTimestamp(false,tsRx);
4004 uint64_t rx = m_rxTimestamp;
4005 rxSerialize.drop();
4006 String s;
4007 String sTx;
4008 String sRx;
4009 String sRxTs;
4010 buildTimestampReport(sTx,true,ourTx,tsTx,codeTx);
4011 buildTimestampReport(sRx,false,ourRx,tsRx,codeRx);
4012 if (!codeRx)
4013 buildTimestampReport(sRxTs,false,rx,tsRx,codeRx,false);
4014 buf.append(sTx,sep) << sep << sRx;
4015 buf.append(sRxTs,sep);
4016 }
4017
dumpDev(String & buf,bool info,bool state,const char * sep,bool fromStatus,bool withHdr)4018 void BrfLibUsbDevice::dumpDev(String& buf, bool info, bool state, const char* sep,
4019 bool fromStatus, bool withHdr)
4020 {
4021 if (!(info || state))
4022 return;
4023 BRF_RX_SERIALIZE_NONE;
4024 BRF_TX_SERIALIZE_NONE;
4025 internalDumpDev(buf,info,state,sep,false,fromStatus,withHdr);
4026 }
4027
dumpBoardStatus(String & buf,const char * sep)4028 void BrfLibUsbDevice::dumpBoardStatus(String& buf, const char* sep)
4029 {
4030 #define ADD_INTERVAL(minVal,maxVal) if (!code) addIntervalInt(buf,minVal,maxVal);
4031 #define BOARD_STATUS_SET_TMP(func,instr_ok) { \
4032 code = func; \
4033 if (!code) \
4034 instr_ok; \
4035 else \
4036 tmp.printf("ERROR %u %s",code,RadioInterface::errorName(code)); \
4037 }
4038 #define BOARD_STATUS_SET(func,instr_ok,prefix,suffix) { \
4039 BOARD_STATUS_SET_TMP(func,instr_ok); \
4040 buf.append(prefix + tmp + (!code ? suffix : ""),sep); \
4041 }
4042 #define dumpDevAppend(func,val,prefix,suffix) BOARD_STATUS_SET(func,tmp = (int64_t)val,prefix,suffix)
4043 #define dumpDevAppendFreq(func,val,prefix,suffix) \
4044 BOARD_STATUS_SET(func,dumpFloatG(tmp,(double)val / 1000000,0,"MHz"),prefix,suffix)
4045 #define reportLpf(tx) { \
4046 BOARD_STATUS_SET(getLpf(intVal,tx),tmp = lookup(intVal,s_lpf),(tx ? "TxLpf=" : "RxLpf="),0); \
4047 if (!code) { \
4048 BOARD_STATUS_SET_TMP(getLpfBandwidth(u32Val,tx),dumpFloatG(tmp,(double)u32Val / 1000000,0,"MHz")); \
4049 buf << " BW: " << tmp; \
4050 } \
4051 }
4052 int intVal = 0;
4053 int16_t int16Val = 0;
4054 uint32_t u32Val = 0;
4055 uint64_t u64Val = 0;
4056 unsigned int code = 0;
4057 String tmp;
4058 dumpDevAppend(getTimestamp(false,u64Val),u64Val,"RxTS=",0);
4059 dumpDevAppend(getTimestamp(true,u64Val),u64Val,"TxTS=",0);
4060 dumpDevAppend(getRxVga1(intVal),intVal,"RxVGA1="," dB");
4061 ADD_INTERVAL(BRF_RXVGA1_GAIN_MIN,BRF_RXVGA1_GAIN_MAX);
4062 dumpDevAppend(getRxVga2(intVal),intVal,"RxVGA2="," dB");
4063 ADD_INTERVAL(BRF_RXVGA2_GAIN_MIN,BRF_RXVGA2_GAIN_MAX);
4064 dumpDevAppend(getTxVga1(intVal),intVal,"TxVGA1="," dB");
4065 ADD_INTERVAL(BRF_TXVGA1_GAIN_MIN,BRF_TXVGA1_GAIN_MAX);
4066 dumpDevAppend(getTxVga2(intVal),intVal,"TxVGA2="," dB");
4067 ADD_INTERVAL(BRF_TXVGA2_GAIN_MIN,BRF_TXVGA2_GAIN_MAX);
4068 dumpDevAppend(getDcOffset(false,true,int16Val),int16Val,"RxDCCorrI=",0);
4069 ADD_INTERVAL(-BRF_RX_DC_OFFSET_MAX,BRF_RX_DC_OFFSET_MAX);
4070 dumpDevAppend(getDcOffset(false,false,int16Val),int16Val,"RxDCCorrQ=",0);
4071 ADD_INTERVAL(-BRF_RX_DC_OFFSET_MAX,BRF_RX_DC_OFFSET_MAX);
4072 dumpDevAppend(getDcOffset(true,true,int16Val),int16Val,"TxDCCorrI=",0);
4073 ADD_INTERVAL(BRF_TX_DC_OFFSET_MIN,BRF_TX_DC_OFFSET_MAX);
4074 dumpDevAppend(getDcOffset(true,false,int16Val),int16Val,"TxDCCorrQ=",0);
4075 ADD_INTERVAL(BRF_TX_DC_OFFSET_MIN,BRF_TX_DC_OFFSET_MAX);
4076 dumpDevAppend(getFpgaCorr(false,CorrFpgaPhase,int16Val),int16Val,"RxCorrFpgaPhase=",0);
4077 ADD_INTERVAL(-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX);
4078 dumpDevAppend(getFpgaCorr(false,CorrFpgaGain,int16Val),int16Val,"RxCorrFpgaGain=",0);
4079 ADD_INTERVAL(-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX);
4080 dumpDevAppend(getFpgaCorr(true,CorrFpgaPhase,int16Val),int16Val,"TxCorrFpgaPhase=",0);
4081 ADD_INTERVAL(-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX);
4082 dumpDevAppend(getFpgaCorr(true,CorrFpgaGain,int16Val),int16Val,"TxCorrFpgaGain=",0);
4083 ADD_INTERVAL(-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX);
4084 dumpDevAppendFreq(getFrequency(u32Val,false),u32Val,"RxFreq=",0);
4085 dumpDevAppendFreq(getFrequency(u32Val,true),u32Val,"TxFreq=",0);
4086 dumpDevAppend(getSamplerate(u32Val,false),u32Val,"RxSampRate=",0);
4087 dumpDevAppend(getSamplerate(u32Val,true),u32Val,"TxSampRate=",0);
4088 reportLpf(false);
4089 reportLpf(true);
4090 {
4091 BRF_TX_SERIALIZE_NONE;
4092 String tmp;
4093 buf.append("calibration-cache=" + dumpCalCache(tmp),sep);
4094 }
4095 #undef ADD_INTERVAL
4096 #undef BOARD_STATUS_SET_TMP
4097 #undef BOARD_STATUS_SET
4098 #undef dumpDevAppend
4099 #undef dumpDevAppendFreq
4100 #undef reportLpf
4101 }
4102
dumpPeripheral(uint8_t dev,uint8_t addr,uint8_t len,String * buf)4103 unsigned int BrfLibUsbDevice::dumpPeripheral(uint8_t dev, uint8_t addr, uint8_t len, String* buf)
4104 {
4105 BRF_TX_SERIALIZE_CHECK_DEV("dumpPeripheral()");
4106 if (dev != UartDevSI5338) {
4107 addr = clampInt(addr,0,0x7f);
4108 len = clampInt(len,1,128 - addr);
4109 }
4110 else {
4111 addr = clampInt(addr,0,256);
4112 len = clampInt(len,1,257 - addr);
4113 }
4114 return internalDumpPeripheral(dev,addr,len,buf,16);
4115 }
4116
4117 // Module reload
reLoad(const NamedList * params)4118 void BrfLibUsbDevice::reLoad(const NamedList* params)
4119 {
4120 NamedList dummy("");
4121 if (!params) {
4122 Lock lck(&__plugin);
4123 dummy = *s_cfg.createSection(YSTRING("general"));
4124 params = &dummy;
4125 }
4126 m_warnClamped = (float)params->getIntValue(YSTRING("warn_clamped"),0,0,100);
4127 setDataDump();
4128 checkTs(true,params->getIntValue(YSTRING("txcheckts"),0));
4129 checkTs(false,params->getIntValue(YSTRING("rxcheckts"),-1));
4130 checkLimit(false,params->getIntValue(YSTRING("rxchecklimit"),0));
4131 updateAlterData(*params);
4132 const NamedString* p = params->getParam(YSTRING("rxoutsw"));
4133 if (p)
4134 setRxOut(p->toBoolean());
4135 m_trace = params->getBoolValue(YSTRING("trace_discipliner"));
4136 if (!m_dumpDelays)
4137 m_dumpDelays = params->getIntValue(YSTRING("trace_discipliner_delays"),0,0);
4138 }
4139
4140 // dir: 0=both negative=rx positive=tx
4141 // level: 0: both negative=app positive=device
setDataDump(int dir,int level,const NamedList * p)4142 void BrfLibUsbDevice::setDataDump(int dir, int level, const NamedList* p)
4143 {
4144 static const String prefix[] = {"tx-data","tx-app","rx-data","rx-app"};
4145
4146 NamedList dummy("");
4147 if (!p) {
4148 Lock lck(__plugin);
4149 dummy = *s_cfg.createSection(YSTRING("filedump"));
4150 p = &dummy;
4151 }
4152 NamedList* upd[4] = {0,0,0,0};
4153 if (dir >= 0) {
4154 if (level >= 0)
4155 upd[0] = &m_txIO.dataDumpParams;
4156 if (level <= 0)
4157 upd[1] = &m_txIO.upDumpParams;
4158 }
4159 if (dir <= 0) {
4160 if (level >= 0)
4161 upd[2] = &m_rxIO.dataDumpParams;
4162 if (level <= 0)
4163 upd[3] = &m_rxIO.upDumpParams;
4164 }
4165 Lock lck(m_dbgMutex);
4166 for (unsigned int i = 0; i < 4; i++) {
4167 if (!upd[i])
4168 continue;
4169 const String& mode = (*p)[prefix[i] + "-mode"];
4170 int n = 0;
4171 if (mode == YSTRING("count")) {
4172 String param = prefix[i] + "-count";
4173 const String& s = (*p)[param];
4174 if (s) {
4175 n = s.toInteger(-1);
4176 if (n <= 0) {
4177 Debug(m_owner,DebugConf,"%s set to '%s': disabling dump [%p]",
4178 param.c_str(),s.c_str(),m_owner);
4179 n = 0;
4180 }
4181 }
4182 else
4183 n = 10;
4184 }
4185 else if (mode.toBoolean())
4186 n = -1;
4187 String file;
4188 if (n) {
4189 file = (*p)[prefix[i] + "-file"];
4190 if (!file)
4191 file = prefix[i] + "-${boardserial}";
4192 }
4193 upd[i]->clearParams();
4194 if (file) {
4195 upd[i]->addParam("file",file);
4196 upd[i]->addParam("count",String(n));
4197 }
4198 // Signal change
4199 upd[i]->assign("1");
4200 }
4201 }
4202
4203 // Initialize the device.
4204 // Call the reset method in order to set the device to a known state
open(const NamedList & params,String & error)4205 unsigned int BrfLibUsbDevice::open(const NamedList& params, String& error)
4206 {
4207 BRF_RX_SERIALIZE;
4208 BRF_TX_SERIALIZE;
4209 doClose();
4210 String e;
4211 unsigned int status = 0;
4212 while (true) {
4213 m_calLms = params.getBoolValue(YSTRING("lms_autocal"));
4214 m_serial = params[YSTRING("serial")];
4215 BRF_FUNC_CALL_BREAK(resetUsb(&e));
4216 BRF_FUNC_CALL_BREAK(openDevice(true,&e));
4217 BRF_FUNC_CALL_BREAK(updateSpeed(params,&e));
4218 m_calCache.clear();
4219 readCalCache();
4220 status = updateFpga(params);
4221 if (status) {
4222 e = "Failed to load FPGA";
4223 break;
4224 }
4225 BRF_FUNC_CALL_BREAK(lusbSetAltInterface(BRF_ALTSET_IDLE,&e));
4226 BRF_FUNC_CALL_BREAK(openChangeLms(params,&e));
4227 BrfDevTmpAltSet tmpAltSet(this,status,&e,"Open device");
4228 if (status)
4229 break;
4230 uint8_t data = 0;
4231 BRF_FUNC_CALL_BREAK(lmsRead(0x04,data,&e));
4232 m_lmsVersion.printf("0x%x (%u.%u)",data,(data >> 4),(data & 0x0f));
4233 BRF_FUNC_CALL_BREAK(tmpAltSet.restore());
4234 m_freqOffset = clampFloatParam(params,YSTRING("RadioFrequencyOffset"),
4235 BRF_FREQ_OFFS_DEF,BRF_FREQ_OFFS_MIN,BRF_FREQ_OFFS_MAX);
4236 m_txGainCorrSoftware = params.getBoolValue(YSTRING("tx_fpga_corr_gain_software"),true);
4237 bool superSpeed = (speed() == LIBUSB_SPEED_SUPER);
4238 m_maxDelay = clampIntParam(params,YSTRING("max_delay"),superSpeed ?
4239 BRF_MAX_DELAY_SUPER_SPEED_DEF : BRF_MAX_DELAY_HIGH_SPEED_DEF,100,2000);
4240 m_bestDelay = clampIntParam(params,YSTRING("best_delay"),superSpeed ?
4241 BRF_BEST_DELAY_SUPER_SPEED_DEF : BRF_BEST_DELAY_HIGH_SPEED_DEF,100,m_maxDelay);
4242 m_knownDelay = clampIntParam(params,YSTRING("known_delay"),superSpeed ?
4243 BRF_KNOWN_DELAY_SUPER_SPEED_DEF : BRF_KNOWN_DELAY_HIGH_SPEED_DEF,100,m_bestDelay);
4244 m_systemAccuracy = clampIntParam(params,YSTRING("system_accuracy"),
4245 BRF_SYSTEM_ACCURACY_DEF,100,2000);
4246 m_accuracyPpb = clampIntParam(params,YSTRING("accuracy_ppb"),BRF_ACCURACY_PPB_DEF,10,200);
4247 // Init TX/RX buffers
4248 m_rxResyncCandidate = 0;
4249 m_state.m_rxDcAuto = params.getBoolValue("rx_dc_autocorrect",true);
4250 m_rxShowDcInfo = params.getIntValue("rx_dc_showinfo");
4251 m_rxDcOffsetMax = BRF_RX_DC_OFFSET_DEF;
4252 m_state.m_rx.dcOffsetI = BRF_RX_DC_OFFSET_MAX + 1;
4253 m_state.m_rx.dcOffsetQ = BRF_RX_DC_OFFSET_MAX + 1;
4254 int tmpInt = 0;
4255 int i = 0;
4256 int q = 0;
4257 i = clampIntParam(params,"RX.OffsetI",0,-BRF_RX_DC_OFFSET_MAX,BRF_RX_DC_OFFSET_MAX);
4258 q = clampIntParam(params,"RX.OffsetQ",0,-BRF_RX_DC_OFFSET_MAX,BRF_RX_DC_OFFSET_MAX);
4259 BRF_FUNC_CALL_BREAK(internalSetCorrectionIQ(false,i,q,&e));
4260 BRF_FUNC_CALL_BREAK(internalEnableRxVga(true,true,&e));
4261 BRF_FUNC_CALL_BREAK(internalEnableRxVga(true,false,&e));
4262 i = clampIntParam(params,"TX.OffsetI",0,BRF_TX_DC_OFFSET_MIN,BRF_TX_DC_OFFSET_MAX);
4263 q = clampIntParam(params,"TX.OffsetQ",0,BRF_TX_DC_OFFSET_MIN,BRF_TX_DC_OFFSET_MAX);
4264 BRF_FUNC_CALL_BREAK(internalSetCorrectionIQ(true,i,q,&e));
4265 // Set RX gain
4266 m_state.m_rx.vga1 = BRF_RXVGA1_GAIN_MAX + 1;
4267 BRF_FUNC_CALL_BREAK(internalSetGain(false,BRF_RXVGA2_GAIN_MIN));
4268 // Pre/post mixer TX VGA
4269 m_state.m_tx.vga1Changed = false;
4270 const String& txVga1 = params["tx_vga1"];
4271 if (txVga1)
4272 BRF_FUNC_CALL_BREAK(internalSetTxVga(txVga1.toInteger(BRF_TXVGA1_GAIN_DEF),true,&e));
4273 const String& txVga2 = params["tx_vga2"];
4274 if (txVga2)
4275 BRF_FUNC_CALL_BREAK(internalSetTxVga(txVga2.toInteger(BRF_TXVGA2_GAIN_MIN),false,&e));
4276 // Set FPGA correction
4277 tmpInt = clampIntParam(params,"tx_fpga_corr_phase",0,-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX);
4278 status = internalSetFpgaCorr(true,CorrFpgaPhase,tmpInt,&e,DebugConf);
4279 if (status)
4280 break;
4281 tmpInt = clampIntParam(params,"tx_fpga_corr_gain",0,-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX);
4282 status = internalSetFpgaCorr(true,CorrFpgaGain,tmpInt,&e,DebugConf);
4283 if (status)
4284 break;
4285 // Make sure we have the correct values for status
4286 BRF_FUNC_CALL_BREAK(updateStatus(&e));
4287 // Set tx I/Q balance
4288 if (!m_txGainCorrSoftware) {
4289 const String& txPB = params["tx_powerbalance"];
4290 internalSetTxIQBalance(false,txPB.toDouble(1),"tx_powerbalance");
4291 }
4292 // Set some optional params
4293 setTxPattern(params["txpattern"]);
4294 showBuf(true,params.getIntValue("txbufoutput",0),
4295 params.getBoolValue("txbufoutput_nodata"));
4296 showBuf(false,params.getIntValue("rxbufoutput",0),
4297 params.getBoolValue("rxbufoutput_nodata"));
4298 m_silenceTimeMs = clampIntParam(params,"silence_time",5000,0,60000);
4299 m_rxTsPastIntervalMs = clampIntParam(params,"rx_ts_past_error_interval",200,50,10000);
4300 const String& sRateSamples = params[YSTRING("srate_buffered_samples")];
4301 if (sRateSamples) {
4302 const char* s = BrfBufsThreshold::init(m_bufThres,sRateSamples,m_radioCaps);
4303 if (s)
4304 Debug(m_owner,DebugConf,"Failed to parse srate_buffered_samples='%s': %s [%p]",
4305 sRateSamples.c_str(),s,m_owner);
4306 }
4307 break;
4308 }
4309 if (status) {
4310 Debug(m_owner,DebugWarn,"Failed to open USB device: %s [%p]",
4311 e.safe("Unknown error"),m_owner);
4312 doClose();
4313 error = e;
4314 return status;
4315 }
4316 String s;
4317 internalDumpDev(s,true,false,"\r\n",true);
4318 Debug(m_owner,DebugAll,"Opened device [%p]%s",m_owner,encloseDashes(s,true));
4319 txSerialize.drop();
4320 rxSerialize.drop();
4321 reLoad(¶ms);
4322 return status;
4323 }
4324
4325 // Initialize operating parameters
initialize(const NamedList & params)4326 unsigned int BrfLibUsbDevice::initialize(const NamedList& params)
4327 {
4328 BRF_RX_SERIALIZE;
4329 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"initialize()");
4330 if (m_initialized)
4331 return 0;
4332 String s;
4333 //params.dump(s,"\r\n");
4334 Debug(m_owner,DebugAll,"Initializing ... [%p]%s",m_owner,encloseDashes(s,true));
4335 String e;
4336 unsigned int status = 0;
4337 while (true) {
4338 // Check for radio operating params
4339 // FILTER, SAMPLERATE, BAND, TX/RX FREQ
4340 const String& bw = params["filter"];
4341 if (bw) {
4342 unsigned int tmp = bw.toInteger(1,0,1);
4343 BRF_FUNC_CALL_BREAK(internalSetLpfBandwidthBoth(tmp,&e));
4344 }
4345 const String& sr = params["samplerate"];
4346 if (sr) {
4347 unsigned int tmp = sr.toInteger(1,0,1);
4348 BRF_FUNC_CALL_BREAK(internalSetSampleRateBoth(tmp,&e));
4349 }
4350 for (int i = 0; i < 2; i++) {
4351 bool tx = (i == 0);
4352 const NamedString* ns = params.getParam(tx ? "txfrequency" : "rxfrequency");
4353 if (!ns)
4354 continue;
4355 BRF_FUNC_CALL_BREAK(internalSetFrequency(tx,ns->toInt64(),&e));
4356 }
4357 if (status)
4358 break;
4359 BRF_FUNC_CALL_BREAK(internalPowerOn(true,true,true,&e));
4360 break;
4361 }
4362 if (!status) {
4363 txSerialize.drop();
4364 rxSerialize.drop();
4365 m_initialized = true;
4366 if (params.getBoolValue(YSTRING("calibrate"))) {
4367 NamedList tmp("");
4368 tmp.copySubParams(params,"calibrate_");
4369 status = calibrate(tmp.getBoolValue(YSTRING("sync")),tmp,&e,true);
4370 }
4371 else {
4372 m_notifyOff = true;
4373 Message* m = buildNotify("start");
4374 BrfDevDirState& dir = getDirState(true);
4375 m->addParam("tx_frequency",String(dir.frequency));
4376 m->addParam("tx_samplerate",String(dir.sampleRate));
4377 m->addParam("tx_filter",String(dir.lpfBw));
4378 Engine::dispatch(*m);
4379 // Lock TX. Re-check our state. Apply params
4380 txSerialize.wait();
4381 if (!txSerialize.status) {
4382 status = checkPubFuncEntry(false,"initialize()");
4383 if (!status)
4384 status = applyStartParams(*m,&e);
4385 }
4386 else
4387 status = txSerialize.status;
4388 TelEngine::destruct(m);
4389 }
4390 if ((!status || status == RadioInterface::Pending) &&
4391 m_owner && m_owner->debugAt(DebugAll)) {
4392 String s;
4393 #ifdef DEBUG
4394 if (!status)
4395 internalDumpDev(s,false,true,"\r\n",true,true,true);
4396 #endif
4397 Debug(m_owner,DebugAll,"Initialized [%p]%s",m_owner,encloseDashes(s,true));
4398 }
4399 if (!status)
4400 return 0;
4401 }
4402 if (status != RadioInterface::Pending)
4403 Debug(m_owner,DebugCrit,"Failed to initialize: %s [%p]",
4404 e.safe("Unknown error"),m_owner);
4405 return status;
4406 }
4407
4408 // Check if parameters are set
isInitialized(bool checkTx,bool checkRx,String * error)4409 unsigned int BrfLibUsbDevice::isInitialized(bool checkTx, bool checkRx, String* error)
4410 {
4411 if (!m_initialized)
4412 return setErrorNotInit(error);
4413 for (int i = 0; i < 2; i++) {
4414 bool tx = (i == 0);
4415 if ((tx && !checkTx) || (!tx && !checkRx))
4416 continue;
4417 BrfDevDirState& s = getDirState(tx);
4418 if (!s.frequency)
4419 return setErrorNotInit(error,String(brfDir(tx)) + " frequency not set");
4420 if (!s.sampleRate)
4421 return setErrorNotInit(error,String(brfDir(tx)) + " sample rate not set");
4422 if (!s.lpfBw)
4423 return setErrorNotInit(error,String(brfDir(tx)) + " filter bandwidth not set");
4424 }
4425 return 0;
4426 }
4427
4428 // Close the device
close()4429 void BrfLibUsbDevice::close()
4430 {
4431 BRF_RX_SERIALIZE_NONE;
4432 BRF_TX_SERIALIZE_NONE;
4433 doClose();
4434 }
4435
4436 // Power on the radio
4437 // Enable timestamps, enable RF TX/RX
powerOn()4438 unsigned int BrfLibUsbDevice::powerOn()
4439 {
4440 BRF_RX_SERIALIZE;
4441 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"powerOn()");
4442 return internalPowerOn(true);
4443 }
4444
4445 // Send an array of samples waiting to be transmitted
syncTx(uint64_t ts,float * data,unsigned int samples,float * powerScale,bool internal)4446 unsigned int BrfLibUsbDevice::syncTx(uint64_t ts, float* data, unsigned int samples,
4447 float* powerScale, bool internal)
4448 {
4449 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(internal,"syncTx()");
4450 unsigned int status = send(ts,data,samples,powerScale);
4451 if (status == RadioInterface::HardwareIOError) {
4452 txSerialize.drop();
4453 Thread::yield();
4454 }
4455 return status;
4456 }
4457
4458 // Receive data from the Rx interface of the bladeRF device
syncRx(uint64_t & ts,float * data,unsigned int & samples,String * error,bool internal)4459 unsigned int BrfLibUsbDevice::syncRx(uint64_t& ts, float* data, unsigned int& samples,
4460 String* error, bool internal)
4461 {
4462 BRF_RX_SERIALIZE_CHECK_PUB_ENTRY(internal,"syncRx()");
4463 unsigned int status = recv(ts,data,samples,error);
4464 if (status == RadioInterface::HardwareIOError) {
4465 rxSerialize.drop();
4466 Thread::yield();
4467 }
4468 return status;
4469 }
4470
4471 // Capture RX data
capture(bool tx,float * buf,unsigned int samples,uint64_t & ts,String * error)4472 unsigned int BrfLibUsbDevice::capture(bool tx, float* buf, unsigned int samples,
4473 uint64_t& ts, String* error)
4474 {
4475 if (!(buf && samples))
4476 return 0;
4477 BrfDevIO& io = getIO(tx);
4478 Lock lck(io.captureMutex);
4479 if (io.captureBuf)
4480 return setErrorFail(error,"Duplicate capture");
4481 io.captureSamples = samples;
4482 io.captureTs = ts;
4483 io.captureOffset = 0;
4484 io.captureStatus = 0;
4485 io.captureError.clear();
4486 io.captureBuf = buf;
4487 lck.drop();
4488 unsigned int tout = ((samples + 999) / 1000) * 20;
4489 unsigned int status = 0;
4490 unsigned int intervals = threadIdleIntervals(tout);
4491 while (!status && io.captureBuf) {
4492 io.captureSemaphore.lock(Thread::idleUsec());
4493 status = cancelled(error);
4494 if (!status && ((intervals--) == 0))
4495 status = setErrorTimeout(error,"Capture timeout");
4496 }
4497 lck.acquire(io.captureMutex);
4498 if (!io.captureBuf) {
4499 ts = io.captureTs;
4500 if (io.captureStatus && error)
4501 *error = io.captureError;
4502 return io.captureStatus;
4503 }
4504 io.captureBuf = 0;
4505 return status;
4506 }
4507
setFrequency(uint64_t hz,bool tx)4508 unsigned int BrfLibUsbDevice::setFrequency(uint64_t hz, bool tx)
4509 {
4510 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"setFrequency()");
4511 return internalSetFrequency(tx,hz);
4512 }
4513
getFrequency(uint32_t & hz,bool tx)4514 unsigned int BrfLibUsbDevice::getFrequency(uint32_t& hz, bool tx)
4515 {
4516 BRF_TX_SERIALIZE_CHECK_DEV("getFrequency()");
4517 return internalGetFrequency(tx,&hz);
4518 }
4519
4520 // Set frequency offset
setFreqOffset(float offs,float * newVal,bool stopAutoCal)4521 unsigned int BrfLibUsbDevice::setFreqOffset(float offs, float* newVal, bool stopAutoCal)
4522 {
4523 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"setFreqOffset()");
4524 unsigned int status = internalSetFreqOffs(offs,newVal);
4525 txSerialize.drop();
4526 if (!status && stopAutoCal && getDirState(true).rfEnabled)
4527 disableDiscipline(true);
4528 return status;
4529 }
4530
4531 // Get frequency offset
getFreqOffset(float & offs)4532 unsigned int BrfLibUsbDevice::getFreqOffset(float& offs)
4533 {
4534 BRF_TX_SERIALIZE_CHECK_DEV("getFreqOffset()");
4535 String val;
4536 unsigned int status = getCalField(val,"DAC","DAC_TRIM");
4537 if (status == 0) {
4538 offs = val.toInteger() / 256.0;
4539 // TODO m_freqOffset = offs ???
4540 }
4541 return status;
4542 }
4543
4544 // Set the bandwidth for a specific module
setLpfBandwidth(uint32_t band,bool tx)4545 unsigned int BrfLibUsbDevice::setLpfBandwidth(uint32_t band, bool tx)
4546 {
4547 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"setLpfBandwidth()");
4548 return internalSetLpfBandwidth(tx,band);
4549 }
4550
4551 // Get the bandwidth for a specific module
getLpfBandwidth(uint32_t & band,bool tx)4552 unsigned int BrfLibUsbDevice::getLpfBandwidth(uint32_t& band, bool tx)
4553 {
4554 BRF_TX_SERIALIZE_CHECK_DEV("getLpfBandwidth()");
4555 String e;
4556 unsigned int status = lusbSetAltInterface(BRF_ALTSET_RF_LINK,&e);
4557 if (status == 0) {
4558 uint8_t data = 0;
4559 status = lmsRead(lmsLpfAddr(tx),data,&e);
4560 if (status == 0) {
4561 data >>= 2;
4562 data &= 0xf;
4563 band = index2bw(15 - data);
4564 getDirState(tx).lpfBw = band;
4565 }
4566 }
4567 if (status == 0)
4568 XDebug(m_owner,DebugAll,"Got %s LPF bandwidth %u [%p]",brfDir(tx),band,m_owner);
4569 else
4570 Debug(m_owner,DebugNote,"Failed to retrieve %s LPF bandwidth: %s [%p]",
4571 brfDir(tx),e.c_str(),m_owner);
4572 return status;
4573 }
4574
setLpf(int lpf,bool tx)4575 unsigned int BrfLibUsbDevice::setLpf(int lpf, bool tx)
4576 {
4577 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"setLpf()");
4578 return internalSetLpf(tx,lpf);
4579 }
4580
getLpf(int & lpf,bool tx)4581 unsigned int BrfLibUsbDevice::getLpf(int& lpf, bool tx)
4582 {
4583 BRF_TX_SERIALIZE_CHECK_DEV("getLpf()");
4584 return internalGetLpf(tx,&lpf);
4585 }
4586
4587 // Set the sample rate on a specific module
setSamplerate(uint32_t value,bool tx)4588 unsigned int BrfLibUsbDevice::setSamplerate(uint32_t value, bool tx)
4589 {
4590 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"setSamplerate()");
4591 return internalSetSampleRate(tx,value);
4592 }
4593
4594 // Get the sample rate on a specific module
getSamplerate(uint32_t & value,bool tx)4595 unsigned int BrfLibUsbDevice::getSamplerate(uint32_t& value, bool tx)
4596 {
4597 BRF_TX_SERIALIZE_CHECK_DEV("getSamplerate()");
4598 String e;
4599 unsigned int status = lusbSetAltInterface(BRF_ALTSET_RF_LINK,&e);
4600 while (!status) {
4601 BrfRationalRate rate;
4602 Si5338MultiSynth synth;
4603 uint8_t val = 0;
4604
4605 synth.index = 1;
4606 if (tx)
4607 synth.index = 2;
4608 synth.base = 53 + synth.index * 11;
4609 // Read the enable bits
4610 if ((status = getSi5338(36 + synth.index,val,&e)) != 0)
4611 break;
4612 synth.enable = val&7;
4613 // Read all of the multisynth registers
4614 for (int i = 0; i < 10; i++)
4615 if ((status = getSi5338(synth.base + i,synth.regs[i],&e)) != 0)
4616 break;
4617 if (status)
4618 break;
4619 // Populate the RxDIV value from the register
4620 if ((status = getSi5338(31 + synth.index,val,&e)) != 0)
4621 break;
4622 // RxDIV is stored as a power of 2, so restore it on readback
4623 val = (val>>2)&7;
4624 synth.r = (1<<val);
4625 // Unpack the regs into appropriate values
4626 unpackRegs(synth);
4627 calcSrate(synth,rate);
4628 if (rate.integer > 0xffffffff) {
4629 e = "The value for the sample rate is too big";
4630 status = RadioInterface::Failure;
4631 break;
4632 }
4633 if (rate.numerator)
4634 Debug(m_owner,DebugMild,
4635 "Truncating the %s fractional part of the samplerate [%p]",
4636 brfDir(tx),m_owner);
4637 value = (uint32_t)rate.integer;
4638 getDirState(tx).sampleRate = value;
4639 break;
4640 }
4641 if (status == 0)
4642 XDebug(m_owner,DebugAll,"Got %s samplerate %u [%p]",brfDir(tx),value,m_owner);
4643 else
4644 Debug(m_owner,DebugNote,"Failed to get %s samplerate: %s [%p]",
4645 brfDir(tx),e.c_str(),m_owner);
4646 return status;
4647 }
4648
4649 // Set the pre-mixer gain on transmission (interval [-35..-4])
4650 // Set the post-mixer gain setting on transmission (interval: [0..25])
setTxVga(int vga,bool preMixer)4651 unsigned int BrfLibUsbDevice::setTxVga(int vga, bool preMixer)
4652 {
4653 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"setTxVga()");
4654 return internalSetTxVga(vga,preMixer);
4655 }
4656
4657 // Retrieve the pre/post mixer gain setting on transmission
getTxVga(int & vga,bool preMixer)4658 unsigned int BrfLibUsbDevice::getTxVga(int& vga, bool preMixer)
4659 {
4660 BRF_TX_SERIALIZE_CHECK_DEV("getTxVga()");
4661 return internalGetTxVga(&vga,preMixer);
4662 }
4663
4664 // Set TX gain expansion
setGainExp(float breakpoint,float max)4665 unsigned int BrfLibUsbDevice::setGainExp(float breakpoint, float max)
4666 {
4667 m_gainExpBreak = pow(10,breakpoint*0.1);
4668 // the base slope is 1, so max gain of 1 is a slope of zero
4669 // we correct for the by subtracting 1 from the max
4670 // we will add it back after we compute the expansion factor
4671 m_gainExpSlope = (max-1) / (2-breakpoint);
4672 calculateAmpTable();
4673 return 0;
4674 }
4675
4676 // Set TX phase expansion
setPhaseExp(float breakpoint,float max)4677 unsigned int BrfLibUsbDevice::setPhaseExp(float breakpoint, float max)
4678 {
4679 m_phaseExpBreak = pow(10,breakpoint*0.1);
4680 // convert max to radians
4681 max = max * M_PI / 180.0;
4682 m_phaseExpSlope = max / (2-breakpoint);
4683 calculateAmpTable();
4684 return 0;
4685 }
4686
setTxIQBalance(float value)4687 unsigned int BrfLibUsbDevice::setTxIQBalance(float value)
4688 {
4689 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"setTxIQBalance()");
4690 return internalSetTxIQBalance(false,value);
4691 }
4692
4693 // Enable or disable the pre/post mixer gain on the receive side
enableRxVga(bool on,bool preMixer)4694 unsigned int BrfLibUsbDevice::enableRxVga(bool on, bool preMixer)
4695 {
4696 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"enableRxVga()");
4697 return internalEnableRxVga(on,preMixer);
4698 }
4699
4700 // Set the pre-mixer gain setting on the receive side (interval [5..30])
4701 // Set the post-mixer Rx gain setting (interval [0..30])
setRxVga(int vga,bool preMixer)4702 unsigned int BrfLibUsbDevice::setRxVga(int vga, bool preMixer)
4703 {
4704 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"setRxVga()");
4705 return internalSetRxVga(vga,preMixer);
4706 }
4707
4708 // Retrieve the pre/post mixer rx gain setting
getRxVga(int & vga,bool preMixer)4709 unsigned int BrfLibUsbDevice::getRxVga(int& vga, bool preMixer)
4710 {
4711 BRF_TX_SERIALIZE_CHECK_DEV("getRxVga()");
4712 return internalGetRxVga(&vga,preMixer);
4713 }
4714
4715 // Set pre and post mixer value
setGain(bool tx,int val,int * newVal)4716 unsigned int BrfLibUsbDevice::setGain(bool tx, int val, int* newVal)
4717 {
4718 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"setGain()");
4719 return internalSetGain(tx,val,newVal);
4720 }
4721
4722 // Run check / calibration procedure
calibrate(bool sync,const NamedList & params,String * error,bool fromInit)4723 unsigned int BrfLibUsbDevice::calibrate(bool sync, const NamedList& params,
4724 String* error, bool fromInit)
4725 {
4726 BRF_RX_SERIALIZE;
4727 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"calibrate()");
4728 #ifdef DEBUG
4729 Debugger d(DebugAll,"CALIBRATE"," %s sync=%s [%p]",
4730 m_owner->debugName(),String::boolText(sync),m_owner);
4731 #endif
4732 int rxDcAutoRestore = -1;
4733 String e;
4734 unsigned int status = 0;
4735 if (!m_initialized)
4736 status = setError(RadioInterface::NotInitialized,&e,"not initialized");
4737 BrfDuration duration;
4738 // force the VCTCXO discipliner to drop it's data
4739 if (sync)
4740 postponeActivity(1,true);
4741 while (!status) {
4742 if (!sync) {
4743 if (m_owner && fromInit)
4744 m_owner->setPending(RadioInterface::PendingInitialize);
4745 BRF_FUNC_CALL_BREAK(startCalibrateThreads(&e,params));
4746 status = RadioInterface::Pending;
4747 break;
4748 }
4749 BrfDevTmpAltSet tmpAltSet(this,status,&e,"Calibrate");
4750 if (status)
4751 break;
4752 rxDcAutoRestore = setRxDcAuto(false) ? 1 : 0;
4753 m_calibrateStatus = Calibrating;
4754 Debug(m_owner,DebugInfo,"Calibrating ... [%p]",m_owner);
4755 // Drop lock. We are going to use public functions to calibrate
4756 txSerialize.drop();
4757 rxSerialize.drop();
4758 // LMS autocalibration
4759 if (params.getBoolValue("device_autocal",true))
4760 BRF_FUNC_CALL_BREAK(calibrateAuto(&e));
4761 // Check
4762 if (params.getBoolValue("loopback_check",true))
4763 BRF_FUNC_CALL_BREAK(loopbackCheck(&e));
4764 // Baseband calibration
4765 BRF_FUNC_CALL_BREAK(calibrateBaseband(&e));
4766 break;
4767 }
4768 duration.stop();
4769 if (rxDcAutoRestore > 0)
4770 setRxDcAuto(true);
4771 // Avoid hard cancelling if we are in calibration thread
4772 if (m_calThread && m_calThread == Thread::current())
4773 m_calThread = 0;
4774 if (sync) {
4775 stopThreads();
4776 if (m_owner && fromInit)
4777 m_owner->setPending(RadioInterface::PendingInitialize,status);
4778 // Calibration done
4779 m_calibrateStatus = status ? Calibrate : Calibrated;
4780 // Notify
4781 Message* m = buildNotify("calibrated");
4782 if (!status)
4783 m->copyParams(m_calibration);
4784 else
4785 m_owner->setError(*m,status,e);
4786 Engine::enqueue(m);
4787 if (!status) {
4788 Debug(m_owner,DebugInfo,"Calibration finished in %s [%p]",
4789 duration.secStr(),m_owner);
4790 return 0;
4791 }
4792 }
4793 else if (RadioInterface::Pending == status) {
4794 Debug(m_owner,DebugAll,"Async calibration started [%p]",m_owner);
4795 return status;
4796 }
4797 return showError(status,e.c_str(),"Calibration failed",error,DebugWarn);
4798 }
4799
4800 // Set Tx/Rx DC I/Q offset correction
setDcOffset(bool tx,bool i,int16_t value)4801 unsigned int BrfLibUsbDevice::setDcOffset(bool tx, bool i, int16_t value)
4802 {
4803 int rxDcAutoRestore = -1;
4804 if (!tx) {
4805 // Temporary disable RX auto correct
4806 BRF_RX_SERIALIZE_CHECK_PUB_ENTRY(false,"setDcOffset()");
4807 rxDcAutoRestore = setRxDcAuto(false) ? 1 : 0;
4808 }
4809 BrfSerialize txSerialize(this,true,true);
4810 if (!txSerialize.status)
4811 txSerialize.status = checkPubFuncEntry(false,"setDcOffset()");
4812 if (txSerialize.status) {
4813 if (rxDcAutoRestore > 0)
4814 m_state.m_rxDcAuto = true;
4815 return txSerialize.status;
4816 }
4817 unsigned int status = internalSetDcOffset(tx,i,value);
4818 if (tx)
4819 return status;
4820 if (status == 0) {
4821 // Don't restore old RX DC autocorrect: the values are set by the upper layer
4822 if (rxDcAutoRestore > 0)
4823 Debug(m_owner,DebugInfo,
4824 "Disabled RX DC autocorrect: I/Q values set by the upper layer [%p]",this);
4825 }
4826 else if (rxDcAutoRestore > 0)
4827 // Failure: restore old RX DC autocorrect
4828 m_state.m_rxDcAuto = true;
4829 return status;
4830 }
4831
4832 // Retrieve Tx/Rx DC I/Q offset correction
getDcOffset(bool tx,bool i,int16_t & value)4833 unsigned int BrfLibUsbDevice::getDcOffset(bool tx, bool i, int16_t& value)
4834 {
4835 BRF_TX_SERIALIZE_CHECK_DEV("getDcOffset()");
4836 return internalGetDcOffset(tx,i,&value);
4837 }
4838
setFpgaCorr(bool tx,int corr,int16_t value)4839 unsigned int BrfLibUsbDevice::setFpgaCorr(bool tx, int corr, int16_t value)
4840 {
4841 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"setFpgaCorr()");
4842 return internalSetFpgaCorr(tx,corr,value);
4843 }
4844
getFpgaCorr(bool tx,int corr,int16_t & value)4845 unsigned int BrfLibUsbDevice::getFpgaCorr(bool tx, int corr, int16_t& value)
4846 {
4847 BRF_TX_SERIALIZE_CHECK_DEV("getFpgaCorr()");
4848 int16_t v = 0;
4849 unsigned int status = internalGetFpgaCorr(tx,corr,&v);
4850 value = v;
4851 return status;
4852 }
4853
getTimestamp(bool tx,uint64_t & ts)4854 unsigned int BrfLibUsbDevice::getTimestamp(bool tx, uint64_t& ts)
4855 {
4856 BRF_TX_SERIALIZE_CHECK_DEV("getTimestamp()");
4857 return internalGetTimestamp(tx,ts);
4858 }
4859
samplesAndTimestamp(uint64_t & samples,uint64_t & timestamp,uint16_t & delay,String * serializeErr)4860 unsigned int BrfLibUsbDevice::samplesAndTimestamp(uint64_t& samples, uint64_t& timestamp,
4861 uint16_t& delay, String* serializeErr)
4862 {
4863 BrfSerialize txSerialize(this,true,false);
4864 txSerialize.wait(serializeErr,12000);
4865 if (!txSerialize.status)
4866 txSerialize.status = checkDev("samplesAndTimestamp()");
4867 if (!txSerialize.status) {
4868 uint64_t initial = Time::now();
4869 txSerialize.status = internalGetTimestamp(true,samples);
4870 timestamp = Time::now();
4871 if (!txSerialize.status && timestamp > initial) {
4872 delay = timestamp - initial;
4873 timestamp = (timestamp + initial) / 2;
4874 return 0;
4875 }
4876 }
4877 samples = 0;
4878 return txSerialize.status;
4879 }
4880
writeLMS(uint8_t addr,uint8_t value,uint8_t * rst,String * error,bool internal)4881 unsigned int BrfLibUsbDevice::writeLMS(uint8_t addr, uint8_t value, uint8_t* rst,
4882 String* error, bool internal)
4883 {
4884 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(internal,"writeLMS()");
4885 if (rst)
4886 return lmsSet(addr,value,*rst,error);
4887 return lmsWrite(addr,value,error);
4888 }
4889
writeLMS(const String & str,String * error,bool internal)4890 unsigned int BrfLibUsbDevice::writeLMS(const String& str, String* error, bool internal)
4891 {
4892 if (!str)
4893 return 0;
4894 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(internal,"writeLMS()");
4895 return lmsWrite(str,!internal,error);
4896 }
4897
4898 // Read LMS register(s)
readLMS(uint8_t addr,uint8_t & value,String * error,bool internal)4899 unsigned int BrfLibUsbDevice::readLMS(uint8_t addr, uint8_t& value, String* error,
4900 bool internal)
4901 {
4902 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(internal,"readLMS()");
4903 return lmsRead(addr & 0x7f,value,error);
4904 }
4905
readLMS(String & dest,const String * read,bool readIsInterleaved,String * error,bool internal)4906 unsigned int BrfLibUsbDevice::readLMS(String& dest, const String* read,
4907 bool readIsInterleaved, String* error, bool internal)
4908 {
4909 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(internal,"readLMS()");
4910 return lmsRead(dest,read,readIsInterleaved,error);
4911 }
4912
4913 // Check LMS registers
checkLMS(const String & what,String * error,bool internal)4914 unsigned int BrfLibUsbDevice::checkLMS(const String& what, String* error, bool internal)
4915 {
4916 if (!what)
4917 return 0;
4918 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(internal,"checkLMS()");
4919 return lmsCheck(what,error);
4920 }
4921
setLoopback(const char * name,const NamedList & params)4922 unsigned int BrfLibUsbDevice::setLoopback(const char* name, const NamedList& params)
4923 {
4924 int mode = LoopNone;
4925 if (!TelEngine::null(name))
4926 mode = lookup(name,s_loopback,LoopUnknown);
4927 if (mode == LoopUnknown) {
4928 Debug(m_owner,DebugNote,"Unknown loopback mode '%s' [%p]",name,m_owner);
4929 return RadioInterface::OutOfRange;
4930 }
4931 BRF_TX_SERIALIZE_CHECK_PUB_ENTRY(false,"setLoopback()");
4932 return internalSetLoopback(mode,params);
4933 }
4934
4935 // Set parameter(s)
setParam(const String & param,const String & value,const NamedList & params)4936 unsigned int BrfLibUsbDevice::setParam(const String& param, const String& value,
4937 const NamedList& params)
4938 {
4939 if (!param)
4940 return 0;
4941 if (param == YSTRING("calibrate_bb_dc_dump")) {
4942 Lock lck(m_dbgMutex);
4943 m_bbCalDcFile = value;
4944 }
4945 else if (param == YSTRING("calibrate_bb_imbalance_dump")) {
4946 Lock lck(m_dbgMutex);
4947 m_bbCalImbalanceFile = value;
4948 }
4949 else if (param == YSTRING("device_check_dump")) {
4950 Lock lck(m_dbgMutex);
4951 m_devCheckFile = value;
4952 }
4953 else {
4954 Debug(m_owner,DebugNote,"Unknown device param '%s' [%p]",param.c_str(),m_owner);
4955 return RadioInterface::NotSupported;
4956 }
4957 Debug(m_owner,DebugAll,"Handled param set '%s'='%s' [%p]",
4958 param.c_str(),value.c_str(),m_owner);
4959 return 0;
4960 }
4961
ts2buffers(uint64_t ts,unsigned int len)4962 static inline unsigned int ts2buffers(uint64_t ts, unsigned int len)
4963 {
4964 return (unsigned int)((ts + len - 1) / len);
4965 }
4966
4967 // Utility: run device send data
runSend(BrfThread * th)4968 void BrfLibUsbDevice::runSend(BrfThread* th)
4969 {
4970 if (!th)
4971 return;
4972 unsigned int samples = 0;
4973 unsigned int rxLatency = 0;
4974 unsigned int txBuffers = 0;
4975 ComplexVector buf;
4976 bool wait = true;
4977 uint64_t rxTs = 0;
4978 uint64_t ts = 0;
4979 unsigned int status = getTimestamp(true,ts);
4980 uint64_t silence = ts + 200000;
4981 bool paused = true;
4982 while (!status && (0 == cancelled())) {
4983 if (th->paused(true,ts,status) || status) {
4984 if (!status)
4985 Thread::idle();
4986 silence = ts + 200000;
4987 wait = true;
4988 setIoDontWarnTs(true);
4989 paused = true;
4990 continue;
4991 }
4992 else if (paused) {
4993 paused = false;
4994 samples = totalSamples(true);
4995 if (!samples)
4996 break;
4997 if (samples != buf.length()) {
4998 rxLatency = (m_radioCaps.rxLatency + samples - 1) / samples;
4999 txBuffers = (m_radioCaps.txLatency + samples - 1) / samples;
5000 buf.resetStorage(samples);
5001 }
5002 }
5003 // Wait for RX
5004 if (wait) {
5005 while (!status && !m_internalIoSemaphore.lock(Thread::idleUsec()))
5006 status = cancelled();
5007 if (status)
5008 break;
5009 if (th->isPaused()) {
5010 m_internalIoSemaphore.unlock();
5011 continue;
5012 }
5013 Lock lck(m_threadMutex);
5014 rxTs = m_internalIoTimestamp;
5015 }
5016 else
5017 wait = true;
5018 uint64_t crtRxTs = rxTs + rxLatency;
5019 unsigned int sendCount = txBuffers;
5020 if (ts >= crtRxTs) {
5021 // TX time is at least RX time. Start sending from it
5022 unsigned int diff = ts2buffers(ts - crtRxTs,samples);
5023 if (sendCount > diff)
5024 sendCount -= diff;
5025 else
5026 sendCount = 0;
5027 }
5028 else {
5029 // Underrun. Start sending from RX time
5030 if (crtRxTs > silence) {
5031 unsigned int u = ts2buffers(crtRxTs - ts,samples);
5032 if (u > 1)
5033 Debug(m_owner,u > 5 ? DebugNote : DebugAll,
5034 "Internal transmit underrun by %u buffer(s) [%p]",u,m_owner);
5035 else
5036 DDebug(m_owner,DebugAll,
5037 "Internal transmit underrun by %u buffer(s) [%p]",u,m_owner);
5038 }
5039 ts = crtRxTs;
5040 }
5041 while (!status && sendCount--) {
5042 status = syncTx(ts,(float*)buf.data(),buf.length(),0,true);
5043 ts += buf.length();
5044 }
5045 if (status)
5046 break;
5047 // Look again at RX time
5048 Lock lck(m_threadMutex);
5049 if (m_internalIoTimestamp < crtRxTs) {
5050 wait = false;
5051 rxTs = crtRxTs;
5052 }
5053 }
5054 }
5055
5056 // Utility: run device send data
runRecv(BrfThread * th)5057 void BrfLibUsbDevice::runRecv(BrfThread* th)
5058 {
5059 if (!th)
5060 return;
5061 ComplexVector buf(totalSamples(false));
5062 uint64_t ts = 0;
5063 unsigned int status = getTimestamp(false,ts);
5064 unsigned int txRate = 0;
5065 unsigned int rxRate = 0;
5066 m_internalIoRateChanged = true;
5067 bool paused = true;
5068 while (!status && (0 == cancelled())) {
5069 if (th->paused(false,ts,status) || status) {
5070 if (!status) {
5071 m_internalIoSemaphore.unlock();
5072 Thread::idle();
5073 setIoDontWarnTs(false);
5074 }
5075 paused = true;
5076 continue;
5077 }
5078 else if (paused) {
5079 paused = false;
5080 if (totalSamples(false) != buf.length())
5081 buf.resetStorage(totalSamples(false));
5082 }
5083 // Simulate some processing to avoid keeping the RX mutex locked
5084 generateExpTone(buf,0);
5085 buf.bzero();
5086 unsigned int len = buf.length();
5087 BRF_FUNC_CALL_BREAK(syncRx(ts,(float*)buf.data(),len,0,true));
5088 ts += len;
5089 m_threadMutex.lock();
5090 if (m_internalIoRateChanged) {
5091 txRate = m_internalIoTxRate;
5092 rxRate = m_internalIoRxRate;
5093 m_internalIoRateChanged = false;
5094 }
5095 if (txRate != rxRate && txRate && rxRate)
5096 m_internalIoTimestamp = (ts * txRate) / rxRate;
5097 else
5098 m_internalIoTimestamp = ts;
5099 m_threadMutex.unlock();
5100 m_internalIoSemaphore.unlock();
5101 }
5102 m_internalIoSemaphore.unlock();
5103 }
5104
5105 // Build notification message
buildNotify(const char * status)5106 Message* BrfLibUsbDevice::buildNotify(const char* status)
5107 {
5108 Message* m = new Message("module.update",0,true);
5109 m->addParam("module",__plugin.name());
5110 m_owner->completeDevInfo(*m,true);
5111 m->addParam("status",status,false);
5112 return m;
5113 }
5114
5115 // Release data
destruct()5116 void BrfLibUsbDevice::destruct()
5117 {
5118 doClose();
5119 for (unsigned int i = 0; i < EpCount; i++)
5120 m_usbTransfer[i].reset();
5121 GenObject::destruct();
5122 }
5123
reduceFurther(uint64_t v1,uint64_t v2)5124 uint64_t BrfLibUsbDevice::reduceFurther(uint64_t v1, uint64_t v2)
5125 {
5126 if (!(v1 && v2))
5127 return 1;
5128 while (v2) {
5129 uint64_t tmp = v1 % v2;
5130 v1 = v2;
5131 v2 = tmp;
5132 }
5133 return v1;
5134 }
5135
reduceRational(BrfRationalRate & rate)5136 void BrfLibUsbDevice::reduceRational(BrfRationalRate& rate)
5137 {
5138 while (rate.denominator > 0 && rate.numerator >= rate.denominator) {
5139 rate.numerator = rate.numerator - rate.denominator;
5140 rate.integer++;
5141 }
5142 // Reduce what's left of the fraction
5143 uint64_t val = reduceFurther(rate.numerator,rate.denominator);
5144 if (val) {
5145 rate.numerator /= val;
5146 rate.denominator /= val;
5147 }
5148 }
5149
calcSrate(Si5338MultiSynth & synth,BrfRationalRate & rate)5150 void BrfLibUsbDevice::calcSrate(Si5338MultiSynth& synth, BrfRationalRate& rate)
5151 {
5152 BrfRationalRate tmp;
5153 tmp.integer = synth.a;
5154 tmp.numerator = synth.b;
5155 tmp.denominator = synth.c;
5156 rate.integer = 0;
5157 rate.numerator = SI5338_F_VCO * tmp.denominator;
5158 rate.denominator = (uint64_t)synth.r * 2 *
5159 (tmp.integer * tmp.denominator + tmp.numerator);
5160 reduceRational(rate);
5161 }
5162
calcMultiSynth(Si5338MultiSynth & synth,BrfRationalRate & rate,String * error)5163 unsigned int BrfLibUsbDevice::calcMultiSynth(Si5338MultiSynth& synth,
5164 BrfRationalRate& rate, String* error)
5165 {
5166 BrfRationalRate tmp;
5167
5168 // Double requested frequency since LMS requires 2:1 clock:sample rate
5169 rationalDouble(rate);
5170 // Find a suitable R value
5171 uint8_t rValue = 1;
5172 uint8_t rPower = 0;
5173 while (rate.integer < 5000000 && rValue < 32) {
5174 rationalDouble(rate);
5175 rValue <<= 1;
5176 rPower++;
5177 }
5178 if (rValue == 32 && rate.integer < 5000000)
5179 return setError(RadioInterface::Failure,error,"Multi synth calculation failed");
5180 // Find suitable MS (a, b, c) values
5181 tmp.integer = 0;
5182 tmp.numerator= SI5338_F_VCO * rate.denominator;
5183 tmp.denominator= rate.integer * rate.denominator + rate.numerator;
5184 reduceRational(tmp);
5185 // Check values to make sure they are OK
5186 if (tmp.integer < 8 || tmp.integer > 567)
5187 return setError(RadioInterface::Failure,error,
5188 "Multi synth calculation - the integer part is out of bounds");
5189 // Loss of precision if numeratoror denominatorare greater than 2^30-1
5190 bool warn = true;
5191 while (tmp.numerator > (1 << 30) || tmp.denominator > (1 << 30)) {
5192 if (warn) {
5193 warn = false;
5194 Debug(&__plugin,DebugMild,
5195 "Multi synth calculation: numerator or denominator are too big, we'll loose precision");
5196 }
5197 tmp.numerator >>= 1;
5198 tmp.denominator >>= 1;
5199 }
5200 if (tmp.integer > 0xffffffff || tmp.numerator > 0xffffffff ||
5201 tmp.denominator > 0xffffffff)
5202 return setError(RadioInterface::Failure,error,
5203 "Multi synth calculation - rate parts are too big");
5204 synth.a = (uint32_t)tmp.integer;
5205 synth.b = (uint32_t)tmp.numerator;
5206 synth.c = (uint32_t)tmp.denominator;
5207 synth.r = rValue;
5208 // Pack the registers
5209 packRegs(synth);
5210 return 0;
5211 }
5212
packRegs(Si5338MultiSynth & synth)5213 void BrfLibUsbDevice::packRegs(Si5338MultiSynth& synth)
5214 {
5215 uint64_t tmp = (uint64_t)synth.a * synth.c + synth.b;
5216 tmp = tmp * 128 ;
5217 tmp = tmp / synth.c - 512;
5218 synth.p1 = (uint32_t)tmp;
5219 tmp = (uint64_t)synth.b * 128;
5220 tmp = tmp % synth.c;
5221 synth.p2 = (uint32_t)tmp;
5222 synth.p3 = synth.c;
5223 // Set regs
5224 synth.regs[0] = (uint8_t)synth.p1;
5225 synth.regs[1] = (uint8_t)(synth.p1 >> 8);
5226 synth.regs[2] = (uint8_t)((synth.p2 & 0x3f) << 2) | ((synth.p1 >> 16) & 0x3);
5227 synth.regs[3] = (uint8_t)(synth.p2 >> 6);
5228 synth.regs[4] = (uint8_t)(synth.p2 >> 14);
5229 synth.regs[5] = (uint8_t)(synth.p2 >> 22);
5230 synth.regs[6] = (uint8_t)synth.p3;
5231 synth.regs[7] = (uint8_t)(synth.p3 >> 8);
5232 synth.regs[8] = (uint8_t)(synth.p3 >> 16);
5233 synth.regs[9] = (uint8_t)(synth.p3 >> 24);
5234 }
5235
unpackRegs(Si5338MultiSynth & synth)5236 void BrfLibUsbDevice::unpackRegs(Si5338MultiSynth& synth)
5237 {
5238 // Populate
5239 synth.p1 = ((synth.regs[2] & 3) << 16) | (synth.regs[1] << 8) | (synth.regs[0]);
5240 synth.p2 = (synth.regs[5] << 22) | (synth.regs[4] << 14) |
5241 (synth.regs[3] << 6) | ((synth.regs[2] >> 2) & 0x3f);
5242 synth.p3 = ((synth.regs[9] & 0x3f) << 24) | (synth.regs[8] << 16) |
5243 (synth.regs[7] << 8) | (synth.regs[6]);
5244 // c = p3
5245 synth.c = synth.p3;
5246 // a = (p1+512)/128
5247 // NOTE: The +64 is for rounding purposes.
5248 synth.a = (synth.p1 + 512) / 128;
5249 // b = (((p1+512)-128*a)*c + (b % c) + 64)/128
5250 uint64_t tmp = (synth.p1 + 512) - 128 * (uint64_t)synth.a;
5251 tmp = (tmp * synth.c) + synth.p2;
5252 tmp = (tmp + 64) / 128;
5253 synth.b = (uint32_t)tmp;
5254 }
5255
lusb2ifaceError(int code)5256 unsigned int BrfLibUsbDevice::lusb2ifaceError(int code)
5257 {
5258 switch (code) {
5259 case LIBUSB_ERROR_ACCESS: // Access denied (insufficient permissions)
5260 case LIBUSB_TRANSFER_ERROR: // Transfer failed
5261 case LIBUSB_ERROR_BUSY: // Resource busy
5262 case LIBUSB_ERROR_INVALID_PARAM: // Invalid parameter
5263 case LIBUSB_ERROR_NO_MEM: // Insufficient memory
5264 case LIBUSB_ERROR_OTHER: // Unknown error
5265 return RadioInterface::Failure;
5266 case LIBUSB_ERROR_TIMEOUT: // Operation timed out
5267 case LIBUSB_TRANSFER_TIMED_OUT: // Transfer timed out
5268 return RadioInterface::Timeout;
5269 case LIBUSB_ERROR_INTERRUPTED: // System call interrupted (perhaps due to signal)
5270 case LIBUSB_TRANSFER_CANCELLED: // Transfer was cancelled
5271 return RadioInterface::Cancelled;
5272 case LIBUSB_TRANSFER_STALL: // For bulk/interrupt endpoints: halt condition detected (endpoint stalled)
5273 // For control endpoints: control request not supported
5274 return RadioInterface::HardwareIOError;
5275 case LIBUSB_ERROR_NOT_FOUND: // Entity not found
5276 case LIBUSB_ERROR_NO_DEVICE: // No such device (it may have been disconnected)
5277 case LIBUSB_TRANSFER_NO_DEVICE: // Device was disconnected
5278 return RadioInterface::HardwareNotAvailable;
5279 case LIBUSB_ERROR_IO: // Input/output error
5280 case LIBUSB_ERROR_PIPE: // Pipe error
5281 return RadioInterface::HardwareIOError;
5282 case LIBUSB_ERROR_OVERFLOW: // Overflow
5283 case LIBUSB_TRANSFER_OVERFLOW: // Device sent more data than requested
5284 return RadioInterface::Failure;
5285 case LIBUSB_ERROR_NOT_SUPPORTED: // Operation not supported or unimplemented on this platform
5286 return RadioInterface::NotSupported;
5287 case LIBUSB_SUCCESS: // Success (no error)
5288 return RadioInterface::NoError;
5289 #if LIBUSB_TRANSFER_COMPLETED != LIBUSB_SUCCESS
5290 case LIBUSB_TRANSFER_COMPLETED: // Transfer completed without error
5291 // Note that this does not indicate that the entire amount of
5292 // requested data was transferred.
5293 return RadioInterface::NoError;
5294 #endif
5295 }
5296 return RadioInterface::Failure;
5297 }
5298
doClose()5299 void BrfLibUsbDevice::doClose()
5300 {
5301 //Debugger d(DebugNote,"doClose "," %s [%p]",m_owner->debugName(),m_owner);
5302 m_closing = true;
5303 closeDevice();
5304 clearDeviceList();
5305 m_closing = false;
5306 }
5307
setState(BrfDevState & state,String * error)5308 unsigned int BrfLibUsbDevice::setState(BrfDevState& state, String* error)
5309 {
5310 #define BRF_SET_STATE_COND(cond,flags,flag,func) { \
5311 if ((cond) && ((flags & flag) != 0)) { \
5312 unsigned int tmp = func; \
5313 if (tmp) { \
5314 if (fatal) \
5315 return tmp; \
5316 if (!status) { \
5317 error = 0; \
5318 status = tmp; \
5319 } \
5320 } \
5321 } \
5322 flags &= ~flag; \
5323 if (!flags) \
5324 continue;\
5325 }
5326 #define BRF_SET_STATE(flags,flag,func) BRF_SET_STATE_COND(true,flags,flag,func)
5327 #define BRF_SET_STATE_NOERROR(flags,flag,func) { \
5328 if ((flags & flag) != 0) { \
5329 func; \
5330 flags &= ~flag; \
5331 } \
5332 if (!flags) \
5333 continue;\
5334 }
5335 unsigned int status = 0;
5336 BRF_FUNC_CALL_RET(cancelled(error));
5337 XDebug(m_owner,DebugAll,"Set state 0x%x / 0x%x / 0x%x [%p]",
5338 state.m_changed,state.m_txChanged,state.m_rxChanged,m_owner);
5339 bool fatal = (state.m_changed & DevStatAbortOnFail) != 0;
5340 state.m_changed &= ~DevStatAbortOnFail;
5341 // Direction related
5342 for (int i = 0; i < 2; i++) {
5343 bool tx = (i == 0);
5344 unsigned int& f = tx ? state.m_txChanged : state.m_rxChanged;
5345 if (!f)
5346 continue;
5347 BrfDevDirState& s = tx ? state.m_tx : state.m_rx;
5348 BRF_SET_STATE(f,DevStatLpf,internalSetLpf(tx,s.lpf,error));
5349 BRF_SET_STATE_COND(s.lpfBw != 0,f,DevStatLpfBw,
5350 internalSetLpfBandwidth(tx,s.lpfBw,error));
5351 BRF_SET_STATE_COND(s.sampleRate != 0,f,DevStatSampleRate,
5352 internalSetSampleRate(tx,s.sampleRate,error));
5353 BRF_SET_STATE_COND(s.frequency != 0,f,DevStatFreq,
5354 internalSetFrequency(tx,s.frequency,error));
5355 BRF_SET_STATE(f,DevStatVga1,internalSetVga(tx,s.vga1,true,error));
5356 BRF_SET_STATE(f,DevStatVga2,internalSetVga(tx,s.vga2,false,error));
5357 BRF_SET_STATE(f,DevStatDcI,internalSetDcOffset(tx,true,s.dcOffsetI,error));
5358 BRF_SET_STATE(f,DevStatDcQ,internalSetDcOffset(tx,false,s.dcOffsetQ,error));
5359 BRF_SET_STATE(f,DevStatFpgaPhase,internalSetFpgaCorr(tx,CorrFpgaPhase,
5360 s.fpgaCorrPhase,error));
5361 BRF_SET_STATE(f,DevStatFpgaGain,internalSetFpgaCorr(tx,CorrFpgaGain,
5362 s.fpgaCorrGain,error));
5363 }
5364 // Common
5365 while (state.m_changed) {
5366 BRF_SET_STATE(state.m_changed,DevStatLoopback,
5367 internalSetLoopback(state.m_loopback,state.m_loopbackParams,error));
5368 BRF_SET_STATE_NOERROR(state.m_changed,DevStatRxDcAuto,
5369 setRxDcAuto(state.m_rxDcAuto));
5370 BRF_SET_STATE_NOERROR(state.m_changed,DevStatTxPattern,
5371 setTxPattern(state.m_txPattern,state.m_txPatternGain));
5372 break;
5373 }
5374 if (state.m_changed || state.m_txChanged || state.m_rxChanged)
5375 Debug(m_owner,DebugWarn,"Set state incomplete: 0x%x / 0x%x / 0x%x [%p]",
5376 state.m_changed,state.m_txChanged,state.m_rxChanged,m_owner);
5377 return status;
5378 #undef BRF_SET_STATE_COND
5379 #undef BRF_SET_STATE
5380 #undef BRF_SET_STATE_NOERROR
5381 }
5382
5383 // Request changes (synchronous TX). Wait for change
setStateSync(String * error)5384 unsigned int BrfLibUsbDevice::setStateSync(String* error)
5385 {
5386 if (m_syncTxStateSet)
5387 return setErrorFail(error,"Sync set state overlapping");
5388 m_syncTxStateCode = 0;
5389 m_syncTxStateSet = true;
5390 unsigned int intervals = threadIdleIntervals(m_syncTout);
5391 unsigned int status = 0;
5392 while (m_syncTxStateSet && !status) {
5393 m_syncSemaphore.lock(Thread::idleUsec());
5394 status = cancelled(error);
5395 if (!status && m_syncTxStateSet && (intervals--) == 0)
5396 status = setErrorTimeout(error,"Sync set state timeout");
5397 }
5398 m_syncTxStateSet = false;
5399 if (status)
5400 return status;
5401 if (!m_syncTxStateCode)
5402 return 0;
5403 return setError(m_syncTxStateCode,error,m_syncTxStateError);
5404 }
5405
internalDumpDev(String & buf,bool info,bool state,const char * sep,bool internal,bool fromStatus,bool withHdr)5406 void BrfLibUsbDevice::internalDumpDev(String& buf, bool info, bool state,
5407 const char* sep, bool internal, bool fromStatus, bool withHdr)
5408 {
5409 String tmp;
5410 if (state) {
5411 BrfDevDirState& tx = getDirState(true);
5412 BrfDevDirState& rx = getDirState(false);
5413 if (withHdr) {
5414 buf.append("RxVGA1=",sep) << rx.vga1;
5415 buf << sep << "RxVGA2=" << rx.vga2;
5416 buf << sep << "RxDCCorrI=" << rx.dcOffsetI;
5417 buf << sep << "RxDCCorrQ=" << rx.dcOffsetQ;
5418 buf << sep << "TxVGA1=" << tx.vga1;
5419 buf << sep << "TxVGA2=" << tx.vga2;
5420 buf << sep << dumpFloatG(tmp,(double)rx.frequency / 1000000,"RxFreq=","MHz");
5421 if (internal) {
5422 buf << sep << "TxDCCorrI=" << tx.dcOffsetI;
5423 buf << sep << "TxDCCorrQ=" << tx.dcOffsetQ;
5424 }
5425 buf << sep << dumpFloatG(tmp,(double)tx.frequency / 1000000,"TxFreq=","MHz");
5426 buf << sep << "FreqOffset=" << m_freqOffset;
5427 buf << sep << "RxSampRate=" << rx.sampleRate;
5428 buf << sep << "TxSampRate=" << tx.sampleRate;
5429 buf << sep << "RxLpfBw=" << rx.lpfBw;
5430 buf << sep << "TxLpfBw=" << tx.lpfBw;
5431 buf << sep << "RxRF=" << onStr(rx.rfEnabled);
5432 buf << sep << "TxRF=" << onStr(tx.rfEnabled);
5433 if (internal) {
5434 buf << sep << "RxLPF=" << lookup(rx.lpf,s_lpf);
5435 buf << sep << "TxLPF=" << lookup(tx.lpf,s_lpf);
5436 buf << sep << "TxCorrFpgaPhase=" << tx.fpgaCorrPhase;
5437 }
5438 }
5439 else {
5440 buf << "|" << rx.vga1;
5441 buf << "|" << rx.vga2;
5442 buf << "|" << rx.dcOffsetI;
5443 buf << "|" << rx.dcOffsetQ;
5444 buf << "|" << tx.vga1;
5445 buf << "|" << tx.vga2;
5446 buf << "|" << dumpFloatG(tmp,(double)rx.frequency / 1000000,0,"MHz");
5447 buf << "|" << dumpFloatG(tmp,(double)tx.frequency / 1000000,0,"MHz");
5448 buf << "|" << m_freqOffset;
5449 buf << "|" << rx.sampleRate;
5450 buf << "|" << tx.sampleRate;
5451 buf << "|" << rx.lpfBw;
5452 buf << "|" << tx.lpfBw;
5453 buf << "|" << onStr(rx.rfEnabled);
5454 buf << "|" << onStr(tx.rfEnabled);
5455 }
5456 }
5457 if (!info)
5458 return;
5459 if (withHdr) {
5460 buf.append("Address=",sep) << address();
5461 buf << sep << "Serial=" << serial();
5462 buf << sep << "Speed=" << speedStr();
5463 buf << sep << "Firmware=" << fwVerStr();
5464 buf << sep << "FPGA=" << fpgaVerStr();
5465 if (!fromStatus) {
5466 buf.append(fpgaFile()," - ");
5467 buf.append(fpgaMD5()," - MD5: ");
5468 }
5469 buf << sep << "LMS_Ver=" << lmsVersion();
5470 }
5471 else {
5472 if (buf)
5473 buf << "|";
5474 buf << address();
5475 buf << "|" << serial();
5476 buf << "|" << speedStr();
5477 buf << "|" << fwVerStr();
5478 buf << "|" << fpgaVerStr();
5479 buf << "|" << lmsVersion();
5480 }
5481 }
5482
internalPowerOn(bool rfLink,bool tx,bool rx,String * error)5483 unsigned int BrfLibUsbDevice::internalPowerOn(bool rfLink, bool tx, bool rx, String* error)
5484 {
5485 String e;
5486 unsigned int status = 0;
5487 BrfDevTmpAltSet tmpAltSet(this);
5488 if (rfLink)
5489 status = lusbSetAltInterface(BRF_ALTSET_RF_LINK,&e);
5490 else
5491 status = tmpAltSet.set(&e,"Power ON/OFF");
5492 bool warn = (tx != m_state.m_tx.rfEnabled) || (rx != m_state.m_rx.rfEnabled);
5493 while (status == 0) {
5494 if (tx || rx) {
5495 BRF_FUNC_CALL_BREAK(enableTimestamps(true,&e));
5496 if (m_calLms)
5497 BRF_FUNC_CALL_BREAK(calibrateAuto(&e));
5498 }
5499 BRF_FUNC_CALL_BREAK(enableRf(true,tx,false,&e));
5500 BRF_FUNC_CALL_BREAK(enableRf(false,rx,false,&e))
5501 if (tx || rx) {
5502 String extra;
5503 if (!(tx && rx))
5504 extra << ", " << brfDir(tx) << " only";
5505 Debug(m_owner,DebugNote,"Powered ON the radio%s [%p]",extra.safe(),m_owner);
5506 }
5507 else if (warn)
5508 Debug(m_owner,DebugNote,"Powered OFF the radio [%p]",m_owner);
5509 return 0;
5510 }
5511 if (!warn)
5512 return 0;
5513 e.printf(1024,"Power %s failed: %s",((tx || rx) ? "ON" :"OFF"),e.c_str());
5514 return showError(status,e,0,error);
5515 }
5516
5517 // Send an array of samples waiting to be transmitted
send(uint64_t ts,float * data,unsigned int samples,float * powerScale)5518 unsigned int BrfLibUsbDevice::send(uint64_t ts, float* data, unsigned int samples,
5519 float* powerScale)
5520 {
5521 #ifndef DEBUG_DEVICE_TX
5522 XDebug(m_owner,DebugAll,"send(" FMT64U ",%p,%u) [%p]",ts,data,samples,m_owner);
5523 #endif
5524 BrfDevIO& io = m_txIO;
5525 BrfDevDirState& dirState = m_state.m_tx;
5526 if (!io.startTime)
5527 io.startTime = Time::now();
5528 if (io.dataDumpParams || io.upDumpParams)
5529 updateIODump(io);
5530 if (!(data && samples))
5531 return 0;
5532 #ifdef DEBUG_DEVICE_TX
5533 Debugger debug(DebugInfo,"BrfLibUsbDevice::send()",
5534 " %s: ts=" FMT64U " (expected=" FMT64U ") samples=%u [%p]",
5535 m_owner->debugName(),ts,io.timestamp,samples,m_owner);
5536 #endif
5537 if (io.upDumpFile.valid() && !(checkDbgInt(io.upDump) &&
5538 io.upDumpFile.write(ts,data,samplesf2bytes(samples),owner())))
5539 io.upDumpFile.terminate(owner());
5540 // Check timestamp
5541 if (io.timestamp != ts) {
5542 if (m_calibrateStatus != Calibrating && io.timestamp &&
5543 m_owner->debugAt(DebugAll)) {
5544 String s;
5545 s << "(our=" << io.timestamp << " requested=" << ts << ")";
5546 if (io.crtBuf || io.crtBufSampOffs)
5547 s << ", dropping previous data " <<
5548 (io.crtBuf * io.bufSamples + io.crtBufSampOffs) << " samples";
5549 Debug(m_owner,DebugAll,"TX: timestamps don't match %s [%p]",s.c_str(),m_owner);
5550 }
5551 io.resetBufPos();
5552 io.timestamp = ts;
5553 }
5554 const long* ampTable = 0;
5555 if (m_ampTableUse)
5556 ampTable = m_ampTable;
5557 float scale = 0;
5558 float* scaleI = &m_wrPowerScaleI;
5559 float* scaleQ = &m_wrPowerScaleQ;
5560 int16_t* maxI = &m_wrMaxI;
5561 int16_t* maxQ = &m_wrMaxQ;
5562 if (m_txPowerBalanceChanged) {
5563 m_txPowerBalanceChanged = false;
5564 m_wrPowerScaleI = m_txPowerScaleI * s_sampleEnergize;
5565 m_wrPowerScaleQ = m_txPowerScaleQ * s_sampleEnergize;
5566 m_wrMaxI = sampleScale(m_txPowerScaleI,s_sampleEnergize);
5567 m_wrMaxQ = sampleScale(m_txPowerScaleQ,s_sampleEnergize);
5568 if (dirState.showPowerBalanceChange == 0)
5569 Debug(m_owner,DebugInfo,"TX using power scale I=%g Q=%g maxI=%d maxQ=%d [%p]",
5570 m_wrPowerScaleI,m_wrPowerScaleQ,m_wrMaxI,m_wrMaxQ,m_owner);
5571 }
5572 if (powerScale && m_wrPowerScaleI == s_sampleEnergize) {
5573 scale = *powerScale * s_sampleEnergize;
5574 scaleI = scaleQ = &scale;
5575 maxI = maxQ = &s_sampleEnergize;
5576 }
5577 if (m_txPatternChanged)
5578 sendTxPatternChanged();
5579 unsigned int clamped = 0;
5580 String e;
5581 unsigned int status = lusbSetAltInterface(BRF_ALTSET_RF_LINK,&e);
5582 unsigned int reqSend = samples;
5583 while (!status) {
5584 while (samples && io.crtBuf < io.buffers) {
5585 unsigned int avail = 0;
5586 int16_t* start = io.crtBufSamples(avail);
5587 if (avail > samples)
5588 avail = samples;
5589 // New buffer: set the timestamp
5590 if (!io.crtBufSampOffs)
5591 io.setBufTs(io.crtBuf,io.timestamp);
5592 samples -= avail;
5593 #ifdef DEBUG_DEVICE_TX
5594 Debugger loopDbg(DebugAll,"TX: processing buffer",
5595 " %u/%u ts=" FMT64U " avail=%u remains=%u [%p]",
5596 io.crtBuf + 1,io.buffers,io.timestamp,avail,samples,m_owner);
5597 #endif
5598 io.crtBufSampOffs += avail;
5599 io.timestamp += avail;
5600 if (m_txPatternBuffer.length() == 0) {
5601 brfCopyTxData(start,data,avail,*scaleI,*maxI,*scaleQ,*maxQ,clamped,ampTable);
5602 data += avail * 2;
5603 }
5604 else
5605 sendCopyTxPattern(start,avail,*scaleI,*maxI,*scaleQ,*maxQ,clamped,ampTable);
5606 if (io.crtBufSampOffs >= io.bufSamples)
5607 io.advanceBuffer();
5608 #ifdef XDEBUG
5609 if (avail) {
5610 float sum = 0.0F;
5611 for (unsigned i=0; i<avail*2; i++) {
5612 sum += start[i]*start[i];
5613 }
5614 const float rms = ::sqrtf(sum/avail);
5615 const float dB = 20.0F*log10f((rms+0.5F)/2048.0F);
5616 XDebug(m_owner,DebugAll,"energized ouput RMS level %f in linear amplitude (%f dB) [%p]",
5617 rms, dB, this);
5618 }
5619 #endif
5620 }
5621 unsigned int nBuf = io.crtBuf;
5622 unsigned int oldBufSampOffs = nBuf ? io.crtBufSampOffs : 0;
5623 if (m_syncTxStateSet) {
5624 m_syncTxStateCode = setState(m_syncTxState,&m_syncTxStateError);
5625 m_syncTxState.m_tx.m_timestamp = ts + nBuf * io.bufSamples;
5626 m_syncTxStateSet = false;
5627 m_syncSemaphore.unlock();
5628 }
5629 if (nBuf < m_minBufsSend)
5630 break;
5631 if (checkDbgInt(io.checkTs))
5632 ioBufCheckTs(true,nBuf);
5633 else
5634 io.lastTs = io.timestamp;
5635 unsigned int nPrint = checkDbgInt(io.showBuf,nBuf);
5636 if (nPrint)
5637 printIOBuffer(true,"SEND",-1,nPrint);
5638 if (io.dataDumpFile.valid())
5639 dumpIOBuffer(io,nBuf);
5640 status = syncTransfer(EpSendSamples,io.bufStart(0),io.bufLen * nBuf,&e);
5641 // Reset buffer to start
5642 io.resetBufPos();
5643 // Copy partial buffer from end
5644 if (oldBufSampOffs) {
5645 #ifdef DEBUG_DEVICE_TX
5646 Debug(m_owner,DebugMild,"TX: copying buffer %u to start [%p]",nBuf,m_owner);
5647 #endif
5648 ::memcpy(io.bufStart(0),io.bufStart(nBuf),io.hdrLen + samplesi2bytes(oldBufSampOffs));
5649 io.crtBufSampOffs = oldBufSampOffs;
5650 }
5651 if (status)
5652 break;
5653 io.transferred += nBuf * io.bufSamples;
5654 }
5655 if (status == 0) {
5656 if (clamped) {
5657 float percent = 100 * (float)clamped / reqSend;
5658 Debug(m_owner,(percent < m_warnClamped) ? DebugAll : DebugNote,
5659 "Output buffer clamped %u/%u (%.2f%%) [%p]",clamped,reqSend,percent,m_owner);
5660 }
5661 if (samples)
5662 Debug(DebugFail,"Exiting with non 0 samples");
5663 }
5664 else if (status != RadioInterface::Cancelled)
5665 Debug(m_owner,DebugNote,"Send failed (TS=" FMT64U "): %s [%p]",
5666 io.timestamp,e.c_str(),m_owner);
5667 return status;
5668 }
5669
sendTxPatternChanged()5670 void BrfLibUsbDevice::sendTxPatternChanged()
5671 {
5672 Lock lck(m_dbgMutex);
5673 if (!m_txPatternChanged)
5674 return;
5675 m_txPatternChanged = false;
5676 m_txPatternBuffer.steal(m_txPattern);
5677 if (m_txPatternBuffer.length())
5678 Debug(m_owner,DebugInfo,
5679 "Using send pattern '%s' %u samples at TS=" FMT64U " [%p]",
5680 m_state.m_txPattern.substr(0,50).c_str(),m_txPatternBuffer.length(),
5681 m_txIO.timestamp,m_owner);
5682 m_txPatternBufPos = m_txPatternBuffer.length();
5683 }
5684
sendCopyTxPattern(int16_t * buf,unsigned int avail,float scaleI,int16_t maxI,float scaleQ,int16_t maxQ,unsigned int & clamped,const long * ampTable)5685 void BrfLibUsbDevice::sendCopyTxPattern(int16_t* buf, unsigned int avail,
5686 float scaleI, int16_t maxI, float scaleQ, int16_t maxQ, unsigned int& clamped,
5687 const long* ampTable)
5688 {
5689 while (avail) {
5690 if (m_txPatternBufPos == m_txPatternBuffer.length())
5691 m_txPatternBufPos = 0;
5692 unsigned int cp = m_txPatternBuffer.length() - m_txPatternBufPos;
5693 if (cp > avail)
5694 cp = avail;
5695 float* b = (float*)m_txPatternBuffer.data(m_txPatternBufPos);
5696 avail -= cp;
5697 m_txPatternBufPos += cp;
5698 brfCopyTxData(buf,b,cp,scaleI,maxI,scaleQ,maxQ,clamped,ampTable);
5699 }
5700 }
5701
5702 // Receive data from the Rx interface of the bladeRF device
5703 // Remember: a sample is an I/Q pair
recv(uint64_t & ts,float * data,unsigned int & samples,String * error)5704 unsigned int BrfLibUsbDevice::recv(uint64_t& ts, float* data, unsigned int& samples,
5705 String* error)
5706 {
5707 #ifndef DEBUG_DEVICE_RX
5708 XDebug(m_owner,DebugAll,"recv(" FMT64U ",%p,%u) [%p]",ts,data,samples,m_owner);
5709 #endif
5710 BrfDevIO& io = m_rxIO;
5711 if (!io.startTime)
5712 io.startTime = Time::now();
5713 if (io.dataDumpParams || io.upDumpParams)
5714 updateIODump(io);
5715 if (!(data && samples))
5716 return 0;
5717 #ifdef DEBUG_DEVICE_RX
5718 Debugger debug(DebugInfo,"BrfLibUsbDevice::recv()",
5719 " %s: ts=" FMT64U " samples=%u data=(%p) [%p]",
5720 m_owner->debugName(),ts,samples,data,m_owner);
5721 #endif
5722 unsigned int samplesCopied = 0;
5723 unsigned int samplesLeft = samples;
5724 float* cpDest = data;
5725 uint64_t crtTs = ts;
5726 String e;
5727 unsigned int status = lusbSetAltInterface(BRF_ALTSET_RF_LINK,&e);
5728 unsigned int nSamplesInPast = 0;
5729 while (!status) {
5730 while (samplesLeft && io.crtBuf < io.buffers) {
5731 // Retrieve buffer timestamp
5732 uint64_t bufTs = io.bufTs(io.crtBuf);
5733 if (io.crtBufSampOffs)
5734 bufTs += io.crtBufSampOffs;
5735 int64_t resync = (io.newBuffer && bufTs != m_rxTimestamp) ?
5736 (int64_t)(bufTs - m_rxTimestamp) : 0;
5737 #ifdef DEBUG_DEVICE_RX
5738 String deltaStr;
5739 if (resync)
5740 deltaStr << " " << (resync > 0 ? "future=" : "past=") <<
5741 (resync > 0 ? resync : -resync);
5742 Debugger loopDbg(DebugAll,"RX: processing buffer",
5743 " %u/%u rx_ts=" FMT64U " (resync_ts=" FMT64U ") "
5744 "ts=" FMT64U " crt_ts=" FMT64U "%s [%p]",
5745 io.crtBuf + 1,io.buffers,m_rxTimestamp,m_rxResyncCandidate,
5746 bufTs,crtTs,deltaStr.safe(),m_owner);
5747 #endif
5748 if (resync) {
5749 if ((resync > -1000 && resync < 1000) || bufTs == m_rxResyncCandidate) {
5750 Debug(m_owner,bufTs > m_silenceTs ? DebugNote : DebugAll,
5751 "RX: timestamp adjusted by " FMT64 " to " FMT64U " [%p]",
5752 resync,bufTs,m_owner);
5753 m_rxTimestamp = bufTs;
5754 m_rxResyncCandidate = 0;
5755 }
5756 else {
5757 Debug(m_owner,bufTs > m_silenceTs ? DebugWarn : DebugAll,
5758 "RX: timestamp jumped by " FMT64 " to " FMT64U " in buffer %u/%u [%p]",
5759 resync,m_rxTimestamp,io.crtBuf + 1,io.buffers,m_owner);
5760 m_rxResyncCandidate = bufTs;
5761 }
5762 }
5763 io.newBuffer = false;
5764 unsigned int avail = 0;
5765 int16_t* start = io.crtBufSamples(avail);
5766 if (avail > samplesLeft)
5767 avail = samplesLeft;
5768 // Check timestamp
5769 if (m_rxTimestamp > crtTs) {
5770 // Buffer timestamp is in the future
5771 #ifdef DEBUG_DEVICE_RX
5772 if (crtTs)
5773 Debug(m_owner,DebugNote,
5774 "RX: timestamp in future in buffer %u/%u requested="
5775 FMT64U " found=" FMT64U " [%p]",
5776 io.crtBuf + 1,io.buffers,crtTs,m_rxTimestamp,m_owner);
5777 #endif
5778 // Pad with 0
5779 uint64_t delta = m_rxTimestamp - crtTs;
5780 if (delta > samplesLeft)
5781 delta = samplesLeft;
5782 crtTs += delta;
5783 samplesLeft -= delta;
5784 samplesCopied += delta;
5785 ::memset(cpDest,0,2 * delta * sizeof(float));
5786 cpDest += 2 * delta;
5787 #ifdef DEBUG_DEVICE_RX
5788 Debug(m_owner,DebugAll,
5789 "RX: zeroed %u samples status=%u/%u remains=%u [%p]",
5790 (unsigned int)delta,samplesCopied,samples,samplesLeft,m_owner);
5791 #endif
5792 if (!samplesLeft)
5793 break;
5794 if (avail > samplesLeft)
5795 avail = samplesLeft;
5796 }
5797 else if (m_rxTimestamp < crtTs) {
5798 // Timestamp in the past: check if can use some data, skip buffer
5799 unsigned int skipSamples = avail;
5800 uint64_t delta = crtTs - m_rxTimestamp;
5801 if (delta < skipSamples)
5802 skipSamples = delta;
5803 #ifdef DEBUG_DEVICE_RX
5804 Debug(m_owner,DebugNote,
5805 "RX: skipping %u/%u samples in buffer %u/%u:"
5806 " timestamp in the past by " FMT64U " [%p]",
5807 skipSamples,avail,io.crtBuf + 1,io.buffers,delta,m_owner);
5808 #endif
5809 avail -= skipSamples;
5810 nSamplesInPast += skipSamples;
5811 io.crtBufSampOffs += skipSamples;
5812 m_rxTimestamp += skipSamples;
5813 if (m_rxResyncCandidate)
5814 m_rxResyncCandidate += skipSamples;
5815 if (io.crtBufSampOffs >= io.bufSamples) {
5816 io.advanceBuffer();
5817 continue;
5818 }
5819 }
5820 // We have some valid data: reset samples in the past counter
5821 if (avail)
5822 nSamplesInPast = 0;
5823 int16_t* last = start + avail * 2;
5824 // Copy data
5825 static const float s_mul = 1.0 / 2048;
5826 while (start != last) {
5827 *cpDest++ = *start++ * s_mul;
5828 *cpDest++ = *start++ * s_mul;
5829 }
5830 samplesCopied += avail;
5831 samplesLeft -= avail;
5832 m_rxTimestamp += avail;
5833 if (m_rxResyncCandidate)
5834 m_rxResyncCandidate += avail;
5835 #ifdef DEBUG_DEVICE_RX
5836 Debug(m_owner,DebugAll,
5837 "RX: copied %u samples from buffer %u/%u status=%u/%u remains=%u [%p]",
5838 avail,io.crtBuf + 1,io.buffers,samplesCopied,
5839 samples,samplesLeft,m_owner);
5840 #endif
5841 // Advance buffer offset, advance the buffer if we used all data
5842 io.crtBufSampOffs += avail;
5843 if (io.crtBufSampOffs >= io.bufSamples) {
5844 io.advanceBuffer();
5845 crtTs += avail;
5846 }
5847 }
5848 if (!samplesLeft)
5849 break;
5850 if (nSamplesInPast > m_rxTsPastSamples) {
5851 // Don't signal error if we have some valid data
5852 // This will allow the upper layer to update timestamps
5853 // Read operation may fail on subsequent reads
5854 if (!samplesCopied) {
5855 e = "Too much data in the past";
5856 status = RadioInterface::Failure;
5857 }
5858 break;
5859 }
5860 status = syncTransfer(EpReadSamples,io.bufStart(0),io.buffer.length(),&e);
5861 if (status)
5862 break;
5863 io.resetBufPos();
5864 if (io.dataDumpFile.valid())
5865 dumpIOBuffer(io,io.buffers);
5866 io.transferred += io.buffers * io.bufSamples;
5867 io.fixEndian();
5868 unsigned int nPrint = checkDbgInt(io.showBuf,io.buffers);
5869 if (nPrint)
5870 printIOBuffer(false,"RECV",-1,nPrint);
5871 if (m_rxAlterData)
5872 rxAlterData(true);
5873 if (checkDbgInt(io.checkLimit))
5874 ioBufCheckLimit(false);
5875 if (checkDbgInt(io.checkTs))
5876 ioBufCheckTs(false);
5877 if (m_state.m_rxDcAuto || m_rxShowDcInfo)
5878 computeRx(crtTs);
5879 if (m_rxAlterData)
5880 rxAlterData(false);
5881 }
5882 samples = samplesCopied;
5883 #ifdef DEBUG_DEVICE_RX
5884 Debug(m_owner,DebugAll,
5885 "BrfLibUsbDevice::recv() exiting status=%u ts=" FMT64U " samples=%u [%p]",
5886 status,ts,samples,m_owner);
5887 #endif
5888 if (io.captureBuf)
5889 captureHandle(io,data,samples,ts,status,&e);
5890 if (status == 0) {
5891 m_rxIO.timestamp = ts;
5892 if (io.upDumpFile.valid() && !(checkDbgInt(io.upDump) &&
5893 io.upDumpFile.write(ts,data,samplesf2bytes(samples),owner())))
5894 io.upDumpFile.terminate(owner());
5895 }
5896 else if (error)
5897 return showError(status,e,"Recv failed",error);
5898 else if (status != RadioInterface::Cancelled)
5899 Debug(m_owner,DebugNote,"Recv failed: %s [%p]",e.c_str(),m_owner);
5900 return status;
5901 }
5902
captureHandle(BrfDevIO & io,const float * buf,unsigned int samples,uint64_t ts,unsigned int status,const String * error)5903 void BrfLibUsbDevice::captureHandle(BrfDevIO& io, const float* buf, unsigned int samples,
5904 uint64_t ts, unsigned int status, const String* error)
5905 {
5906 //#define BRF_CAPTURE_HANDLE_TRACE
5907 Lock lck(io.captureMutex);
5908 if (!io.captureBuf)
5909 return;
5910 bool done = false;
5911 if (!status) {
5912 // Handle data
5913 unsigned int cp = 0;
5914 unsigned int bufOffs = 0;
5915 uint64_t tsCapture = io.captureTs + io.captureOffset;
5916 unsigned int samplesLeft = io.captureSamples - io.captureOffset;
5917 #ifdef BRF_CAPTURE_HANDLE_TRACE
5918 Output("CAPTURE[%s] (%u) " FMT64U "/%u (" FMT64U ") IO: " FMT64U
5919 "/%u (last=" FMT64U ") delta=" FMT64 " samplesLeft=%u",
5920 brfDir(io.tx()),io.captureSamples,io.captureTs,io.captureOffset,tsCapture,
5921 ts,samples,(ts + samples),(int64_t)(ts + samples - tsCapture),samplesLeft);
5922 #endif
5923 if (tsCapture == ts)
5924 cp = (samplesLeft < samples) ? samplesLeft : samples;
5925 else {
5926 uint64_t lastTs = ts + samples;
5927 bool useData = false;
5928 bool reset = true;
5929 if (tsCapture > ts) {
5930 useData = !io.captureOffset && (lastTs > tsCapture);
5931 reset = !useData && (lastTs >= tsCapture);
5932 }
5933 if (useData) {
5934 cp = (unsigned int)(lastTs - tsCapture);
5935 if (cp > samples)
5936 cp = samples;
5937 if (cp > samplesLeft)
5938 cp = samplesLeft;
5939 if (cp)
5940 bufOffs = samples - cp;
5941 }
5942 else if (reset) {
5943 // Reset buffer (avoid data gaps)
5944 io.captureTs = lastTs;
5945 io.captureOffset = 0;
5946 #ifdef BRF_CAPTURE_HANDLE_TRACE
5947 Output(" reset TS=" FMT64U,io.captureTs);
5948 #endif
5949 }
5950 }
5951 if (cp) {
5952 unsigned int nCopy = samplesf2bytes(cp);
5953 ::memcpy(io.captureBuf + 2 * io.captureOffset,buf + 2 * bufOffs,nCopy);
5954 io.captureOffset += cp;
5955 samplesLeft -= cp;
5956 #ifdef BRF_CAPTURE_HANDLE_TRACE
5957 Output(" cp=%u from=%u offset=%u samplesLeft=%u",
5958 cp,bufOffs,io.captureOffset,samplesLeft);
5959 #endif
5960 }
5961 if (!samplesLeft) {
5962 done = true;
5963 io.captureStatus = 0;
5964 io.captureError.clear();
5965 }
5966 }
5967 else {
5968 io.captureStatus = status;
5969 if (!TelEngine::null(error))
5970 io.captureError = (io.tx() ? "Send failed: " : "Recv failed: ") + *error;
5971 else
5972 io.captureError.clear();
5973 done = true;
5974 }
5975 if (!done)
5976 return;
5977 io.captureBuf = 0;
5978 io.captureSemaphore.unlock();
5979 }
5980
internalSetSampleRate(bool tx,uint32_t value,String * error)5981 unsigned int BrfLibUsbDevice::internalSetSampleRate(bool tx, uint32_t value,
5982 String* error)
5983 {
5984 String e;
5985 unsigned int status = 0;
5986 if (value <= m_radioCaps.maxSampleRate)
5987 status = lusbSetAltInterface(BRF_ALTSET_RF_LINK,&e);
5988 else {
5989 status = RadioInterface::InsufficientSpeed;
5990 e << "insufficient speed required=" << value << " max=" << m_radioCaps.maxSampleRate;
5991 }
5992 while (!status) {
5993 Si5338MultiSynth synth;
5994 BrfRationalRate rate;
5995
5996 rate.integer = value;
5997 rate.numerator = 0; // keeping the numerator and the donominator
5998 rate.denominator = 1; // for future use
5999 // Enforce minimum sample rate
6000 reduceRational(rate);
6001 if (rate.integer < BRF_SAMPLERATE_MIN)
6002 Debug(m_owner,DebugConf,
6003 "Requested %s sample rate %u is smaller than allowed minimum value [%p]",
6004 brfDir(tx),value,m_owner);
6005 // Setup the multisynth enables and index
6006 synth.enable = 0x01;
6007 synth.index = 1;
6008 if (tx) {
6009 synth.enable |= 0x02;
6010 synth.index = 2;
6011 }
6012 // Update the base address register
6013 synth.base = 53 + synth.index * 11;
6014 // Calculate multisynth values
6015 BRF_FUNC_CALL_BREAK(calcMultiSynth(synth,rate,&e));
6016 // Program it to the part
6017 // Write out the enables
6018 uint8_t val = 0;
6019 BRF_FUNC_CALL_BREAK(getSi5338(36 + synth.index,val,&e));
6020 val &= ~(7);
6021 val |= synth.enable;
6022 BRF_FUNC_CALL_BREAK(setSi5338(36 + synth.index,val,&e));
6023 // Write out the registers
6024 for (int i = 0 ; i < 10; i++)
6025 BRF_FUNC_CALL_BREAK(setSi5338(synth.base + i,*(synth.regs + i),&e));
6026 if (status)
6027 break;
6028 // Calculate r_power from c_count
6029 uint8_t rPower = 0;
6030 uint8_t rCount = synth.r >> 1;
6031 while (rCount) {
6032 rCount >>= 1;
6033 rPower++;
6034 }
6035 // Set the r value to the log2(r_count) to match Figure 18
6036 val = 0xc0;
6037 val |= (rPower<<2);
6038 BRF_FUNC_CALL_BREAK(setSi5338(31 + synth.index,val,&e));
6039 if (getDirState(tx).sampleRate != value) {
6040 getDirState(tx).sampleRate = value;
6041 Debug(m_owner,DebugInfo,"%s samplerate set to %u [%p]",
6042 brfDir(tx),value,m_owner);
6043 // Signal sample rate change to internal TX/RX
6044 Lock lck(m_threadMutex);
6045 if (tx)
6046 m_internalIoTxRate = value;
6047 else
6048 m_internalIoRxRate = value;
6049 m_internalIoRateChanged = true;
6050 }
6051 if (!tx) {
6052 unsigned int samplesMs = (value + 999) / 1000;
6053 // Calculate RX samples allowed to be in the past
6054 m_rxTsPastSamples = m_rxTsPastIntervalMs * samplesMs;
6055 // Calculate RX timestamp silence
6056 m_silenceTs = m_silenceTimeMs * samplesMs;
6057 }
6058 BrfDevIO& io = getIO(tx);
6059 bool first = !io.firstBufsThres.sampleRate;
6060 if (first) {
6061 io.firstBufsThres.sampleRate = value;
6062 io.firstBufsThres.bufferedSamples = totalSamples(tx);
6063 io.firstBufsThres.txMinBufs = m_minBufsSend;
6064 }
6065 // Check for I/O buffers info
6066 const BrfBufsThreshold* t = BrfBufsThreshold::findThres(m_bufThres,value);
6067 if (!t && !first)
6068 // No threshold set: rollback to first values
6069 t = &io.firstBufsThres;
6070 if (t)
6071 initBuffers(&tx,t->bufferedSamples,t->txMinBufs);
6072 return 0;
6073 }
6074 e.printf(1024,"Failed to set %s samplerate %u: %s",brfDir(tx),value,e.c_str());
6075 return showError(status,e,0,error);
6076 }
6077
6078 // Update FPGA (load, get version)
updateFpga(const NamedList & params)6079 unsigned int BrfLibUsbDevice::updateFpga(const NamedList& params)
6080 {
6081 const String& oper = params[YSTRING("fpga_load")];
6082 int load = 0;
6083 if (!oper)
6084 load = 1;
6085 else if (oper == YSTRING("auto")) {
6086 unsigned int code = checkFpga();
6087 if (code == RadioInterface::NoError)
6088 load = -1;
6089 else {
6090 load = 1;
6091 if (code != RadioInterface::NotInitialized)
6092 Debug(m_owner,DebugNote,"Forcing FPGA load (check failure) [%p]",m_owner);
6093 }
6094 }
6095 else
6096 load = oper.toBoolean(true) ? 1 : 0;
6097 if (load > 0)
6098 Debug(m_owner,DebugAll,"Updating FPGA [%p]",m_owner);
6099 else
6100 Debug(m_owner,DebugInfo,"Skipping FPGA load: %s [%p]",
6101 (load ? "checked, already loaded" : "disabled by config"),m_owner);
6102 m_devFpgaFile.clear();
6103 m_devFpgaVerStr.clear();
6104 m_devFpgaMD5.clear();
6105 String e;
6106 unsigned int status = 0;
6107 while (load > 0) {
6108 MD5 md5;
6109 String val;
6110 status = getCalField(val,"B","FPGA size",&e);
6111 if (status)
6112 break;
6113 String fName;
6114 if (val == YSTRING("115") || val == YSTRING("40"))
6115 fName = params.getValue("fpga_file_" + val,
6116 "${sharedpath}/data/hostedx" + val + ".rbf");
6117 else {
6118 e << "Unknown FPGA size value '" << val << "'";
6119 status = RadioInterface::Failure;
6120 break;
6121 }
6122 Engine::runParams().replaceParams(fName);
6123 const char* oper = 0;
6124 // Read the FPGA contents
6125 File f;
6126 DataBlock buf;
6127 if (f.openPath(fName,false,true)) {
6128 int64_t len = f.length();
6129 if (len > 0) {
6130 buf.assign(0,len);
6131 int rd = f.readData(buf.data(),buf.length());
6132 if (rd != len)
6133 oper = "read";
6134 }
6135 else if (f.error())
6136 oper = "detect length";
6137 }
6138 else
6139 oper = "open";
6140 if (oper) {
6141 status = RadioInterface::Failure;
6142 String tmp;
6143 Thread::errorString(tmp,f.error());
6144 e << "File '" << fName << "' " << oper << " failed (" <<
6145 f.error() << " '" << tmp << "')";
6146 break;
6147 }
6148 md5 << buf;
6149 Debug(m_owner,DebugAll,"Loading FPGA from '%s' len=%u [%p]",
6150 fName.c_str(),buf.length(),m_owner);
6151 // Write the FPGA
6152 BrfDevTmpAltSet tmpAltSet(this,BRF_ALTSET_FPGA,status,&e,"FPGA load");
6153 if (status)
6154 break;
6155 status = vendorCommand0_4(BRF_USB_CMD_BEGIN_PROG,LIBUSB_ENDPOINT_IN,&e);
6156 if (status == 0) {
6157 status = lusbBulkTransfer(BRF_ENDP_TX_CTRL,buf.data(0),buf.length(),
6158 0,&e,3 * m_bulkTout);
6159 if (status == 0) {
6160 status = vendorCommand0_4(BRF_USB_CMD_QUERY_FPGA_STATUS,
6161 LIBUSB_ENDPOINT_IN,&e);
6162 if (status)
6163 e = "Failed to end FPGA programming - " + e;
6164 }
6165 else
6166 e = "Failed to send FPGA image - " + e;
6167 }
6168 else
6169 e = "Failed to start FPGA programming - " + e;
6170 tmpAltSet.restore();
6171 status = restoreAfterFpgaLoad(&e);
6172 if (status == 0) {
6173 m_devFpgaFile = fName;
6174 m_devFpgaMD5 = md5.hexDigest();
6175 Debug(m_owner,DebugAll,"Loaded FPGA from '%s' [%p]",fName.c_str(),m_owner);
6176 }
6177 break;
6178 }
6179 if (status) {
6180 Debug(m_owner,DebugWarn,"Failed to load FPGA: %s [%p]",e.c_str(),m_owner);
6181 return status;
6182 }
6183 BrfDevTmpAltSet tmpAltSet(this,status,&e,"FPGA version get");
6184 if (status)
6185 return 0;
6186 uint32_t ver = 0;
6187 if (0 == gpioRead(0x0c,ver,4,&e))
6188 ver2str(m_devFpgaVerStr,ver);
6189 else
6190 Debug(m_owner,DebugNote,"Failed to retrieve FPGA version: %s [%p]",
6191 e.c_str(),m_owner);
6192 return 0;
6193 }
6194
internalSetFpgaCorr(bool tx,int corr,int16_t value,String * error,int lvl)6195 unsigned int BrfLibUsbDevice::internalSetFpgaCorr(bool tx, int corr, int16_t value,
6196 String* error, int lvl)
6197 {
6198 XDebug(m_owner,DebugAll,"internalSetFpgaCorr(%u,%d,%d) [%p]",tx,corr,value,m_owner);
6199 String e;
6200 unsigned int status = 0;
6201 int orig = value;
6202 uint8_t addr = 0;
6203 int* old = 0;
6204 BrfDevDirState& io = getDirState(tx);
6205 bool setBoard = true;
6206 if (corr == CorrFpgaGain) {
6207 old = &io.fpgaCorrGain;
6208 addr = fpgaCorrAddr(tx,false);
6209 if (tx && m_txGainCorrSoftware) {
6210 // Because FPGA Gain cal is broken in older images, we fake it in software.
6211 // We should probably just keep faking it, even in newer FPGA images.
6212 const float bal = 1 + 0.1*(((float)orig) / BRF_FPGA_CORR_MAX);
6213 status = internalSetTxIQBalance(false,bal);
6214 setBoard = false;
6215 }
6216 else {
6217 orig = clampInt(orig,-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX,"FPGA GAIN",lvl);
6218 value = orig + BRF_FPGA_CORR_MAX;
6219 }
6220 }
6221 else if (corr == CorrFpgaPhase) {
6222 old = &io.fpgaCorrPhase;
6223 orig = clampInt(orig,-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX,"FPGA PHASE",lvl);
6224 value = orig;
6225 addr = fpgaCorrAddr(tx,true);
6226 }
6227 else
6228 status = setUnkValue(e,0,"FPGA corr value " + String(corr));
6229 if (!status) {
6230 if (setBoard)
6231 status = gpioWrite(addr,value,2,&e);
6232 if (!status) {
6233 if (old) {
6234 if (io.showFpgaCorrChange == 0 && *old != orig)
6235 Debug(m_owner,DebugInfo,"%s FPGA corr %s %s to %d (reg %d) [%p]",
6236 brfDir(tx),lookup(corr,s_corr),(setBoard ? "set" : "faked"),
6237 orig,value,m_owner);
6238 *old = orig;
6239 }
6240 return 0;
6241 }
6242 }
6243 e.printf(1024,"Failed to %s %s FPGA corr %s to %d (from %d) - %s [%p]",
6244 (setBoard ? "set" : "fake"),brfDir(tx),lookup(corr,s_corr),
6245 value,orig,e.c_str(),m_owner);
6246 return showError(status,e,0,error);
6247 }
6248
internalGetFpgaCorr(bool tx,int corr,int16_t * value,String * error)6249 unsigned int BrfLibUsbDevice::internalGetFpgaCorr(bool tx, int corr, int16_t* value,
6250 String* error)
6251 {
6252 String e;
6253 unsigned int status = 0;
6254 uint8_t addr = 0;
6255 int* update = 0;
6256 BrfDevDirState& io = getDirState(tx);
6257 if (corr == CorrFpgaGain) {
6258 if (tx && m_txGainCorrSoftware) {
6259 if (value)
6260 *value = io.fpgaCorrGain;
6261 return 0;
6262 }
6263 update = &io.fpgaCorrGain;
6264 addr = fpgaCorrAddr(tx,false);
6265 }
6266 else if (corr == CorrFpgaPhase) {
6267 update = &io.fpgaCorrPhase;
6268 addr = fpgaCorrAddr(tx,true);
6269 }
6270 else
6271 status = setUnkValue(e,0,"FPGA corr value " + String(corr));
6272 if (!status) {
6273 uint32_t u = 0;
6274 status = gpioRead(addr,u,2,&e);
6275 if (status == 0) {
6276 int v = (int)u;
6277 if (corr == CorrFpgaGain)
6278 v -= BRF_FPGA_CORR_MAX;
6279 if (value)
6280 *value = v;
6281 XDebug(m_owner,DebugAll,"Got %s FPGA corr %s %d [%p]",
6282 brfDir(tx),lookup(corr,s_corr),v,m_owner);
6283 if (update)
6284 *update = v;
6285 return 0;
6286 }
6287 }
6288 e.printf(1024,"Failed to retrieve %s FPGA corr %s - %s [%p]",
6289 brfDir(tx),lookup(corr,s_corr),e.c_str(),m_owner);
6290 return showError(status,e,0,error);
6291 }
6292
internalSetTxVga(int vga,bool preMixer,String * error)6293 unsigned int BrfLibUsbDevice::internalSetTxVga(int vga, bool preMixer, String* error)
6294 {
6295 String e;
6296 unsigned int status = 0;
6297 BrfDevTmpAltSet tmpAltSet(this,status,&e,"TX VGA set");
6298 while (status == 0) {
6299 uint8_t addr = lmsVgaAddr(true,preMixer);
6300 uint8_t data = 0;
6301 BRF_FUNC_CALL_BREAK(lmsRead(addr,data,&e));
6302 if (preMixer) {
6303 vga = clampInt(vga,BRF_TXVGA1_GAIN_MIN,BRF_TXVGA1_GAIN_MAX,"TX VGA1");
6304 data = (uint8_t)((vga - BRF_TXVGA1_GAIN_MIN) & 0x1f);
6305 }
6306 else {
6307 vga = clampInt(vga,BRF_TXVGA2_GAIN_MIN,BRF_TXVGA2_GAIN_MAX,"TX VGA2");
6308 data &= ~0xf8;
6309 data |= (uint8_t)(vga << 3);
6310 }
6311 BRF_FUNC_CALL_BREAK(lmsWrite(addr,data,&e));
6312 if (preMixer)
6313 m_state.m_tx.vga1Changed = true;
6314 int& old = preMixer ? m_state.m_tx.vga1 : m_state.m_tx.vga2;
6315 if (old != vga) {
6316 old = vga;
6317 Debug(m_owner,DebugInfo,"TX VGA%c set to %ddB (0x%x) [%p]",
6318 mixer(preMixer),vga,data,m_owner);
6319 if (!preMixer)
6320 internalSetTxIQBalance(true);
6321 }
6322 return 0;
6323 }
6324 e.printf(1024,"Failed to set TX VGA%c to from %d: %s",mixer(preMixer),vga,e.c_str());
6325 return showError(status,e,0,error);
6326 }
6327
internalGetTxVga(int * vga,bool preMixer,String * error)6328 unsigned int BrfLibUsbDevice::internalGetTxVga(int* vga, bool preMixer, String* error)
6329 {
6330 uint8_t data = 0;
6331 String e;
6332 int v = 0;
6333 unsigned int status = lmsRead(lmsVgaAddr(true,preMixer),data,&e);
6334 if (status == 0) {
6335 if (preMixer) {
6336 v = (int)(data & 0x1f) + BRF_TXVGA1_GAIN_MIN;
6337 m_state.m_tx.vga1 = v;
6338 }
6339 else {
6340 v = (data >> 3) & 0x1f;
6341 if (v > BRF_TXVGA2_GAIN_MAX)
6342 v = BRF_TXVGA2_GAIN_MAX;
6343 m_state.m_tx.vga2 = v;
6344 }
6345 if (vga)
6346 *vga = v;
6347 XDebug(m_owner,DebugAll,"Got TX VGA%c %ddB (0x%x) [%p]",
6348 mixer(preMixer),v,data,m_owner);
6349 return 0;
6350 }
6351 e.printf(1024,"Failed to retrieve TX VGA%c: %s",mixer(preMixer),e.c_str());
6352 return showError(status,e,0,error);
6353 }
6354
6355 // Enable or disable the pre/post mixer gain on the receive side
internalEnableRxVga(bool on,bool preMixer,String * error)6356 unsigned int BrfLibUsbDevice::internalEnableRxVga(bool on, bool preMixer, String* error)
6357 {
6358 XDebug(m_owner,DebugAll,"internalEnableRxVga(%u,%u) [%p]",on,preMixer,m_owner);
6359 String e;
6360 unsigned int status = 0;
6361 BrfDevTmpAltSet tmpAltSet(this,status,&e,"Enable RX VGA");
6362 while (status == 0) {
6363 uint8_t addr = preMixer ? 0x7d : 0x64;
6364 uint8_t data = 0;
6365 BRF_FUNC_CALL_BREAK(lmsRead(addr,data,&e));
6366 bool old = false;
6367 if (preMixer) {
6368 old = (data & 0x08) == 0;
6369 if (on)
6370 data &= ~0x08;
6371 else
6372 data |= 0x08;
6373 }
6374 else {
6375 old = (data & 0x02) != 0;
6376 if (on)
6377 data |= 0x02;
6378 else
6379 data &= ~0x02;
6380 }
6381 BRF_FUNC_CALL_BREAK(lmsWrite(addr,data,&e));
6382 if (old != on)
6383 Debug(m_owner,DebugInfo,"%s RX VGA%c [%p]",
6384 enabledStr(on),mixer(preMixer),m_owner);
6385 return 0;
6386 }
6387 e.printf(1024,"Failed to %s RX VGA%c: %s",enableStr(on),mixer(preMixer),e.c_str());
6388 return showError(status,e,0,error);
6389 }
6390
internalSetRxVga(int vga,bool preMixer,String * error)6391 unsigned int BrfLibUsbDevice::internalSetRxVga(int vga, bool preMixer, String* error)
6392 {
6393 String e;
6394 unsigned int status = 0;
6395 BrfDevTmpAltSet tmpAltSet(this,status,&e,"RX VGA set");
6396 while (status == 0) {
6397 uint8_t addr = lmsVgaAddr(false,preMixer);
6398 uint8_t data = 0;
6399 BRF_FUNC_CALL_BREAK(lmsRead(addr,data,&e));
6400 int orig = vga;
6401 bool changed = false;
6402 if (preMixer) {
6403 vga = clampInt(vga,BRF_RXVGA1_GAIN_MIN,BRF_RXVGA1_GAIN_MAX,"RX VGA1");
6404 data = (uint8_t)((data & ~0x7f) | s_rxvga1_set[vga]);
6405 BRF_FUNC_CALL_BREAK(lmsWrite(addr,data,&e));
6406 changed = (m_state.m_rx.vga1 != vga);
6407 m_state.m_rx.vga1 = vga;
6408 }
6409 else {
6410 vga = clampInt(vga / 3 * 3,BRF_RXVGA2_GAIN_MIN,BRF_RXVGA2_GAIN_MAX,"RX VGA2");
6411 data = (uint8_t)((data & ~0x1f) | (vga / 3));
6412 BRF_FUNC_CALL_BREAK(lmsWrite(addr,data,&e));
6413 changed = (m_state.m_rx.vga2 != vga);
6414 m_state.m_rx.vga2 = vga;
6415 m_rxDcOffsetMax = (int)brfRxDcOffset(clampInt(orig,BRF_RXVGA2_GAIN_MIN,BRF_RXVGA2_GAIN_MAX));
6416 }
6417 if (changed)
6418 Debug(m_owner,DebugInfo,"RX VGA%c set to %ddB 0x%x (from %d) [%p]",
6419 mixer(preMixer),vga,data,orig,m_owner);
6420 return 0;
6421 }
6422 e.printf(1024,"Failed to set RX VGA%c to %d: %s",mixer(preMixer),vga,e.c_str());
6423 return showError(status,e,0,error);
6424 }
6425
internalGetRxVga(int * vga,bool preMixer,String * error)6426 unsigned int BrfLibUsbDevice::internalGetRxVga(int* vga, bool preMixer, String* error)
6427 {
6428 uint8_t data = 0;
6429 String e;
6430 unsigned int status = lmsRead(lmsVgaAddr(false,preMixer),data,&e);
6431 if (status == 0) {
6432 int v = 0;
6433 if (preMixer) {
6434 int idx = (data & 0x7f);
6435 m_state.m_rx.vga1 = v = s_rxvga1_get[idx < 121 ? idx : 120];
6436 }
6437 else {
6438 m_state.m_rx.vga2 = v = (data & 0x1f) * 3;
6439 m_rxDcOffsetMax = (int)brfRxDcOffset(clampInt(v,BRF_RXVGA2_GAIN_MIN,BRF_RXVGA2_GAIN_MAX));
6440 }
6441 XDebug(m_owner,DebugAll,"Got RX VGA%c %ddB (reg=0x%x) [%p]",
6442 mixer(preMixer),v,data,m_owner);
6443 if (vga)
6444 *vga = v;
6445 return 0;
6446 }
6447 e.printf(1024,"Failed to retrieve RX VGA%c: %s",mixer(preMixer),e.c_str());
6448 return showError(status,e,0,error);
6449 }
6450
6451 // Set pre and post mixer value
internalSetGain(bool tx,int val,int * newVal,String * error)6452 unsigned int BrfLibUsbDevice::internalSetGain(bool tx, int val, int* newVal, String* error)
6453 {
6454 int vga1 = 0;
6455 if (tx) {
6456 vga1 = (m_state.m_tx.vga1Changed && m_state.m_tx.vga1 >= BRF_TXVGA1_GAIN_MIN) ?
6457 m_state.m_tx.vga1 : BRF_TXVGA1_GAIN_DEF;
6458 val = clampInt(val + BRF_TXVGA2_GAIN_MAX,BRF_TXVGA2_GAIN_MIN,BRF_TXVGA2_GAIN_MAX);
6459 }
6460 else {
6461 vga1 = (m_state.m_rx.vga1 > BRF_RXVGA1_GAIN_MAX) ?
6462 BRF_RXVGA1_GAIN_MAX : m_state.m_rx.vga1;
6463 val = clampInt(val,BRF_RXVGA2_GAIN_MIN,BRF_RXVGA2_GAIN_MAX);
6464 }
6465 unsigned int status = internalSetVga(tx,vga1,true,error);
6466 if (!status)
6467 status = internalSetVga(tx,val,false,error);
6468 if (status == 0 && newVal) {
6469 *newVal = val;
6470 if (tx)
6471 *newVal -= BRF_TXVGA2_GAIN_MAX;
6472 }
6473 return status;
6474 }
6475
internalSetTxIQBalance(bool newGain,float newBalance,const char * param)6476 unsigned int BrfLibUsbDevice::internalSetTxIQBalance(bool newGain, float newBalance,
6477 const char* param)
6478 {
6479 bool dbg = true;
6480 if (!newGain) {
6481 if (newBalance <= 0 || newBalance >= 2) {
6482 if (!param) {
6483 Debug(m_owner,DebugNote,
6484 "Failed to set power balance to %g expected interval (0..2) [%p]",
6485 newBalance,m_owner);
6486 return RadioInterface::OutOfRange;
6487 }
6488 Debug(m_owner,DebugConf,"Invalid %s=%g defaults to 1 [%p]",
6489 param,newBalance,m_owner);
6490 newBalance = 1;
6491 }
6492 if (m_txPowerBalance != newBalance) {
6493 dbg = (m_state.m_tx.showPowerBalanceChange == 0);
6494 if (dbg)
6495 Debug(m_owner,DebugInfo,"TX power balance changed %g -> %g [%p]",
6496 m_txPowerBalance,newBalance,m_owner);
6497 m_txPowerBalance = newBalance;
6498 }
6499 }
6500 float oldI = m_txPowerScaleI;
6501 float oldQ = m_txPowerScaleQ;
6502 // Update TX power scale
6503 m_txPowerScaleI = m_txPowerScaleQ = 1;
6504 if (m_txPowerBalance > 1)
6505 m_txPowerScaleQ /= m_txPowerBalance;
6506 else if (m_txPowerBalance < 1)
6507 m_txPowerScaleI *= m_txPowerBalance;
6508 if (oldI == m_txPowerScaleI && oldQ == m_txPowerScaleQ)
6509 return 0;
6510 if (dbg)
6511 Debug(m_owner,DebugInfo,"TX power scale changed I: %g -> %g Q: %g -> %g [%p]",
6512 oldI,m_txPowerScaleI,oldQ,m_txPowerScaleQ,m_owner);
6513 m_txPowerBalanceChanged = true;
6514 return 0;
6515 }
6516
internalSetFreqOffs(float val,float * newVal,String * error)6517 unsigned int BrfLibUsbDevice::internalSetFreqOffs(float val, float* newVal, String* error)
6518 {
6519 val = clampFloat(val,BRF_FREQ_OFFS_MIN,BRF_FREQ_OFFS_MAX,"FrequencyOffset");
6520 String e;
6521 // val has an 8 bit integer range with float precision, which need to be converted to 16 bit integer
6522 uint32_t voltageDAC = val * 256;
6523 unsigned int status = gpioWrite(0x22,voltageDAC,2,&e);
6524 if (status)
6525 return showError(status,e,"FrequencyOffset set failed",error);
6526 if (m_freqOffset != val) {
6527 Debug(m_owner,(m_freqOffset != val) ? DebugInfo : DebugAll,
6528 "FrequencyOffset changed %g -> %g [%p]",m_freqOffset,val,m_owner);
6529 m_freqOffset = val;
6530 }
6531 else
6532 Debug(m_owner,DebugAll,"FrequencyOffset set to %g [%p]",val,m_owner);
6533 if (newVal)
6534 *newVal = val;
6535 return 0;
6536 }
6537
internalSetFrequency(bool tx,uint64_t val,String * error)6538 unsigned int BrfLibUsbDevice::internalSetFrequency(bool tx, uint64_t val, String* error)
6539 {
6540 XDebug(m_owner,DebugAll,"BrfLibUsbDevice::setFrequency(" FMT64U ",%s) [%p]",
6541 val,brfDir(tx),m_owner);
6542 String e;
6543 unsigned int status = 0;
6544 BrfDevTmpAltSet tmpAltSet(this,status,&e,"frequency set");
6545 if (val < BRF_FREQUENCY_MIN || val > BRF_FREQUENCY_MAX) {
6546 status = RadioInterface::OutOfRange;
6547 e = "Value out of range";
6548 }
6549 uint32_t hz = (uint32_t)val;
6550 while (!status) {
6551 uint8_t addr = lmsFreqAddr(tx);
6552 uint8_t pllFreq = 0xff;
6553 for (int i = 0; s_freqLimits[i]; i += 3)
6554 if (hz >= s_freqLimits[i] && hz <= s_freqLimits[i + 1]) {
6555 pllFreq = s_freqLimits[i + 2];
6556 break;
6557 }
6558 if (pllFreq == 0xff) {
6559 status = setUnkValue(e,"frequency " + String(hz));
6560 break;
6561 }
6562 // Integer part
6563 uint64_t vco_x = ((uint64_t)1) << ((pllFreq & 7) - 3);
6564 uint64_t tmp = (vco_x * hz) / s_freqRefClock;
6565 if (tmp > 0xffff) {
6566 e.printf("The integer part " FMT64U " of the frequency is too big",tmp);
6567 status = RadioInterface::Failure;
6568 break;
6569 }
6570 uint16_t nint = (uint16_t)tmp;
6571 // Fractional part
6572 tmp = (1 << 23) * (vco_x * hz - nint * s_freqRefClock);
6573 tmp = (tmp + s_freqRefClock / 2) / s_freqRefClock;
6574 if (tmp > 0xffffffff) {
6575 e.printf("The fractional part " FMT64U " of the frequency is too big",tmp);
6576 status = RadioInterface::Failure;
6577 break;
6578 }
6579 uint32_t nfrac = (uint32_t)tmp;
6580 bool lowBand = brfIsLowBand(hz);
6581 // Reset CLK_EN for Rx/Tx DSM SPI
6582 BRF_FUNC_CALL_BREAK(lmsSet(0x09,0x05,&e));
6583 // Set PLL frequency and output buffer selection
6584 pllFreq <<= 2;
6585 pllFreq |= (lowBand ? 0x01 : 0x02);
6586 BRF_FUNC_CALL_BREAK(lmsWrite(addr + 5,pllFreq,&e));
6587 // Set frequency NINT/NFRAC
6588 uint8_t d[4] = {(uint8_t)(nint >> 1),
6589 (uint8_t)(((nint & 1) << 7) | ((nfrac >> 16) & 0x7f)),
6590 (uint8_t)(nfrac >> 8),(uint8_t)nfrac};
6591 BRF_FUNC_CALL_BREAK(accessPeripheral(UartDevLMS,true,addr,d,&e,4));
6592 // Set PLL currents (ICHP=1.2mA, OFFUP=30uA, OFFDOWN=0mA)
6593 BRF_FUNC_CALL_BREAK(lmsSet(addr + 6,0x0c,0x1f,&e));
6594 BRF_FUNC_CALL_BREAK(lmsSet(addr + 7,0x03,0x1f,&e));
6595 BRF_FUNC_CALL_BREAK(lmsSet(addr + 8,0x00,0x1f,&e));
6596 // Loop through the VCOCAP to figure out optimal values
6597 BRF_FUNC_CALL_BREAK(tuneVcocap(addr,&e));
6598 // Reset CLK_EN for Rx/Tx DSM SPI
6599 BRF_FUNC_CALL_BREAK(lmsReset(0x09,0x05,&e));
6600 // Select PA/LNA amplifier (don't do it if loopback is enabled)
6601 if (m_state.m_loopback == LoopNone)
6602 BRF_FUNC_CALL_BREAK(selectPaLna(tx,lowBand,&e));
6603 // Set GPIO band according to the frequency
6604 uint32_t gpio = 0;
6605 BRF_FUNC_CALL_BREAK(gpioRead(0,gpio,4,&e));
6606 uint32_t band = lowBand ? 2 : 1;
6607 int shift = tx ? 3 : 5;
6608 gpio &= (uint32_t)~(3 << shift);
6609 gpio |= (uint32_t)(band << shift);
6610 BRF_FUNC_CALL_BREAK(gpioWrite(0,gpio,4,&e));
6611 BRF_FUNC_CALL_BREAK(internalSetFreqOffs(m_freqOffset,0,&e));
6612 break;
6613 }
6614 if (status) {
6615 e.printf(1024,"Failed to set %s frequency to " FMT64U "Hz - %s",brfDir(tx),val,e.c_str());
6616 return showError(status,e,0,error);
6617 }
6618 if (getDirState(tx).frequency != hz) {
6619 getDirState(tx).frequency = hz;
6620 Debug(m_owner,DebugInfo,"%s frequency set to %gMHz offset=%g [%p]",
6621 brfDir(tx),(double)hz / 1000000,m_freqOffset,m_owner);
6622 }
6623 else
6624 Debug(m_owner,DebugAll,"%s frequency set to %gMHz offset=%g [%p]",
6625 brfDir(tx),(double)hz / 1000000,m_freqOffset,m_owner);
6626 return 0;
6627 }
6628
internalGetFrequency(bool tx,uint32_t * hz,String * error)6629 unsigned int BrfLibUsbDevice::internalGetFrequency(bool tx, uint32_t* hz, String* error)
6630 {
6631 String e;
6632 unsigned int status = 0;
6633 uint32_t freq = 0;
6634 BrfDevTmpAltSet tmpAltSet(this,status,&e,tx ? "TX frequency get" : "RX frequency get");
6635 while (!status) {
6636 uint8_t addr = lmsFreqAddr(tx);
6637 uint8_t data = 0;
6638 uint64_t fint = 0; // Integer part of the freq
6639 // Reading the integer part of the frequency
6640 BRF_FUNC_CALL_BREAK(lmsRead(addr + 0,data,&e));
6641 fint = (uint64_t)data << 24;
6642 BRF_FUNC_CALL_BREAK(lmsRead(addr + 1,data,&e));
6643 fint |= (data & 0x80) << 16;
6644 // Read the fractionary part of the frequency
6645 fint |= ((uint64_t)data & 0x7f) << 16;
6646 BRF_FUNC_CALL_BREAK(lmsRead(addr + 2,data,&e));
6647 fint |= (uint64_t)data << 8;
6648 BRF_FUNC_CALL_BREAK(lmsRead(addr + 3,data,&e));
6649 fint |= data;
6650 // read the freq division
6651 BRF_FUNC_CALL_BREAK(lmsRead(addr + 5,data,&e));
6652 uint32_t division = data >> 2; // VCO division ratio
6653 division = 1 << ((division & 7) + 20);
6654 freq = (uint32_t)(((s_freqRefClock * fint) + (division >> 1)) / division);
6655 break;
6656 }
6657 if (status == 0) {
6658 getDirState(tx).frequency = freq;
6659 if (hz)
6660 *hz = freq;
6661 XDebug(m_owner,DebugAll,"Got %s frequency %uHz [%p]",brfDir(tx),freq,m_owner);
6662 return 0;
6663 }
6664 e.printf(1024,"Failed to retrieve %s frequency - %s",brfDir(tx),e.c_str());
6665 return showError(status,e,0,error);
6666 }
6667
6668 // Retrieve TX/RX timestamp
internalGetTimestamp(bool tx,uint64_t & ts,String * error)6669 unsigned int BrfLibUsbDevice::internalGetTimestamp(bool tx, uint64_t& ts, String* error)
6670 {
6671 String e;
6672 unsigned int status = 0;
6673 while (true) {
6674 uint32_t low = 0;
6675 uint32_t high = 0;
6676 uint8_t addr = tx ? 0x18 : 0x10;
6677 BRF_FUNC_CALL_BREAK(gpioRead(addr,low,4,&e));
6678 BRF_FUNC_CALL_BREAK(gpioRead(addr + 4,high,4,&e));
6679 ts = ((uint64_t)high << 31) | (low >> 1);
6680 XDebug(m_owner,DebugAll,"Got %s ts=" FMT64U " [%p]",brfDir(tx),ts,m_owner);
6681 return 0;
6682 }
6683 e.printf(1024,"Failed to retrieve %s timestamp - %s",brfDir(tx),e.c_str());
6684 return showError(status,e,0,error);
6685 }
6686
6687 // USB peripheral operation method
lusbSetAltInterface(int val,String * error)6688 unsigned int BrfLibUsbDevice::lusbSetAltInterface(int val, String* error)
6689 {
6690 if (m_altSetting == val)
6691 return 0;
6692 unsigned int status = 0;
6693 String e;
6694 if (val >= BRF_ALTSET_MIN && val <= BRF_ALTSET_MAX)
6695 status = lusbCheckSuccess(
6696 ::libusb_set_interface_alt_setting(m_devHandle,0,val),&e);
6697 else
6698 status = setUnkValue(e);
6699 if (status == 0) {
6700 DDebug(m_owner,DebugAll,"Alt interface changed %s -> %s [%p]",
6701 altSetName(m_altSetting),altSetName(val),m_owner);
6702 m_altSetting = val;
6703 return 0;
6704 }
6705 String prefix;
6706 prefix << "Failed to change alt interface to ";
6707 if (val >= BRF_ALTSET_MIN && val <= BRF_ALTSET_MAX)
6708 prefix << altSetName(val);
6709 else
6710 prefix << val;
6711 return showError(status,e,prefix,error);
6712 }
6713
6714 // Wrapper for libusb_control_transfer
lusbCtrlTransfer(uint8_t reqType,int8_t request,uint16_t value,uint16_t index,uint8_t * data,uint16_t len,String * error,unsigned int tout)6715 unsigned int BrfLibUsbDevice::lusbCtrlTransfer(uint8_t reqType, int8_t request,
6716 uint16_t value, uint16_t index, uint8_t* data, uint16_t len, String* error,
6717 unsigned int tout)
6718 {
6719 #ifdef DEBUGGER_DEVICE_METH
6720 String tmp;
6721 //tmp.hexify(data,len,' ');
6722 //tmp = " data=" + tmp;
6723 Debugger d(DebugAll,"BrfLibUsbDevice::lusbCtrlTransfer()",
6724 " (0x%x,0x%x,0x%x,%u,%p,%u,%u)%s [%p]",
6725 reqType,request,value,index,data,len,tout,tmp.safe(),m_owner);
6726 #endif
6727 int code = ::libusb_control_transfer(m_devHandle,reqType,request,value,
6728 index,data,len,tout ? tout : m_ctrlTout);
6729 if (code == (int)len)
6730 return 0;
6731 String e;
6732 unsigned int status = (code < 0) ? lusbCheckSuccess(code,&e) :
6733 RadioInterface::Failure;
6734 return showError(status,e,"Incomplete USB CTRL transfer",error);
6735 }
6736
6737 // Wrapper for libusb bulk transfer
lusbBulkTransfer(uint8_t endpoint,uint8_t * data,unsigned int len,unsigned int * transferred,String * error,unsigned int tout)6738 unsigned int BrfLibUsbDevice::lusbBulkTransfer(uint8_t endpoint, uint8_t* data,
6739 unsigned int len, unsigned int* transferred, String* error, unsigned int tout)
6740 {
6741 #ifdef DEBUGGER_DEVICE_METH
6742 Debugger d(DebugAll,"BrfLibUsbDevice::lusbBulkTransfer()",
6743 " (0x%x,%p,%u,%u) [%p]",endpoint,data,len,tout,m_owner);
6744 #endif
6745 int nIO = 0;
6746 int code = ::libusb_bulk_transfer(m_devHandle,endpoint,
6747 data,len,&nIO,tout ? tout : m_bulkTout);
6748 if (transferred)
6749 *transferred = nIO;
6750 if ((int)len == nIO)
6751 return 0;
6752 String e;
6753 unsigned int status = (code < 0) ? lusbCheckSuccess(code,&e) :
6754 RadioInterface::Failure;
6755 return showError(status,e,"Incomplete USB BULK transfer",error);
6756 }
6757
6758 // Make an async usb transfer
syncTransfer(int ep,uint8_t * data,unsigned int len,String * error)6759 unsigned int BrfLibUsbDevice::syncTransfer(int ep, uint8_t* data, unsigned int len,
6760 String* error)
6761 {
6762 LusbTransfer& t = m_usbTransfer[ep];
6763 #ifdef DEBUG
6764 if ((ep == EpReadSamples || ep == EpSendSamples) &&
6765 !getIO(ep == EpSendSamples).mutex.locked())
6766 Debug(m_owner,DebugFail,"syncTransfer() %s not locked [%p]",
6767 brfDir(ep == EpSendSamples),m_owner);
6768 if (t.running())
6769 Debug(m_owner,DebugFail,"EP %s transfer is running [%p]",
6770 lookup(ep,s_usbEndpoint),m_owner);
6771 #endif
6772 #ifdef DEBUGGER_DEVICE_METH
6773 String tmp;
6774 //tmp.hexify(data,len,' ');
6775 //tmp = " data=" + tmp;
6776 Debugger d(DebugAll,"BrfLibUsbDevice::syncTransfer()",
6777 " (%s,%p,%u) transfer=(%p)%s [%p]",
6778 lookup(ep,s_usbEndpoint),data,len,&t,tmp.safe(),m_owner);
6779 #else
6780 XDebug(m_owner,DebugAll,"syncTransfer ep=%s data=(%p) len=%u [%p]",
6781 lookup(ep,s_usbEndpoint),data,len,m_owner);
6782 #endif
6783 t.running(true);
6784 unsigned int cStatus = 0;
6785 bool checkCancelled = !m_closingDevice;
6786 if (t.fillBulk(data,len,m_syncTout) && t.submit()) {
6787 while (t.running()) {
6788 struct timeval tv;
6789 tv.tv_usec = 3 * Thread::idleUsec();
6790 tv.tv_sec = 0;
6791 ::libusb_handle_events_timeout_completed(m_context,&tv,0);
6792 if (checkCancelled && t.running() && cStatus == 0 &&
6793 (cStatus = cancelled()) != 0) {
6794 Debug(m_owner,DebugInfo,"Cancelling transfer %s [%p]",
6795 lookup(ep,s_usbEndpoint),m_owner);
6796 t.cancel();
6797 }
6798 }
6799 }
6800 Lock lck(t);
6801 t.running(false);
6802 if (checkCancelled && !t.status)
6803 t.status = cancelled(&t.error);
6804 return showError(t.status,t.error,"SYNC transfer failed",error);
6805 }
6806
6807 // Read the value of a specific GPIO register
gpioRead(uint8_t addr,uint32_t & value,uint8_t len,String * error,const char * loc)6808 unsigned int BrfLibUsbDevice::gpioRead(uint8_t addr, uint32_t& value, uint8_t len,
6809 String* error, const char* loc)
6810 {
6811 len = clampInt(len,1,sizeof(value),"GPIO read items",DebugCrit);
6812 uint8_t t[sizeof(value)];
6813 unsigned int status = accessPeripheral(UartDevGPIO,false,addr,t,error,len,loc);
6814 if (status)
6815 return status;
6816 value = 0;
6817 // Data is in little endian order
6818 #ifdef LITTLE_ENDIAN
6819 for (uint8_t i = 0; i < len; i++)
6820 value |= (uint64_t)(t[i] << (i * 8));
6821 #else
6822 for (uint8_t i = 0; i < len; i++)
6823 value |= (uint64_t)(t[i] << ((len - i - 1) * 8));
6824 #endif
6825 return 0;
6826 }
6827
6828 // Write a value to a specific GPIO register
gpioWrite(uint8_t addr,uint32_t value,uint8_t len,String * error,const char * loc)6829 unsigned int BrfLibUsbDevice::gpioWrite(uint8_t addr, uint32_t value, uint8_t len,
6830 String* error, const char* loc)
6831 {
6832 if (addr == 0) {
6833 if (m_devSpeed == LIBUSB_SPEED_SUPER)
6834 value &= ~BRF_GPIO_SMALL_DMA_XFER;
6835 else if (m_devSpeed == LIBUSB_SPEED_HIGH)
6836 value |= BRF_GPIO_SMALL_DMA_XFER;
6837 else
6838 Debug(m_owner,DebugStub,"GPIO write: unhandled speed [%p]",m_owner);
6839 }
6840 len = clampInt(len,1,sizeof(value),"GPIO write items",DebugCrit);
6841 uint8_t t[sizeof(value)];
6842 // Data is in little endian order
6843 #ifdef LITTLE_ENDIAN
6844 for (uint8_t i = 0; i < len; i++)
6845 t[i] = (uint8_t)(value >> (i * 8));
6846 #else
6847 for (uint8_t i = 0; i < len; i++)
6848 t[i] = (uint8_t)(value >> ((len - i - 1) * 8));
6849 #endif
6850 return accessPeripheral(UartDevGPIO,true,addr,t,error,len,loc);
6851 }
6852
lmsWrite(const String & str,bool updStat,String * error)6853 unsigned int BrfLibUsbDevice::lmsWrite(const String& str, bool updStat, String* error)
6854 {
6855 if (!str)
6856 return 0;
6857 String e;
6858 unsigned int status = 0;
6859 while (true) {
6860 DataBlock db;
6861 if (!db.unHexify(str)) {
6862 status = setErrorFail(&e,"Invalid hex string");
6863 break;
6864 }
6865 if ((db.length() % 2) != 0) {
6866 status = setErrorFail(&e,"Invalid string length");
6867 break;
6868 }
6869 Debug(m_owner,DebugAll,"Writing '%s' to LMS [%p]",str.c_str(),m_owner);
6870 uint8_t* b = db.data(0);
6871 for (unsigned int i = 0; !status && i < db.length(); i += 2) {
6872 b[i] &= ~0x80;
6873 status = lmsWrite(b[i],b[i + 1],&e);
6874 }
6875 if (!status && updStat)
6876 status = updateStatus(&e);
6877 if (!status)
6878 return 0;
6879 break;
6880 }
6881 e.printf(1024,"LMS write '%s' failed - %s",str.c_str(),e.c_str());
6882 return showError(status,e,0,error);
6883 }
6884
6885 // Read the lms configuration
lmsRead(String & dest,const String * read,bool readIsInterleaved,String * error)6886 unsigned int BrfLibUsbDevice::lmsRead(String& dest, const String* read,
6887 bool readIsInterleaved, String* error)
6888 {
6889 String e;
6890 unsigned int status = 0;
6891 while (true) {
6892 DataBlock db;
6893 if (read) {
6894 DataBlock tmp;
6895 if (!tmp.unHexify(*read)) {
6896 status = setErrorFail(&e,"Invalid hex string");
6897 break;
6898 }
6899 if (readIsInterleaved) {
6900 if ((tmp.length() % 2) != 0) {
6901 status = setErrorFail(&e,"Invalid string length");
6902 break;
6903 }
6904 db = tmp;
6905 }
6906 else {
6907 db.resize(tmp.length() * 2);
6908 for (unsigned int i = 0; i < tmp.length(); i++)
6909 *db.data(i * 2) = tmp[i];
6910 }
6911 }
6912 else {
6913 db.resize(127 * 2);
6914 for (uint8_t i = 0; i < 127; i++)
6915 *db.data(i * 2) = i;
6916 }
6917 Debug(m_owner,DebugAll,"Reading LMS [%p]",m_owner);
6918 uint8_t* b = db.data(0);
6919 for (unsigned int i = 0; !status && i < db.length(); i += 2) {
6920 b[i] &= ~0x80;
6921 status = lmsRead(b[i],b[i + 1],&e);
6922 }
6923 if (status)
6924 break;
6925 dest.hexify(db.data(),db.length());
6926 return 0;
6927 }
6928 e.printf(1024,"LMS read '%s' failed - %s",TelEngine::c_safe(read),e.c_str());
6929 return showError(status,e,0,error);
6930 }
6931
6932 // Check LMS registers
lmsCheck(const String & what,String * error)6933 unsigned int BrfLibUsbDevice::lmsCheck(const String& what, String* error)
6934 {
6935 if (!what)
6936 return 0;
6937 String e;
6938 unsigned int status = 0;
6939 while (true) {
6940 DataBlock db;
6941 bool haveMask = (what[0] == '+');
6942 unsigned int delta = haveMask ? 1 : 0;
6943 if (!db.unHexify(what.c_str() + delta,what.length() - delta)) {
6944 status = setErrorFail(&e,"Invalid hex string");
6945 break;
6946 }
6947 unsigned int div = haveMask ? 3 : 2;
6948 if ((db.length() % div) != 0) {
6949 status = setErrorFail(&e,"Invalid string length");
6950 break;
6951 }
6952 unsigned int n = db.length() / div;
6953 uint8_t b[4];
6954 uint8_t* d = db.data(0);
6955 String diff;
6956 String s;
6957 for (unsigned int i = 0; i < n; i++) {
6958 b[0] = *d++ & ~0x80;
6959 b[1] = *d++;
6960 b[2] = 0;
6961 b[3] = (div > 2) ? *d++ : 0xff;
6962 BRF_FUNC_CALL_BREAK(lmsRead(b[0],b[2],&e));
6963 if ((b[1] & b[3]) != (b[2] & b[3]))
6964 diff.append(s.hexify(b,div + 1)," ");
6965 }
6966 if (status)
6967 break;
6968 if (error)
6969 *error = diff;
6970 else if (diff)
6971 Debug(m_owner,DebugNote,"Check LMS '%s' diff: %s [%p]",
6972 what.c_str(),diff.c_str(),m_owner);
6973 return 0;
6974 }
6975 e.printf(1024,"LMS check '%s' - %s",what.c_str(),e.c_str());
6976 return showError(status,e,0,error);
6977 }
6978
lnaSelect(int lna,String * error)6979 unsigned int BrfLibUsbDevice::lnaSelect(int lna, String* error)
6980 {
6981 String e;
6982 unsigned int status = 0;
6983 bool valid = (lna >= 0 && lna <= 3);
6984 while (valid) {
6985 uint8_t data = 0;
6986 BRF_FUNC_CALL_BREAK(lmsRead(0x75,data,&e));
6987 BRF_FUNC_CALL_BREAK(lmsWrite(0x75,(data & ~0x30) | (lna << 4),&e));
6988 int old = (data >> 4) & 0x03;
6989 int level = old != lna ? DebugInfo : DebugAll;
6990 if (lna != LmsLnaNone)
6991 Debug(m_owner,level,"LNA %d selected [%p]",lna,m_owner);
6992 else
6993 Debug(m_owner,level,"LNAs disabled [%p]",m_owner);
6994 return 0;
6995 }
6996 if (!valid)
6997 status = setUnkValue(e);
6998 if (lna != LmsLnaNone)
6999 e.printf(1024,"Failed to select LNA %d - %s",lna,e.c_str());
7000 else
7001 e.printf(1024,"Failed to disable LNAs - %s",e.c_str());
7002 return showError(status,e,0,error);
7003 }
7004
lnaEnable(bool on,String * error)7005 unsigned int BrfLibUsbDevice::lnaEnable(bool on, String* error)
7006 {
7007 String e;
7008 unsigned int status = 0;
7009 while (true) {
7010 uint8_t data = 0;
7011 BRF_FUNC_CALL_BREAK(lmsRead(0x7d,data,&e));
7012 BRF_FUNC_CALL_BREAK(lmsWrite(0x7d,on ? (data & ~0x01) : (data | 0x01),&e));
7013 Debug(m_owner,on == ((data & 0x01) == 0) ? DebugAll : DebugInfo,
7014 "%s LNA RXFE [%p]",enabledStr(on),m_owner);
7015 return 0;
7016 }
7017 e.printf("Failed to %s LNA RXFE - %s",enableStr(on),e.c_str());
7018 return showError(status,e,0,error);
7019 }
7020
lnaGainSet(uint8_t value,String * error)7021 unsigned int BrfLibUsbDevice::lnaGainSet(uint8_t value, String* error)
7022 {
7023 const char* what = lookup(value,s_lnaGain);
7024 XDebug(m_owner,DebugAll,"lnaGainSet(%u,'%s') [%p]",value,what,m_owner);
7025 String e;
7026 unsigned int status = 0;
7027 if (!what || value == LnaGainUnhandled)
7028 status = setUnkValue(e);
7029 while (status == 0) {
7030 uint8_t data = 0;
7031 BRF_FUNC_CALL_BREAK(lmsRead(0x75,data,&e));
7032 uint8_t old = (uint8_t)((data >> 6) & 0x03);
7033 data &= ~(3 << 6);
7034 data |= ((value & 3) << 6);
7035 BRF_FUNC_CALL_BREAK(lmsWrite(0x75,data,&e));
7036 if (old != value)
7037 Debug(m_owner,DebugInfo,"LNA GAIN set to %s [%p]",what,m_owner);
7038 return 0;
7039 }
7040 e.printf(1024,"Failed to set LNA GAIN %u (%s) - %s",value,what,e.c_str());
7041 return showError(status,e,0,error);
7042 }
7043
lnaGainGet(uint8_t & value,String * error)7044 unsigned int BrfLibUsbDevice::lnaGainGet(uint8_t& value, String* error)
7045 {
7046 uint8_t data = 0;
7047 unsigned int status = lmsRead(0x75,data,error,"LNA gain read register");
7048 if (status)
7049 return status;
7050 data >>= 6;
7051 data &= 3;
7052 value = data;
7053 if (value != LnaGainUnhandled)
7054 return 0;
7055 String e;
7056 e.printf("LNA gain read abnormal value 0x%x",data);
7057 return showError(RadioInterface::OutOfRange,e,0,error);
7058 }
7059
internalSetLpfBandwidth(bool tx,uint32_t band,String * error)7060 unsigned int BrfLibUsbDevice::internalSetLpfBandwidth(bool tx, uint32_t band,
7061 String* error)
7062 {
7063 String e;
7064 unsigned int status = lusbSetAltInterface(BRF_ALTSET_RF_LINK,&e);
7065 while (!status) {
7066 uint8_t data = 0;
7067 uint8_t reg = lmsLpfAddr(tx);
7068 BRF_FUNC_CALL_BREAK(lmsRead(reg,data,&e));
7069 uint8_t i = bw2index(band);
7070 uint8_t bw = 15 - i;
7071 data &= ~0x3c; // Clear out previous bandwidth setting
7072 data |= (bw << 2); // Apply new bandwidth setting
7073 BRF_FUNC_CALL_BREAK(lmsWrite(reg,data,&e));
7074 bool changed = (getDirState(tx).lpfBw != s_bandSet[i]);
7075 getDirState(tx).lpfBw = s_bandSet[i];
7076 Debug(m_owner,changed ? DebugInfo : DebugAll,
7077 "%s LPF bandwidth set to %u (from %u, reg=0x%x) [%p]",
7078 brfDir(tx),getDirState(tx).lpfBw,band,data,m_owner);
7079 return 0;
7080 }
7081 e.printf(1024,"Failed to set %s LPF bandwidth %u: %s",brfDir(tx),band,e.c_str());
7082 return showError(status,e,0,error);
7083 }
7084
internalSetLpf(bool tx,int lpf,String * error)7085 unsigned int BrfLibUsbDevice::internalSetLpf(bool tx, int lpf, String* error)
7086 {
7087 const char* what = lookup(lpf,s_lpf);
7088 XDebug(m_owner,DebugAll,"internalSetLpf(%u,%d,'%s') [%p]",tx,lpf,what,m_owner);
7089 uint8_t addr = lmsLpfAddr(tx);
7090 uint8_t reg1 = 0;
7091 uint8_t reg2 = 0;
7092 String e;
7093 unsigned int status = 0;
7094 if (what)
7095 status = lmsRead2(addr,reg1,addr + 1,reg2,&e);
7096 else
7097 status = setUnkValue(e,0,"value");
7098 if (status == 0) {
7099 // Clear EN_LPF
7100 switch (lpf) {
7101 case LpfDisabled:
7102 reg1 &= 0xfd; // Disable LPF: reset EN_LPF
7103 reg2 &= 0xbf; // Normal operation: reset BYP_EN_LPF
7104 break;
7105 case LpfBypass:
7106 reg1 &= 0xfd; // Disable LPF: reset EN_LPF
7107 reg1 |= 0x40; // Bypass LPF: set BYP_EN_LPF
7108 break;
7109 case LpfNormal:
7110 reg1 |= 0x02; // Enable LPF: set EN_LPF
7111 reg2 &= 0xbf; // Normal operation: reset BYP_EN_LPF
7112 break;
7113 default:
7114 status = setUnkValue(e,0,"value");
7115 }
7116 if (status == 0) {
7117 status = lmsWrite2(addr,reg1,addr + 1,reg2,&e);
7118 if (status == 0) {
7119 if (getDirState(tx).lpf != lpf) {
7120 getDirState(tx).lpf = lpf;
7121 Debug(m_owner,DebugInfo,"%s LPF set to '%s' [%p]",
7122 brfDir(tx),what,m_owner);
7123 }
7124 return 0;
7125 }
7126 }
7127 }
7128 e.printf(1024,"Failed to set %s LPF %u (%s) - %s",
7129 brfDir(tx),lpf,TelEngine::c_safe(what),e.c_str());
7130 return showError(status,e,0,error);
7131 }
7132
internalGetLpf(bool tx,int * lpf,String * error)7133 unsigned int BrfLibUsbDevice::internalGetLpf(bool tx, int* lpf, String* error)
7134 {
7135 uint8_t addr = lmsLpfAddr(tx);
7136 uint8_t reg1 = 0;
7137 uint8_t reg2 = 0;
7138 String e;
7139 unsigned int status = lmsRead2(addr,reg1,addr + 1,reg2,&e);
7140 if (status == 0) {
7141 int l = decodeLpf(reg1,reg2);
7142 if (l != LpfInvalid) {
7143 getDirState(tx).lpf = l;
7144 if (lpf)
7145 *lpf = l;
7146 XDebug(m_owner,DebugAll,"Got %s LPF %d (%s) [%p]",
7147 brfDir(tx),l,lookup(l,s_lpf),m_owner);
7148 return 0;
7149 }
7150 status = RadioInterface::OutOfRange;
7151 e = "Invalid values, enabled and bypassed";
7152 }
7153 e.printf(1024,"Failed to retrieve %s LPF - %s",brfDir(tx),e.c_str());
7154 return showError(status,e,0,error);
7155 }
7156
7157 // Fill the m_list member of the class
updateDeviceList(String * error)7158 unsigned int BrfLibUsbDevice::updateDeviceList(String* error)
7159 {
7160 clearDeviceList();
7161 int n = ::libusb_get_device_list(m_context,&m_list);
7162 if (n >= 0) {
7163 m_listCount = n;
7164 return 0;
7165 }
7166 String e;
7167 unsigned int status = lusbCheckSuccess(n,&e);
7168 return showError(status,e,"Failed to enumerate USB devices",error);
7169 }
7170
7171 // Enable/disable RF and sample circulation on both RX and TX sides
enableRf(bool tx,bool on,bool frontEndOnly,String * error)7172 unsigned int BrfLibUsbDevice::enableRf(bool tx, bool on, bool frontEndOnly, String* error)
7173 {
7174 #ifdef DEBUGGER_DEVICE_METH
7175 Debugger d(DebugAll,"BrfLibUsbDevice::enableRf()",
7176 " tx=%s on=%s frontEndOnly=%s [%p]",String::boolText(tx),String::boolText(on),
7177 String::boolText(frontEndOnly),m_owner);
7178 #endif
7179 BrfDevDirState& dirState = getDirState(tx);
7180 unsigned int status = 0;
7181 String e;
7182 resetTimestamps(tx);
7183 if (!m_devHandle) {
7184 if (!on) {
7185 dirState.rfEnabled = false;
7186 return 0;
7187 }
7188 status = RadioInterface::NotInitialized;
7189 e = "Not open";
7190 }
7191 if (!status) {
7192 // RF front end
7193 uint8_t addr = tx ? 0x40 : 0x70;
7194 uint8_t val = tx ? 0x02 : 0x01;
7195 status = lmsChangeMask(addr,val,on,&e);
7196 if (!status && !frontEndOnly)
7197 status = enableRfFpga(tx,on,&e);
7198 }
7199 bool ok = on && (status == 0);
7200 if (dirState.rfEnabled == ok) {
7201 dirState.rfEnabled = ok;
7202 return status;
7203 }
7204 dirState.rfEnabled = ok;
7205 const char* fEnd = frontEndOnly ? " front end" : "";
7206 if (status == 0) {
7207 Debug(m_owner,DebugAll,"%s RF %s%s [%p]",
7208 enabledStr(on),brfDir(tx),fEnd,m_owner);
7209 return 0;
7210 }
7211 e.printf(1024,"Failed to %s RF %s%s - %s",enableStr(on),brfDir(tx),fEnd,e.c_str());
7212 return showError(status,e,0,error);
7213 }
7214
enableRfFpga(bool tx,bool on,String * error)7215 unsigned int BrfLibUsbDevice::enableRfFpga(bool tx, bool on, String* error)
7216 {
7217 uint8_t request = tx ? BRF_USB_CMD_RF_TX : BRF_USB_CMD_RF_RX;
7218 uint32_t buf = (uint32_t)-1;
7219 uint16_t value = on ? 1 : 0;
7220 String e;
7221 unsigned int status = lusbCtrlTransfer(LUSB_CTRLTRANS_IFACE_VENDOR_IN,
7222 request,value,0,(uint8_t*)&buf,sizeof(buf),&e);
7223 if (status == 0 && le32toh(buf))
7224 status = setErrorFail(&e,"Device failure");
7225 if (!status)
7226 return 0;
7227 e.printf(1024,"FPGA RF %s failed - %s",enableStr(on),e.c_str());
7228 return showError(status,e,0,error);
7229 }
7230
7231 // Check if fpga is loaded
checkFpga()7232 unsigned int BrfLibUsbDevice::checkFpga()
7233 {
7234 String error;
7235 int32_t data = 0;
7236 unsigned int status = vendorCommand(BRF_USB_CMD_QUERY_FPGA_STATUS,BRF_ENDP_RX_SAMPLES,
7237 data,&error);
7238 if (status == 0) {
7239 if (le32toh(data)) {
7240 Debug(m_owner,DebugAll,"The FPGA is already configured [%p]",m_owner);
7241 return 0;
7242 }
7243 Debug(m_owner,DebugAll,"The FPGA is not configured [%p]",m_owner);
7244 return RadioInterface::NotInitialized;
7245 }
7246 Debug(m_owner,DebugNote,"FPGA check failed: %s [%p]",error.c_str(),m_owner);
7247 return status;
7248 }
7249
7250 // Restore device after loading the FPGA
restoreAfterFpgaLoad(String * error)7251 unsigned int BrfLibUsbDevice::restoreAfterFpgaLoad(String* error)
7252 {
7253 String e;
7254 unsigned int status = 0;
7255 BrfDevTmpAltSet tmpAltSet(this,status,&e,"Restore after FPGA load");
7256 while (!status) {
7257 uint32_t gpio = 0;
7258 status = gpioRead(0,gpio,4,&e);
7259 if (status)
7260 break;
7261 if (gpio & 0x7fff) {
7262 e.printf("Unexpected FPGA state 0x%x",gpio);
7263 status = RadioInterface::Failure;
7264 break;
7265 }
7266 // Enable the LMS and select the low band
7267 status = gpioWrite(0,0x57,4,&e,"Failed to enable LMS and/or low band");
7268 if (status)
7269 break;
7270 // Disable the TX/RX
7271 if ((status = enableRfBoth(false,true,&e)) != 0)
7272 break;
7273 // Enabling LMS on TX side
7274 status = lmsWrite(0x05,0x3e,&e,"Failed to enable LMS TX");
7275 if (status)
7276 break;
7277 break;
7278 }
7279 if (status == 0) {
7280 XDebug(m_owner,DebugAll,"Restored device after FPGA load [%p]",m_owner);
7281 return 0;
7282 }
7283 return showError(status,e,"Failed to restore device after FPGA load",error);
7284 }
7285
7286 // Change some LMS registers default value on open
openChangeLms(const NamedList & params,String * error)7287 unsigned int BrfLibUsbDevice::openChangeLms(const NamedList& params, String* error)
7288 {
7289 // See Lime FAQ document Section 5.27
7290 static const String s_def = "4740592964367937";
7291
7292 String e;
7293 unsigned int status = 0;
7294 BrfDevTmpAltSet tmpAltSet(this,status,&e,"Open change LMS");
7295 if (!status) {
7296 const String* s = params.getParam(YSTRING("open_write_lms"));
7297 if (s && *s != s_def)
7298 Debug(m_owner,DebugNote,"Open: writing LMS '%s' [%p]",s->c_str(),m_owner);
7299 else
7300 s = &s_def;
7301 status = lmsWrite(*s,false,&e);
7302 }
7303 if (status == 0) {
7304 XDebug(m_owner,DebugAll,"Changed default LMS values [%p]",m_owner);
7305 return 0;
7306 }
7307 return showError(status,e,"Failed to change LMS defaults",error);
7308 }
7309
7310 // Reset the Usb interface using an ioctl call
resetUsb(String * error)7311 unsigned int BrfLibUsbDevice::resetUsb(String* error)
7312 {
7313 String e;
7314 unsigned int status = openDevice(false,&e);
7315 if (status)
7316 return showError(status,e,"USB reset failed",error);
7317 status = lusbCheckSuccess(::libusb_reset_device(m_devHandle),&e,"USB reset failed ");
7318 if (!status)
7319 Debug(m_owner,DebugAll,"Reset USB device bus=%d addr=%d [%p]",
7320 m_devBus,m_devAddr,m_owner);
7321 closeDevice();
7322 return showError(status,e,0,error);
7323 }
7324
7325 // Set the VCTCXO configuration to the correct value
tuneVcocap(uint8_t addr,String * error)7326 unsigned int BrfLibUsbDevice::tuneVcocap(uint8_t addr, String* error)
7327 {
7328 uint8_t data = 0;
7329 unsigned int status = lmsRead(addr + 9,data,error,"VCTCXO tune");
7330 if (status)
7331 return status;
7332 uint8_t vcocap = 32;
7333 uint8_t vtune = 0;
7334 uint8_t step = vcocap >> 1;
7335 data &= ~(0x3f);
7336 for (int i = 0; i < 6; i++) {
7337 if ((status = lmsWrite(addr + 9,vcocap | data,error,"VCTCXO tune")) != 0)
7338 return status;
7339 if ((status = lmsRead(addr + 10,vtune,error,"VCTCXO tune")) != 0)
7340 return status;
7341 vtune >>= 6;
7342 if (vtune == VCO_NORM) {
7343 XDebug(m_owner,DebugInfo,"tuneVcocap: Found normal VCO [%p]",m_owner);
7344 break;
7345 }
7346 if (vtune == VCO_HIGH) {
7347 XDebug(m_owner,DebugInfo,"tuneVcocap: VCO high [%p]",m_owner);
7348 vcocap += step;
7349 }
7350 else if (vtune == VCO_LOW) {
7351 XDebug(m_owner,DebugInfo,"tuneVcocap: VCO low [%p]",m_owner);
7352 vcocap -= step ;
7353 }
7354 else
7355 return setError(RadioInterface::Failure,error,
7356 "VCTCXO tune - invalid tunning");
7357 step >>= 1;
7358 }
7359 if (vtune != VCO_NORM)
7360 return setError(RadioInterface::Failure,error,"VCTCXO tune - tunning not locked");
7361 uint8_t start = vcocap;
7362 while (start > 0 && vtune == VCO_NORM) {
7363 start--;
7364 if ((status = lmsWrite(addr + 9,start | data,error,"VCTCXO tune")) != 0)
7365 return status;
7366 if ((status = lmsRead(addr + 10,vtune,error,"VCTCXO tune")) != 0)
7367 return status;
7368 vtune >>= 6;
7369 }
7370 start++;
7371 XDebug(m_owner,DebugInfo,"tuneVcocap: Found lower limit %u [%p]",start,m_owner);
7372 if ((status = lmsWrite(addr + 9,vcocap | data,error,"VCTCXO tune")) != 0)
7373 return status;
7374 if ((status = lmsRead(addr + 10,vtune,error,"VCTCXO tune")) != 0)
7375 return status;
7376 vtune >>= 6;
7377 uint8_t stop = vcocap;
7378 while (stop < 64 && vtune == VCO_NORM) {
7379 stop++;
7380 if ((status = lmsWrite(addr + 9,stop | data,error,"VCTCXO tune")) != 0)
7381 return status;
7382 if ((status = lmsRead(addr + 10,vtune,error,"VCTCXO tune")) != 0)
7383 return status;
7384 vtune >>= 6;
7385 }
7386 stop--;
7387 XDebug(m_owner,DebugAll,"tuneVcocap: Found lower limit %u [%p]",stop,m_owner);
7388 vcocap = (start + stop) >> 1;
7389 XDebug(m_owner,DebugInfo,"tuneVcocap: VCOCAP=%u [%p]",vcocap,m_owner);
7390 if ((status = lmsWrite(addr + 9,vcocap | data,error,"VCTCXO tune")) != 0)
7391 return status;
7392 if ((status = lmsRead(addr + 10,vtune,error,"VCTCXO tune")) != 0)
7393 return status;
7394 vtune >>= 6;
7395 DDebug(m_owner,DebugInfo,"tuneVcocap: VCTCXO=%u [%p]",vtune,m_owner);
7396 if (vtune == VCO_NORM)
7397 return 0;
7398 return setError(RadioInterface::Failure,error,"VCTCXO tune failed");
7399 }
7400
7401 // Send requests to the bladeRF device regarding the FPGA image configuration.
vendorCommand(uint8_t cmd,uint8_t ep,uint8_t * data,uint16_t len,String * error)7402 unsigned int BrfLibUsbDevice::vendorCommand(uint8_t cmd, uint8_t ep, uint8_t* data,
7403 uint16_t len, String* error)
7404 {
7405 #ifdef DEBUGGER_DEVICE_METH
7406 Debugger d(DebugAll,"BrfLibUsbDevice::vendorCommand()",
7407 " (0x%x,0x%x,%p,%u) [%p]",cmd,ep,data,len,m_owner);
7408 #endif
7409 String e;
7410 unsigned int status = lusbCtrlTransfer(LUSB_CTRLTRANS_IFACE_VENDOR | ep,
7411 cmd,0,0,data,len,&e);
7412 if (!status)
7413 return 0;
7414 e.printf(1024,"Vendor command 0x%x endpoint=0x%x failed - %s",cmd,ep,e.c_str());
7415 return showError(status,e,0,error);
7416 }
7417
7418 // Access the bladeRF board in order to transmit data
accessPeripheral(uint8_t dev,bool tx,uint8_t addr,uint8_t * data,String * error,uint8_t len,const char * loc)7419 unsigned int BrfLibUsbDevice::accessPeripheral(uint8_t dev, bool tx, uint8_t addr,
7420 uint8_t* data, String* error, uint8_t len, const char* loc)
7421 {
7422 if (dev >= UartDevCount)
7423 return RadioInterface::Failure;
7424 const BrfPeripheral& uartDev = s_uartDev[dev];
7425 #ifdef DEBUGGER_DEVICE_METH
7426 String tmp;
7427 if (tx)
7428 tmp.hexify(data,len,' ');
7429 Debugger debug(DebugInfo,"BrfLibUsbDevice::accessPeripheral()",
7430 " dev=%s dir=%s addr=0x%x len=%u bits=%s [%p]",
7431 uartDev.c_str(),brfDir(tx),addr,len,tmp.safe(),m_owner);
7432 #endif
7433 String e;
7434 unsigned int status = 0;
7435 uint8_t a = addr;
7436 uint8_t* d = data;
7437 uint8_t n = len;
7438 uint8_t maskDirDev = (uint8_t)((tx ? 0x40 : 0x80) | uartDev.devId());
7439 uint8_t buf[16] = {(uint8_t)'N'};
7440 #define BRF_ACCESS_PERIPHERAL(nItems) \
7441 { \
7442 buf[1] = (uint8_t)(maskDirDev | nItems); \
7443 uint8_t* b = &buf[2]; \
7444 ::memset(b,0,sizeof(buf) - 2); \
7445 for (uint8_t i = 0; i < nItems; i++) { \
7446 *b++ = a + i; \
7447 if (tx) \
7448 *b = d[i]; \
7449 b++; \
7450 } \
7451 status = syncTransfer(EpSendCtrl,buf,sizeof(buf),&e); \
7452 if (!status) \
7453 status = syncTransfer(EpReadCtrl,buf,sizeof(buf),&e); \
7454 if (status == 0 && !tx) { \
7455 b = &buf[3]; \
7456 for (uint8_t i = 0; i < nItems; i++, b += 2) \
7457 d[i] = *b; \
7458 } \
7459 }
7460 if (n > 7) {
7461 n = len % 7;
7462 for (uint8_t full = len / 7; !status && full; full--, a += 7, d += 7)
7463 BRF_ACCESS_PERIPHERAL(7);
7464 }
7465 if (n && !status)
7466 BRF_ACCESS_PERIPHERAL(n);
7467 #undef BRF_ACCESS_PERIPHERAL
7468 if (status) {
7469 e.printf(1024,"%s%s%s %s failed addr=0x%x len=%d - %s",
7470 TelEngine::c_safe(loc),(loc ? " - " : ""),uartDev.c_str(),
7471 tx ? "write" : "read",addr,len,e.c_str());
7472 return showError(status,e,0,error);
7473 }
7474 if (!uartDev.trackDir(tx))
7475 return 0;
7476 String s;
7477 if (!uartDev.haveTrackAddr()) {
7478 if (m_owner->debugAt(DebugAll))
7479 Debug(m_owner,DebugAll,"%s %s addr=0x%x len=%u '%s' [%p]",
7480 uartDev.c_str(),brfDir(tx),addr,len,
7481 s.hexify(data,len,' ').c_str(),m_owner);
7482 }
7483 else {
7484 int level = uartDev.trackLevel();
7485 bool levelOk = !level || m_owner->debugAt(level);
7486 if (levelOk && (uartDev.isTrackRange(addr,len) >= 0)) {
7487 unsigned int a = addr;
7488 for (unsigned int i = 0; i < len && a < 256; i++, a++)
7489 if (uartDev.isTrackAddr(a)) {
7490 String tmp;
7491 if (!s)
7492 s << uartDev.c_str() << " " << brfDir(tx);
7493 s.append(tmp.printf("(0x%x=0x%x)",(uint8_t)a,data[i])," ");
7494 }
7495 if (s) {
7496 if (level)
7497 Debug(m_owner,level,"%s [%p]",s.c_str(),m_owner);
7498 else {
7499 char b[50];
7500 Debugger::formatTime(b);
7501 Output("%s<%s> %s [%p]",b,m_owner->debugName(),s.c_str(),m_owner);
7502 }
7503 }
7504 }
7505 }
7506 return 0;
7507 }
7508
internalSetDcOffset(bool tx,bool i,int16_t value,String * error)7509 unsigned int BrfLibUsbDevice::internalSetDcOffset(bool tx, bool i, int16_t value,
7510 String* error)
7511 {
7512 int& old = i ? getDirState(tx).dcOffsetI : getDirState(tx).dcOffsetQ;
7513 if (old == value)
7514 return 0;
7515 uint8_t addr = lmsCorrIQAddr(tx,i);
7516 String e;
7517 uint8_t data = 0;
7518 unsigned int status = 0;
7519 while (true) {
7520 if (tx) {
7521 if (value < BRF_TX_DC_OFFSET_MIN || value > BRF_TX_DC_OFFSET_MAX) {
7522 status = setUnkValue(e,0,"value");
7523 break;
7524 }
7525 }
7526 else if (value < -BRF_RX_DC_OFFSET_MAX || value > BRF_RX_DC_OFFSET_MAX) {
7527 status = setUnkValue(e,0,"value");
7528 break;
7529 }
7530 BrfDevTmpAltSet tmpAltSet(this,status,&e,"DC offset set");
7531 if (status)
7532 break;
7533 status = lmsRead(addr,data,&e);
7534 if (status)
7535 break;
7536 if (tx)
7537 // MSB bit is the sign (1: positive)
7538 data = 128 + value;
7539 else {
7540 // MSB bit has nothing to do with RX DC offset
7541 // Bit 6 is the sign bit (1: negative)
7542 uint8_t b7 = (uint8_t)(data & 0x80);
7543 if (value >= 0)
7544 data = (uint8_t)((value >= 64) ? 0x3f : (value & 0x3f));
7545 else {
7546 data = (uint8_t)((value <= -64) ? 0x3f : ((-value) & 0x3f));
7547 data |= 0x40;
7548 }
7549 data |= b7;
7550 }
7551 status = lmsWrite(addr,data,&e);
7552 break;
7553 }
7554 if (status == 0) {
7555 int tmp = decodeDCOffs(tx,data);
7556 if (tmp != old) {
7557 old = tmp;
7558 if (getDirState(tx).showDcOffsChange == 0)
7559 Debug(m_owner,DebugAll,"%s DC offset %c set to %d (from %d) reg=0x%x [%p]",
7560 brfDir(tx),brfIQ(i),old,value,data,m_owner);
7561 }
7562 return 0;
7563 }
7564 e.printf(1024,"%s DC offset %c set to %d failed - %s",
7565 brfDir(tx),brfIQ(i),value,e.c_str());
7566 return showError(status,e,0,error);
7567 }
7568
internalGetDcOffset(bool tx,bool i,int16_t * value,String * error)7569 unsigned int BrfLibUsbDevice::internalGetDcOffset(bool tx, bool i, int16_t* value,
7570 String* error)
7571 {
7572 uint8_t addr = lmsCorrIQAddr(tx,i);
7573 String e;
7574 uint8_t data = 0;
7575 unsigned int status = 0;
7576 BrfDevTmpAltSet tmpAltSet(this,status,&e,"DC offset get");
7577 if (!status)
7578 status = lmsRead(addr,data,&e);
7579 if (!status) {
7580 int& old = i ? getDirState(tx).dcOffsetI : getDirState(tx).dcOffsetQ;
7581 old = decodeDCOffs(tx,data);
7582 if (value)
7583 *value = old;
7584 XDebug(m_owner,DebugAll,"Got %s DC offset %c %d (0x%x) [%p]",
7585 brfDir(tx),brfIQ(i),old,data,m_owner);
7586 return 0;
7587 }
7588 e.printf(1024,"%s DC offset %c get failed - %s",brfDir(tx),brfIQ(i),e.c_str());
7589 return showError(status,e,0,error);
7590 }
7591
enableTimestamps(bool on,String * error)7592 unsigned int BrfLibUsbDevice::enableTimestamps(bool on, String* error)
7593 {
7594 String e;
7595 unsigned int status = 0;
7596 while (true) {
7597 uint32_t val = 0;
7598 BRF_FUNC_CALL_BREAK(gpioRead(0,val,4,&e));
7599 if (on)
7600 val |= 0x10000;
7601 else
7602 val &= ~0x10000;
7603 BRF_FUNC_CALL_BREAK(gpioWrite(0,val,4,&e));
7604 if (on) {
7605 BRF_FUNC_CALL_BREAK(gpioRead(0,val,4,&e));
7606 if ((val & 0x10000) == 0) {
7607 status = setError(RadioInterface::Failure,&e,"not enabled");
7608 break;
7609 }
7610 resetTimestamps(true);
7611 resetTimestamps(false);
7612 setIoDontWarnTs(true);
7613 setIoDontWarnTs(false);
7614 }
7615 Debug(m_owner,DebugAll,"%s timestamps [%p]",enabledStr(on),m_owner);
7616 return 0;
7617 }
7618 e.printf(1024,"Failed to %s timestamps - %s",enableStr(on),e.c_str());
7619 return showError(status,e,0,error);
7620 }
7621
updateStatus(String * error)7622 unsigned int BrfLibUsbDevice::updateStatus(String* error)
7623 {
7624 unsigned int status = 0;
7625 // Frequency (only if already set)
7626 if (m_state.m_tx.frequency)
7627 BRF_FUNC_CALL(internalGetFrequency(true));
7628 if (m_state.m_rx.frequency)
7629 BRF_FUNC_CALL(internalGetFrequency(false));
7630 // Update VGA data
7631 BRF_FUNC_CALL(internalGetTxVga(0,true,error));
7632 BRF_FUNC_CALL(internalGetTxVga(0,false,error));
7633 BRF_FUNC_CALL(internalGetRxVga(0,true,error));
7634 BRF_FUNC_CALL(internalGetRxVga(0,false,error));
7635 // LPF
7636 internalGetLpf(true,0,error);
7637 internalGetLpf(false,0,error);
7638 // Update DC offsets
7639 BRF_FUNC_CALL(internalGetDcOffset(true,true,0,error));
7640 BRF_FUNC_CALL(internalGetDcOffset(true,false,0,error))
7641 BRF_FUNC_CALL(internalGetDcOffset(false,true,0,error));
7642 BRF_FUNC_CALL(internalGetDcOffset(false,false,0,error));
7643 // Update FPGA correction
7644 BRF_FUNC_CALL(internalGetFpgaCorr(true,CorrFpgaGain,0,error));
7645 BRF_FUNC_CALL(internalGetFpgaCorr(true,CorrFpgaPhase,0,error));
7646 BRF_FUNC_CALL(internalGetFpgaCorr(false,CorrFpgaGain,0,error));
7647 BRF_FUNC_CALL(internalGetFpgaCorr(false,CorrFpgaPhase,0,error));
7648 return status;
7649 }
7650
paSelect(int pa,String * error)7651 unsigned int BrfLibUsbDevice::paSelect(int pa, String* error)
7652 {
7653 String e;
7654 unsigned int status = 0;
7655 while (true) {
7656 uint8_t data = 0;
7657 BRF_FUNC_CALL_BREAK(lmsRead(0x44,data,&e));
7658 // PA_EN bits 4-3: PA 1/2/none - bit 2: AUXPA (0: powered up, 1: powered down)
7659 bool changed = false;
7660 switch (pa) {
7661 case LmsPaAux:
7662 changed = (data & 0x04) != 0;
7663 status = lmsWrite(0x44,data & ~0x04,&e);
7664 break;
7665 case LmsPa1:
7666 changed = (data & 0x18) != 0x08;
7667 status = lmsWrite(0x44,(data & ~0x18) | 0x08,&e);
7668 break;
7669 case LmsPa2:
7670 changed = (data & 0x18) != 0x10;
7671 status = lmsWrite(0x44,(data & ~0x18) | 0x10,&e);
7672 break;
7673 case LmsPaNone:
7674 changed = (data & 0x18) != 0;
7675 status = lmsWrite(0x44,data & ~0x18,&e);
7676 break;
7677 default:
7678 Debug(m_owner,DebugFail,"Unhandled PA %d [%p]",pa,m_owner);
7679 status = setUnkValue(e);
7680 }
7681 if (status)
7682 break;
7683 int level = changed ? DebugInfo : DebugAll;
7684 if (pa != LmsPaNone)
7685 Debug(m_owner,level,"%s enabled [%p]",lookup(pa,s_pa),m_owner);
7686 else
7687 Debug(m_owner,level,"PAs disabled [%p]",m_owner);
7688 return 0;
7689 }
7690 if (pa != LmsPaNone)
7691 e.printf(1024,"Failed to enable PA %s - %s",lookup(pa,s_pa),e.c_str());
7692 else
7693 e.printf(1024,"Failed to disable PAs - %s",e.c_str());
7694 return showError(status,e,0,error);
7695 }
7696
clampInt(int64_t val,int64_t minVal,int64_t maxVal,const char * what,int level)7697 int64_t BrfLibUsbDevice::clampInt(int64_t val, int64_t minVal, int64_t maxVal, const char* what,
7698 int level)
7699 {
7700 if (val >= minVal && val <= maxVal)
7701 return val;
7702 int64_t c = val < minVal ? minVal : maxVal;
7703 if (what)
7704 Debug(m_owner,level,"Clamping %s " FMT64 " -> " FMT64 " [%p]",what,val,c,m_owner);
7705 return c;
7706 }
7707
clampFloat(float val,float minVal,float maxVal,const char * what,int level)7708 float BrfLibUsbDevice::clampFloat(float val, float minVal, float maxVal, const char* what,
7709 int level)
7710 {
7711 if (val >= minVal && val <= maxVal)
7712 return val;
7713 float c = val < minVal ? minVal : maxVal;
7714 if (what)
7715 Debug(m_owner,level,"Clamping %s %g -> %g [%p]",what,val,c,m_owner);
7716 return c;
7717 }
7718
openDevice(bool claim,String * error)7719 unsigned int BrfLibUsbDevice::openDevice(bool claim, String* error)
7720 {
7721 closeDevice();
7722 m_dev = 0;
7723 unsigned int status = updateDeviceList(error);
7724 if (status)
7725 return status;
7726 bool haveMatch = !m_serial.null();
7727 bool foundMatched = false;
7728 unsigned int failedDesc = 0;
7729 ObjList found;
7730 for (unsigned int i = 0; i < m_listCount; i++) {
7731 libusb_device_descriptor desc;
7732 if (::libusb_get_device_descriptor(m_list[i],&desc)) {
7733 failedDesc++;
7734 continue;
7735 }
7736 // OpenMoko 0x1d50 Product=0x6066
7737 // Nuand 0x2cf0 Product=0x5246
7738 if (!((desc.idVendor == 0x1d50 && desc.idProduct == 0x6066) ||
7739 (desc.idVendor == 0x2cf0 && desc.idProduct == 0x5246)))
7740 continue;
7741 m_dev = m_list[i];
7742 m_devBus = ::libusb_get_bus_number(m_dev);
7743 m_devAddr = ::libusb_get_device_address(m_dev);
7744 m_devSpeed = ::libusb_get_device_speed(m_dev);
7745 DDebug(m_owner,DebugAll,"Opening device bus=%u addr=%u [%p]",bus(),addr(),m_owner);
7746 String tmpError;
7747 unsigned int tmpStatus = lusbCheckSuccess(::libusb_open(m_dev,&m_devHandle),
7748 &tmpError,"Failed to open the libusb device ");
7749 while (!tmpStatus) {
7750 getDevStrDesc(m_devSerial,desc.iSerialNumber,"serial number");
7751 if (haveMatch) {
7752 if (m_serial != m_devSerial)
7753 break;
7754 foundMatched = true;
7755 }
7756 getDevStrDesc(m_devFwVerStr,4,"firmware version");
7757 if (claim)
7758 tmpStatus = lusbCheckSuccess(::libusb_claim_interface(m_devHandle,0),
7759 &tmpError,"Failed to claim the interface ");
7760 if (!tmpStatus) {
7761 m_address.clear();
7762 m_address << "USB/" << bus() << "/" << addr();
7763 Debug(m_owner,DebugAll,"Opened device bus=%u addr=%u [%p]",bus(),addr(),m_owner);
7764 return 0;
7765 }
7766 break;
7767 }
7768 String* tmp = new String(m_devBus);
7769 *tmp << "/" << m_devAddr << "/" << m_devSerial;
7770 found.append(tmp);
7771 closeUsbDev();
7772 m_dev = 0;
7773 if (tmpStatus) {
7774 status = tmpStatus;
7775 if (error)
7776 *error = tmpError;
7777 }
7778 if (foundMatched)
7779 break;
7780 }
7781 String e;
7782 if (haveMatch) {
7783 e << "serial='" << m_serial << "' [";
7784 if (!foundMatched)
7785 e << "not ";
7786 e << "found] ";
7787 }
7788 if (found.count()) {
7789 e << "checked_devices=" << found.count();
7790 String failed;
7791 failed.append(found,",");
7792 e << " (" << failed << ")";
7793 }
7794 else if (!haveMatch)
7795 e << "no device found";
7796 if (failedDesc)
7797 e << " (failed_desc_retrieval=" << failedDesc << " device descriptor(s))";
7798 if (status)
7799 return setError(status,error,e);
7800 if (found.skipNull() && (!haveMatch || foundMatched))
7801 return setError(RadioInterface::NotInitialized,error,e);
7802 return setError(RadioInterface::HardwareNotAvailable,error,e);
7803 }
7804
closeDevice()7805 void BrfLibUsbDevice::closeDevice()
7806 {
7807 if (!m_devHandle)
7808 return;
7809 if (m_notifyOff) {
7810 Engine::enqueue(buildNotify("stop"));
7811 m_notifyOff = false;
7812 }
7813 //Debugger d(DebugNote,"closeDevice "," %s [%p]",m_owner->debugName(),m_owner);
7814 m_closingDevice = true;
7815 stopThreads();
7816 internalPowerOn(false,false,false);
7817 m_closingDevice = false;
7818 closeUsbDev();
7819 m_txIO.dataDumpFile.terminate(owner());
7820 m_txIO.upDumpFile.terminate(owner());
7821 m_rxIO.dataDumpFile.terminate(owner());
7822 m_rxIO.upDumpFile.terminate(owner());
7823 m_initialized = false;
7824 Debug(m_owner,DebugAll,"Device closed [%p]",m_owner);
7825 }
7826
closeUsbDev()7827 void BrfLibUsbDevice::closeUsbDev()
7828 {
7829 if (m_devHandle) {
7830 ::libusb_close(m_devHandle);
7831 m_devHandle = 0;
7832 }
7833 m_devBus = -1;
7834 m_devAddr = -1;
7835 m_devSpeed = LIBUSB_SPEED_HIGH;
7836 m_devSerial.clear();
7837 m_devFwVerStr.clear();
7838 m_devFpgaVerStr.clear();
7839 m_devFpgaFile.clear();
7840 m_devFpgaMD5.clear();
7841 m_lmsVersion.clear();
7842 }
7843
getDevStrDesc(String & data,uint8_t index,const char * what)7844 void BrfLibUsbDevice::getDevStrDesc(String& data, uint8_t index, const char* what)
7845 {
7846 unsigned char buf[256];
7847 int len = ::libusb_get_string_descriptor_ascii(m_devHandle,index,buf,sizeof(buf) - 1);
7848 if (len >= 0) {
7849 buf[len] = 0;
7850 data = (const char*)buf;
7851 return;
7852 }
7853 data.clear();
7854 String tmp;
7855 Debug(m_owner,DebugNote,"Failed to retrieve device %s %s [%p]",
7856 what,appendLusbError(tmp,len).c_str(),m_owner);
7857 }
7858
7859 // Read pages from device using control transfer
ctrlTransferReadPage(uint8_t request,DataBlock & buf,String * error)7860 unsigned int BrfLibUsbDevice::ctrlTransferReadPage(uint8_t request, DataBlock& buf,
7861 String* error)
7862 {
7863 if (!m_ctrlTransferPage)
7864 return setError(RadioInterface::Failure,error,"Invalid CTRL transfer page size");
7865 buf.resize(BRF_FLASH_PAGE_SIZE);
7866 uint8_t* b = buf.data(0);
7867 // Retrieve data from the firmware page buffer
7868 for (unsigned int offs = 0; offs < buf.length(); offs += m_ctrlTransferPage) {
7869 unsigned int status = lusbCtrlTransfer(LUSB_CTRLTRANS_DEV_VENDOR_IN,
7870 request,0,offs,b + offs,m_ctrlTransferPage,error);
7871 if (status)
7872 return status;
7873 }
7874 return 0;
7875 }
7876
7877 // Read calibration cache page from device
readCalCache(String * error)7878 unsigned int BrfLibUsbDevice::readCalCache(String* error)
7879 {
7880 unsigned int status = 0;
7881 BrfDevTmpAltSet tmpAltSet(this,BRF_ALTSET_SPI_FLASH,status,error,
7882 "read calibration cache");
7883 m_calCache.clear();
7884 if (status == 0)
7885 return ctrlTransferReadPage(BRF_USB_CMD_READ_CAL_CACHE,m_calCache,error);
7886 return status;
7887 }
7888
crc16(uint8_t * buf,unsigned int len)7889 static uint16_t crc16(uint8_t* buf, unsigned int len)
7890 {
7891 uint16_t crc = 0;
7892 for (uint8_t* last = buf + len; buf < last; buf++) {
7893 crc ^= (uint16_t)(((uint16_t)*buf) << 8);
7894 for (int i = 0; i < 8; i++) {
7895 if ((crc & 0x8000) != 0)
7896 crc = (uint16_t)(crc << 1) ^ 0x1021;
7897 else
7898 crc = (uint16_t)(crc << 1);
7899 }
7900 }
7901 return crc;
7902 }
7903
7904 // Retrieve a filed from a buffer of elements
7905 // Buffer format: 1 byte length + data + 2 bytes CRC16
getBufField(String & value,const char * field)7906 const char* BrfLibUsbDevice::getBufField(String& value, const char* field)
7907 {
7908 if (TelEngine::null(field))
7909 return "empty-field";
7910 uint8_t* b = m_calCache.data(0);
7911 unsigned int len = m_calCache.length();
7912 if (!len)
7913 return "calibration-cache-not-loaded";
7914 for (uint8_t dataLen = 0; len; len -= dataLen, b += dataLen) {
7915 dataLen = *b;
7916 // No more data ?
7917 if (dataLen == 0xff)
7918 return "unexpected end of data";
7919 // Do we have enough data ?
7920 if (len < (dataLen + 2u))
7921 return "wrong data - invalid field length";
7922 uint16_t crc = le32toh(*(uint16_t*)(b + dataLen + 1));
7923 uint16_t crcCheck = crc16(b,dataLen + 1);
7924 if (crcCheck != crc)
7925 return "wrong data - invalid CRC";
7926 unsigned int fLen = 0;
7927 const char* s = (const char*)(b + 1);
7928 const char* f = field;
7929 for (; fLen <= dataLen && *f && *s == *f; s++, f++)
7930 fLen++;
7931 if (!*f) {
7932 value.assign(s,dataLen - fLen);
7933 return 0;
7934 }
7935 dataLen += 3;
7936 }
7937 return "not found";
7938 }
7939
7940 // Read calibration cache field
getCalField(String & value,const String & name,const char * desc,String * error)7941 unsigned int BrfLibUsbDevice::getCalField(String& value, const String& name,
7942 const char* desc, String* error)
7943 {
7944 // NOTE calibration cache may be obsolete, readCalCache is called at initialization only
7945 String e = getBufField(value,name);
7946 if (!e)
7947 return 0;
7948 e.printf(2048,"Failed to retrieve calibration cache field '%s' (%s) - %s",
7949 name.c_str(),desc,e.c_str());
7950 return showError(RadioInterface::Failure,e,0,error);
7951 }
7952
dumpCalCache(String & dest)7953 String& BrfLibUsbDevice::dumpCalCache(String& dest)
7954 {
7955 String e;
7956 dest.append("(LEN|VALUE|CRC)"," ");
7957 uint8_t* b = m_calCache.data(0);
7958 unsigned int len = m_calCache.length();
7959 for (uint8_t dataLen = 0; len; len -= dataLen, b += dataLen) {
7960 dataLen = *b;
7961 // No more data ?
7962 if (dataLen == 0xff) {
7963 len = 0;
7964 break;
7965 }
7966 dest << " " << dataLen;
7967 // Do we have enough data ?
7968 if (len < (dataLen + 2u)) {
7969 dest << "-|-";
7970 break;
7971 }
7972 String crcS;
7973 crcS.hexify(b + dataLen + 1,2);
7974 uint16_t crc = le32toh(*(uint16_t*)(b + dataLen + 1));
7975 uint16_t crcCheck = crc16(b,dataLen + 1);
7976 if (crcCheck != crc)
7977 crcS << "(invalid)";
7978 dest << "|" << String((const char*)(b + 1),dataLen) << "|" << crcS;
7979 dataLen += 3;
7980 }
7981 if (len)
7982 dest << " garbage=" << len;
7983 return dest;
7984 }
7985
7986 // Update speed related data
updateSpeed(const NamedList & params,String * error)7987 unsigned int BrfLibUsbDevice::updateSpeed(const NamedList& params, String* error)
7988 {
7989 if (speed() == LIBUSB_SPEED_SUPER || speed() == LIBUSB_SPEED_HIGH) {
7990 initBuffers(0,params.getIntValue("buffered_samples",2048),
7991 params.getIntValue("tx_min_buffers"));
7992 if (speed() == LIBUSB_SPEED_SUPER) {
7993 m_radioCaps.rxLatency = clampIntParam(params,"rx_latency_super",4000,0,150000);
7994 m_radioCaps.txLatency = clampIntParam(params,"tx_latency_super",10000,0,150000);
7995 m_radioCaps.maxSampleRate = clampIntParam(params,"max_samplerate_super",
7996 MAX_SAMPLERATE_SUPER,2 * BRF_SAMPLERATE_MIN,BRF_SAMPLERATE_MAX);
7997 m_ctrlTransferPage = BRF_FLASH_PAGE_SIZE;
7998 }
7999 else {
8000 m_radioCaps.rxLatency = clampIntParam(params,"rx_latency_high",7000,0,150000);
8001 m_radioCaps.txLatency = clampIntParam(params,"tx_latency_high",20000,0,150000);
8002 m_radioCaps.maxSampleRate = clampIntParam(params,"max_samplerate_high",
8003 MAX_SAMPLERATE_HIGH,2 * BRF_SAMPLERATE_MIN,BRF_SAMPLERATE_MAX);
8004 m_ctrlTransferPage = 64;
8005 }
8006 return 0;
8007 }
8008 m_minBufsSend = 1;
8009 m_radioCaps.rxLatency = 0;
8010 m_radioCaps.txLatency = 0;
8011 m_radioCaps.maxSampleRate = BRF_SAMPLERATE_MAX;
8012 m_ctrlTransferPage = 0;
8013 String e;
8014 e << "Unsupported USB speed " << m_devSpeed;
8015 return setError(RadioInterface::InsufficientSpeed,error,e);
8016 }
8017
8018 // Set I/O buffers
initBuffers(bool * txSet,unsigned int totalSamples,unsigned int txMinSend)8019 void BrfLibUsbDevice::initBuffers(bool* txSet, unsigned int totalSamples, unsigned int txMinSend)
8020 {
8021 totalSamples = clampInt(totalSamples,1024,16384,"buffered_samples",DebugConf);
8022 unsigned int bufSamples = (speed() == LIBUSB_SPEED_HIGH) ? 252 : 508;
8023 unsigned int nBuffs = totalSamples / bufSamples;
8024 if (!nBuffs)
8025 nBuffs = 1;
8026 for (int tx = 1; tx > -1; tx--) {
8027 if (txSet && *txSet != tx)
8028 continue;
8029 BrfDevIO& io = getIO(tx);
8030 if (io.buffers == nBuffs && io.bufSamples == bufSamples)
8031 continue;
8032 // Lock I/O to make sure we don't use the buffers
8033 BrfSerialize lck(this,tx,false);
8034 String error;
8035 for (unsigned int i = 0; !lck.devLocked() && i < 3; i++)
8036 lck.wait(&error,1000000);
8037 if (!lck.devLocked()) {
8038 Debug(m_owner,DebugCrit,"Failed to initialize %s buffers: serialize [%p]",
8039 brfDir(tx),m_owner);
8040 continue;
8041 }
8042 bool first = !io.buffers;
8043 io.resetSamplesBuffer(bufSamples,16,nBuffs);
8044 String extra;
8045 if (tx) {
8046 if (txMinSend)
8047 m_minBufsSend = clampInt(txMinSend,1,nBuffs,"tx_min_buffers",DebugConf);
8048 else
8049 m_minBufsSend = nBuffs;
8050 extra << " tx_min_buffers=" << m_minBufsSend;
8051 }
8052 Debug(m_owner,first ? DebugAll : DebugInfo,
8053 "Initialized I/O %s buffers=%u samples/buffer=%u total_bytes=%u%s [%p]",
8054 brfDir(tx),io.buffers,io.bufSamples,io.buffer.length(),extra.safe(),m_owner);
8055 lck.drop();
8056 if (tx) {
8057 // Regenerate TX pattern: it may have the same length as used buffers
8058 Lock d(m_dbgMutex);
8059 String pattern = m_state.m_txPattern;
8060 m_state.m_txPattern = "";
8061 float gain = m_state.m_txPatternGain;
8062 d.drop();
8063 setTxPattern(pattern,gain);
8064 }
8065 }
8066 }
8067
8068 // Check timestamps before send / after read
ioBufCheckTs(bool tx,unsigned int nBufs)8069 void BrfLibUsbDevice::ioBufCheckTs(bool tx, unsigned int nBufs)
8070 {
8071 String invalid;
8072 BrfDevIO& io = getIO(tx);
8073 if (!nBufs)
8074 nBufs = io.buffers;
8075 unsigned int i = 0;
8076 if (!io.lastTs) {
8077 io.lastTs = io.bufTs(0);
8078 i = 1;
8079 }
8080 unsigned int dontWarn = checkDbgInt(getIO(tx).dontWarnTs,nBufs);
8081 for (; i < nBufs; i++) {
8082 uint64_t crt = io.bufTs(i);
8083 if (!dontWarn && (io.lastTs + io.bufSamples) != crt) {
8084 if (!invalid)
8085 invalid << ": invalid timestamps (buf=ts/delta)";
8086 invalid << " " << (i + 1) << "=" << crt << "/" << (int64_t)(crt - io.lastTs);
8087 }
8088 if (dontWarn)
8089 dontWarn--;
8090 io.lastTs = crt;
8091 }
8092 if (invalid)
8093 Debug(m_owner,DebugMild,"%s buf_samples=%u: %u buffers%s [%p]",
8094 brfDir(tx),io.bufSamples,nBufs,invalid.safe(),m_owner);
8095 }
8096
setIoDontWarnTs(bool tx)8097 void BrfLibUsbDevice::setIoDontWarnTs(bool tx)
8098 {
8099 BrfDevIO& io = getIO(tx);
8100 Lock lck(m_dbgMutex);
8101 io.dontWarnTs = io.buffers * 40;
8102 XDebug(m_owner,DebugAll,"%s don't warn ts set to %d [%p]",
8103 brfDir(tx),io.dontWarnTs,m_owner);
8104 }
8105
8106 // Check samples limit before send / after read
ioBufCheckLimit(bool tx,unsigned int nBufs)8107 void BrfLibUsbDevice::ioBufCheckLimit(bool tx, unsigned int nBufs)
8108 {
8109 BrfDevIO& io = getIO(tx);
8110 if (!nBufs)
8111 nBufs = io.buffers;
8112 String invalid;
8113 String tmp;
8114 unsigned int check = 10;
8115 for (unsigned int i = 0; i < nBufs; i++) {
8116 int16_t* s = io.samples(i);
8117 int16_t* e = io.samplesEOF(i);
8118 for (unsigned int j = 0; check && s != e; s++, j++)
8119 if (*s < -2048 || *s > 2047) {
8120 invalid << tmp.printf(" %c=%d (%u at %u)",
8121 brfIQ((j % 2) == 0),*s,i + 1,j / 2);
8122 check--;
8123 }
8124 }
8125 if (invalid)
8126 Debug(m_owner,DebugConf,"%s: sample value out of range buffers=%u:%s [%p]",
8127 brfDir(tx),nBufs,invalid.c_str(),m_owner);
8128 }
8129
updateAlterData(const NamedList & params)8130 void BrfLibUsbDevice::updateAlterData(const NamedList& params)
8131 {
8132 Lock lck(m_dbgMutex);
8133 m_rxAlterDataParams = params;
8134 m_rxAlterDataParams.assign("-");
8135 m_rxAlterData = true;
8136 }
8137
rxAlterData(bool first)8138 void BrfLibUsbDevice::rxAlterData(bool first)
8139 {
8140 while (m_rxAlterDataParams.c_str()) {
8141 Lock lck(m_dbgMutex);
8142 if (!m_rxAlterDataParams.c_str())
8143 break;
8144 if (m_rxAlterDataParams.getBoolValue(YSTRING("rx_alter_increment"))) {
8145 if (!m_rxAlterIncrement)
8146 m_rxAlterIncrement = 1;
8147 }
8148 else
8149 m_rxAlterIncrement = 0;
8150 m_rxAlterData = (m_rxAlterIncrement != 0);
8151 const String& tsJumpPattern = m_rxAlterDataParams[YSTRING("rx_alter_ts_jump_pattern")];
8152 if (tsJumpPattern != m_rxAlterTsJumpPatern) {
8153 m_rxAlterTsJumpPatern = tsJumpPattern;
8154 ObjList* list = m_rxAlterTsJumpPatern.split(',');
8155 m_rxAlterTsJump.overAlloc(10 * sizeof(int64_t));
8156 m_rxAlterTsJump.resize(list->count() * sizeof(int64_t));
8157 int64_t* d = (int64_t*)m_rxAlterTsJump.data();
8158 bool ok = false;
8159 unsigned int index = 0;
8160 for (ObjList* o = list->skipNull(); o; o = o->skipNext()) {
8161 const String* s = static_cast<String*>(o->get());
8162 if (!s->startsWith("rep_")) {
8163 d[index] = s->toInt64();
8164 if (d[index])
8165 ok = true;
8166 index++;
8167 continue;
8168 }
8169 int64_t lastVal = index ? d[index - 1] : 0;
8170 unsigned int repeat = s->substr(4).toInteger(0,0,0);
8171 if (repeat < 2) {
8172 d[index++] = lastVal;
8173 continue;
8174 }
8175 DataBlock tmp = m_rxAlterTsJump;
8176 m_rxAlterTsJump.resize(tmp.length() + (sizeof(int64_t) * (repeat - 1)));
8177 d = (int64_t*)m_rxAlterTsJump.data();
8178 ::memcpy(d,tmp.data(),index * sizeof(int64_t));
8179 while (repeat--)
8180 d[index++] = lastVal;
8181 }
8182 TelEngine::destruct(list);
8183 if (!ok)
8184 m_rxAlterTsJump.clear();
8185 m_rxAlterTsJumpPos = 0;
8186 }
8187 m_rxAlterTsJumpSingle = m_rxAlterDataParams.getBoolValue(
8188 YSTRING("rx_alter_ts_jump_single"),true);
8189 if (m_rxAlterTsJump.length())
8190 m_rxAlterData = true;
8191 m_rxAlterDataParams.assign("");
8192 m_rxAlterDataParams.clear();
8193 if (!m_rxAlterData)
8194 return;
8195 }
8196 BrfDevIO& io = m_rxIO;
8197 if (first) {
8198 // Change timestamps
8199 if (m_rxAlterTsJump.length()) {
8200 int64_t* d = (int64_t*)m_rxAlterTsJump.data();
8201 unsigned int len = m_rxAlterTsJump.length() / sizeof(int64_t);
8202 for (unsigned int i = 0; i < io.buffers; i++) {
8203 if (d[m_rxAlterTsJumpPos])
8204 io.setBufTs(i,io.bufTs(i) + d[m_rxAlterTsJumpPos]);
8205 m_rxAlterTsJumpPos++;
8206 if (m_rxAlterTsJumpPos >= len) {
8207 m_rxAlterTsJumpPos = 0;
8208 if (m_rxAlterTsJumpSingle) {
8209 m_rxAlterTsJump.clear();
8210 // Signal update on next call
8211 m_rxAlterData = true;
8212 break;
8213 }
8214 }
8215 }
8216 }
8217 }
8218 else {
8219 // Change radio data
8220 if (m_rxAlterIncrement && !first) {
8221 for (unsigned int i = 0; i < io.buffers; i++) {
8222 int16_t* p = io.samples(i);
8223 int16_t* last = io.samplesEOF(i);
8224 while (p != last) {
8225 *p++ = m_rxAlterIncrement;
8226 *p++ = -m_rxAlterIncrement;
8227 m_rxAlterIncrement++;
8228 if (m_rxAlterIncrement >= 2048)
8229 m_rxAlterIncrement = 1;
8230 }
8231 }
8232 }
8233 }
8234 #if 0
8235 if (!first)
8236 printIOBuffer(false,"alter");
8237 #endif
8238 }
8239
calLPFBandwidth(const BrfCalData & bak,uint8_t subMod,uint8_t dcCnt,uint8_t & dcReg,String & e)8240 unsigned int BrfLibUsbDevice::calLPFBandwidth(const BrfCalData& bak, uint8_t subMod,
8241 uint8_t dcCnt, uint8_t& dcReg, String& e)
8242 {
8243 #ifdef DEBUG_DEVICE_AUTOCAL
8244 Debugger d(DebugAll,"CAL PROC"," submod=%u dcCnt=0x%x [%p]",subMod,dcCnt,m_owner);
8245 #endif
8246 uint8_t data = 0;
8247 unsigned int status = 0;
8248 // Programing and Calibration Guide 4.5
8249 // PLL Reference Clock Frequency == 40MHz?
8250 if (s_freqRefClock != 40000000) {
8251 // Power down TxVGA2 -- (is optional)
8252 BRF_FUNC_CALL_RET(lmsSet(0x44,0x0c,0x0c,&e));
8253 // Enable TxPPL Register 0x14 set bit 4 to 1
8254 BRF_FUNC_CALL_RET(lmsSet(0x14,0x08,&e));
8255
8256 // Produce 320 MHz
8257 // TODO FIXME The values are hard codded for 38.4 MHz as reference clock
8258 BRF_FUNC_CALL_RET(lmsWrite(0x10,0x42,&e));
8259 BRF_FUNC_CALL_RET(lmsWrite(0x11,0xaa,&e));
8260 BRF_FUNC_CALL_RET(lmsWrite(0x12,0xaa,&e));
8261 BRF_FUNC_CALL_RET(lmsWrite(0x13,0xaa,&e));
8262 // TopSPI:CLKSEL_LPFCAL = 0
8263 BRF_FUNC_CALL_RET(lmsReset(0x06,0x08,&e));
8264 // Power up LPF tuning clock generation block TOPSPI:PD_CLKLPFCAL = 0
8265 BRF_FUNC_CALL_RET(lmsReset(0x06,0x04,&e));
8266 }
8267
8268 BRF_FUNC_CALL_RET(lmsRead(0x54,data,&e));
8269 BRF_FUNC_CALL_RET(lmsSet(0x07,(data >> 2) & 0x0f,0x0f,&e));
8270 // TopSPI:En_CAL_LPFCAL=1(enable)
8271 BRF_FUNC_CALL_RET(lmsSet(0x07,0x80,&e));
8272 // TopSPI:RST_CAL_LPFCAL=1 (RST active)
8273 BRF_FUNC_CALL_RET(lmsSet(0x06,0x01,&e));
8274 // Reset signal used at the beginning of calibration cycle.
8275 // Reset signal needs to be longer than 100ns
8276 Thread::msleep(1);
8277 // TopSPI:RST_CAL_LPFCAL=0 (RST inactive)
8278 BRF_FUNC_CALL_RET(lmsReset(0x06,0x01,&e));
8279 // RCCAL = TopSPI::RCCAL_LPFCAL
8280 BRF_FUNC_CALL_RET(lmsRead(0x01,data,&e));
8281 dcReg = data >> 5;
8282 BRF_FUNC_CALL_RET(lmsSet(0x56,dcReg << 4,0x70,&e));
8283 DDebug(m_owner,DebugAll,"%s calibrated submodule %u -> %u [%p]",
8284 bak.modName(),subMod,dcReg,m_owner);
8285 return 0;
8286 }
8287
dumpState(String & s,const NamedList & p,bool lockPub,bool force)8288 void BrfLibUsbDevice::dumpState(String& s, const NamedList& p, bool lockPub, bool force)
8289 {
8290 BrfSerialize txSerialize(this,true,false);
8291 if (lockPub) {
8292 txSerialize.wait(0,5000000);
8293 if (txSerialize.status) {
8294 if (RadioInterface::Failure == txSerialize.status)
8295 s << "Failed to retrieve state: lock failed";
8296 return;
8297 }
8298 }
8299
8300 String lmsModules, lpStatus, lms, lmsStr;
8301 if (p.getBoolValue(YSTRING("dump_dev"),force)) {
8302 BrfDevDirState& tx = getDirState(true);
8303 BrfDevDirState& rx = getDirState(false);
8304 s << " TX / RX";
8305 s << "\r\nFREQ(Hz): " << tx.frequency << " / " << rx.frequency;
8306 s << "\r\nVGA1: " << tx.vga1 << " / " << rx.vga1;
8307 s << "\r\nVGA2: " << tx.vga2 << " / " << rx.vga2;
8308 s << "\r\nSampleRate: " << tx.sampleRate << " / " << rx.sampleRate;
8309 s << "\r\nFilter: " << tx.lpfBw << " / " << rx.lpfBw;
8310 s << "\r\ntxpattern: " << m_state.m_txPattern;
8311 s << "\r\nloopback: " << lookup(m_state.m_loopback,s_loopback);
8312 if (force) {
8313 s << "\r\nSerial: " << serial();
8314 s << "\r\nSpeed: " << speedStr();
8315 s << "\r\nFirmware: " << fwVerStr();
8316 s << "\r\nFPGA: " << fpgaVerStr();
8317 }
8318 }
8319 if (p.getBoolValue(YSTRING("dump_lms_modules"),force)) {
8320 dumpLmsModulesStatus(&lmsModules);
8321 s.append("LMS modules:","\r\n\r\n") << lmsModules;
8322 }
8323 if (p.getBoolValue(YSTRING("dump_loopback_status"),force)) {
8324 dumpLoopbackStatus(&lpStatus);
8325 s.append("Loopback switches:","\r\n\r\n") << lpStatus;
8326 }
8327 if (p.getBoolValue(YSTRING("dump_lms"),force)) {
8328 internalDumpPeripheral(UartDevLMS,0,128,&lms,16);
8329 s.append("LMS:","\r\n\r\n") << lms;
8330 }
8331 String readLms = p[YSTRING("dump_lms_str")];
8332 if (readLms) {
8333 if (readLms == "-")
8334 lmsRead(lmsStr,0,false);
8335 else {
8336 bool interleaved = (readLms[0] == '+');
8337 if (interleaved)
8338 readLms = readLms.substr(1);
8339 lmsRead(lmsStr,&readLms,interleaved);
8340 }
8341 s.append("LMS string:\r\n","\r\n\r\n") << lmsStr;
8342 }
8343 }
8344
8345 // LMS autocalibration
calibrateAuto(String * error)8346 unsigned int BrfLibUsbDevice::calibrateAuto(String* error)
8347 {
8348 BrfSerialize txSerialize(this,true,false);
8349 BrfSerialize rxSerialize(this,false,false);
8350 unsigned int status = 0;
8351 // Pause I/O threads if calibration is running
8352 if (m_calibrateStatus == Calibrating) {
8353 BRF_FUNC_CALL_RET(calThreadsPause(true,error));
8354 }
8355 if (!rxSerialize.devLocked()) {
8356 BRF_FUNC_CALL_RET(rxSerialize.wait(error));
8357 }
8358 if (!txSerialize.devLocked()) {
8359 BRF_FUNC_CALL_RET(txSerialize.wait(error));
8360 }
8361 #ifdef DEBUG_DEVICE_AUTOCAL
8362 Debugger debug(DebugAll,"AUTOCALIBRATION"," '%s' [%p]",m_owner->debugName(),m_owner);
8363 #endif
8364 Debug(m_owner,DebugInfo,"LMS autocalibration starting ... [%p]",m_owner);
8365
8366 BrfDuration duration;
8367 String e;
8368 BrfDevState oldState(m_state,0,DevStatDc,DevStatDc);
8369 // Set TX/RX DC I/Q to 0
8370 BrfDevState set0(DevStatAbortOnFail,DevStatDc,DevStatDc);
8371 status = setState(set0,&e);
8372 int8_t calVal[BRF_CALIBRATE_LAST][BRF_CALIBRATE_MAX_SUBMODULES];
8373 ::memset(calVal,-1,sizeof(calVal));
8374 for (int m = BRF_CALIBRATE_FIRST; !status && m <= BRF_CALIBRATE_LAST; m++) {
8375 BrfCalData bak(m);
8376 #ifdef DEBUG_DEVICE_AUTOCAL
8377 Debugger d(DebugAll,"AUTOCALIBRATION"," module: %s [%p]",bak.modName(),m_owner);
8378 #endif
8379 if ((status = cancelled(&e)) != 0)
8380 break;
8381 Debug(m_owner,DebugAll,"Calibrating %s [%p]",bak.modName(),m_owner);
8382 if ((status = calBackupRestore(bak,true,&e)) != 0)
8383 break;
8384 status = calInitFinal(bak,true,&e);
8385 for (uint8_t subMod = 0; !status && subMod < bak.desc->subModules; subMod++) {
8386 status = dcCalProcPrepare(bak,subMod,e);
8387 if (!status) {
8388 uint8_t dcReg = 0;
8389 if (m == BRF_CALIBRATE_LPF_BANDWIDTH)
8390 status = calLPFBandwidth(bak,subMod,31,dcReg,e);
8391 else
8392 status = dcCalProc(bak,subMod,31,dcReg,e);
8393 if (!status) {
8394 calVal[m][subMod] = dcReg;
8395 status = dcCalProcPost(bak,subMod,dcReg,e);
8396 }
8397 }
8398 if (status)
8399 e.printf(2048,"Failed to calibrate module %s - %s",
8400 bak.modName(),e.c_str());
8401 }
8402 unsigned int tmp = calInitFinal(bak,false,status ? 0 : &e);
8403 if (!status)
8404 status = tmp;
8405 tmp = calBackupRestore(bak,false,status ? 0 : &e);
8406 if (!status)
8407 status = tmp;
8408 if (status)
8409 break;
8410 Debug(m_owner,DebugAll,"Calibrated %s [%p]",bak.modName(),m_owner);
8411 }
8412 setState(oldState);
8413 duration.stop();
8414 if (status) {
8415 e = "LMS autocalibration failed - " + e;
8416 return showError(status,e,0,error);
8417 }
8418 String s;
8419 #ifdef DEBUG
8420 for (int m = BRF_CALIBRATE_FIRST; m <= BRF_CALIBRATE_LAST; m++) {
8421 const BrfCalDesc& d = s_calModuleDesc[m];
8422 String t;
8423 if (d.subModules > 1)
8424 for (uint8_t sm = 0; sm < d.subModules; sm++) {
8425 t.printf("\r\n%s - %s: %d",calModName(m),d.subModName[sm],calVal[m][sm]);
8426 s << t;
8427 }
8428 else
8429 s << t.printf("\r\n%s: %d",calModName(m),calVal[m][0]);
8430 }
8431 #endif
8432 Debug(m_owner,DebugInfo,"LMS autocalibration finished in %s [%p]%s",
8433 duration.secStr(),m_owner,encloseDashes(s));
8434 if (m_calibrateStatus != Calibrating)
8435 return 0;
8436 txSerialize.drop();
8437 rxSerialize.drop();
8438 return calThreadsPause(false,error);
8439 }
8440
calBackupRestore(BrfCalData & bak,bool backup,String * error)8441 unsigned int BrfLibUsbDevice::calBackupRestore(BrfCalData& bak, bool backup,
8442 String* error)
8443 {
8444 const char* what = backup ? "backup" : "restore";
8445 #ifdef DEBUG_DEVICE_AUTOCAL
8446 Debugger d(DebugAll,"CAL BACKUP/RESTORE"," %s [%p]",what,m_owner);
8447 #endif
8448 unsigned int status = 0;
8449 String e;
8450 while (true) {
8451 // We will backup the data in the CLK_EN register in case something goes wrong
8452 status = lms(backup,0x09,bak.clkEn,&e);
8453 if (status)
8454 break;
8455 if (bak.module == BRF_CALIBRATE_RX_LPF || bak.module == BRF_CALIBRATE_RX_VGA2) {
8456 // BRF_FUNC_CALL_BREAK(lms(backup,0x71,bak.inputMixer,&e));
8457 // BRF_FUNC_CALL_BREAK(lms(backup,0x7c,bak.loOpt,&e));
8458 BRF_FUNC_CALL_BREAK(lnaGain(backup,bak.lnaGain,&e));
8459 BRF_FUNC_CALL_BREAK(internalRxVga(backup,bak.rxVga1,true,&e));
8460 if (bak.module == BRF_CALIBRATE_RX_VGA2) {
8461 BRF_FUNC_CALL_BREAK(lms(backup,0x68,bak.rxVga2GainAB,&e));
8462 }
8463 status = internalRxVga(backup,bak.rxVga2,false,&e);
8464 break;
8465 }
8466 if (bak.module == BRF_CALIBRATE_TX_LPF ||
8467 bak.module == BRF_CALIBRATE_LPF_TUNING) {
8468 DDebug(m_owner,DebugAll,"calBackupRestore: nothing to do for %s [%p]",
8469 bak.modName(),this);
8470 break;
8471 }
8472 if (bak.module == BRF_CALIBRATE_LPF_BANDWIDTH) {
8473 BRF_FUNC_CALL_BREAK(lms(backup,0x06,bak.clkLPFCAL,&e));
8474 BRF_FUNC_CALL_BREAK(lms(backup,0x07,bak.enLPFCAL,&e));
8475 BRF_FUNC_CALL_BREAK(lms(backup,0x14,bak.txPPL,&e));
8476 BRF_FUNC_CALL_BREAK(lms(backup,0x44,bak.txVGA2PwAmp,&e));
8477
8478 BRF_FUNC_CALL_BREAK(lms(backup,0x10,bak.nInt,&e));
8479 BRF_FUNC_CALL_BREAK(lms(backup,0x11,bak.nFrac1,&e));
8480 BRF_FUNC_CALL_BREAK(lms(backup,0x12,bak.nFrac2,&e));
8481 BRF_FUNC_CALL_BREAK(lms(backup,0x13,bak.nFrac3,&e));
8482 break;
8483 }
8484 status = setUnhandled(e,bak.module,"module");
8485 break;
8486 }
8487 if (status == 0)
8488 return 0;
8489 e.printf(2048,"Failed to %s calibration data for module %s - %s",
8490 what,bak.modName(),e.c_str());
8491 return showError(status,e,0,error);
8492 }
8493
calInitFinal(BrfCalData & bak,bool init,String * error)8494 unsigned int BrfLibUsbDevice::calInitFinal(BrfCalData& bak, bool init, String* error)
8495 {
8496 const char* what = init ? "initialize" : "finalize";
8497 #ifdef DEBUG_DEVICE_AUTOCAL
8498 String lmsDump;
8499 #if 0
8500 if (init) {
8501 internalDumpPeripheral(UartDevLMS,0,128,&lmsDump,16);
8502 encloseDashes(lmsDump);
8503 }
8504 #endif
8505 Debugger d(DebugAll,"CAL INIT/FINAL"," %s [%p]%s",what,m_owner,lmsDump.safe());
8506 #endif
8507 String e;
8508 unsigned int status = 0;
8509 while (true) {
8510 // Enable the appropriate CLK_EN bit
8511 if (init)
8512 status = lmsWrite(0x09,bak.clkEn | bak.desc->clkEnMask,&e);
8513 if (status)
8514 break;
8515 if (bak.module == BRF_CALIBRATE_LPF_TUNING ||
8516 bak.module == BRF_CALIBRATE_LPF_BANDWIDTH) {
8517 DDebug(m_owner,DebugAll,"calInitFinal(%s): nothing to do for %s [%p]",
8518 what,bak.modName(),this);
8519 break;
8520 }
8521 // Enable special conditions
8522 if (bak.module == BRF_CALIBRATE_RX_LPF || bak.module == BRF_CALIBRATE_RX_VGA2) {
8523 if (bak.module == BRF_CALIBRATE_RX_VGA2) {
8524 // Set RXVGA2 DECODE on init/finalize
8525 if (!init)
8526 BRF_FUNC_CALL_BREAK(setRxVga2Decode(true,&e));
8527 // TODO: Check it BRF_FUNC_CALL_BREAK(lmsChangeMask(0x63,0xc0,!init,&e));
8528 }
8529 else {
8530 // FAQ 5.26 (rev 1.0r13) DC comparators should be
8531 // powered up before calibration and then powered down after it
8532 BRF_FUNC_CALL_BREAK(lmsChangeMask(0x5f,0x80,!init,&e));
8533 if (init) {
8534 BRF_FUNC_CALL_BREAK(lmsSet(0x56,0x04,&e));
8535 }
8536 else {
8537 BRF_FUNC_CALL_BREAK(lmsReset(0x56,0x04,&e));
8538 }
8539 }
8540 // Done for finalize
8541 if (!init)
8542 break;
8543 #if 0
8544 // TODO: Check it !!! It is really necessary ?
8545 // Connect LNA to the external pads and internally terminate
8546 status = lmsWrite2(0x71,bak.inputMixer & 0x7f,0x7c,bak.loOpt | 0x04,&e);
8547 if (status)
8548 break;
8549 #endif
8550 // FAQ 4.2 (rev 1.0r13): Attempt to calibrate RX at max gain
8551 BRF_FUNC_CALL_BREAK(lnaGainSet(LnaGainMax,&e));
8552 BRF_FUNC_CALL_BREAK(internalSetRxVga(BRF_RXVGA1_GAIN_MAX,true,&e));
8553 BRF_FUNC_CALL_BREAK(internalSetRxVga(BRF_RXVGA2_GAIN_MAX,false,&e));
8554 if (bak.module == BRF_CALIBRATE_RX_VGA2)
8555 status = setRxVga2Decode(true,&e);
8556 break;
8557 }
8558 if (bak.module == BRF_CALIBRATE_TX_LPF) {
8559 // TX_DACBUF_PD (TX data DAC buffers)
8560 // LMS6002 Quick starter manual, Section 6.1
8561 // No signal should be applied to DACs (power down: bit is 1)
8562 // PD_DCOCMP_LPF (DC offset comparator of DC offset cancellation)
8563 // It must be powered down (bit set to 1) when calibrating
8564 if (init) {
8565 //BRF_FUNC_CALL_BREAK(lmsSet(0x36,0x80,&e));
8566 BRF_FUNC_CALL_BREAK(lmsSet(0x36,0x04,&e));
8567 BRF_FUNC_CALL_BREAK(lmsReset(0x3f,0x80,&e));
8568 }
8569 else {
8570 //BRF_FUNC_CALL_BREAK(lmsReset(0x36,0x80,&e));
8571 BRF_FUNC_CALL_BREAK(lmsReset(0x36,0x04,&e));
8572 BRF_FUNC_CALL_BREAK(lmsSet(0x3f,0x80,&e));
8573 }
8574 break;
8575 }
8576 status = setUnhandled(e,bak.module,"module");
8577 break;
8578 }
8579 if (status == 0)
8580 return 0;
8581 e.printf(2048,"Failed to %s calibration for module %s - %s",
8582 what,bak.modName(),e.c_str());
8583 return showError(status,e,0,error);
8584 }
8585
dcCalProcPrepare(const BrfCalData & bak,uint8_t subMod,String & e)8586 unsigned int BrfLibUsbDevice::dcCalProcPrepare(const BrfCalData& bak, uint8_t subMod,
8587 String& e)
8588 {
8589 #ifdef DEBUG_DEVICE_AUTOCAL
8590 Debugger d(DebugAll,"CAL PREPARE"," submod=%u [%p]",subMod,m_owner);
8591 #endif
8592 if (bak.module != BRF_CALIBRATE_RX_VGA2)
8593 return 0;
8594 // Prepare RX VGA2 calibration
8595 if (subMod > 4)
8596 return setUnhandled(e,subMod,"submodule");
8597 // RXVGA2 DC REF module (subMod 0)
8598 // Set RXVGA2GAIN A and B to default values
8599 if (subMod == 0)
8600 return lmsWrite(0x68,0x01,&e);
8601 // VGA2 A/B I/Q channels
8602 // Set DECODE bit to direct signal on start
8603 if (subMod == 1) {
8604 unsigned int status = setRxVga2Decode(false,&e);
8605 if (status)
8606 return status;
8607 }
8608 // subMod 1: set RXVGA2GAIN A=18dB and B=0
8609 // subMod 3: set RXVGA2GAIN A=0 and B=18dB
8610 if (subMod == 1 || subMod == 3)
8611 return lmsWrite(0x68,(subMod == 1) ? 0x06 : 0x60,&e);
8612 return 0;
8613 }
8614
dcCalProc(const BrfCalData & bak,uint8_t subMod,uint8_t dcCnt,uint8_t & dcReg,String & e)8615 unsigned int BrfLibUsbDevice::dcCalProc(const BrfCalData& bak, uint8_t subMod,
8616 uint8_t dcCnt, uint8_t& dcReg, String& e)
8617 {
8618 #ifdef DEBUG_DEVICE_AUTOCAL
8619 Debugger d(DebugAll,"CAL PROC"," submod=%u dcCnt=0x%x [%p]",subMod,dcCnt,m_owner);
8620 #endif
8621 // Set active calibration module address
8622 uint8_t data = 0;
8623 unsigned int status = 0;
8624 BRF_FUNC_CALL_RET(lmsRead(bak.desc->addr + 3,data,&e));
8625 data &= ~(0x07);
8626 data |= subMod & 0x07;
8627 BRF_FUNC_CALL_RET(lmsWrite(bak.desc->addr + 3,data,&e));
8628 // Set CNTVAL
8629 BRF_FUNC_CALL_RET(lmsWrite(bak.desc->addr + 2,dcCnt & 0x1f,&e));
8630 // DC_LOAD: Auto load DC_CNTVAL (1: load, 0: don't load)
8631 data |= 0x10;
8632 BRF_FUNC_CALL_RET(lmsWrite(bak.desc->addr + 3,data,&e));
8633 // Disable auto load of DC_CNTVAL, just in case something goes wrong
8634 data &= ~0x10;
8635 BRF_FUNC_CALL_RET(lmsWrite(bak.desc->addr + 3,data,&e));
8636 uint8_t clbrStart = data | 0x20;
8637 uint8_t clbrStop = data & ~0x20;
8638 // See Section 4.1: General DC calibration procedure
8639 bool first = true;
8640 while (true) {
8641 // Calibrate
8642 // Enable and disable DC_START_CLBR
8643 BRF_FUNC_CALL_RET(lmsWrite2(bak.desc->addr + 3,clbrStart,bak.desc->addr + 3,clbrStop,&e));
8644 // We should wait for 6.4 us for calibration to end
8645 Thread::msleep(1);
8646 dcReg = 0xff;
8647 for (unsigned int i = 0; i < 30; i++) {
8648 String tmp;
8649 BRF_FUNC_CALL_RET(cancelled(&e));
8650 // Poll for DC_CLBR_DONE
8651 status = lmsRead(bak.desc->addr + 1,data,&tmp);
8652 if (status) {
8653 Debug(m_owner,DebugMild,"%s [%p]",e.c_str(),m_owner);
8654 status = 0;
8655 continue;
8656 }
8657 if ((data & 0x02) != 0)
8658 continue;
8659 // Read DC_REG
8660 BRF_FUNC_CALL_RET(lmsRead(bak.desc->addr,data,&e));
8661 dcReg = (data & 0x3f);
8662 break;
8663 }
8664 if (dcReg == 0xff)
8665 return setError(RadioInterface::Failure,&e,"Calibration loop timeout");
8666 if (first) {
8667 if (dcReg != 31)
8668 break;
8669 first = false;
8670 continue;
8671 }
8672 if (dcReg == 0) {
8673 e << "Algorithm does not converge for submodule " << subMod;
8674 return RadioInterface::Failure;
8675 }
8676 break;
8677 }
8678 DDebug(m_owner,DebugAll,"%s calibrated submodule %u -> %u [%p]",
8679 bak.modName(),subMod,dcReg,m_owner);
8680 return 0;
8681 }
8682
dcCalProcPost(const BrfCalData & bak,uint8_t subMod,uint8_t dcReg,String & e)8683 unsigned int BrfLibUsbDevice::dcCalProcPost(const BrfCalData& bak, uint8_t subMod,
8684 uint8_t dcReg, String& e)
8685 {
8686 #ifdef DEBUG_DEVICE_AUTOCAL
8687 Debugger d(DebugAll,"CAL PROC POST"," submod=%u dcReg=0x%x [%p]",subMod,dcReg,m_owner);
8688 #endif
8689 unsigned int status = 0;
8690 if (bak.module == BRF_CALIBRATE_LPF_TUNING) {
8691 // Set DC_REG in TX/RX LPF DCO_DACCAL
8692 uint8_t addr[] = {0x55,0x35};
8693 for (uint8_t i = 0; !status && i < sizeof(addr); i++)
8694 status = lmsSet(addr[i],dcReg,0x3f,&e);
8695 if (status)
8696 e.printf("Failed to set DCO_DACCAL - %s",e.c_str());
8697 }
8698 return status;
8699 }
8700
calibrateBbCorrection(BrfBbCalData & data,int corr,int range,int step,int pass,String * error)8701 unsigned int BrfLibUsbDevice::calibrateBbCorrection(BrfBbCalData& data,
8702 int corr, int range, int step, int pass, String* error)
8703 {
8704 static const int corrPeer[CorrCount] = {CorrLmsQ, CorrLmsI,
8705 CorrFpgaGain, CorrFpgaPhase};
8706 static const unsigned int syncFlags[CorrCount] = {DevStatDcI, DevStatDcQ,
8707 DevStatFpgaPhase, DevStatFpgaGain};
8708
8709 int* corrVal[CorrCount] = {&data.m_dcI, &data.m_dcQ, &data.m_phase, &data.m_gain};
8710 BrfDevDirState& t = m_syncTxState.m_tx;
8711 int* syncSet[CorrCount] = {&t.dcOffsetI, &t.dcOffsetQ, &t.fpgaCorrPhase, &t.fpgaCorrGain};
8712
8713 bool dc = (CorrLmsI == corr || CorrLmsQ == corr);
8714 if (!dc && CorrFpgaPhase != corr && CorrFpgaGain != corr)
8715 return setErrorFail(error,"calibrateBbCorrection: unhandled corr");
8716 BrfDuration duration;
8717 // Set peer (fixed) correction
8718 *syncSet[corrPeer[corr]] = *corrVal[corrPeer[corr]];
8719 unsigned int status = setStateSyncTx(syncFlags[corrPeer[corr]],error);
8720 // Set calibration range
8721 int minV = dc ? BRF_TX_DC_OFFSET_MIN : -BRF_FPGA_CORR_MAX;
8722 int maxV = dc ? BRF_TX_DC_OFFSET_MAX : BRF_FPGA_CORR_MAX;
8723 int calVal = *corrVal[corr] - range;
8724 int calValMax = *corrVal[corr] + range;
8725 if (calVal < minV)
8726 calVal = minV;
8727 if (calValMax > maxV)
8728 calValMax = maxV;
8729
8730 Debug(m_owner,DebugNote,"Calibrating %s pass=%d [%p]",
8731 lookup(corr,s_corr),pass,this);
8732 unsigned int trace = data.uintParam(dc,"trace");
8733 if (trace)
8734 Output("Pass #%u calibrating %s (crt: %d) %s=%d "
8735 "samples=%u range=%d step=%d interval=[%d..%d]",
8736 pass,lookup(corr,s_corr),*corrVal[corr],
8737 lookup(corrPeer[corr],s_corr),*corrVal[corrPeer[corr]],
8738 data.samples(),range,step,calVal,calValMax);
8739 bool traceRepeat = trace && data.boolParam(dc,"trace_repeat",true);
8740 bool traceFailed = trace && data.boolParam(dc,"trace_failed",true);
8741 bool accum = false;
8742 if (data.m_dump.valid()) {
8743 data.dumpCorrStart(pass,corr,*corrVal[corr],corrPeer[corr],
8744 *corrVal[corrPeer[corr]],range,step,calVal,calValMax);
8745 accum = (0 != data.m_calAccum.data.length());
8746 data.m_dump.resetDumpOkFail();
8747 }
8748
8749 float totalStop = data.m_params.getDoubleValue("stop_total_threshold",BRF_MAX_FLOAT);
8750 float limit = getSampleLimit(data.m_params,1);
8751 const char* waitReason = 0;
8752
8753 // Allow TX/RX threads to properly start and synchronize
8754 Thread::msleep(100);
8755 data.prepareCalculate();
8756 int dumpTx = data.intParam(dc,"trace_dump_tx");
8757 BrfBbCalDataResult* res = new BrfBbCalDataResult[data.m_repeatRxLoop];
8758 unsigned int i = 0;
8759 // Disable DC/FPGA change debug message
8760 unsigned int& showCorrChange = dc ? m_state.m_tx.showDcOffsChange :
8761 m_state.m_tx.showFpgaCorrChange;
8762 showCorrChange++;
8763 if (!dc)
8764 m_state.m_tx.showPowerBalanceChange++;
8765 uint64_t ts = 0;
8766 uint64_t tsOffs = m_radioCaps.rxLatency;
8767 if (!dc)
8768 tsOffs += m_radioCaps.txLatency;
8769 for (; !status && calVal <= calValMax; calVal += step) {
8770 i = 0;
8771 *syncSet[corr] = calVal;
8772 BRF_FUNC_CALL_BREAK(setStateSyncTx(syncFlags[corr],error));
8773 ts = m_syncTxState.m_tx.m_timestamp + tsOffs;
8774 bool ok = false;
8775 for (; i < data.m_repeatRxLoop; ++i) {
8776 res[i].status = 0;
8777 if (traceRepeat && i) {
8778 String s;
8779 Output(" REPEAT[%u/%u] [%10s] %s=%-5d %s",i + 1,data.m_repeatRxLoop,
8780 String(ts).c_str(),lookup(corr,s_corr),
8781 calVal,data.dump(s,res[i-1]).c_str());
8782 }
8783 if (dumpTx) {
8784 if (dumpTx > 0)
8785 showBuf(true,dumpTx,false);
8786 else
8787 showBuf(true,-dumpTx,true);
8788 }
8789 ts += data.samples();
8790 BRF_FUNC_CALL_BREAK(capture(false,data.buf(),data.samples(),ts,error));
8791 if (m_calibrateStop)
8792 break;
8793 if (trace > 4)
8794 showBuf(false,trace - 4,false);
8795 ok = data.calculate(res[i]);
8796 status = checkSampleLimit(data.buf(),data.samples(),limit,error);
8797 if (status) {
8798 data.m_dump.appendFormatted(data.buffer(),false);
8799 if (trace) {
8800 String s;
8801 data.dump(s,true);
8802 Output(" %s=%-5d [%10s] %s\tSAMPLE OUT OF RANGE",
8803 lookup(corr,s_corr),calVal,String(ts).c_str(),s.c_str());
8804 }
8805 res[i].status = status;
8806 if (i == (data.m_repeatRxLoop - 1))
8807 break;
8808 status = 0;
8809 if (error)
8810 error->clear();
8811 continue;
8812 }
8813 if (data.m_dump.valid() &&
8814 ((ok && data.m_dump.dumpOk()) || (!ok && data.m_dump.dumpFail())))
8815 data.m_dump.appendFormatted(data.buffer(),ok);
8816 res[i].status = ok ? 0 : RadioInterface::Failure;
8817 if (ok)
8818 break;
8819 }
8820 if (status || m_calibrateStop)
8821 break;
8822 if (i >= data.m_repeatRxLoop)
8823 i = data.m_repeatRxLoop - 1;
8824 data.setResult(res[i]);
8825 bool better = (data.m_best > data.m_cal.value);
8826 if (accum) {
8827 data.m_calAccum.append(data.m_cal);
8828 data.m_testAccum.append(data.m_test);
8829 data.m_totalAccum.append(data.m_total);
8830 }
8831 if (trace) {
8832 String s;
8833 if (trace > 1 && ok && (better || trace > 2))
8834 data.dump(s,trace > 2);
8835 else if (!ok && traceFailed)
8836 data.dump(s,true);
8837 if (s)
8838 Output(" %s=%-5d [%10s] %s%s",lookup(corr,s_corr),calVal,
8839 String(ts).c_str(),s.c_str(),better ? "\tBEST" : "");
8840 }
8841 if (!ok && data.m_stopOnRecvFail) {
8842 if (data.m_stopOnRecvFail < 0)
8843 waitReason = "Recv data check failure";
8844 res[i].status = status = setErrorFail(error,"Recv data check failure");
8845 break;
8846 }
8847 if (totalStop < data.m_total) {
8848 waitReason = "Total error threshold reached";
8849 res[i].status = status = setErrorFail(error,waitReason);
8850 break;
8851 }
8852 // Update best values
8853 if (better) {
8854 data.m_best = data.m_cal;
8855 *corrVal[corr] = calVal;
8856 }
8857 }
8858 // Print last failures if we stopped due to data check failure
8859 if (status && !m_calibrateStop && status != RadioInterface::Cancelled &&
8860 (i == data.m_repeatRxLoop || res[i].status)) {
8861 String s;
8862 if (i < data.m_repeatRxLoop)
8863 i++;
8864 for (unsigned int j = 0; j < i; j++) {
8865 BrfBbCalDataResult& r = res[j];
8866 String tmp;
8867 s << tmp.printf(512,"\r\ntest_tone=%f total=%f test/total=%.2f cal_tone=%f cal/test=%.2f",
8868 r.test,r.total,r.test_total,r.cal,r.cal_test);
8869 if (r.status == RadioInterface::Saturation)
8870 s << " (Sample out of range)";
8871 else if (r.status) {
8872 if (error)
8873 s << " (" << *error << ")";
8874 else
8875 s << " (" << r.status << " " << RadioInterface::errorName(r.status) << ")";
8876 }
8877 }
8878 Debug(owner(),DebugWarn,"BB Calibration (%s) stopping on data check failure."
8879 " Signal values (test/total interval=(0.5-1]): [%p]\r\n-----%s\r\n-----",
8880 lookup(corr,s_corr),this,s.c_str());
8881 }
8882 delete[] res;
8883 showCorrChange--;
8884 if (!dc)
8885 m_state.m_tx.showPowerBalanceChange--;
8886 duration.stop();
8887 if (trace)
8888 Output(" %d/%d [%s]: min/max - cal=%f/%f test=%f/%f total=%f/%f test/total=%.2f/%.2f",
8889 (dc ? data.m_dcI : data.m_phase),(dc ? data.m_dcQ : data.m_gain),
8890 duration.secStr(),
8891 data.m_cal.min,data.m_cal.max,data.m_test.min,data.m_test.max,
8892 data.m_total.min,data.m_total.max,data.m_test_total.min,data.m_test_total.max);
8893 if (data.m_dump.valid())
8894 data.dumpCorrEnd(dc);
8895 if (waitReason)
8896 return waitCancel("Calibration stopped",waitReason,error);
8897 return status;
8898 }
8899
prepareCalibrateBb(BrfBbCalData & data,bool dc,String * error)8900 unsigned int BrfLibUsbDevice::prepareCalibrateBb(BrfBbCalData& data, bool dc,
8901 String* error)
8902 {
8903 Debug(m_owner,DebugAll,"prepareCalibrateBb dc=%d [%p]",dc,this);
8904 // Reset cal structure
8905 unsigned int status = 0;
8906 while (true) {
8907 BRF_FUNC_CALL_BREAK(isInitialized(true,true,error));
8908 unsigned int flags = DevStatFreq | DevStatLpfBw | DevStatSampleRate | DevStatVga;
8909 BrfDevState s(DevStatAbortOnFail | DevStatLoopback,flags,flags);
8910 s.m_tx.frequency = data.m_tx.frequency;
8911 s.m_tx.lpfBw = data.m_tx.lpfBw;
8912 s.m_tx.sampleRate = data.m_tx.sampleRate;
8913 data.m_calFreq = data.m_tx.frequency;
8914 data.m_calSampleRate = data.m_tx.sampleRate;
8915 unsigned int rxFreq = 0;
8916 unsigned int Fs = data.m_calSampleRate;
8917 unsigned int bw = data.m_rx.sampleRate;
8918 // Prepare device
8919 if (dc) {
8920 // TX/RX frequency difference MUST be greater than 1MHz to avoid interferences
8921 // rxFreq = FreqTx - (Fs / 4)
8922 // Choose Fs (RX sample rate):
8923 // Fs > TxSampleRate
8924 // Fs / 4 > 1MHz => Fs > 4MHz
8925 if (Fs < 4000000) {
8926 Fs = 4001000;
8927 bw = 3840000;
8928 }
8929 else {
8930 unsigned int delta = data.uintParam(dc,"samplerate_delta",10000);
8931 if (delta) {
8932 Fs += delta;
8933 // Round up to a multiple of 4 to avoid division errors
8934 if ((Fs % 4) != 0)
8935 Fs = Fs + 4 - (Fs % 4);
8936 }
8937 // Choose next upper filter bandwidth after TX
8938 uint8_t bwIndex = bw2index(data.m_tx.lpfBw + 1);
8939 bw = index2bw(bwIndex);
8940 if (bw <= data.m_tx.lpfBw) {
8941 // !!! OOPS !!!
8942 return setErrorFail(error,"Unable to choose RX filter bandwidth");
8943 }
8944 }
8945 // cal, test
8946 // For DC, test and cal differ by pi/2
8947 // FIXME - This works only for RX and TX same sample rate.
8948 rxFreq = data.m_tx.frequency - (Fs / 4);
8949 data.resetOmega(-M_PI_2,-M_PI);
8950 }
8951 else {
8952 // parameters for Gain/Phase calibration
8953 // cal, test
8954 // For phase/gain, test and cal differ by pi
8955 // FIXME - This works only for RX and TX same sample rate.
8956 rxFreq = data.m_tx.frequency + (Fs / 4);
8957 data.resetOmega(M_PI,0);
8958 }
8959 s.m_tx.lpfBw = bw;
8960 s.m_tx.sampleRate = Fs;
8961 s.m_rx.lpfBw = bw;
8962 s.m_rx.sampleRate = Fs;
8963 s.m_rx.frequency = rxFreq;
8964 s.m_tx.vga1 = data.intParam(dc,YSTRING("txvga1"),
8965 BRF_TXVGA1_GAIN_DEF,BRF_TXVGA1_GAIN_MIN,BRF_TXVGA1_GAIN_MAX);
8966 s.m_tx.vga2 = data.intParam(dc,YSTRING("txvga2"),
8967 20,BRF_TXVGA2_GAIN_MIN,BRF_TXVGA2_GAIN_MAX);
8968 s.m_rx.vga1 = data.intParam(dc,YSTRING("rxvga1"),
8969 BRF_RXVGA1_GAIN_DEF,BRF_RXVGA1_GAIN_MIN,BRF_RXVGA1_GAIN_MAX);
8970 s.m_rx.vga2 = data.intParam(dc,YSTRING("rxvga2"),
8971 BRF_RXVGA2_GAIN_DEF,BRF_RXVGA2_GAIN_MIN,BRF_RXVGA2_GAIN_MAX);
8972 if (dc) {
8973 m_syncTxState.m_tx.fpgaCorrPhase = data.m_phase;
8974 m_syncTxState.m_tx.fpgaCorrGain = data.m_gain;
8975 s.m_tx.fpgaCorrPhase = data.m_phase;
8976 s.m_tx.fpgaCorrGain = data.m_gain;
8977 s.m_txChanged |= DevStatFpga;
8978 }
8979 else {
8980 m_syncTxState.m_tx.dcOffsetI = data.m_dcI;
8981 m_syncTxState.m_tx.dcOffsetQ = data.m_dcQ;
8982 s.m_tx.dcOffsetI = data.m_dcI;
8983 s.m_tx.dcOffsetQ = data.m_dcQ;
8984 s.m_txChanged |= DevStatDc;
8985 }
8986 NamedList lpParams("");
8987 lpParams.copySubParams(data.m_params,YSTRING("loopback_"));
8988 int defLp = brfIsLowBand(s.m_tx.frequency) ? LoopRfLna1 : LoopRfLna2;
8989 int lp = data.m_params.getIntValue(YSTRING("loopback"),s_loopback,defLp);
8990 s.setLoopback(lp,lpParams);
8991 // Stop I/O threads (use internal functions to set params)
8992 BRF_FUNC_CALL_BREAK(calThreadsPause(true,error));
8993 BRF_FUNC_CALL_BREAK(setState(s,error));
8994 // RX buffers may change: adjust it in cal data!
8995 unsigned int samples = getRxSamples(data.m_params);
8996 if (samples != data.samples())
8997 data.resetBuffer(samples);
8998 // Toggle timestamps (reset FPGA timestamps)
8999 enableRfFpgaBoth(false);
9000 enableTimestamps(false);
9001 Thread::msleep(50);
9002 BRF_FUNC_CALL_BREAK(enableTimestamps(true,error));
9003 BRF_FUNC_CALL_BREAK(enableRfFpgaBoth(true,error));
9004 BRF_FUNC_CALL_BREAK(calThreadsPause(false,error));
9005 return 0;
9006 }
9007 return status;
9008 }
9009
calibrateBb(BrfBbCalData & data,bool dc,String * error)9010 unsigned int BrfLibUsbDevice::calibrateBb(BrfBbCalData& data, bool dc, String* error)
9011 {
9012 const char* oper = dc ? "TX I/Q DC Offset (LO Leakage)" :
9013 "TX I/Q Imbalance";
9014 Debug(m_owner,DebugAll,"calibrateBb %s [%p]",oper,this);
9015
9016 // VGA tests
9017 String e;
9018 unsigned int status = testVgaCheck(data.m_params,oper,data.omega(false),&e,
9019 data.prefix(dc));
9020 if (status) {
9021 e.printf(2048,"%s failed - %s",oper,e.c_str());
9022 return showError(status,e,0,error);
9023 }
9024
9025 // FIXME: testing
9026 if (data.boolParam(dc,"disable"))
9027 return 0;
9028
9029 // Prepare file dump
9030 m_dbgMutex.lock();
9031 String fName = dc ? m_bbCalDcFile : m_bbCalImbalanceFile;
9032 m_dbgMutex.unlock();
9033 data.initCal(*this,dc,fName);
9034
9035 int level = DebugNote;
9036 bool dbg = m_owner && m_owner->debugAt(level);
9037 if (dbg || data.uintParam(dc,"trace")) {
9038 String s;
9039 if (data.boolParam(dc,"dump_status_start"))
9040 dumpState(s,data.m_params,true);
9041 if (dbg)
9042 Debug(m_owner,level,"%s calibration starting [%p]%s",oper,m_owner,encloseDashes(s,true));
9043 else
9044 Output("%s calibration starting omega_cal=%f omega_test=%f [%p]%s",
9045 oper,data.omega(true),data.omega(false),m_owner,encloseDashes(s,true));
9046 }
9047
9048 BrfDuration duration;
9049 int range = dc ? (BRF_TX_DC_OFFSET_MAX + 1) : BRF_FPGA_CORR_MAX;
9050 unsigned int loops = data.uintParam(dc,"loops",2,1,10);
9051 int step = dc ? 1 : 16*(1 << loops);
9052 unsigned int origSamples = 0;
9053 if (data.boolParam(dc,"increase_buffer",true))
9054 origSamples = data.samples();
9055 int corr1 = dc ? CorrLmsI : CorrFpgaPhase;
9056 int corr2 = dc ? CorrLmsQ : CorrFpgaGain;
9057
9058 for (unsigned int pass = 1; !status && (range > 1) && pass <= loops; pass++) {
9059 BRF_FUNC_CALL_BREAK(calibrateBbCorrection(data,corr1,range,step,pass,&e));
9060 if (m_calibrateStop)
9061 break;
9062 BRF_FUNC_CALL_BREAK(calibrateBbCorrection(data,corr2,range,step,pass,&e));
9063 if (m_calibrateStop)
9064 break;
9065 range >>= 1;
9066 step >>= 1;
9067 if (!step || pass == (loops - 1))
9068 step = 1;
9069 if (origSamples)
9070 data.resetBuffer(data.samples() * 2);
9071 }
9072
9073 if (origSamples)
9074 data.resetBuffer(origSamples);
9075 duration.stop();
9076 String result;
9077 if (!status) {
9078 if (dc)
9079 result << "I=" << data.m_dcI << " " << "Q=" << data.m_dcQ;
9080 else
9081 result << "PHASE=" << data.m_phase << " " << "GAIN=" << data.m_gain;
9082 Debug(m_owner,level,"%s calibration finished in %s %s [%p]",
9083 oper,duration.secStr(),result.c_str(),m_owner);
9084 }
9085
9086 // Dump result to file
9087 data.finalizeCal(result);
9088
9089 // Wait for cancel ?
9090 if (!status && dc && !m_calibrateStop) {
9091 const String& i = data.m_params[YSTRING("stop_dc_i_out_of_range")];
9092 if (i && !isInterval(data.m_dcI,BRF_TX_DC_OFFSET_MIN,BRF_TX_DC_OFFSET_MAX,i))
9093 status = waitCancel("Calibration stopped","DC I " +
9094 String(data.m_dcI) + " out of range " + i,&e);
9095 else {
9096 const String& q = data.m_params[YSTRING("stop_dc_q_out_of_range")];
9097 if (q && !isInterval(data.m_dcQ,BRF_TX_DC_OFFSET_MIN,BRF_TX_DC_OFFSET_MAX,q))
9098 status = waitCancel("Calibration stopped","DC Q " +
9099 String(data.m_dcQ) + " out of range " + q,&e);
9100 }
9101 }
9102
9103 if (!status)
9104 return 0;
9105 e.printf(2048,"%s failed - %s",oper,e.c_str());
9106 return showError(status,e,0,error);
9107 }
9108
calibrateBaseband(String * error)9109 unsigned int BrfLibUsbDevice::calibrateBaseband(String* error)
9110 {
9111 Configuration cfg;
9112 loadCfg(&cfg,false);
9113 NamedList& p = *cfg.createSection(YSTRING("calibrate-bb"));
9114
9115 Debug(m_owner,DebugInfo,"Baseband calibration starting ... [%p]",m_owner);
9116 BrfDuration duration;
9117 m_calibrateStop = 0;
9118 String e;
9119 unsigned int status = 0;
9120 unsigned int chg = DevStatLoopback | DevStatTxPattern;
9121 unsigned int dirChg = DevStatFreq | DevStatSampleRate | DevStatVga | DevStatLpfBw;
9122 BrfDevState oldState(m_state,chg,dirChg,dirChg);
9123 setTxPattern(p.getValue(YSTRING("txpattern"),"circle"));
9124 BrfBbCalData data(getRxSamples(p),p);
9125 data.m_tx = m_state.m_tx;
9126 data.m_rx = m_state.m_rx;
9127 while (status == 0) {
9128 m_calibration.assign("");
9129 m_calibration.clearParams();
9130 BRF_FUNC_CALL_BREAK(writeLMS(p[YSTRING("lms_write")],&e,true));
9131 //
9132 // Calibrate TX LO Leakage (I/Q DC Offset)
9133 BRF_FUNC_CALL_BREAK(prepareCalibrateBb(data,true,&e));
9134 BRF_FUNC_CALL_BREAK(writeLMS(p[YSTRING("lms_write_alter")],&e,true));
9135 for (int n = data.intParam(true,"repeat",1,1); n && !m_calibrateStop; n--) {
9136 data.m_dcI = data.m_dcQ = 0;
9137 BRF_FUNC_CALL_BREAK(calibrateBb(data,true,&e));
9138 }
9139 if (status || m_calibrateStop) {
9140 Debug(m_owner,DebugInfo,"Calibration stopping with status=%d stop=%d [%p]",
9141 status,m_calibrateStop,this);
9142 break;
9143 }
9144 // Calibrate TX I/Q Imbalance
9145 // This will set TX DC I/Q also
9146 // test pattern and tuning data must change
9147 BRF_FUNC_CALL_BREAK(prepareCalibrateBb(data,false,&e));
9148 BRF_FUNC_CALL_BREAK(calibrateBb(data,false,&e));
9149 //
9150 // and do it all again
9151 // LO leakage
9152 if (status || m_calibrateStop) {
9153 Debug(m_owner,DebugInfo,"Calibration stopping with status=%d stop=%d [%p]",
9154 status,m_calibrateStop,this);
9155 break;
9156 }
9157 BRF_FUNC_CALL_BREAK(prepareCalibrateBb(data,true,&e));
9158 BRF_FUNC_CALL_BREAK(writeLMS(p[YSTRING("lms_write_alter")],&e,true));
9159 BRF_FUNC_CALL_BREAK(calibrateBb(data,true,&e));
9160 // I/Q balance
9161 if (status || m_calibrateStop) {
9162 Debug(m_owner,DebugInfo,"Calibration stopping with status=%d stop=%d [%p]",
9163 status,m_calibrateStop,this);
9164 break;
9165 }
9166 BRF_FUNC_CALL_BREAK(prepareCalibrateBb(data,false,&e));
9167 BRF_FUNC_CALL_BREAK(calibrateBb(data,false,&e));
9168 // Update calibrated data
9169 // Use initial tunning values: we may change them during calibration
9170 m_calibration.addParam("frequency",String(oldState.m_tx.frequency));
9171 m_calibration.addParam("samplerate",String(oldState.m_tx.sampleRate));
9172 m_calibration.addParam("filter",String(oldState.m_tx.lpfBw));
9173 m_calibration.addParam("cal_tx_dc_i",String(data.m_dcI));
9174 m_calibration.addParam("cal_tx_dc_q",String(data.m_dcQ));
9175 m_calibration.addParam("cal_tx_fpga_corr_phase",String(data.m_phase));
9176 m_calibration.addParam("cal_tx_fpga_corr_gain",String(data.m_gain));
9177 break;
9178 }
9179 Debug(m_owner,DebugAll,"Finalizing BB calibration [%p]",m_owner);
9180
9181 // amplifier linearization
9182 #if 0
9183 static const float startSweep = -20;
9184 static const float stopSweep = 0;
9185 static const float stepSweep = 1.0;
9186 ComplexVector sweep = sweepPower(startSweep, stopSweep, stepSweep);
9187 if (sweep.length()) {
9188 String tmp;
9189 sweep.dump(tmp,Math::dumpComplex," ","(%g,%g)");
9190 Debug(m_owner,DebugInfo,"amp sweep: %s [%p]",tmp.c_str(),this);
9191 findGainExpParams(sweep, startSweep, stepSweep);
9192 findPhaseExpParams(sweep, startSweep, stepSweep);
9193 calculateAmpTable();
9194 }
9195 else
9196 Debug(m_owner,DebugWarn,"amplifier calibration sweep failed");
9197 #endif
9198
9199 if (m_calibrateStop) {
9200 bool a = (m_calibrateStop < 0);
9201 m_calibrateStop = 0;
9202 Output("Calibration stopped: %s",(a ? "abort, no restore" : "restoring state"));
9203 if (a)
9204 return status;
9205 }
9206
9207 calThreadsPause(true);
9208 if (!status) {
9209 oldState.m_tx.dcOffsetI = data.m_dcI;
9210 oldState.m_tx.dcOffsetQ = data.m_dcQ;
9211 oldState.m_tx.fpgaCorrPhase = data.m_phase;
9212 oldState.m_tx.fpgaCorrGain = data.m_gain;
9213 oldState.m_txChanged |= DevStatDc | DevStatFpga;
9214 oldState.m_changed |= DevStatAbortOnFail;
9215 status = setState(oldState,&e);
9216 }
9217 else
9218 setState(oldState);
9219 writeLMS(p[YSTRING("lms_write_post")],0,true);
9220 duration.stop();
9221 if (status == 0) {
9222 String tmp;
9223 m_calibration.dump(tmp,"\r\n");
9224 Debug(m_owner,DebugNote,"Baseband calibration ended in %s [%p]%s",
9225 duration.secStr(),m_owner,encloseDashes(tmp,true));
9226 return 0;
9227 }
9228 e.printf(1024,"BB calibration failed: %s",e.c_str());
9229 return showError(status,e,0,error);
9230 }
9231
loopbackCheck(String * error)9232 unsigned int BrfLibUsbDevice::loopbackCheck(String* error)
9233 {
9234 Configuration cfg;
9235 loadCfg(&cfg,false);
9236 NamedList& p = *cfg.createSection(YSTRING("loopback-check"));
9237 // Prepare data dump
9238 m_dbgMutex.lock();
9239 BrfDumpFile dump(&p,m_devCheckFile);
9240 m_dbgMutex.unlock();
9241
9242 Debug(m_owner,DebugNote,"Loopback check starting ... [%p]",m_owner);
9243 BrfDuration duration;
9244 String e;
9245 unsigned int status = 0;
9246 unsigned int chg = DevStatLoopback | DevStatTxPattern;
9247 unsigned int dirChg = DevStatFreq | DevStatVga | DevStatLpfBw | DevStatSampleRate;
9248 BrfDevState oldState(m_state,chg,dirChg,dirChg);
9249 setTxPattern(p.getValue(YSTRING("txpattern"),"circle"));
9250 while (status == 0) {
9251 unsigned int txFreq = p.getIntValue(YSTRING("txfrequency"),
9252 m_state.m_tx.frequency,0);
9253 if (!txFreq)
9254 BRF_FUNC_CALL_BREAK(setErrorFail(&e,"Frequency not set"));
9255 unsigned int nBuffs = p.getIntValue("buffers",10,1);
9256 unsigned int bw = m_state.m_tx.lpfBw;
9257 unsigned int sampleRate = m_state.m_tx.sampleRate;
9258 bw = p.getIntValue(YSTRING("bandwidth"),bw ? bw : 1500000,1500000);
9259 sampleRate = p.getIntValue(YSTRING("samplerate"),
9260 sampleRate ? sampleRate : 2166667,2166667);
9261 if (!sampleRate)
9262 BRF_FUNC_CALL_BREAK(setErrorFail(&e,"Sample rate not set"));
9263 // deltaFreq = RxFreq - TxFreq
9264 // deltaFreq MUST be
9265 // (1) 1MHz < deltaFreq < (sampleRate / 2)
9266 // (2) deltaFreq != (sampleRate / 4)
9267 // Sampling rate MUST be greater than 2MHz
9268 unsigned int minDeltaFreq = 1000001;
9269 unsigned int maxDeltaFreq = sampleRate / 2 - 1;
9270 unsigned int deltaFreq = p.getIntValue(YSTRING("delta_freq"),
9271 minDeltaFreq + (maxDeltaFreq - minDeltaFreq) / 2,minDeltaFreq,maxDeltaFreq);
9272 if (deltaFreq == (sampleRate / 4)) {
9273 // TODO: Properly adjust it
9274 Debug(m_owner,DebugStub,"Loopback check adjusting delta freq [%p]",m_owner);
9275 deltaFreq += 1000;
9276 }
9277 // Sanity check
9278 if (deltaFreq <= 1000000 || (deltaFreq >= (sampleRate / 2)) ||
9279 (deltaFreq == (sampleRate / 4))) {
9280 e.printf("Invalid delta freq %u samplerate=%u",deltaFreq,sampleRate);
9281 status = RadioInterface::Failure;
9282 break;
9283 }
9284 unsigned int rxFreq = txFreq + deltaFreq;
9285
9286 // Prepare device
9287 unsigned int flags = DevStatLpfBw | DevStatSampleRate | DevStatFreq | DevStatVga;
9288 BrfDevState s(DevStatAbortOnFail | DevStatLoopback,flags,flags);
9289 s.m_tx.lpfBw = bw;
9290 s.m_rx.lpfBw = bw;
9291 s.m_tx.sampleRate = sampleRate;
9292 s.m_rx.sampleRate = sampleRate;
9293 s.m_tx.frequency = txFreq;
9294 s.m_rx.frequency = rxFreq;
9295 s.m_tx.vga1 = p.getIntValue(YSTRING("txvga1"),
9296 BRF_TXVGA1_GAIN_DEF,BRF_TXVGA1_GAIN_MIN,BRF_TXVGA1_GAIN_MAX);
9297 s.m_tx.vga2 = p.getIntValue(YSTRING("txvga2"),
9298 BRF_TXVGA2_GAIN_DEF,BRF_TXVGA2_GAIN_MIN,BRF_TXVGA2_GAIN_MAX);
9299 s.m_rx.vga1 = p.getIntValue(YSTRING("rxvga1"),
9300 BRF_RXVGA1_GAIN_DEF,BRF_RXVGA1_GAIN_MIN,BRF_RXVGA1_GAIN_MAX);
9301 s.m_rx.vga2 = p.getIntValue(YSTRING("rxvga2"),
9302 BRF_RXVGA2_GAIN_DEF,BRF_RXVGA2_GAIN_MIN,BRF_RXVGA2_GAIN_MAX);
9303 NamedList lpParams("");
9304 lpParams.copySubParams(p,YSTRING("loopback_"));
9305 int defLp = brfIsLowBand(txFreq) ? LoopRfLna1 : LoopRfLna2;
9306 int lp = p.getIntValue(YSTRING("loopback"),s_loopback,defLp);
9307 s.setLoopback(lp,lpParams);
9308 // Stop I/O threads (use internal functions to set params)
9309 BRF_FUNC_CALL_BREAK(calThreadsPause(true,&e));
9310 BRF_FUNC_CALL_BREAK(setState(s,&e));
9311 // Toggle timestamps (reset FPGA timestamps)
9312 enableRfFpgaBoth(false);
9313 enableTimestamps(false);
9314 Thread::idle();
9315 BRF_FUNC_CALL_BREAK(enableTimestamps(true,&e));
9316 BRF_FUNC_CALL_BREAK(enableRfFpgaBoth(true,&e));
9317 BRF_FUNC_CALL_BREAK(calThreadsPause(false,&e));
9318
9319 // Utility: check / write LMS
9320 checkLMS(p[YSTRING("lms_check")],0,true);
9321 BRF_FUNC_CALL_BREAK(writeLMS(p[YSTRING("lms_write")],&e,true));
9322
9323 Thread::msleep(50);
9324
9325 // Set read / test signal buffers. Generate tone
9326 float omega = ((float)sampleRate / 4 - deltaFreq) * 2 * M_PI / sampleRate;
9327 ComplexVector buf(getRxSamples(p));
9328 ComplexVector testTone(buf.length());
9329 omega = -omega;
9330 generateExpTone(testTone,omega);
9331
9332 float limit = getSampleLimit(p);
9333
9334 ComplexVector testPattern;
9335 const String& pattern = p[YSTRING("test_pattern")];
9336 if (pattern) {
9337 String ep;
9338 if (!buildVector(ep,pattern,testPattern,buf.length(),true)) {
9339 status = RadioInterface::Failure;
9340 e << "invalid/unknown test_pattern='" << pattern << "' - " << ep;
9341 break;
9342 }
9343 if (testPattern.length() > buf.length())
9344 testPattern.resize(buf.length());
9345 }
9346
9347 unsigned int trace = p.getIntValue(YSTRING("trace"),0,0);
9348 bool dumpTxTs = (trace > 1) && p.getBoolValue("dump_tx_ts");
9349 String t;
9350 if (trace) {
9351 if (p.getBoolValue("dump_status_start"))
9352 dumpState(t,p,true);
9353 String tmp;
9354 unsigned int h = p.getIntValue("dump_test_tone",0,0);
9355 if (h) {
9356 if (h > testTone.length())
9357 h = testTone.length();
9358 tmp.printf("TEST TONE HEAD(%d):",h);
9359 testTone.head(h).dump(tmp,Math::dumpComplex," ","(%g,%g)");
9360 }
9361 if (testPattern.length()) {
9362 h = p.getIntValue("dump_test_pattern",0,0);
9363 if (h) {
9364 String t2;
9365 t2.printf("TEST PATTERN len=%u HEAD(%d):",testPattern.length(),h);
9366 if (h > testPattern.length())
9367 h = testPattern.length();
9368 testPattern.head(h).dump(t2,Math::dumpComplex," ","(%g,%g)");
9369 tmp.append(t2,"\r\n");
9370 }
9371 }
9372 t.append(tmp,"\r\n");
9373 Output("Loopback check: frequency tx=%u rx=%u (delta=%u omega=%f) "
9374 "samplerate=%u bandwidth=%u samples=%u buffers=%u [%p]%s",
9375 txFreq,rxFreq,deltaFreq,omega,sampleRate,bw,buf.length(),
9376 nBuffs,m_owner,encloseDashes(t,true));
9377 }
9378 else if (p.getBoolValue("dump_dev")) {
9379 String t;
9380 dumpState(t,p,true);
9381 Debug(m_owner,DebugNote,"Loopback check. Device params: [%p]%s",this,encloseDashes(t));
9382 }
9383 // Dump header to file
9384 if (dump.dumpHeader()) {
9385 String* tmp = new String;
9386 dumpState(*tmp,p,true,true);
9387 String extra;
9388 extra.printf("\r\nSAMPLES: %u\r\nBUFFERS: %u\r\nomega: %f\r\ndelta_freq=%u",
9389 buf.length(),nBuffs,omega,deltaFreq);
9390 *tmp << "\r\n" << extra << "\r\n";
9391 dump.append(tmp);
9392 }
9393
9394 // Run it
9395 int dumpRxBeforeRead = p.getIntValue(YSTRING("dump_before_read_rx"),0,0);
9396 int dumpTxBeforeRead = p.getIntValue(YSTRING("dump_before_read_tx"),0,0);
9397 unsigned int tmp = nBuffs / 4;
9398 unsigned int limitFailures =
9399 p.getIntValue(YSTRING("sample_limit_allow_fail"),tmp,0,nBuffs - 1);
9400 unsigned int allowFail = p.getIntValue(YSTRING("allow_fail"),tmp,0,nBuffs - 1);
9401 for (int i = 0; i < (int)nBuffs; i++) {
9402 if (dumpRxBeforeRead) {
9403 dumpRxBeforeRead--;
9404 showBuf(false,1,false);
9405 }
9406 if (dumpTxBeforeRead || dumpTxTs) {
9407 if (dumpTxBeforeRead)
9408 dumpTxBeforeRead--;
9409 showBuf(true,1,dumpTxTs);
9410 }
9411 BRF_FUNC_CALL_BREAK(setStateSyncTx(0,&e));
9412 uint64_t ts = m_syncTxState.m_tx.m_timestamp + m_radioCaps.rxLatency;
9413 BRF_FUNC_CALL_BREAK(capture(false,(float*)buf.data(),buf.length(),ts,&e));
9414 // Check for out of range values
9415 status = checkSampleLimit((float*)buf.data(),buf.length(),limit,&e);
9416 if (status) {
9417 if (trace)
9418 Output("%-5u [%10s]\tsample invalid (remains=%d): %s",
9419 i,String(ts).c_str(),limitFailures,e.c_str());
9420 if (!limitFailures)
9421 break;
9422 limitFailures--;
9423 i--;
9424 e.clear();
9425 status = 0;
9426 continue;
9427 }
9428 // Apply test pattern (check algorithm)
9429 if (testPattern.length())
9430 buf.copy(testPattern,testPattern.length());
9431 // Calculate test / total signal
9432 const Complex* last = 0;
9433 const Complex* b = buf.data(0,buf.length(),last);
9434 Complex testSum;
9435 float total = 0;
9436 for (const Complex* tt = testTone.data(); b != last; ++b, ++tt) {
9437 total += b->norm2();
9438 testSum += *tt * *b;
9439 }
9440 float test = testSum.norm2() / buf.length();
9441 bool ok = ((0.5 * total) < test) && (test <= total);
9442 float ratio = total ? test / total : -1;
9443 if (trace > 1)
9444 Output("%-5u [%10s]\ttest:%-15f total:%-15f %.2f %s",
9445 i,String(ts).c_str(),test,total,ratio,(ok ? "" : "FAILURE"));
9446
9447 // Dump to file
9448 if ((ok && dump.dumpOk()) || (!ok && dump.dumpFail())) {
9449 String* tmp = new String;
9450 tmp->printf("\r\n# %u [%s] test:%f total:%f\r\n",
9451 i,(ok ? "SUCCESS" : "FAILURE"),test,total);
9452 dump.append(tmp);
9453 dump.appendFormatted(buf,ok);
9454 }
9455
9456 if (ok)
9457 continue;
9458 e.printf("test_tone_power=%f total_energy=%f (%.2f)",test,total,ratio);
9459 if (!allowFail) {
9460 status = RadioInterface::Failure;
9461 break;
9462 }
9463 allowFail--;
9464 DDebug(m_owner,DebugInfo,"Loopback check failure %s [%p]",e.safe(),m_owner);
9465 e.clear();
9466 }
9467 if (status)
9468 break;
9469 if (trace == 1)
9470 Output("Loopback check succesfully ended");
9471 // VGA test
9472 BRF_FUNC_CALL_BREAK(testVgaCheck(p,"Loopback check",omega,&e));
9473 break;
9474 }
9475 Debug(m_owner,DebugAll,"Finalizing loopback check [%p]",m_owner);
9476 if (!status) {
9477 calThreadsPause(true);
9478 status = setState(oldState,&e);
9479 calThreadsPause(false);
9480 }
9481 duration.stop();
9482 if (status == 0) {
9483 Debug(m_owner,DebugNote,"Loopback check ended duration=%s [%p]",
9484 duration.secStr(),m_owner);
9485 return 0;
9486 }
9487 e.printf(1024,"Loopback check failed: %s",e.c_str());
9488 return showError(status,e,0,error);
9489 }
9490
testVga(const char * loc,bool tx,bool preMixer,float omega,String * error)9491 unsigned int BrfLibUsbDevice::testVga(const char* loc, bool tx, bool preMixer,
9492 float omega, String* error)
9493 {
9494 Configuration cfg;
9495 loadCfg(&cfg,false);
9496 NamedList& params = *cfg.createSection("test-vga");
9497 String e;
9498 unsigned int status = 0;
9499
9500 String what;
9501 what << (tx ? "tx_vga" : "rx_vga") << mixer(preMixer);
9502 String testName;
9503 testName.printf("Test %s VGA %c",brfDir(tx),mixer(preMixer));
9504 String fName = params.getValue("dump_file","test_${what}_${sec_now}");
9505 replaceDumpParams(fName,new NamedString("what",what),true,
9506 new NamedString("loopback",lookup(m_state.m_loopback,s_loopback)));
9507 BrfDumpFile dump(&NamedList::empty(),fName,true);
9508 if (!dump.valid()) {
9509 int e = dump.file().error();
9510 Debug(m_owner,DebugNote,"%s '%s' failed to create dump file '%s': %d [%p]",
9511 testName.c_str(),loc,dump.fileName().c_str(),e,m_owner);
9512 return 0;
9513 }
9514
9515 int start = 0;
9516 int end = 0;
9517 uint8_t mask = 0;
9518 uint8_t shift = 0;
9519 #define BRF_TEST_INIT(from,to,ma,sh) { \
9520 start = from; \
9521 end = to; \
9522 mask = ma; \
9523 shift = sh; \
9524 }
9525 if (tx) {
9526 if (preMixer)
9527 BRF_TEST_INIT(BRF_TXVGA1_GAIN_MIN,BRF_TXVGA1_GAIN_MAX,0x1f,0)
9528 else
9529 BRF_TEST_INIT(BRF_TXVGA2_GAIN_MIN,BRF_TXVGA2_GAIN_MAX,0xf8,3)
9530 }
9531 else if (preMixer)
9532 BRF_TEST_INIT(BRF_RXVGA1_GAIN_MIN,BRF_RXVGA1_GAIN_MAX,0x7f,0)
9533 else
9534 BRF_TEST_INIT(BRF_RXVGA2_GAIN_MIN,BRF_RXVGA2_GAIN_MAX,0x1f,0)
9535 #undef BRF_TEST_INIT
9536 unsigned int flags = preMixer ? DevStatVga1 : DevStatVga2;
9537 unsigned int len = end - start + 1;
9538 BrfDevState oldState(m_state,0,DevStatVga,DevStatVga);
9539
9540 FloatVector totalMed(len);
9541 FloatVector totalMin(len);
9542 FloatVector totalMax(len);
9543 FloatVector totalDelta(len);
9544 FloatVector testMed(len);
9545 FloatVector testDelta(len);
9546 FloatVector testMin(len);
9547 FloatVector testMax(len);
9548 FloatVector testTotalMed(len);
9549 FloatVector testTotalDelta(len);
9550 FloatVector testTotalMin(len);
9551 FloatVector testTotalMax(len);
9552 totalMin.fill(BRF_MAX_FLOAT);
9553 totalMax.fill(-BRF_MAX_FLOAT);
9554 testMin.fill(BRF_MAX_FLOAT);
9555 testMax.fill(-BRF_MAX_FLOAT);
9556 testTotalMin.fill(BRF_MAX_FLOAT);
9557 testTotalMax.fill(-BRF_MAX_FLOAT);
9558
9559 ComplexVector buf(getRxSamples(params));
9560 ComplexVector testTone(buf.length());
9561 generateExpTone(testTone,omega);
9562
9563 const String& regFmt = params["dump_reg"];
9564 uint8_t addr = 0;
9565 DataBlock regVal;
9566 if (regFmt) {
9567 addr = lmsVgaAddr(tx,preMixer);
9568 regVal.resize(len);
9569 }
9570 bool div = params.getBoolValue("divide_by_samples");
9571 float limit = getSampleLimit(params);
9572 unsigned int nBuffs = params.getIntValue("buffers",10,2);
9573
9574 // Set all VGA values to default
9575 m_syncTxState.m_tx.vga1 = BRF_TXVGA1_GAIN_DEF;
9576 m_syncTxState.m_tx.vga2 = BRF_TXVGA2_GAIN_DEF;
9577 m_syncTxState.m_rx.vga1 = BRF_RXVGA1_GAIN_DEF;
9578 m_syncTxState.m_rx.vga2 = BRF_RXVGA2_GAIN_DEF;
9579 m_syncTxState.setFlags(0,DevStatVga,DevStatVga);
9580 status = setStateSync(&e);
9581 // Dump the header now to have current VGA values
9582 const String& hdr = params["dump_header"];
9583 if (hdr) {
9584 NamedString* ns = new NamedString("data");
9585 if (loc)
9586 *ns << "\r\n" << loc;
9587 String tmp;
9588 tmp.printf("\r\n%s\r\nRange: [%d..%d] (%u)\r\n\r\n",
9589 testName.c_str(),start,end,len);
9590 *ns << tmp;
9591 dumpState(*ns,params,true,true);
9592 if (*ns)
9593 *ns << "\r\n";
9594 *ns <<
9595 "\r\nSAMPLES: " << buf.length() <<
9596 "\r\nBUFFERS: " << nBuffs;
9597 dump.append(replaceDumpParamsFmt(hdr,ns));
9598 }
9599
9600 String tmp;
9601 BrfDevDirState& setSync = tx ? m_syncTxState.m_tx : m_syncTxState.m_rx;
9602 int& set = preMixer ? setSync.vga1 : setSync.vga2;
9603 for (unsigned int i = 0; !status && i < len; i++) {
9604 set = start + i;
9605 m_syncTxState.setFlags(0,tx ? flags : 0,tx ? 0 : flags);
9606 BRF_FUNC_CALL_BREAK(setStateSync(&e));
9607 Thread::msleep(100);
9608 BRF_FUNC_CALL_BREAK(setStateSyncTx(0,&e));
9609 uint64_t ts = m_syncTxState.m_tx.m_timestamp + m_radioCaps.rxLatency;
9610 if (regVal.length())
9611 readLMS(addr,*regVal.data(i),0,true);
9612 for (unsigned int n = 0; n < nBuffs; n++) {
9613 BRF_FUNC_CALL_BREAK(capture(false,(float*)buf.data(),buf.length(),ts,&e));
9614 ts += buf.length();
9615 // Check for out of range values
9616 BRF_FUNC_CALL_BREAK(checkSampleLimit((float*)buf.data(),buf.length(),
9617 limit,&e));
9618 // Calculate test / total signal
9619 const Complex* last = 0;
9620 const Complex* b = buf.data(0,buf.length(),last);
9621 Complex testSum;
9622 float tmpTotal = 0;
9623 for (const Complex* tt = testTone.data(); b != last; ++b, ++tt) {
9624 tmpTotal += b->norm2();
9625 testSum += *tt * *b;
9626 }
9627 float tmpTest = testSum.norm2() / buf.length();
9628 if (div) {
9629 tmpTotal /= buf.length();
9630 tmpTest /= buf.length();
9631 }
9632 float t_t = 100 * (tmpTotal ? (tmpTest / tmpTotal) : 0);
9633 setMinMax(totalMin[i],totalMax[i],tmpTotal);
9634 setMinMax(testMin[i],testMax[i],tmpTest);
9635 setMinMax(testTotalMin[i],testTotalMax[i],t_t);
9636 totalMed[i] += tmpTotal;
9637 testMed[i] += tmpTest;
9638 testTotalMed[i] += t_t;
9639 }
9640 if (status)
9641 break;
9642 totalMed[i] /= nBuffs;
9643 testMed[i] /= nBuffs;
9644 testTotalMed[i] /= nBuffs;
9645 if (totalMed[i])
9646 totalDelta[i] = 100 * (totalMax[i] - totalMin[i]) / totalMed[i];
9647 if (testMed[i])
9648 testDelta[i] = 100 * (testMax[i] - testMin[i]) / testMed[i];
9649 if (testTotalMed[i])
9650 testTotalDelta[i] = 100 * (testTotalMax[i] - testTotalMin[i]) / testTotalMed[i];
9651 }
9652 m_syncTxState = oldState;
9653 setStateSync();
9654 Debug(m_owner,DebugInfo,"%s '%s' dumping to '%s' [%p]",
9655 testName.c_str(),loc,dump.fileName().c_str(),m_owner);
9656 String count(len);
9657 if (regVal.length()) {
9658 NamedString* a = new NamedString("address","0x" + tmp.hexify(&addr,1));
9659 NamedString* reg_val = new NamedString("data");
9660 NamedString* value = new NamedString("value");
9661 for (unsigned int i = 0; i < regVal.length(); i++) {
9662 uint8_t* d = regVal.data(i);
9663 reg_val->append("0x" + tmp.hexify(d,1),",");
9664 value->append(String((*d & mask) >> shift),",");
9665 }
9666 dump.append(replaceDumpParamsFmt(regFmt,a,false,reg_val,value));
9667 }
9668 #define BRF_CHECK_FMT_DUMP_VECT(param,v) { \
9669 const String& fmt = params[param]; \
9670 if (fmt) \
9671 dump.appendFormatted(v,fmt); \
9672 }
9673 BRF_CHECK_FMT_DUMP_VECT("dump_total_med",totalMed);
9674 BRF_CHECK_FMT_DUMP_VECT("dump_total_delta",totalDelta);
9675 BRF_CHECK_FMT_DUMP_VECT("dump_test_med",testMed);
9676 BRF_CHECK_FMT_DUMP_VECT("dump_test_delta",testDelta);
9677 BRF_CHECK_FMT_DUMP_VECT("dump_test_total_med",testTotalMed);
9678 BRF_CHECK_FMT_DUMP_VECT("dump_test_total_delta",testTotalDelta);
9679 #undef BRF_CHECK_FMT_DUMP_VECT
9680 const String& mm = params["dump_total_minmax"];
9681 if (mm)
9682 dump.append(replaceDumpParamsFmt(mm,new NamedString("count",count),
9683 false,dumpNsData(totalMin,"total_min"),dumpNsData(totalMax,"total_max")));
9684 const String& extra = params["dump_extra"];
9685 if (extra)
9686 dump.append(replaceDumpParamsFmt(extra,new NamedString("count",count)));
9687 // Done dumping
9688 if (!status)
9689 return 0;
9690 e.printf(2048,"%s '%s' failed - %s",loc,testName.c_str(),e.c_str());
9691 return showError(status,e,0,error);
9692 }
9693
computeMinMax(int & minVal,int & maxVal,int val)9694 static inline void computeMinMax(int& minVal, int& maxVal, int val)
9695 {
9696 if (minVal > val)
9697 minVal = val;
9698 if (maxVal < val)
9699 maxVal = val;
9700 }
9701
computeRxAdjustPeak(int & p,int val,uint64_t & peakTs,uint64_t & ts)9702 static inline void computeRxAdjustPeak(int& p, int val, uint64_t& peakTs, uint64_t& ts)
9703 {
9704 if (p >= val)
9705 return;
9706 p = val;
9707 peakTs = ts;
9708 }
9709
9710 // DC offsets compensation feedback using an exponential moving average
computeCorrection(int & rxDcAvg,int offs,int avg,int dcOffsMax)9711 static inline int computeCorrection(int& rxDcAvg, int offs, int avg, int dcOffsMax)
9712 {
9713 rxDcAvg = avg + ((BRF_RX_DC_OFFSET_AVG_DAMPING - 1) * rxDcAvg /
9714 BRF_RX_DC_OFFSET_AVG_DAMPING);
9715 if ((rxDcAvg > dcOffsMax)) {
9716 if (offs < BRF_RX_DC_OFFSET_MAX) {
9717 offs++;
9718 rxDcAvg = 0;
9719 }
9720 }
9721 else if ((rxDcAvg < -dcOffsMax) && (offs > -BRF_RX_DC_OFFSET_MAX)) {
9722 offs--;
9723 rxDcAvg = 0;
9724 }
9725 return offs;
9726 }
9727
9728 // Compute Rx avg values, autocorrect offsets if configured
computeRx(uint64_t ts)9729 void BrfLibUsbDevice::computeRx(uint64_t ts)
9730 {
9731 unsigned int dbg = checkDbgInt(m_rxShowDcInfo);
9732 if (!(dbg || m_state.m_rxDcAuto))
9733 return;
9734 // Compute averages and peak values
9735 int dcIMin = 32767;
9736 int dcIMax = -32767;
9737 int dcIAvg = 0;
9738 int dcQMin = 32767;
9739 int dcQMax = -32767;
9740 int dcQAvg = 0;
9741 int peak = 0;
9742 uint64_t peakTs = 0;
9743 for (unsigned int i = 0; i < m_rxIO.buffers; i++) {
9744 int16_t* d = m_rxIO.samples(i);
9745 for (int16_t* last = m_rxIO.samplesEOF(i); d != last;) {
9746 int dcI = *d++;
9747 int dcQ = *d++;
9748 dcIAvg += dcI;
9749 dcQAvg += dcQ;
9750 if (!dbg)
9751 continue;
9752 computeMinMax(dcIMin,dcIMax,dcI);
9753 computeMinMax(dcQMin,dcQMax,dcQ);
9754 computeRxAdjustPeak(peak,dcIMax,peakTs,ts);
9755 computeRxAdjustPeak(peak,-dcIMin,peakTs,ts);
9756 computeRxAdjustPeak(peak,dcQMax,peakTs,ts);
9757 computeRxAdjustPeak(peak,-dcQMin,peakTs,ts);
9758 ts++;
9759 }
9760 }
9761 int div = m_rxIO.buffers * m_rxIO.bufSamples;
9762 dcIAvg /= div;
9763 dcQAvg /= div;
9764 if (dbg)
9765 Debug(m_owner,DebugInfo,
9766 "RX DC values min/avg/max I=%d/%d/%d Q=%d/%d/%d peak=%d TS=" FMT64U " [%p]",
9767 dcIMin,dcIAvg,dcIMax,dcQMin,dcQAvg,dcQMax,peak,peakTs,m_owner);
9768 if (!m_state.m_rxDcAuto)
9769 return;
9770 int corrI = computeCorrection(m_rxDcAvgI,m_state.m_rx.dcOffsetI,dcIAvg,m_rxDcOffsetMax);
9771 int corrQ = computeCorrection(m_rxDcAvgQ,m_state.m_rx.dcOffsetQ,dcQAvg,m_rxDcOffsetMax);
9772 if (corrI == m_state.m_rx.dcOffsetI && corrQ == m_state.m_rx.dcOffsetQ)
9773 return;
9774 BRF_TX_SERIALIZE_NONE;
9775 DDebug(m_owner,DebugInfo,"Adjusting Rx DC offsets I=%d Q=%d [%p]",
9776 corrI,corrQ,m_owner);
9777 internalSetCorrectionIQ(false,corrI,corrQ);
9778 }
9779
9780 // Set error string or put a debug message
showError(unsigned int code,const char * error,const char * prefix,String * buf,int level)9781 unsigned int BrfLibUsbDevice::showError(unsigned int code, const char* error,
9782 const char* prefix, String* buf, int level)
9783 {
9784 if (buf)
9785 return setError(code,buf,error,prefix);
9786 String tmp;
9787 setError(code,&tmp,error,prefix);
9788 switch (code) {
9789 case RadioInterface::Pending:
9790 case RadioInterface::Cancelled:
9791 level = DebugAll;
9792 break;
9793 }
9794 Debug(m_owner,level,"%s [%p]",tmp.c_str(),m_owner);
9795 return code;
9796 }
9797
printIOBuffer(bool tx,const char * loc,int index,unsigned int nBufs)9798 void BrfLibUsbDevice::printIOBuffer(bool tx, const char* loc, int index, unsigned int nBufs)
9799 {
9800 BrfDevIO& io = getIO(tx);
9801 if (!nBufs)
9802 nBufs = io.buffers;
9803 for (unsigned int i = 0; i < nBufs; i++) {
9804 if (index >= 0 && index != (int)i)
9805 continue;
9806 String s;
9807 if (io.showBufData)
9808 io.dumpInt16Samples(s,i);
9809 Output("%s: %s [%s] buffer %u TS=" FMT64U " [%p]%s",
9810 m_owner->debugName(),brfDir(tx),loc,i,io.bufTs(i),m_owner,
9811 encloseDashes(s,true));
9812 }
9813 }
9814
dumpIOBuffer(BrfDevIO & io,unsigned int nBufs)9815 void BrfLibUsbDevice::dumpIOBuffer(BrfDevIO& io, unsigned int nBufs)
9816 {
9817 nBufs = checkDbgInt(io.dataDump,nBufs);
9818 for (unsigned int i = 0; i < nBufs; i++)
9819 if (!io.dataDumpFile.write(io.bufTs(i),io.samples(i),io.bufSamplesLen,owner()))
9820 nBufs = 0;
9821 if (!nBufs)
9822 io.dataDumpFile.terminate(owner());
9823 }
9824
updateIODump(BrfDevIO & io)9825 void BrfLibUsbDevice::updateIODump(BrfDevIO& io)
9826 {
9827 Lock lck(m_dbgMutex);
9828 NamedList lst[2] = {io.dataDumpParams,io.upDumpParams};
9829 io.dataDumpParams.assign("");
9830 io.dataDumpParams.clearParams();
9831 io.upDumpParams.assign("");
9832 io.upDumpParams.clearParams();
9833 lck.drop();
9834 NamedList p(Engine::runParams());
9835 p.addParam("boardserial",serial());
9836 for (uint8_t i = 0; i < 2; i++) {
9837 NamedList& nl = lst[i];
9838 if (!nl)
9839 continue;
9840 RadioDataFile& f = i ? io.upDumpFile : io.dataDumpFile;
9841 int& dump = i ? io.upDump : io.dataDump;
9842 f.terminate(owner());
9843 dump = 0;
9844 int n = 0;
9845 String file = nl[YSTRING("file")];
9846 if (file) {
9847 n = nl.getIntValue(YSTRING("count"),-1);
9848 if (!n)
9849 file = 0;
9850 }
9851 if (file)
9852 p.replaceParams(file);
9853 if (!file)
9854 continue;
9855 RadioDataDesc d;
9856 if (!i) {
9857 d.m_elementType = RadioDataDesc::Int16;
9858 d.m_littleEndian = true;
9859 }
9860 if (f.open(file,&d,owner()))
9861 dump = n;
9862 }
9863 }
9864
9865 // Enable or disable loopback
internalSetLoopback(int mode,const NamedList & params,String * error)9866 unsigned int BrfLibUsbDevice::internalSetLoopback(int mode, const NamedList& params,
9867 String* error)
9868 {
9869 if (m_state.m_loopback == mode)
9870 return 0;
9871 const char* what = lookup(mode,s_loopback);
9872 #if 1
9873 XDebug(m_owner,DebugAll,"internalSetLoopback(%d) '%s' [%p]",mode,what,m_owner);
9874 #else
9875 Debugger d(DebugAll,"BrfLibUsbDevice::internalSetLoopback()"," %d '%s' [%p]",
9876 mode,what,m_owner);
9877 #endif
9878 String e;
9879 unsigned int status = 0;
9880 BrfDevTmpAltSet tmpAltSet(this,status,&e,"Set loopback");
9881 int lna = LmsLnaNone;
9882 while (status == 0) {
9883 // Disable everything before enabling the loopback
9884 BRF_FUNC_CALL_BREAK(lnaSelect(LmsLnaNone,&e));
9885 BRF_FUNC_CALL_BREAK(paSelect(LmsPaNone,&e));
9886 BRF_FUNC_CALL_BREAK(setLoopbackPath(LoopNone,e));
9887 // Prepare the loopback (enable / disable modules)
9888 switch (mode) {
9889 case LoopFirmware:
9890 status = RadioInterface::OutOfRange;
9891 e = "Not implemented";
9892 break;
9893 case LoopLpfToRxOut:
9894 // Disable RX VGA2 and LPF
9895 BRF_FUNC_CALL_BREAK(internalEnableRxVga(false,false,&e));
9896 BRF_FUNC_CALL_BREAK(internalSetLpf(false,LpfDisabled,&e));
9897 break;
9898 case LoopLpfToVga2:
9899 case LoopVga1ToVga2:
9900 // Disable RX VGA1 and LPF
9901 BRF_FUNC_CALL_BREAK(internalEnableRxVga(false,false,&e));
9902 BRF_FUNC_CALL_BREAK(internalSetLpf(false,LpfDisabled,&e));
9903 break;
9904 case LoopLpfToLpf:
9905 case LoopVga1ToLpf:
9906 // Disable RX VGA1, Enable RX LPF and RX VGA2
9907 BRF_FUNC_CALL_BREAK(internalEnableRxVga(false,true,&e));
9908 BRF_FUNC_CALL_BREAK(internalSetLpf(false,LpfNormal,&e));
9909 BRF_FUNC_CALL_BREAK(internalEnableRxVga(true,false,&e));
9910 break;
9911 case LoopRfLna1:
9912 lna = LmsLna1;
9913 // falthrough
9914 case LoopRfLna2:
9915 if (lna == LmsLnaNone)
9916 lna = LmsLna2;
9917 // falthrough
9918 case LoopRfLna3:
9919 if (lna == LmsLnaNone)
9920 lna = LmsLna3;
9921 // Select PA AUX and enable LNA
9922 BRF_FUNC_CALL_BREAK(paSelect(LmsPaAux,&e));
9923 BRF_FUNC_CALL_BREAK(lnaEnable(true,&e));
9924 BRF_FUNC_CALL_BREAK(lnaSelect(lna,&e));
9925 // Enable RX path
9926 BRF_FUNC_CALL_BREAK(internalEnableRxVga(true,true,&e));
9927 BRF_FUNC_CALL_BREAK(internalSetLpf(false,LpfNormal,&e));
9928 BRF_FUNC_CALL_BREAK(internalEnableRxVga(true,false,&e));
9929 // Select output buffer in RX PLL
9930 BRF_FUNC_CALL_BREAK(lmsSet(0x25,lna,0x03,&e));
9931 break;
9932 case LoopNone:
9933 BRF_FUNC_CALL_BREAK(restoreFreq(true,&e));
9934 BRF_FUNC_CALL_BREAK(internalEnableRxVga(true,true,&e));
9935 BRF_FUNC_CALL_BREAK(internalSetLpf(false,LpfNormal,&e));
9936 BRF_FUNC_CALL_BREAK(internalEnableRxVga(true,false,&e));
9937 BRF_FUNC_CALL_BREAK(lnaEnable(true,&e));
9938 BRF_FUNC_CALL_BREAK(restoreFreq(false,&e));
9939 lna = LmsLnaDetect;
9940 break;
9941 default:
9942 Debug(m_owner,DebugStub,"Loopback: unhandled value %d [%p]",mode,m_owner);
9943 status = setUnkValue(e,"mode " + String(mode));
9944 }
9945 if (status)
9946 break;
9947 BRF_FUNC_CALL_BREAK(setLoopbackPath(mode,e));
9948 bool lowBand = brfIsLowBand(m_state.m_tx.frequency);
9949 if (lna == LmsLnaDetect)
9950 BRF_FUNC_CALL_BREAK(lnaSelect(lowBand ? LmsLna1 : LmsLna2,&e));
9951 if (params.getBoolValue(YSTRING("transmit"),mode == LoopNone))
9952 BRF_FUNC_CALL_BREAK(paSelect(lowBand,&e));
9953 break;
9954 }
9955 if (status == 0) {
9956 Debug(m_owner,DebugNote,"Loopback changed '%s' -> '%s' [%p]",
9957 lookup(m_state.m_loopback,s_loopback),what,m_owner);
9958 m_state.setLoopback(mode,params);
9959 return 0;
9960 }
9961 if (mode != LoopNone)
9962 e.printf(1024,"Failed to set loopback to %d (%s): %s",
9963 mode,what,e.c_str());
9964 else
9965 e.printf(1024,"Failed to disable loopback: %s",e.c_str());
9966 return showError(status,e,0,error);
9967 }
9968
setLoopbackPath(int mode,String & error)9969 unsigned int BrfLibUsbDevice::setLoopbackPath(int mode, String& error)
9970 {
9971 const char* what = lookup(mode,s_loopback);
9972 XDebug(m_owner,DebugAll,"setLoopbackPath(%d) '%s' [%p]",mode,what,m_owner);
9973 uint8_t rf = 0;
9974 uint8_t baseband = 0;
9975 String e;
9976 unsigned int status = lmsRead2(0x08,rf,0x46,baseband,&e);
9977 if (status == 0) {
9978 // Stop all loopbacks
9979 rf &= ~0x7f;
9980 baseband &= ~0x0c;
9981 switch (mode) {
9982 case LoopFirmware:
9983 status = RadioInterface::OutOfRange;
9984 e = "Not implemented";
9985 break;
9986 case LoopLpfToRxOut:
9987 rf |= 0x10; // LBEN_OPIN
9988 baseband |= 0x04; // LOOPBBEN[1:0] 1
9989 break;
9990 case LoopLpfToVga2:
9991 rf |= 0x20; // LBEN_VGA2IN
9992 baseband |= 0x04; // LOOPBBEN[1:0] 1
9993 break;
9994 case LoopVga1ToVga2:
9995 rf |= 0x20; // LBEN_VGA2IN
9996 baseband |= 0x08; // LOOPBBEN[1:0] 2
9997 break;
9998 case LoopLpfToLpf:
9999 rf |= 0x40; // LBEN_LPFIN
10000 baseband |= 0x04; // LOOPBBEN[1:0] 1
10001 break;
10002 case LoopVga1ToLpf:
10003 rf |= 0x40; // LBEN_LPFIN
10004 baseband |= 0x08; // LOOPBBEN[1:0] 2
10005 break;
10006 case LoopRfLna1:
10007 rf |= 0x01;
10008 break;
10009 case LoopRfLna2:
10010 rf |= 0x02;
10011 break;
10012 case LoopRfLna3:
10013 rf |= 0x03;
10014 break;
10015 case LoopNone:
10016 break;
10017 default:
10018 Debug(m_owner,DebugStub,"Loopback path set: unhandled value %d [%p]",
10019 mode,m_owner);
10020 status = setUnkValue(e,"mode " + String(mode));
10021 }
10022 if (status == 0)
10023 status = lmsWrite2(0x08,rf,0x46,baseband,&e);
10024 }
10025 if (status == 0)
10026 Debug(m_owner,DebugAll,"Loopback path switches configured for '%s' [%p]",
10027 what,m_owner);
10028 else
10029 error << "Failed to configure path switches - " << e;
10030 return status;
10031 }
10032
dumpLoopbackStatus(String * dest)10033 void BrfLibUsbDevice::dumpLoopbackStatus(String* dest)
10034 {
10035 #define BRF_LS_RESULT(name,mask) \
10036 s << "\r\n " << name << ": " << (status ? "ERROR" : tmp.printf("0x%x",data & mask).c_str())
10037 #define BRF_LS_RESULT_OPEN(name,mask,valueOpen) \
10038 BRF_LS_RESULT(name,mask); \
10039 if (status == 0) \
10040 s << " - " << (((data & mask) == valueOpen) ? "open" : "closed");
10041 String s;
10042 String tmp;
10043 uint8_t data = 0;
10044 unsigned int status = 0;
10045 // TX Path
10046 s << "\r\nTX PATH:";
10047 status = lmsRead(0x35,data);
10048 BRF_LS_RESULT("BYP_EN_LPF",0x40); // LPF bypass enable (1: bypass, 0: normal)
10049 if (!status)
10050 s << " - " << lookup((data & 0x40) == 0x40 ? LpfBypass : LpfNormal,s_lpf);
10051 status = lmsRead(0x46,data);
10052 BRF_LS_RESULT_OPEN("LOOPBBEN[1:0]",0x0c,0x00); // Baseband loopback swithes control (00: open, 11: closed)
10053 status = lmsRead(0x08,data);
10054 BRF_LS_RESULT_OPEN("LBEN_OPIN",0x10,0x00); // enabled: RX VGA2 and RXLPF should be disabled
10055 BRF_LS_RESULT_OPEN("LBEN_VGA2IN",0x20,0x00); // enabled: LPF should be disabled
10056 BRF_LS_RESULT_OPEN("LBEN_LPFIN",0x40,0x00); // enabled: RXTIA should be disabled
10057 BRF_LS_RESULT("LBRFEN (TXMIX)",0x0f); // LNAs should be disabled
10058 if (!status) {
10059 s << " - ";
10060 switch (data & 0x0f) {
10061 case 0: s << "open"; break;
10062 case 1: s << "LNA1"; break;
10063 case 2: s << "LNA2"; break;
10064 case 3: s << "LNA3"; break;
10065 default: s << "invalid";
10066 }
10067 }
10068 s << "\r\nRX PATH:";
10069 status = lmsRead(0x55,data);
10070 BRF_LS_RESULT("BYP_EN_LPF",0x40); // LPF bypass enable
10071 if (!status)
10072 s << " - " << lookup((data & 0x40) == 0x40 ? LpfBypass : LpfNormal,s_lpf);
10073 status = lmsRead(0x09,data);
10074 BRF_LS_RESULT_OPEN("RXOUTSW",0x80,0x00); // RXOUTSW switch
10075 if (dest)
10076 *dest = s;
10077 else
10078 Debug(m_owner,DebugAll,"Loopback switches: [%p]%s",m_owner,encloseDashes(s));
10079 #undef BRF_LS_RESULT
10080 #undef BRF_LS_RESULT_OPEN
10081 }
10082
dumpLmsModulesStatus(String * dest)10083 void BrfLibUsbDevice::dumpLmsModulesStatus(String* dest)
10084 {
10085 #define BRF_MS_RESULT(name,result) \
10086 s << "\r\n " << name << ": " << (status ? "ERROR" : result)
10087 #define BRF_MS_RESULT_ACTIVE(name,result,mask,valueActive) \
10088 BRF_MS_RESULT(name,result); \
10089 if (status == 0) \
10090 s << tmp.printf("0x%x - %s",data & mask,activeStr((data & mask) == valueActive))
10091 String s;
10092 String tmp;
10093 int tmpInt = 0;
10094 uint8_t data = 0;
10095 unsigned int status = 0;
10096 // TX
10097 s << "\r\nTX:";
10098 status = internalGetLpf(true,&tmpInt);
10099 BRF_MS_RESULT("LPF",lookup(tmpInt,s_lpf));
10100 status = lmsRead(0x44,data);
10101 BRF_MS_RESULT("AUXPA",tmp.printf("0x%x - %s",data & 0x04,enableStr((data & 0x04) == 0)));
10102 BRF_MS_RESULT("PA",tmp.printf("0x%x - %d",data & 0x18,((data & 0x18) >> 3)));
10103 s << "\r\nRX:";
10104 status = lmsRead(0x75,data);
10105 tmp.clear();
10106 if (status == 0)
10107 tmp.printf("0x%x (%d)",data & 0x30,(data & 0x30) >> 4);
10108 BRF_MS_RESULT("LNA","");
10109 s << "Selected: " << tmp.safe("ERROR");
10110 status = lmsRead(0x7d,data);
10111 if (status == 0)
10112 s << tmp.printf(" - (0x%x %s)",data & 0x01,activeStr((data & 0x01) == 0));
10113 else
10114 s << " - Active: ERROR";
10115 BRF_MS_RESULT_ACTIVE("VGA1","",0x08,0);
10116 status = internalGetLpf(false,&tmpInt);
10117 BRF_MS_RESULT("LPF",lookup(tmpInt,s_lpf));
10118 status = lmsRead(0x64,data);
10119 BRF_MS_RESULT_ACTIVE("VGA2","",0x02,0x02);
10120 if (dest)
10121 *dest = s;
10122 else
10123 Debug(m_owner,DebugAll,"LMS modules status: [%p]%s",m_owner,encloseDashes(s));
10124 #undef BRF_MS_RESULT_ACTIVE
10125 #undef BRF_MS_RESULT
10126 }
10127
internalDumpPeripheral(uint8_t dev,uint8_t addr,uint8_t len,String * buf,uint8_t lineLen)10128 unsigned int BrfLibUsbDevice::internalDumpPeripheral(uint8_t dev, uint8_t addr,
10129 uint8_t len, String* buf, uint8_t lineLen)
10130 {
10131 uint8_t data[256];
10132 unsigned int status = 0;
10133 BRF_FUNC_CALL_RET(accessPeripheral(dev,false,addr,data,0,len));
10134 bool outHere = (buf == 0);
10135 String s;
10136 if (!buf)
10137 buf = &s;
10138 if (lineLen) {
10139 String s1, s2;
10140 uint8_t* d = data;
10141 uint8_t a = addr;
10142 uint8_t n = len / lineLen;
10143 for (; n; n--, d += lineLen, a += lineLen)
10144 *buf << "\r\n" << s1.hexify(&a,1) << "\t" << s2.hexify(d,lineLen,' ');
10145 n = len % lineLen;
10146 if (n)
10147 *buf << "\r\n" << s1.hexify(&a,1) << "\t" << s2.hexify(d,n,' ');
10148 }
10149 else
10150 buf->hexify(data,len,' ');
10151 if (outHere)
10152 Output("%s %s status (addr=0x%x):%s",
10153 m_owner->debugName(),s_uartDev[dev].c_str(),addr,encloseDashes(*buf));
10154 return 0;
10155 }
10156
startCalibrateThreads(String * error,const NamedList & params)10157 unsigned int BrfLibUsbDevice::startCalibrateThreads(String* error, const NamedList& params)
10158 {
10159 static String s_s[3] = {"recv_data", "send_data", "calibrate"};
10160 static const char* s_n[3] = {"BrfDevRecv", "BrfDevSend", "BrfDevCalibrate"};
10161 static int s_t[3] = {BrfThread::DevRecv, BrfThread::DevSend, BrfThread::DevCalibrate};
10162 static Thread::Priority s_prio[3] = {Thread::High, Thread::High, Thread::Normal};
10163
10164 stopThreads();
10165 BrfThread** threads[3] = {&m_recvThread,&m_sendThread,&m_calThread};
10166 int i = 0;
10167 for (; i < 3; i++) {
10168 BrfThread*& th = *threads[i];
10169 const char* prioStr = params.getValue(s_s[i] + "_priority");
10170 Thread::Priority prio = Thread::priority(prioStr,s_prio[i]);
10171 th = new BrfThread(this,s_t[i],params,s_n[i],prio);
10172 th = th->start();
10173 if (!th)
10174 break;
10175 }
10176 if (i >= 3)
10177 return 0;
10178 stopThreads();
10179 String e;
10180 e << "Failed to start " << s_s[i] << " worker thread";
10181 return showError(RadioInterface::Failure,e,0,error);
10182 }
10183
calThreadsPause(bool on,String * error)10184 unsigned int BrfLibUsbDevice::calThreadsPause(bool on, String* error)
10185 {
10186 unsigned int status = 0;
10187 if (on) {
10188 status = BrfThread::pause(m_sendThread,&m_threadMutex,error);
10189 if (!status)
10190 status = BrfThread::pause(m_recvThread,&m_threadMutex,error);
10191 }
10192 else {
10193 status = BrfThread::resume(m_recvThread,&m_threadMutex,error);
10194 if (!status)
10195 status = BrfThread::resume(m_sendThread,&m_threadMutex,error);
10196 }
10197 return status;
10198 }
10199
10200 // Stop internal threads
stopThreads()10201 void BrfLibUsbDevice::stopThreads()
10202 {
10203 // Soft cancel
10204 BrfThread::cancelThread(m_calThread,&m_threadMutex,0,m_owner,m_owner);
10205 // Wait for a while (avoid calibrate failure due to I/O thread termination)
10206 if (m_calThread)
10207 Thread::msleep(20);
10208 BrfThread::cancelThread(m_sendThread,&m_threadMutex,0,m_owner,m_owner);
10209 BrfThread::cancelThread(m_recvThread,&m_threadMutex,0,m_owner,m_owner);
10210 // Hard cancel
10211 BrfThread::cancelThread(m_calThread,&m_threadMutex,1000,m_owner,m_owner);
10212 BrfThread::cancelThread(m_sendThread,&m_threadMutex,1000,m_owner,m_owner);
10213 BrfThread::cancelThread(m_recvThread,&m_threadMutex,1000,m_owner,m_owner);
10214 m_internalIoSemaphore.unlock();
10215 m_internalIoTimestamp = 0;
10216 }
10217
waitCancel(const char * loc,const char * reason,String * error)10218 unsigned int BrfLibUsbDevice::waitCancel(const char* loc, const char* reason,
10219 String* error)
10220 {
10221 Debug(m_owner,DebugCrit,"%s: %s. Waiting for cancel... [%p]",loc,reason,m_owner);
10222 unsigned int status = 0;
10223 while (!status && !m_calibrateStop) {
10224 Thread::idle();
10225 status = cancelled(error);
10226 }
10227 return status;
10228 }
10229
10230 // Apply parameters from start notification message
applyStartParams(const NamedList & params,String * error)10231 unsigned int BrfLibUsbDevice::applyStartParams(const NamedList& params, String* error)
10232 {
10233 const NamedString* fOffs = 0;
10234 const NamedString* dc[] = {0,0};
10235 const NamedString* fpga[] = {0,0};
10236 bool haveParams = false;
10237 for (const ObjList* o = params.paramList()->skipNull(); o; o = o->skipNext()) {
10238 const NamedString* ns = static_cast<const NamedString*>(o->get());
10239 if (ns->name() == YSTRING("RadioFrequencyOffset"))
10240 fOffs = ns;
10241 else if (ns->name() == YSTRING("tx_dc_i"))
10242 dc[0] = ns;
10243 else if (ns->name() == YSTRING("tx_dc_q"))
10244 dc[1] = ns;
10245 else if (ns->name() == YSTRING("tx_fpga_corr_phase"))
10246 fpga[0] = ns;
10247 else if (ns->name() == YSTRING("tx_fpga_corr_gain"))
10248 fpga[1] = ns;
10249 else
10250 continue;
10251 haveParams = true;
10252 }
10253 if (!haveParams)
10254 return 0;
10255 unsigned int status = 0;
10256 if (fOffs) {
10257 float f = fOffs->toDouble(m_freqOffset);
10258 f = clampFloat(f,BRF_FREQ_OFFS_MIN,BRF_FREQ_OFFS_MAX,fOffs->name());
10259 BRF_FUNC_CALL_RET(internalSetFreqOffs(f,0,error));
10260 }
10261 if (dc[0] && dc[1]) {
10262 for (int i = 0; i < 2; i++) {
10263 int val = dc[i]->toInteger();
10264 val = clampInt(val,BRF_TX_DC_OFFSET_MIN,BRF_TX_DC_OFFSET_MAX,dc[i]->name());
10265 BRF_FUNC_CALL_RET(internalSetDcOffset(true,i == 0,val,error));
10266 }
10267 }
10268 else if (dc[0] || dc[1])
10269 Debug(m_owner,DebugConf,"Initialize. Ignoring %s: tx_dc_%c is missing [%p]",
10270 (dc[0] ? dc[0] : dc[1])->name().c_str(),(dc[0] ? 'q' : 'i'),m_owner);
10271 if (fpga[0] && fpga[1]) {
10272 for (int i = 0; i < 2; i++) {
10273 int val = fpga[i]->toInteger();
10274 val = clampInt(val,-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX,fpga[i]->name());
10275 BRF_FUNC_CALL_RET(internalSetFpgaCorr(true,i ? CorrFpgaGain : CorrFpgaPhase,val,error));
10276 }
10277 }
10278 else if (fpga[0] || fpga[1])
10279 Debug(m_owner,DebugConf,"Initialize. Ignoring %s: tx_fpga_corr_%s is missing [%p]",
10280 (fpga[0] ? fpga[0] : fpga[1])->name().c_str(),(fpga[0] ? "gain" : "phase"),m_owner);
10281 return 0;
10282 }
10283
10284
10285 //
10286 // BrfInterface
10287 //
BrfInterface(const char * name)10288 BrfInterface::BrfInterface(const char* name)
10289 : RadioInterface(name),
10290 m_dev(0)
10291 {
10292 debugChain(&__plugin);
10293 Debug(this,DebugAll,"Interface created [%p]",this);
10294 }
10295
~BrfInterface()10296 BrfInterface::~BrfInterface()
10297 {
10298 Debug(this,DebugAll,"Interface destroyed [%p]",this);
10299 }
10300
notifyError(unsigned int status,const char * str,const char * oper)10301 void BrfInterface::notifyError(unsigned int status, const char* str, const char* oper)
10302 {
10303 if (!status)
10304 return;
10305 Message* m = new Message("module.update",0,true);
10306 m->addParam("module",__plugin.name());
10307 m->addParam("status","failure");
10308 m->addParam("operation",oper,false);
10309 completeDevInfo(*m);
10310 setError(*m,status,str);
10311 Engine::enqueue(m);
10312 }
10313
init(const NamedList & params,String & error)10314 unsigned int BrfInterface::init(const NamedList& params, String& error)
10315 {
10316 if (m_dev)
10317 return 0;
10318 unsigned int status = 0;
10319 if (!s_usbContextInit) {
10320 Lock lck(__plugin);
10321 if (!s_usbContextInit) {
10322 status = BrfLibUsbDevice::lusbCheckSuccess(::libusb_init(0),&error,"libusb init failed");
10323 if (!status) {
10324 Debug(&__plugin,DebugAll,"Initialized libusb context");
10325 s_usbContextInit = true;
10326 lusbSetDebugLevel();
10327 }
10328 else
10329 Debug(this,DebugNote,"Failed to create device: %s [%p]",error.c_str(),this);
10330 }
10331 }
10332 if (!status) {
10333 m_dev = new BrfLibUsbDevice(this);
10334 m_radioCaps = &m_dev->capabilities();
10335 Debug(this,DebugAll,"Created device (%p) [%p]",m_dev,this);
10336 status = m_dev->open(params,error);
10337 }
10338 return status;
10339 }
10340
initialize(const NamedList & params)10341 unsigned int BrfInterface::initialize(const NamedList& params)
10342 {
10343 return m_dev->initialize(params);
10344 }
10345
setParams(NamedList & params,bool shareFate)10346 unsigned int BrfInterface::setParams(NamedList& params, bool shareFate)
10347 {
10348 unsigned int code = 0;
10349 NamedList failed("");
10350 #define SETPARAMS_HANDLE_CODE(c) { \
10351 if (c) { \
10352 if (!code || code == Pending) \
10353 code = c; \
10354 failed.addParam(cmd + "_failed",String(c)); \
10355 if (shareFate && c != Pending) \
10356 break; \
10357 } \
10358 }
10359 #define METH_CALL(func) { \
10360 unsigned int c = func(); \
10361 SETPARAMS_HANDLE_CODE(c); \
10362 continue; \
10363 }
10364 #define METH_CALL_1(func,value) { \
10365 unsigned int c = func(value); \
10366 SETPARAMS_HANDLE_CODE(c); \
10367 continue; \
10368 }
10369 #define METH_CALL_2(func,value1,value2) { \
10370 unsigned int c = func(value1,value2); \
10371 SETPARAMS_HANDLE_CODE(c); \
10372 continue; \
10373 }
10374 #ifdef XDEBUG
10375 String tmp;
10376 params.dump(tmp,"\r\n");
10377 Debug(this,DebugAll,"setParams [%p]%s",this,encloseDashes(tmp,true));
10378 #endif
10379 for (ObjList* o = params.paramList()->skipNull(); o; o = o->skipNext()) {
10380 NamedString* ns = static_cast<NamedString*>(o->get());
10381 if (!ns->name().startsWith("cmd:"))
10382 continue;
10383 String cmd = ns->name().substr(4);
10384 if (!cmd)
10385 continue;
10386 if (cmd == YSTRING("setSampleRate"))
10387 METH_CALL_1(setSampleRate,(uint64_t)ns->toInt64());
10388 if (cmd == YSTRING("setFilter"))
10389 METH_CALL_1(setFilter,(uint64_t)ns->toInt64());
10390 if (cmd == YSTRING("setTxFrequency"))
10391 METH_CALL_2(setFrequency,(uint64_t)ns->toInt64(),true);
10392 if (cmd == YSTRING("setRxFrequency"))
10393 METH_CALL_2(setFrequency,(uint64_t)ns->toInt64(),false);
10394 if (cmd == "calibrate")
10395 METH_CALL(calibrate);
10396 if (cmd.startsWith("devparam:")) {
10397 unsigned int c = NotInitialized;
10398 if (m_dev) {
10399 NamedList p("");
10400 p.copySubParams(params,cmd + "_");
10401 c = m_dev->setParam(cmd.substr(9),*ns,p);
10402 }
10403 SETPARAMS_HANDLE_CODE(c);
10404 continue;
10405 }
10406 Debug(this,DebugNote,"setParams: unhandled cmd '%s' [%p]",cmd.c_str(),this);
10407 SETPARAMS_HANDLE_CODE(NotSupported);
10408 }
10409 #undef SETPARAMS_HANDLE_CODE
10410 #undef METH_CALL
10411 #undef METH_CALL_1
10412 if (code)
10413 params.copyParams(failed);
10414 #ifdef XDEBUG
10415 tmp.clear();
10416 params.dump(tmp,"\r\n");
10417 Debug(this,DebugAll,"setParams [%p]%s",this,encloseDashes(tmp,true));
10418 #endif
10419 return code;
10420 }
10421
send(uint64_t when,float * samples,unsigned size,float * powerScale)10422 unsigned int BrfInterface::send(uint64_t when, float* samples, unsigned size,
10423 float* powerScale)
10424 {
10425 #ifdef XDEBUG
10426 if (size) {
10427 float sum = 0.0F;
10428 for (unsigned i=0; i<2*size; i++)
10429 sum += samples[i]*samples[i];
10430 float dB = 10.0F*log10f(sum/size);
10431 float scaleDB = 0.0F;
10432 if (powerScale) scaleDB = 20.0F*log10f(*powerScale);
10433 XDebug(this,DebugAll,"Sending at time " FMT64U " power %f dB to be scaled %f dB [%p]",
10434 when, dB, scaleDB, this);
10435 }
10436 #endif
10437 return m_dev->syncTx(when,samples,size,powerScale);
10438 }
10439
recv(uint64_t & when,float * samples,unsigned int & size)10440 unsigned int BrfInterface::recv(uint64_t& when, float* samples, unsigned int& size)
10441 {
10442 return m_dev->syncRx(when,samples,size);
10443 }
10444
setFrequency(uint64_t hz,bool tx)10445 unsigned int BrfInterface::setFrequency(uint64_t hz, bool tx)
10446 {
10447 XDebug(this,DebugAll,"BrfInterface::setFrequency(" FMT64U ",%s) [%p]",
10448 hz,brfDir(tx),this);
10449 unsigned int status = m_dev->setFrequency(hz,tx);
10450 if (status)
10451 return status;
10452 uint32_t tmp = 0;
10453 status = m_dev->getFrequency(tmp,tx);
10454 if (status)
10455 return status;
10456 uint32_t freq = (uint32_t)hz;
10457 if (tmp == freq)
10458 return 0;
10459 int delta = tmp - freq;
10460 Debug(this,DebugNote,"Set %s frequency requested=%u read=%u delta=%d [%p]",
10461 brfDir(tx),freq,tmp,delta,this);
10462 return NotExact;
10463 }
10464
getFrequency(uint64_t & hz,bool tx) const10465 unsigned int BrfInterface::getFrequency(uint64_t& hz, bool tx) const
10466 {
10467 uint32_t freq = 0;
10468 unsigned int status = m_dev->getFrequency(freq,tx);
10469 if (status == 0)
10470 hz = freq;
10471 return status;
10472 }
10473
setSampleRate(uint64_t hz)10474 unsigned int BrfInterface::setSampleRate(uint64_t hz)
10475 {
10476 XDebug(this,DebugAll,"BrfInterface::setSampleRate(" FMT64U ") [%p]",hz,this);
10477 uint32_t srate = (uint32_t)hz;
10478 unsigned int status = m_dev->setSamplerate(srate,true);
10479 if (status)
10480 return status;
10481 status = m_dev->setSamplerate(srate,false);
10482 if (status)
10483 return status;
10484 uint32_t tmp = 0;
10485 status = m_dev->getSamplerate(tmp,true);
10486 if (status)
10487 return status;
10488 if (tmp != srate) {
10489 Debug(this,DebugNote,"Failed to set TX samplerate requested=%u read=%u [%p]",
10490 srate,tmp,this);
10491 return NotExact;
10492 }
10493 status = m_dev->getSamplerate(tmp,false);
10494 if (status)
10495 return status;
10496 if (tmp != srate) {
10497 Debug(this,DebugNote,"Failed to set RX samplerate requested=%u read=%u [%p]",
10498 srate,tmp,this);
10499 return NotExact;
10500 }
10501 return NoError;
10502 }
10503
getSampleRate(uint64_t & hz) const10504 unsigned int BrfInterface::getSampleRate(uint64_t& hz) const
10505 {
10506 uint32_t srate = 0;
10507 unsigned int status = m_dev->getSamplerate(srate,true);
10508 if (status == 0)
10509 hz = srate;
10510 return status;
10511 }
10512
setFilter(uint64_t hz)10513 unsigned int BrfInterface::setFilter(uint64_t hz)
10514 {
10515 XDebug(this,DebugAll,"BrfInterface::setFilter(" FMT64U ") [%p]",hz,this);
10516 if (hz > 0xffffffff) {
10517 Debug(this,DebugNote,
10518 "Failed to set filter " FMT64U ": out of range [%p]",
10519 hz,this);
10520 return OutOfRange;
10521 }
10522 uint32_t band = hz;
10523 unsigned int status = m_dev->setLpfBandwidth(band,true);
10524 if (status)
10525 return status;
10526 status = m_dev->setLpfBandwidth(band,false);
10527 if (status)
10528 return status;
10529 uint32_t tmp = 0;
10530 status = m_dev->getLpfBandwidth(tmp,true);
10531 if (status)
10532 return status;
10533 if (tmp != band){
10534 Debug(this,DebugNote,"Failed to set TX filter band requested=%u read=%u [%p]",
10535 band,tmp,this);
10536 return NotExact;
10537 }
10538 status = m_dev->getLpfBandwidth(tmp,false);
10539 if (status)
10540 return status;
10541 if (tmp != band){
10542 Debug(this,DebugNote,"Failed to set RX filter band requested=%u read=%u [%p]",
10543 band,tmp,this);
10544 return NotExact;
10545 }
10546 return NoError;
10547 }
10548
getFilterWidth(uint64_t & hz) const10549 unsigned int BrfInterface::getFilterWidth(uint64_t& hz) const
10550 {
10551 uint32_t band = 0;
10552 unsigned int status = m_dev->getLpfBandwidth(band,true);
10553 if (status == 0)
10554 hz = band;
10555 return status;
10556 }
10557
setRxGain(int val,unsigned port,bool preMixer)10558 unsigned int BrfInterface::setRxGain(int val, unsigned port, bool preMixer)
10559 {
10560 XDebug(this,DebugAll,"BrfInterface::setRxGain(%d,%u,VGA%c) [%p]",
10561 val,port,mixer(preMixer),this);
10562 if (!m_dev->validPort(port))
10563 return InvalidPort;
10564 unsigned int status = m_dev->enableRxVga(true,preMixer);
10565 if (status)
10566 return status;
10567 return m_dev->setRxVga(val,preMixer);
10568 }
10569
setTxGain(int val,unsigned port,bool preMixer)10570 unsigned int BrfInterface::setTxGain(int val, unsigned port, bool preMixer)
10571 {
10572 XDebug(this,DebugAll,"BrfInterface::setTxGain(%d,%u,VGA%c) [%p]",
10573 val,port,mixer(preMixer),this);
10574 if (!m_dev->validPort(port))
10575 return InvalidPort;
10576 unsigned int status = m_dev->setTxVga(val,preMixer);
10577 if (status)
10578 return status;
10579 int tmp = 0;
10580 status = m_dev->getTxVga(tmp,preMixer);
10581 if (status)
10582 return status;
10583 if (tmp == val)
10584 return NoError;
10585 Debug(this,DebugNote,"Failed to set TX VGA%c requested=%d read=%d [%p]",
10586 mixer(preMixer),val,tmp,this);
10587 return NotExact;
10588 }
10589
completeDevInfo(NamedList & p,bool full,bool retData)10590 void BrfInterface::completeDevInfo(NamedList& p, bool full, bool retData)
10591 {
10592 RadioInterface::completeDevInfo(p,full,retData);
10593 if (full && m_dev) {
10594 p.addParam("address",m_dev->address(),false);
10595 p.addParam("speed",String(m_dev->speedStr()).toLower());
10596 p.addParam("serial",m_dev->serial(),false);
10597 }
10598 }
10599
10600 // Calibration. Automatic tx/rx gain setting
10601 // Set pre and post mixer value
setGain(bool tx,int val,unsigned int port,int * newVal) const10602 unsigned int BrfInterface::setGain(bool tx, int val, unsigned int port,
10603 int* newVal) const
10604 {
10605 if (!m_dev->validPort(port))
10606 return InvalidPort;
10607 return m_dev->setGain(tx,val,newVal);
10608 }
10609
destroyed()10610 void BrfInterface::destroyed()
10611 {
10612 Debug(this,DebugAll,"Destroying device=(%p) [%p]",m_dev,this);
10613 Lock lck(__plugin);
10614 __plugin.m_ifaces.remove(this,false);
10615 lck.drop();
10616 TelEngine::destruct(m_dev);
10617 RadioInterface::destroyed();
10618 }
10619
10620
10621 //
10622 // BrfModule
10623 //
BrfModule()10624 BrfModule::BrfModule()
10625 : Module("bladerf","misc",true),
10626 m_ifaceId(0),
10627 m_disciplineBusy(false),
10628 m_lastDiscipline(0)
10629 {
10630 String tmp;
10631 #ifdef HAVE_LIBUSB_VER
10632 const libusb_version* ver = ::libusb_get_version();
10633 tmp.printf(" using libusb %u.%u.%u.%u",ver->major,ver->minor,ver->micro,ver->nano);
10634 if (!TelEngine::null(ver->rc))
10635 tmp << " rc='" << ver->rc << "'";
10636 if (!TelEngine::null(ver->describe))
10637 tmp << " desc='" << ver->describe << "'";
10638 #else
10639 tmp = " using old libusb 1.0";
10640 #endif
10641 Output("Loaded module BladeRF%s",tmp.safe());
10642 }
10643
~BrfModule()10644 BrfModule::~BrfModule()
10645 {
10646 Output("Unloading module BladeRF");
10647 if (m_ifaces.skipNull())
10648 Debug(this,DebugWarn,"Exiting with %u interface(s) in list!!!",m_ifaces.count());
10649 else if (s_usbContextInit) {
10650 ::libusb_exit(0);
10651 Debug(this,DebugAll,"Cleared libusb context");
10652 }
10653 }
10654
findIfaceByDevice(RefPointer<BrfInterface> & iface,void * dev)10655 bool BrfModule::findIfaceByDevice(RefPointer<BrfInterface>& iface, void* dev)
10656 {
10657 if (!dev)
10658 return false;
10659 Lock lck(this);
10660 for (ObjList* o = m_ifaces.skipNull(); o; o = o->skipNext()) {
10661 iface = static_cast<BrfInterface*>(o->get());
10662 if (iface && iface->isDevice(dev))
10663 return true;
10664 iface = 0;
10665 }
10666 return false;
10667 }
10668
initialize()10669 void BrfModule::initialize()
10670 {
10671 Output("Initializing module BladeRF");
10672 lock();
10673 loadCfg();
10674 NamedList gen(*s_cfg.createSection(YSTRING("general")));
10675 NamedList lusb(*s_cfg.createSection(YSTRING("libusb")));
10676 unlock();
10677 if (!relayInstalled(RadioCreate)) {
10678 setup();
10679 installRelay(Timer);
10680 installRelay(Halt);
10681 installRelay(Control);
10682 installRelay(RadioCreate,"radio.create",gen.getIntValue("priority",90));
10683 }
10684 lusbSetDebugLevel();
10685 s_lusbSyncTransferTout = lusb.getIntValue(YSTRING("sync_transfer_timeout"),
10686 LUSB_SYNC_TIMEOUT,20,500);
10687 s_lusbCtrlTransferTout = lusb.getIntValue(YSTRING("ctrl_transfer_timeout"),
10688 LUSB_CTRL_TIMEOUT,200,2000);
10689 s_lusbBulkTransferTout = lusb.getIntValue(YSTRING("bulk_transfer_timeout"),
10690 LUSB_BULK_TIMEOUT,200,2000);
10691 setDebugPeripheral(gen);
10692 setSampleEnergize(gen[YSTRING("sampleenergize")]);
10693 // Reload interfaces
10694 lock();
10695 if (m_ifaces.skipNull()) {
10696 ListIterator iter(m_ifaces);
10697 for (GenObject* gen = 0; (gen = iter.get()) != 0; ) {
10698 RefPointer<BrfInterface> iface = static_cast<BrfInterface*>(gen);
10699 if (!iface)
10700 continue;
10701 unlock();
10702 iface->reLoad();
10703 iface = 0;
10704 lock();
10705 }
10706 }
10707 unlock();
10708 }
10709
received(Message & msg,int id)10710 bool BrfModule::received(Message& msg, int id)
10711 {
10712 if (id == RadioCreate) {
10713 if (Engine::exiting())
10714 return false;
10715 // Override parameters from received params
10716 const String& what = msg[YSTRING("radio_driver")];
10717 if (what && what != YSTRING("bladerf"))
10718 return false;
10719 return createIface(msg);
10720 }
10721 if (id == Control) {
10722 const String& comp = msg[YSTRING("component")];
10723 RefPointer<BrfInterface> ifc;
10724 if (comp == name() || findIface(ifc,comp))
10725 return onCmdControl(ifc,msg);
10726 return false;
10727 }
10728 if (id == Timer && msg.msgTime().sec() > m_lastDiscipline + 4) {
10729 m_lastDiscipline = msg.msgTime().sec();
10730 // protect BrfVctcxoDiscipliner objects from multiple threads
10731 lock();
10732 if (!m_disciplineBusy) {
10733 m_disciplineBusy = true;
10734 ListIterator iter(m_ifaces);
10735 for (GenObject* gen = iter.get(); gen != 0; gen = iter.get()) {
10736 RefPointer<BrfInterface> ifc = static_cast<BrfInterface*>(gen);
10737 if (!ifc)
10738 continue;
10739 unlock();
10740 BrfLibUsbDevice* dev = ifc->device();
10741 // discipline VCTCXO according to BrfLibUsbDevice's local settings
10742 if (dev)
10743 dev->trimVctcxo(msg.msgTime().usec());
10744 ifc = 0;
10745 lock();
10746 }
10747 m_disciplineBusy = false;
10748 }
10749 unlock();
10750 }
10751 return Module::received(msg,id);
10752 }
10753
statusModule(String & str)10754 void BrfModule::statusModule(String& str)
10755 {
10756 Module::statusModule(str);
10757 }
10758
statusParams(String & str)10759 void BrfModule::statusParams(String& str)
10760 {
10761 Module::statusParams(str);
10762 Lock lck(this);
10763 str.append("ifaces=",",") << m_ifaces.count();
10764 }
10765
statusDetail(String & str)10766 void BrfModule::statusDetail(String& str)
10767 {
10768 Module::statusDetail(str);
10769 }
10770
commandComplete(Message & msg,const String & partLine,const String & partWord)10771 bool BrfModule::commandComplete(Message& msg, const String& partLine,
10772 const String& partWord)
10773 {
10774 if (partLine == YSTRING("control")) {
10775 itemComplete(msg.retValue(),name(),partWord);
10776 completeIfaces(msg.retValue(),partWord);
10777 return false;
10778 }
10779 String tmp = partLine;
10780 if (tmp.startSkip("control")) {
10781 if (tmp == name())
10782 return completeStrList(msg.retValue(),partWord,s_modCmds);
10783 RefPointer<BrfInterface> ifc;
10784 if (findIface(ifc,tmp))
10785 return completeStrList(msg.retValue(),partWord,s_ifcCmds);
10786 }
10787 return Module::commandComplete(msg,partLine,partWord);
10788 }
10789
createIface(NamedList & params)10790 bool BrfModule::createIface(NamedList& params)
10791 {
10792 // Debugger d(debugLevel(),"BrfModule::createIface()");
10793 Lock lck(this);
10794 NamedList p(*s_cfg.createSection("general"));
10795 // Allow using a different interface profile
10796 // Override general parameters
10797 const String& profile = params[YSTRING("profile")];
10798 if (profile && profile != YSTRING("general")) {
10799 NamedList* sect = s_cfg.getSection(profile);
10800 if (sect)
10801 p.copyParams(*sect);
10802 }
10803 // Override parameters from received params
10804 String prefix = params.getValue(YSTRING("radio_params_prefix"),"radio.");
10805 if (prefix)
10806 p.copySubParams(params,prefix,true,true);
10807 BrfInterface* ifc = new BrfInterface(name() + "/" + String(++m_ifaceId));
10808 lck.drop();
10809 String error;
10810 unsigned int status = ifc->init(p,error);
10811 if (!status) {
10812 ifc->completeDevInfo(params,true,true);
10813 Lock lck(this);
10814 m_ifaces.append(ifc)->setDelete(false);
10815 return true;
10816 }
10817 ifc->setError(params,status,error);
10818 ifc->notifyError(status,error,"create");
10819 TelEngine::destruct(ifc);
10820 return false;
10821 }
10822
completeIfaces(String & dest,const String & partWord)10823 void BrfModule::completeIfaces(String& dest, const String& partWord)
10824 {
10825 Lock lck(this);
10826 for (ObjList* o = m_ifaces.skipNull(); o; o = o->skipNext()) {
10827 RefPointer<BrfInterface> ifc = static_cast<BrfInterface*>(o->get());
10828 if (ifc)
10829 itemComplete(dest,ifc->toString(),partWord);
10830 }
10831 }
10832
onCmdControl(BrfInterface * ifc,Message & msg)10833 bool BrfModule::onCmdControl(BrfInterface* ifc, Message& msg)
10834 {
10835 static const char* s_help =
10836 // FIXME:
10837 "\r\ncontrol ifc_name txgain1 [value=]"
10838 "\r\n Set or retrieve TX VGA 1 mixer gain"
10839 "\r\ncontrol ifc_name txgain2 [value=]"
10840 "\r\n Set or retrieve TX VGA 2 mixer gain"
10841 "\r\ncontrol ifc_name rxgain1 [value=]"
10842 "\r\n Set or retrieve RX VGA 1 mixer gain"
10843 "\r\ncontrol ifc_name rxgain2 [value=]"
10844 "\r\n Set or retrieve RX VGA 2 mixer gain"
10845 "\r\ncontrol ifc_name txdci [value=]"
10846 "\r\n Set or retrieve TX DC I correction"
10847 "\r\ncontrol ifc_name txdcq [value=]"
10848 "\r\n Set or retrieve TX DC Q correction"
10849 "\r\ncontrol ifc_name txfpgaphase [value=]"
10850 "\r\n Set or retrieve TX FPGA PHASE correction"
10851 "\r\ncontrol ifc_name txfpgagain [value=]"
10852 "\r\n Set or retrieve TX FPGA GAIN correction"
10853 "\r\ncontrol ifc_name rxdci [value=]"
10854 "\r\n Set or retrieve RX DC I correction"
10855 "\r\ncontrol ifc_name rxdcq [value=]"
10856 "\r\n Set or retrieve RX DC Q correction"
10857 "\r\ncontrol ifc_name rxfpgaphase [value=]"
10858 "\r\n Set or retrieve RX FPGA PHASE correction"
10859 "\r\ncontrol ifc_name rxfpgagain [value=]"
10860 "\r\n Set or retrieve RX FPGA GAIN correction"
10861 "\r\ncontrol ifc_name balance value="
10862 "\r\n Set software IQ gain balance"
10863 "\r\ncontrol ifc_name gainexp bp= max="
10864 "\r\n Set amp gain expansion breakpoint (dB) and +3 dB expansion (dB)"
10865 "\r\ncontrol ifc_name phaseexp bp= max="
10866 "\r\n Set amp phase expansion breakpoint (dB) and +3 dB expansion (deg)"
10867 "\r\ncontrol ifc_name showstatus"
10868 "\r\n Output interface status"
10869 "\r\ncontrol ifc_name showboardstatus"
10870 "\r\n Output board status"
10871 "\r\ncontrol ifc_name showstatistics"
10872 "\r\n Output interface statistics"
10873 "\r\ncontrol ifc_name showtimestamps"
10874 "\r\n Output interface and board timestamps"
10875 "\r\ncontrol ifc_name showlms [addr=] [len=]"
10876 "\r\n Output LMS registers"
10877 "\r\ncontrol ifc_name lmswrite addr= value= [resetmask=]"
10878 "\r\n Set LMS value at given address. Use reset mask for partial register set"
10879 "\r\ncontrol ifc_name bufoutput tx=boolean [count=] [nodata=boolean]"
10880 "\r\n Set TX/RX buffer output"
10881 "\r\ncontrol ifc_name rxdcoutput [count=]"
10882 "\r\n Set interface RX DC info output"
10883 "\r\ncontrol ifc_name txpattern [pattern=]"
10884 "\r\n Set interface TX pattern"
10885 "\r\ncontrol ifc_name vgagain tx=boolean vga={1|2} [gain=]"
10886 "\r\n Set or retrieve TX/RX VGA mixer gain"
10887 "\r\ncontrol ifc_name correction tx=boolean corr={dc-i|dc-q|fpga-gain|fpga-phase} [value=]"
10888 "\r\n Set or retrieve TX/RX DC I/Q or FPGA GAIN/PHASE correction"
10889 "\r\ncontrol ifc_name freqoffs [{value= [stop=YES|no]}|drift=]"
10890 "\r\n Set (absolute value or a drift expressed in ppb to force a clock trim) or retrieve the frequency offset"
10891 "\r\ncontrol ifc_name show [info=status|statistics|timestamps|boardstatus|peripheral|freqcal] [peripheral=all|list(lms,gpio,vctcxo,si5338)] [addr=] [len=]"
10892 "\r\n Verbose output various interface info"
10893 "\r\ncontrol ifc_name freqcalstart [system_accuracy=] [count=]"
10894 "\r\n Start or re-configure the frequency calibration process"
10895 "\r\ncontrol ifc_name freqcalstop"
10896 "\r\n Stop the frequency calibration process";
10897
10898 const String& cmd = msg[YSTRING("operation")];
10899 // Module commands
10900 if (!ifc) {
10901 if (cmd == YSTRING("help")) {
10902 msg.retValue() << s_help;
10903 return true;
10904 }
10905 return false;
10906 }
10907 // Interface commands
10908 if (cmd == YSTRING("txgain1"))
10909 return onCmdGain(ifc,msg,1,true);
10910 if (cmd == YSTRING("txgain2"))
10911 return onCmdGain(ifc,msg,1,false);
10912 if (cmd == YSTRING("rxgain1"))
10913 return onCmdGain(ifc,msg,0,true);
10914 if (cmd == YSTRING("rxgain2"))
10915 return onCmdGain(ifc,msg,0,false);
10916 if (cmd == YSTRING("vgagain"))
10917 return onCmdGain(ifc,msg);
10918 if (cmd == YSTRING("txdci"))
10919 return onCmdCorrection(ifc,msg,1,BrfLibUsbDevice::CorrLmsI);
10920 if (cmd == YSTRING("txdcq"))
10921 return onCmdCorrection(ifc,msg,1,BrfLibUsbDevice::CorrLmsQ);
10922 if (cmd == YSTRING("txfpgaphase"))
10923 return onCmdCorrection(ifc,msg,1,BrfLibUsbDevice::CorrFpgaPhase);
10924 if (cmd == YSTRING("txfpgagain"))
10925 return onCmdCorrection(ifc,msg,1,BrfLibUsbDevice::CorrFpgaGain);
10926 if (cmd == YSTRING("rxdci"))
10927 return onCmdCorrection(ifc,msg,0,BrfLibUsbDevice::CorrLmsI);
10928 if (cmd == YSTRING("rxdcq"))
10929 return onCmdCorrection(ifc,msg,0,BrfLibUsbDevice::CorrLmsQ);
10930 if (cmd == YSTRING("rxfpgaphase"))
10931 return onCmdCorrection(ifc,msg,0,BrfLibUsbDevice::CorrFpgaPhase);
10932 if (cmd == YSTRING("rxfpgagain"))
10933 return onCmdCorrection(ifc,msg,0,BrfLibUsbDevice::CorrFpgaGain);
10934 if (cmd == YSTRING("correction"))
10935 return onCmdCorrection(ifc,msg);
10936 if (cmd == YSTRING("lmswrite"))
10937 return onCmdLmsWrite(ifc,msg);
10938 if (cmd == YSTRING("bufoutput"))
10939 return onCmdBufOutput(ifc,msg);
10940 if (cmd == YSTRING("rxdcoutput")) {
10941 if (!ifc->device())
10942 return retMsgError(msg,"No device");
10943 ifc->device()->showRxDCInfo(msg.getIntValue(YSTRING("count")));
10944 return true;
10945 }
10946 if (cmd == YSTRING("txpattern")) {
10947 if (!ifc->device())
10948 return retMsgError(msg,"No device");
10949 ifc->device()->setTxPattern(msg[YSTRING("pattern")]);
10950 return true;
10951 }
10952 if (cmd == YSTRING("balance")) {
10953 if (!ifc->device())
10954 return retMsgError(msg,"No device");
10955 const String txPB = msg[YSTRING("value")];
10956 const float val = txPB.toDouble(1);
10957 ifc->device()->setTxIQBalance(val);
10958 return true;
10959 }
10960 if (cmd == YSTRING("gainexp")) {
10961 if (!ifc->device())
10962 return retMsgError(msg,"No device");
10963 const String bp = msg[YSTRING("bp")];
10964 const String max = msg[YSTRING("max")];
10965 ifc->device()->setGainExp(bp.toDouble(1),max.toDouble(1));
10966 return true;
10967 }
10968 if (cmd == YSTRING("phaseexp")) {
10969 if (!ifc->device())
10970 return retMsgError(msg,"No device");
10971 const String bp = msg[YSTRING("bp")];
10972 const String max = msg[YSTRING("max")];
10973 ifc->device()->setPhaseExp(bp.toDouble(1),max.toDouble(1));
10974 return true;
10975 }
10976 if (cmd == YSTRING("showstatus"))
10977 return onCmdShow(ifc,msg,YSTRING("status"));
10978 if (cmd == YSTRING("showboardstatus"))
10979 return onCmdShow(ifc,msg,YSTRING("boardstatus"));
10980 if (cmd == YSTRING("showstatistics"))
10981 return onCmdShow(ifc,msg,YSTRING("statistics"));
10982 if (cmd == YSTRING("showtimestamps"))
10983 return onCmdShow(ifc,msg,YSTRING("timestamps"));
10984 if (cmd == YSTRING("showlms"))
10985 return onCmdShow(ifc,msg,YSTRING("lms"));
10986 if (cmd == YSTRING("show"))
10987 return onCmdShow(ifc,msg);
10988 if (cmd == YSTRING("freqoffs"))
10989 return onCmdFreqOffs(ifc,msg);
10990 if (cmd == YSTRING("freqcalstart"))
10991 return onCmdFreqCal(ifc,msg,true);
10992 if (cmd == YSTRING("freqcalstop")) {
10993 ifc->device()->disableDiscipline(true);
10994 msg.retValue() << "frequency calibration disabled";
10995 return true;
10996 }
10997 bool calStop = (cmd == YSTRING("cal_stop"));
10998 if (calStop || cmd == YSTRING("cal_abort")) {
10999 if (!ifc->device())
11000 return retMsgError(msg,"No device");
11001 ifc->device()->m_calibrateStop = calStop ? 1 : -1;
11002 return true;
11003 }
11004 return false;
11005 }
11006
onCmdStatus(String & retVal,String & line)11007 bool BrfModule::onCmdStatus(String& retVal, String& line)
11008 {
11009 static const String s_devInfo("withdevinfo");
11010 String ifcName;
11011 bool devInfo = false;
11012 if (line && getFirstStr(ifcName,line)) {
11013 if (ifcName == s_devInfo) {
11014 devInfo = true;
11015 ifcName.clear();
11016 }
11017 else if (line) {
11018 String tmp;
11019 devInfo = getFirstStr(tmp,line) && (tmp == s_devInfo);
11020 }
11021 }
11022 String extra;
11023 String stats;
11024 String info;
11025 if (ifcName) {
11026 stats << "interface=" << ifcName;
11027 RefPointer<BrfInterface> ifc;
11028 if (findIface(ifc,ifcName) && ifc->device())
11029 ifc->device()->dumpDev(info,devInfo,true,",",true,true);
11030 }
11031 else {
11032 unsigned int n = 0;
11033 lock();
11034 ListIterator iter(m_ifaces);
11035 for (GenObject* gen = 0; (gen = iter.get()) != 0; ) {
11036 RefPointer<BrfInterface> ifc = static_cast<BrfInterface*>(gen);
11037 if (!ifc)
11038 continue;
11039 unlock();
11040 n++;
11041 BrfLibUsbDevice* dev = ifc->device();
11042 if (dev) {
11043 String tmp;
11044 dev->dumpDev(tmp,devInfo,true,",",true,false);
11045 info.append(ifc->toString(),",") << "=" << tmp;
11046 }
11047 lock();
11048 }
11049 unlock();
11050 extra << "format=RxVGA1|RxVGA2|RxDCCorrI|RxDCCorrQ|TxVGA1|TxVGA2|"
11051 "RxFreq|TxFreq|RxSampRate|TxSampRate|RxLpfBw|TxLpfBw|RxRF|TxRF";
11052 if (devInfo)
11053 extra << "|Address|Serial|Speed|Firmware|FPGA|LMS_Ver";
11054 stats << "count=" << n;
11055 }
11056 retVal << "module=" << name();
11057 retVal.append(extra,",") << ";";
11058 if (stats)
11059 retVal << stats << ";";
11060 retVal << info;
11061 retVal << "\r\n";
11062 return true;
11063 }
11064
11065 #define BRF_GET_BOOL_PARAM(bDest,param) \
11066 const String& tmpGetBParamStr = msg[YSTRING(param)]; \
11067 if (!tmpGetBParamStr.isBoolean()) \
11068 return retParamError(msg,param); \
11069 bDest = tmpGetBParamStr.toBoolean();
11070
11071 // control ifc_name vgagain tx=boolean mixer={1|2} [value=]
11072 // control ifc_name {tx|rx}vga{1|2}gain [value=]
onCmdGain(BrfInterface * ifc,Message & msg,int tx,bool preMixer)11073 bool BrfModule::onCmdGain(BrfInterface* ifc, Message& msg, int tx, bool preMixer)
11074 {
11075 if (!ifc->device())
11076 return retMsgError(msg,"No device");
11077 const String* value = 0;
11078 if (tx >= 0)
11079 value = msg.getParam(YSTRING("value"));
11080 else {
11081 bool tmpTx = true;
11082 BRF_GET_BOOL_PARAM(tmpTx,"tx");
11083 const String& what = msg[YSTRING("vga")];
11084 preMixer = (what == YSTRING("1"));
11085 if (!preMixer && what != YSTRING("2"))
11086 return retParamError(msg,"vga");
11087 tx = tmpTx ? 1 : 0;
11088 value = msg.getParam(YSTRING("gain"));
11089 }
11090 unsigned int code = 0;
11091 int crt = 0;
11092 if (!TelEngine::null(value))
11093 code = tx ? ifc->device()->setTxVga(value->toInteger(),preMixer) :
11094 ifc->device()->setRxVga(value->toInteger(),preMixer);
11095 if (!code)
11096 code = tx ? ifc->device()->getTxVga(crt,preMixer) :
11097 ifc->device()->getRxVga(crt,preMixer);
11098 if (code)
11099 return retValFailure(msg,code);
11100 msg.setParam(YSTRING("value"),String(crt));
11101 msg.retValue() = crt;
11102 return true;
11103 }
11104
11105 // control ifc_name correction tx=boolean corr={dc-i/dc-q/fpga-gain/fpga-phase} [value=]
onCmdCorrection(BrfInterface * ifc,Message & msg,int tx,int corr)11106 bool BrfModule::onCmdCorrection(BrfInterface* ifc, Message& msg, int tx, int corr)
11107 {
11108 if (!ifc->device())
11109 return retMsgError(msg,"No device");
11110 if (tx < 0) {
11111 bool tmpTx = true;
11112 BRF_GET_BOOL_PARAM(tmpTx,"tx");
11113 const String& corrStr = msg[YSTRING("corr")];
11114 if (corrStr == YSTRING("dc-i"))
11115 corr = BrfLibUsbDevice::CorrLmsI;
11116 else if (corrStr == YSTRING("dc-q"))
11117 corr = BrfLibUsbDevice::CorrLmsQ;
11118 else if (corrStr == YSTRING("fpga-phase"))
11119 corr = BrfLibUsbDevice::CorrFpgaPhase;
11120 else if (corrStr == YSTRING("fpga-gain"))
11121 corr = BrfLibUsbDevice::CorrFpgaGain;
11122 else
11123 return retParamError(msg,"corr");
11124 tx = tmpTx ? 1 : 0;
11125 }
11126 const String& value = msg[YSTRING("value")];
11127 unsigned int code = 0;
11128 int16_t crt = 0;
11129 if (corr == BrfLibUsbDevice::CorrLmsI || corr == BrfLibUsbDevice::CorrLmsQ) {
11130 bool i = (corr == BrfLibUsbDevice::CorrLmsI);
11131 if (value)
11132 code = ifc->device()->setDcOffset(tx,i,value.toInteger());
11133 if (!code)
11134 code = ifc->device()->getDcOffset(tx,i,crt);
11135 }
11136 else {
11137 if (value)
11138 code = ifc->device()->setFpgaCorr(tx,corr,value.toInteger());
11139 if (!code)
11140 code = ifc->device()->getFpgaCorr(tx,corr,crt);
11141 }
11142 if (code)
11143 return retValFailure(msg,code);
11144 msg.setParam(YSTRING("value"),String(crt));
11145 msg.retValue() = crt;
11146 return true;
11147 }
11148
11149 // control ifc_name lmswrite addr= value= [resetmask=]
onCmdLmsWrite(BrfInterface * ifc,Message & msg)11150 bool BrfModule::onCmdLmsWrite(BrfInterface* ifc, Message& msg)
11151 {
11152 if (!ifc->device())
11153 return retMsgError(msg,"No device");
11154 int addr = msg.getIntValue(YSTRING("addr"),-1);
11155 if (addr < 0 || addr > 127)
11156 return retParamError(msg,"addr");
11157 int val = msg.getIntValue(YSTRING("value"),-1);
11158 if (val < 0 || val > 255)
11159 return retParamError(msg,"value");
11160 const String& rstStr = msg[YSTRING("resetmask")];
11161 unsigned int code = 0;
11162 if (rstStr) {
11163 uint8_t rst = (uint8_t)rstStr.toInteger();
11164 code = ifc->device()->writeLMS(addr,val,&rst);
11165 }
11166 else
11167 code = ifc->device()->writeLMS(addr,val);
11168 if (!code)
11169 return true;
11170 return retValFailure(msg,code);
11171 }
11172
11173 // control ifc_name bufoutput tx=boolean [count=value] [nodata=false]
onCmdBufOutput(BrfInterface * ifc,Message & msg)11174 bool BrfModule::onCmdBufOutput(BrfInterface* ifc, Message& msg)
11175 {
11176 if (!ifc->device())
11177 return retMsgError(msg,"No device");
11178 bool tx = true;
11179 BRF_GET_BOOL_PARAM(tx,"tx");
11180 ifc->device()->showBuf(tx,msg.getIntValue(YSTRING("count")),
11181 msg.getBoolValue(YSTRING("nodata")));
11182 return true;
11183 }
11184
11185 // control ifc_name show [info=status|statistics|timestamps|boardstatus|peripheral|freqcal] [peripheral=all|list(lms,gpio,vctcxo,si5338)] [addr=] [len=]
onCmdShow(BrfInterface * ifc,Message & msg,const String & what)11186 bool BrfModule::onCmdShow(BrfInterface* ifc, Message& msg, const String& what)
11187 {
11188 if (!ifc->device())
11189 return retMsgError(msg,"No device");
11190 String info;
11191 if (what)
11192 info = what;
11193 else
11194 info = msg.getValue(YSTRING("info"),"status");
11195 if (info == YSTRING("freqcal"))
11196 return onCmdFreqCal(ifc,msg,false);
11197 String str;
11198 if (info == YSTRING("status"))
11199 ifc->device()->dumpDev(str,true,true,"\r\n");
11200 else if (info == YSTRING("boardstatus"))
11201 ifc->device()->dumpBoardStatus(str,"\r\n");
11202 else if (info == YSTRING("statistics"))
11203 ifc->device()->dumpStats(str,"\r\n");
11204 else if (info == YSTRING("timestamps"))
11205 ifc->device()->dumpTimestamps(str,"\r\n");
11206 else if (info == YSTRING("peripheral") || info == YSTRING("lms")) {
11207 String peripheralList;
11208 if (what)
11209 peripheralList = what;
11210 else {
11211 peripheralList = msg.getValue(YSTRING("peripheral"),"all");
11212 if (peripheralList == YSTRING("all"))
11213 peripheralList = "lms,gpio,vctcxo,si5338";
11214 }
11215 uint8_t addr = (uint8_t)msg.getIntValue("addr",0,0);
11216 uint8_t len = (uint8_t)msg.getIntValue("len",128,1);
11217 ObjList* lst = peripheralList.split(',');
11218 for (ObjList* o = lst->skipNull(); o; o = o->skipNext()) {
11219 String* s = static_cast<String*>(o->get());
11220 s->toUpper();
11221 for (uint8_t i = 0; i < BrfLibUsbDevice::UartDevCount; i++) {
11222 if (*s != s_uartDev[i])
11223 continue;
11224 String tmp;
11225 ifc->device()->dumpPeripheral(i,addr,len,&tmp);
11226 if (tmp)
11227 str.append(s_uartDev[i],"\r\n") << tmp;
11228 break;
11229 }
11230 }
11231 TelEngine::destruct(lst);
11232 }
11233 else
11234 return retParamError(msg,"info");
11235 if (str) {
11236 char buf[50];
11237 Debugger::formatTime(buf);
11238 Output("Interface '%s' info=%s time=%s [%p]%s",
11239 ifc->debugName(),info.c_str(),buf,ifc,encloseDashes(str,true));
11240 }
11241 return true;
11242 }
11243
11244 // control ifc_name freqoffs [{value|drift}=]
onCmdFreqOffs(BrfInterface * ifc,Message & msg)11245 bool BrfModule::onCmdFreqOffs(BrfInterface* ifc, Message& msg)
11246 {
11247 if (!ifc->device())
11248 return retMsgError(msg,"No device");
11249 const String* strRet = msg.getParam(YSTRING("value"));
11250 if (strRet) {
11251 float freqoffs = strRet->toDouble(-1);
11252 if (freqoffs > 0) {
11253 bool stop = msg.getBoolValue(YSTRING("stop"),true);
11254 unsigned code = ifc->device()->setFreqOffset(freqoffs,0,stop);
11255 if (code)
11256 return retValFailure(msg,code);
11257 }
11258 else
11259 return retParamError(msg,"value");
11260 }
11261 else if ((strRet = msg.getParam(YSTRING("drift"))) != 0) {
11262 int drift = strRet->toInteger();
11263 if (!drift)
11264 return retParamError(msg,"drift");
11265 if (!waitDisciplineFree())
11266 return false;
11267 ifc->device()->trimVctcxo(Time::now(),drift);
11268 m_disciplineBusy = false;
11269 }
11270 msg.retValue() << "freqoffs=" << ifc->device()->freqOffset();
11271 return true;
11272 }
11273
11274 // control ifc_name freqcalstart [system_accuracy=] [count=] or control ifc_name show info=freqcal
onCmdFreqCal(BrfInterface * ifc,Message & msg,bool start)11275 bool BrfModule::onCmdFreqCal(BrfInterface* ifc, Message& msg, bool start)
11276 {
11277 if (!ifc->device())
11278 return retMsgError(msg,"No device");
11279 if (!waitDisciplineFree())
11280 return false;
11281 bool ret = ifc->device()->onCmdFreqCal(msg,start);
11282 m_disciplineBusy = false;
11283 return ret;
11284 }
11285
setDebugPeripheral(const NamedList & params)11286 void BrfModule::setDebugPeripheral(const NamedList& params)
11287 {
11288 for (uint8_t i = 0; i < BrfLibUsbDevice::UartDevCount; i++) {
11289 BrfPeripheral& p = s_uartDev[i];
11290 const String& tmp = params[p.lowCase + "_debug"];
11291 bool tx = false;
11292 bool rx = false;
11293 if (tmp) {
11294 if (tmp == YSTRING("tx"))
11295 tx = true;
11296 else if (tmp == YSTRING("rx"))
11297 rx = true;
11298 else if (tmp == YSTRING("both"))
11299 tx = rx = true;
11300 }
11301 p.setTrack(tx,rx,params[p.lowCase + "_trackaddr"],
11302 params.getIntValue(p.lowCase + "_level",-1));
11303 }
11304 }
11305
setSampleEnergize(const String & value)11306 void BrfModule::setSampleEnergize(const String& value)
11307 {
11308 Lock lck(this);
11309 int val = value.toInteger(2047);
11310 if (val == (int)s_sampleEnergize)
11311 return;
11312 if (val < 1 || val > 2047) {
11313 Debug(this,DebugConf,"Invalid sampleenergize=%s",value.c_str());
11314 return;
11315 }
11316 Debug(this,DebugInfo,"sampleenergize changed %u -> %d",s_sampleEnergize,val);
11317 s_sampleEnergize = val;
11318 // Notify devices
11319 ListIterator iter(m_ifaces);
11320 for (GenObject* gen = 0; (gen = iter.get()) != 0; ) {
11321 RefPointer<BrfInterface> ifc = static_cast<BrfInterface*>(gen);
11322 if (!ifc)
11323 continue;
11324 lck.drop();
11325 // Just set flags used by the device to update data using sample energize value
11326 if (ifc->device()) {
11327 ifc->device()->m_txPowerBalanceChanged = true;
11328 ifc->device()->m_txPatternChanged = true;
11329 }
11330 ifc = 0;
11331 lck.acquire(this);
11332 }
11333 }
11334
11335
11336 //
11337 // BrfThread
11338 //
11339 // Device thread
BrfThread(BrfLibUsbDevice * dev,int type,const NamedList & params,const char * name,Thread::Priority prio)11340 BrfThread::BrfThread(BrfLibUsbDevice* dev, int type, const NamedList& params,
11341 const char* name, Thread::Priority prio)
11342 : Thread(name,prio),
11343 m_type(type),
11344 m_params(params),
11345 m_device(dev),
11346 m_paused(false),
11347 m_pauseToggle(false),
11348 m_priority(Thread::priority(prio))
11349 {
11350 m_params.assign(name);
11351 }
11352
11353 // Start this thread. Set destination pointer on success. Delete object on failure
start()11354 BrfThread* BrfThread::start()
11355 {
11356 if (startup())
11357 return this;
11358 Debug(ifc(),DebugNote,"Failed to start worker '%s' [%p]",name(),ifc());
11359 delete this;
11360 return 0;
11361 }
11362
11363 // Pause / resume a thread
pauseToggle(BrfThread * & th,Mutex * mtx,bool on,String * error)11364 unsigned int BrfThread::pauseToggle(BrfThread*& th, Mutex* mtx, bool on, String* error)
11365 {
11366 Lock lck(mtx);
11367 if (!th)
11368 return BrfLibUsbDevice::setErrorFail(error,"Worker abnormally terminated");
11369 if (th->m_paused == on)
11370 return 0;
11371 th->m_pauseToggle = true;
11372 lck.drop();
11373 for (unsigned int n = threadIdleIntervals(200); n; n--) {
11374 Thread::idle();
11375 Lock lck(mtx);
11376 if (!th)
11377 return BrfLibUsbDevice::setErrorFail(error,"Worker abnormally terminated");
11378 if (!th->m_pauseToggle)
11379 return 0;
11380 if (th->m_device) {
11381 unsigned int status = th->m_device->cancelled(error);
11382 if (status)
11383 return status;
11384 }
11385 else if (Thread::check(false))
11386 return BrfLibUsbDevice::setError(RadioInterface::Cancelled,error,"Cancelled");
11387 }
11388 return BrfLibUsbDevice::setErrorTimeout(error,"Worker pause toggle timeout");
11389 }
11390
cancelThread(BrfThread * & th,Mutex * mtx,unsigned int waitMs,DebugEnabler * dbg,void * ptr)11391 void BrfThread::cancelThread(BrfThread*& th, Mutex* mtx, unsigned int waitMs,
11392 DebugEnabler* dbg, void* ptr)
11393 {
11394 if (!th)
11395 return;
11396 Lock lck(mtx);
11397 if (!th)
11398 return;
11399 //Debugger d(DebugAll,"BrfThread::cancelThread()"," [%p]",ptr);
11400 th->cancel();
11401 lck.drop();
11402 if (!waitMs)
11403 return;
11404 unsigned int intervals = threadIdleIntervals(waitMs);
11405 bool cancelled = Thread::check(false);
11406 while (th && intervals-- && (cancelled || !Thread::check(false)))
11407 Thread::idle();
11408 if (!th)
11409 return;
11410 lck.acquire(mtx);
11411 if (!th)
11412 return;
11413 Debug(dbg,DebugWarn,"Hard cancelling (%p) '%s' worker [%p]",th,th->name(),ptr);
11414 th->cancel(true);
11415 th = 0;
11416 }
11417
run()11418 void BrfThread::run()
11419 {
11420 if (!m_device)
11421 return;
11422 Debug(ifc(),DebugAll,"Worker (%p) '%s' started prio=%s [%p]",
11423 this,name(),m_priority,ifc());
11424 switch (m_type) {
11425 case DevCalibrate:
11426 m_device->calibrate(true,m_params,0,true);
11427 break;
11428 case DevSend:
11429 m_device->runSend(this);
11430 break;
11431 case DevRecv:
11432 m_device->runRecv(this);
11433 break;
11434 default:
11435 ;
11436 }
11437 notify();
11438 }
11439
notify()11440 void BrfThread::notify()
11441 {
11442 BrfLibUsbDevice* dev = m_device;
11443 m_device = 0;
11444 if (!dev)
11445 return;
11446 bool ok = ((String)m_params == Thread::currentName());
11447 Debug(dev->owner(),ok ? DebugAll : DebugWarn,"Worker (%p) '%s' terminated [%p]",
11448 this,name(),dev->owner());
11449 Lock lck(dev->m_threadMutex);
11450 if (dev->m_calThread == this)
11451 dev->m_calThread = 0;
11452 else if (dev->m_sendThread == this)
11453 dev->m_sendThread = 0;
11454 else if (dev->m_recvThread == this)
11455 dev->m_recvThread = 0;
11456 }
11457
11458 // amplifier linearization functions
11459
11460 // mean complex gain between two vectors
meanComplexGain(const Complex * rx,const Complex * tx,unsigned length)11461 static Complex meanComplexGain(const Complex* rx, const Complex* tx, unsigned length)
11462 {
11463 // no data? unity gain
11464 if (!length)
11465 return Complex(1,0);
11466 Complex sum = 0;
11467 unsigned count = 0;
11468 for (unsigned i=0; i<length; i++) {
11469 if (i<8)
11470 Debug(DebugAll,"meanComplexGain rx[%u]=%f%+f tx[%u]=%f%+f",
11471 i,rx[i].re(),rx[i].im(),i,tx[i].re(),tx[i].im());
11472 Complex gain = rx[i] / tx[i];
11473 sum += gain;
11474 count++;
11475 }
11476 return sum / length;
11477 }
11478
findBreakAndSlope(const FloatVector & v,float startdB,float stepdB,float * bp,float * slope)11479 static unsigned findBreakAndSlope(const FloatVector& v, float startdB, float stepdB, float *bp, float *slope)
11480 {
11481 if (v.length()==0) {
11482 Debug(DebugWarn,"findBreakAndSlope zero length vector");
11483 return -1;
11484 }
11485 unsigned imax = v.length()-1;
11486 // get the last two power values
11487 float lastdB = startdB + stepdB*imax;
11488 float pmax = pow(10,lastdB*0.1);
11489 float pmax_1 = pow(10,(lastdB-stepdB)*0.1);
11490 // slope at high end of the scale
11491 // defines a line through the two two samples
11492 *slope = (v[imax] - v[imax-1]) / (pmax - pmax_1);
11493 // breakpoint is the intersection of the two lines
11494 *bp = pmax - (v[imax] - v[0]) / (*slope);
11495 return 0;
11496 }
11497
findGainExpParams(const ComplexVector & sweep,float startdB,float stepdB)11498 unsigned BrfLibUsbDevice::findGainExpParams(const ComplexVector& sweep, float startdB, float stepdB)
11499 {
11500 FloatVector gain(sweep.length());
11501 for (unsigned i=0; i<gain.length(); i++)
11502 gain[i] = sweep[i].norm2();
11503 if (findBreakAndSlope(gain, startdB, stepdB, &m_gainExpBreak, &m_gainExpSlope) < 0)
11504 return -1;
11505 Debug(m_owner,DebugInfo,"amp gain expansion: bp = %f linear slope = %f linear [%p]",
11506 m_gainExpBreak,m_gainExpSlope,this);
11507 return 0;
11508 }
11509
findPhaseExpParams(const ComplexVector & sweep,float startdB,float stepdB)11510 unsigned BrfLibUsbDevice::findPhaseExpParams(const ComplexVector& sweep, float startdB, float stepdB)
11511 {
11512 FloatVector phase(sweep.length());
11513 for (unsigned i=0; i<phase.length(); i++)
11514 phase[i] = sweep[i].arg();
11515 if (findBreakAndSlope(phase, startdB, stepdB, &m_phaseExpBreak, &m_phaseExpSlope) < 0)
11516 return -1;
11517 Debug(m_owner,DebugInfo,"amp phase expansion: bp = %f linear slope = %f deg/lin [%p]",
11518 m_phaseExpBreak,180*m_phaseExpSlope/M_PI,this);
11519 return 0;
11520 }
11521
11522 // sweep function
11523 // sweeps power over a range and records gain and phase of the loopback signal
sweepPower(float startdB,float stopdB,float stepdB)11524 ComplexVector BrfLibUsbDevice::sweepPower(float startdB, float stopdB, float stepdB)
11525 {
11526 Debug(m_owner,DebugInfo,"sweepPower start=%4.2f stop=%4.2f step=%4.2f",
11527 startdB, stopdB, stepdB);
11528 unsigned steps = 1 + (unsigned)((stopdB-startdB)/stepdB);
11529 ComplexVector sweep(steps);
11530 Complex rxBuf[2004];
11531 unsigned int status = 0;
11532 String e;
11533 for (unsigned step=0; step<steps; step++) {
11534 // set up the reference signal
11535 float dB = startdB + stepdB*step;
11536 float gain = pow(10,dB/10);
11537 setTxPattern("circle",gain);
11538 // receive the amp output
11539 Thread::msleep(10);
11540 BRF_FUNC_CALL_BREAK(setStateSyncTx(0,&e));
11541 uint64_t ts = m_syncTxState.m_tx.m_timestamp + m_radioCaps.rxLatency;
11542 BRF_FUNC_CALL_BREAK(capture(false,(float*)rxBuf,2004,ts,&e));
11543 // calculate and save the gain
11544 unsigned base = (4 - (ts % 4)) % 4;
11545 Complex sGain = meanComplexGain(rxBuf+2*base, m_txPatternBuffer.data(), 2000);
11546 Debug(m_owner,DebugAll,"sweepPower[%u] result=(%g,%g) when=" FMT64U " base=%u"
11547 " power=%4.2f (%4.2f linear) gain=%4.2f dB @ %4.2f deg",
11548 step,sGain.re(),sGain.im(),ts,base,dB,gain,
11549 10*log10(sGain.norm2()),sGain.arg()*180/M_PI);
11550 sweep[step] = sGain;
11551 }
11552 if (status) {
11553 Debug(m_owner,DebugWarn,"sweep: %u %s",status,e.c_str());
11554 sweep.resetStorage(0);
11555 }
11556 return sweep;
11557 }
11558
11559 // generic expansion function
11560 // returns the expansion factor for this power level x
11561 // x and breakpoint in linear power units
11562 // slope in units of <whatever> / <linear power>
11563 // expansion factor in units of <whatever>, determined by the units of the slope
expansion(float x,float breakpoint,float slope)11564 inline float expansion(float x, float breakpoint, float slope)
11565 {
11566 const float delta = x - breakpoint;
11567 if (delta<0) return 0;
11568 return delta*slope;
11569 }
11570
11571 // recaluclate the amplifier linearization table
11572 // should be called any time an amplifier linearization parameter changes
calculateAmpTable()11573 unsigned BrfLibUsbDevice::calculateAmpTable()
11574 {
11575 float maxGain = 1 + expansion(2, m_gainExpBreak, m_gainExpSlope);
11576 float maxPhase = expansion(2, m_phaseExpBreak, m_phaseExpSlope);
11577 float midGain = 1 + expansion(1, m_gainExpBreak, m_gainExpSlope);
11578 float midPhase = expansion(1, m_phaseExpBreak, m_phaseExpSlope);
11579 Debug(m_owner,DebugInfo,
11580 "calculateAmpTable gBp=%4.2f gS=%4.2f g0=%4.2f gMax=%4.2f "
11581 "pBp=%4.2f pS=%+4.2f p0=%+4.2f deg pMax=%+4.2f deg",
11582 m_gainExpBreak, m_gainExpSlope, midGain, maxGain, m_phaseExpBreak,
11583 m_phaseExpSlope*180/M_PI, midPhase*180/M_PI, maxPhase*180/M_PI);
11584 for (unsigned i=0; i<2*2048; i++) {
11585 // normalized power level (0..2)
11586 float p = ((float)i) / 2048.0F;
11587 // base gain is 1 - this is where we compensate the 1 we subtracted from the max
11588 float gainExp = 1 + expansion(p, m_gainExpBreak, m_gainExpSlope);
11589 float phaseExp = expansion(p, m_phaseExpBreak, m_phaseExpSlope);
11590 Complex c(0,phaseExp);
11591 float adjGain = gainExp / maxGain;
11592 Complex adjust = c.exp() * adjGain;
11593 m_ampTable[2*i] = 2048*adjust.re();
11594 m_ampTable[2*i+1] = 2048*adjust.im();
11595 }
11596 m_ampTableUse = true;
11597 return 0;
11598 }
11599
11600 }; // anonymous namespace
11601
11602 /* vi: set ts=8 sw=4 sts=4 noet enc=utf-8: */
11603