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(&params);
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