Project

General

Profile

bladeRFDevice.cpp

Vladimir, 08/10/2017 02:33 PM

 
1
/*
2
* Copyright 2014 Free Software Foundation, Inc.
3
*
4
* This software is distributed under the terms of the GNU Affero Public License.
5
* See the COPYING file in the main directory for details.
6
*
7
* This use of this software may be subject to additional restrictions.
8
* See the LEGAL file in the main directory for details.
9

10
        This program is free software: you can redistribute it and/or modify
11
        it under the terms of the GNU Affero General Public License as published by
12
        the Free Software Foundation, either version 3 of the License, or
13
        (at your option) any later version.
14

15
        This program is distributed in the hope that it will be useful,
16
        but WITHOUT ANY WARRANTY; without even the implied warranty of
17
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
        GNU Affero General Public License for more details.
19

20
        You should have received a copy of the GNU Affero General Public License
21
        along with this program.  If not, see <http://www.gnu.org/licenses/>.
22

23
*/
24

    
25

    
26
#include <stdint.h>
27
#include <string.h>
28
#include <stdlib.h>
29
#include <stdio.h>
30
#include <unistd.h>
31
#include <signal.h>
32
#include <iomanip>
33

    
34
#include "Threads.h"
35
#include "bladeRFDevice.h"
36

    
37
#include <Logger.h>
38

    
39
#ifdef HAVE_CONFIG_H
40
#include "config.h"
41
#endif
42

    
43
#define HEALTH_BAD 10
44
#define HEALTH_DEF 20
45
#define HEALTH_MAX 30
46

    
47
 /* Stream defaults */
48
#define DEFAULT_STREAM_RX_XFERS        1
49
#define DEFAULT_STREAM_RX_BUFFERS      8
50
#define DEFAULT_STREAM_TX_XFERS        1
51
#define DEFAULT_STREAM_TX_BUFFERS      8
52
#define DEFAULT_STREAM_SAMPLES      2048
53
#define DEFAULT_STREAM_TIMEOUT       500
54

    
55
#define BANDWIDTH 1500000
56

    
57
#define TX_GAIN1 BLADERF_TXVGA1_GAIN_MAX
58
#define MAX_RX_DC_OFFSET 63
59
#define MAX_TX_DC_OFFSET 63
60
#define SHIFT_RX_DC 5
61
#define SHIFT_TX_DC 4
62

    
63
// There seems to be constant delay between RX and TX offsets.
64
// Value `10` for sps == 1 is taken from OpenBTS code and checked
65
// experimentally. Value 28 for sps == 4 was derived from experiments.
66
#define RX_TIMESTAMP_OFFSET(sps) ((sps) == 1 ? 10 : 28);
67

    
68
#define RX_OFFSET_ERROR 10
69
#define RX_OFFSET_COEF 1.5
70
#define RX_AVERAGE_DAMPING 1024
71

    
72
#if (RX_AVERAGE_DAMPING < 2)
73
#error RX_AVERAGE_DAMPING must be at least 2
74
#endif
75

    
76
//#define SHOW_COUNTERS 4333
77

    
78
#define STRING(s) #s
79

    
80

    
81
using namespace std;
82

    
83
bladeRFDevice::bladeRFDevice(int sps_rx, int sps_tx, bool skipRx)
84
    : sps_rx(sps_rx), sps_tx(sps_tx), skipRx(skipRx), rxGain(0.0)
85
{
86
    LOG(INFO) << "creating bladeRF device...";
87
    isSuperSpeed = false;
88
}
89

    
90
int bladeRFDevice::open(const std::string &args, bool)
91
{
92
    // Global libbladeRF log level, order is reversed so 0 = silent, 6 = verbose
93
    // bladerf_log_set_verbosity((bladerf_log_level)BLADERF_LOG_LEVEL_SILENT - gConfig.getNum("TRX.BladeRF.Debug")));
94
    bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_DEBUG);
95

    
96
    ScopedLock myLock(writeLock);
97

    
98
    struct bladerf_version ver;
99
    bladerf_version(&ver);
100
    LOG(INFO) << "bladeRF library version " << ver.major << "." << ver.minor << "."
101
        << ver.patch << " (" << ver.describe << ")";
102
    int status = bladerf_open(&bdev, args.c_str());
103
    if (status < 0) {
104
        LOG(ALERT) << "Could not open bladeRF device: " << bladerf_strerror(status);
105
        return false;
106
    }
107
    char buf[34];
108
    bladerf_get_serial(bdev, buf);
109
    status = bladerf_fw_version(bdev, &ver);
110
    if (status < 0) {
111
        LOG(WARNING) << "Opened bladeRF serial=" << buf << " firmware version error: " << bladerf_strerror(status);
112
    }
113
    else
114
        LOG(NOTICE) << "Opened bladeRF serial=" << buf << " firmware version " << ver.major
115
            << "." << ver.minor << "." << ver.patch << " (" << ver.describe << ")";
116

    
117
    // bladerf_fpga_size bfs;
118
    // const char* fpgaName = "none";
119
    // if (!(status = bladerf_get_fpga_size(bdev, &bfs))) {
120
    //     fpgaName = (bfs == BLADERF_FPGA_40KLE) ? "hostedx40.rbf" : "hostedx115.rbf";
121
    //     status = bladerf_load_fpga(bdev, fpgaName);
122
    //     if (status < 0) {
123
    //         LOG(ALERT) << "Error loading FPGA file " << fpgaName << ": " << bladerf_strerror(status);
124
    //         return false;
125
    //     }
126
    // } else {
127
    //     LOG(ALERT) << "Error fetching FPGA size: " << bladerf_strerror(status);
128
    //     return false;
129
    // }
130
    // status = bladerf_fpga_version(bdev, &ver);
131
    // if (status < 0) {
132
    //     LOG(WARNING) << "bladeRF FPGA " << fpgaName << " is loaded, version error: " << bladerf_strerror(status);
133
    // }
134
    // else
135
    //     LOG(INFO) << "bladeRF FPGA " << fpgaName << " is loaded with version " << ver.major << "." << ver.minor
136
    //         << "." << ver.patch << " (" << ver.describe << ")";
137

    
138
    switch (bladerf_device_speed(bdev)) {
139
        case BLADERF_DEVICE_SPEED_HIGH:
140
            break;
141
        case BLADERF_DEVICE_SPEED_SUPER:
142
            isSuperSpeed = true;
143
            break;
144
        default:
145
            LOG(EMERG) << "Unsupported USB device speed";
146
            return false;
147
    }
148
    int vco = getFactoryValue(std::string("freq"));
149
    printf("vco %d\n",  vco);
150
    setVCTCXOrad1(vco);
151

    
152
    struct bladerf_rational_rate rate, actual;
153
    rate.integer = (sps_rx * 13e6) / 48;
154
    rate.num = (sps_rx * 13e6) - rate.integer * 48;
155
    rate.den = 48;
156

    
157
    LOG(INFO) << "Setting rate " << rate.integer << " + " << rate.num << " / " << rate.den;
158
    if ((status = bladerf_set_rational_sample_rate(bdev, BLADERF_MODULE_RX, &rate, &actual) < 0)) {
159
        LOG(ALERT) << "Error setting RX sampling rate: " << bladerf_strerror(status);
160
        return false;
161
    }
162
    printf("RX rate: %lu %lu/%lu, actual %lu %lu/%lu\n", rate.integer, rate.num, rate.den,
163
           actual.integer, actual.num, actual.den);
164

    
165
    rate.integer = (sps_tx * 13e6) / 48;
166
    rate.num = (sps_tx * 13e6) - rate.integer * 48;
167
    rate.den = 48;
168
    if ((status = bladerf_set_rational_sample_rate(bdev, BLADERF_MODULE_TX, &rate, &actual)) < 0) {
169
        LOG(ALERT) << "Error setting TX sampling rate: " << bladerf_strerror(status);
170
        return false;
171
    }
172
    printf("RX rate: %lu %lu/%lu, actual %lu %lu/%lu\n", rate.integer, rate.num, rate.den,
173
           actual.integer, actual.num, actual.den);
174
    LOG(INFO) << "Actual rate " << actual.integer << " + " << actual.num << " / " << actual.den;
175

    
176
    mRxHealth = HEALTH_DEF;
177
    mTxHealth = HEALTH_DEF;
178

    
179
    unsigned int bw = 0;
180
    if ((status = bladerf_set_bandwidth(bdev, BLADERF_MODULE_RX, BANDWIDTH, &bw) < 0)) {
181
        LOG(ALERT) << "Error setting RX bandwidth: " << bladerf_strerror(status);
182
        checkHealth(mRxHealth, false);
183
    }
184

    
185
    if ((status = bladerf_set_bandwidth(bdev, BLADERF_MODULE_TX, BANDWIDTH, &bw) < 0)) {
186
        LOG(ALERT) << "Error setting TX bandwidth: " << bladerf_strerror(status);
187
        checkHealth(mTxHealth, false);
188
    }
189
    else
190
        LOG(INFO) << "Actual bandwidth " << bw;
191

    
192
    status = bladerf_sync_config(bdev,
193
        BLADERF_MODULE_RX,
194
        BLADERF_FORMAT_SC16_Q11,
195
        DEFAULT_STREAM_RX_BUFFERS,
196
        DEFAULT_STREAM_SAMPLES,
197
        DEFAULT_STREAM_RX_XFERS,
198
        DEFAULT_STREAM_TIMEOUT
199
    );
200

    
201
    if (status < 0) {
202
        LOG(CRIT) << "Failed to intialize RX sync handle: " << bladerf_strerror(status);
203
        checkHealth(mRxHealth, false);
204
    }
205

    
206
    status = bladerf_sync_config(bdev,
207
        BLADERF_MODULE_TX,
208
        BLADERF_FORMAT_SC16_Q11,
209
        DEFAULT_STREAM_TX_BUFFERS,
210
        DEFAULT_STREAM_SAMPLES,
211
        DEFAULT_STREAM_TX_XFERS,
212
        DEFAULT_STREAM_TIMEOUT
213
    );
214

    
215
    if (status < 0) {
216
        LOG(CRIT) << "Failed to intialize TX sync handle: " << bladerf_strerror(status);
217
        checkHealth(mTxHealth, false);
218
    }
219

    
220
    uint32_t val = 0;
221
    bladerf_config_gpio_read(bdev, &val);
222
    val |= 0x10000; //enable timestamps, clears and resets everything on write
223
    bladerf_config_gpio_write(bdev, val);
224
    bladerf_config_gpio_read(bdev, &val);
225
    if (!(val & 0x10000)) {
226
        LOG(ALERT) << "Could not enable timestamps";
227
        return false;
228
    }
229
    LOG(INFO) << "bladeRF timestamping enabled";
230

    
231
    mRxGain1 = BLADERF_RXVGA1_GAIN_MAX;
232
    mDcCorrect = true;
233
    mRxMaxOffset = RX_OFFSET_ERROR * RX_AVERAGE_DAMPING;
234
    mRxCorrectionI = mRxCorrectionQ = MAX_RX_DC_OFFSET + 1;
235
    // setRxOffsets(gConfig.getNum("TRX.RX.OffsetI"), gConfig.getNum("TRX.RX.OffsetQ"));
236
    // setTxOffsets(gConfig.getNum("TRX.TX.OffsetI"), gConfig.getNum("TRX.TX.OffsetQ"));
237
    setRxOffsets(0, 0);
238
    setTxOffsets(0, 0);
239

    
240
    // Set initial gains to minimum, the transceiver will adjust them later
241
    setTxGain(minTxGain(), 0);
242
    setRxGain(minRxGain(), 0);
243

    
244
    samplesRead = 0;
245
    samplesWritten = 0;
246
    pulseMode = -1;
247
    rxShowInfo = 0;
248
    txShowInfo = 0;
249
    spammy = false;
250
    return NORMAL;
251
}
252

    
253

    
254
bool bladeRFDevice::start()
255
{
256
  LOG(NOTICE) << "starting bladeRF in " << (isSuperSpeed ? "super" : "high") << " speed mode...";
257
  if (!bdev) return false;
258

    
259
  writeLock.lock();
260

    
261
  int status;
262
  if ((status = bladerf_enable_module(bdev, BLADERF_MODULE_RX, 1)) < 0) {
263
      LOG(ALERT) << "Error enabling RX: " << bladerf_strerror(status);
264
      return false;
265
  }
266

    
267
  if ((status = bladerf_enable_module(bdev, BLADERF_MODULE_TX, 1)) < 0) {
268
      LOG(ALERT) << "Error enabling TX: " << bladerf_strerror(status);
269
      return false;
270
  }
271

    
272
  writeLock.unlock();
273

    
274
  data = new short[currDataSize];
275
  rxBufIndex = 0;
276
  rxBufCount = 0;
277
  rxConsumed = useSamples();
278
  txBuffered = 0;
279
  rxTimestamp = initialReadTimestamp();
280
  txTimestamp = initialWriteTimestamp();
281
  rxResyncCandidate = 0;
282
  samplesRead = 0;
283
  samplesWritten = 0;
284
  mRxAverageI = 0;
285
  mRxAverageQ = 0;
286

    
287
  return true;
288
}
289

    
290
bool bladeRFDevice::stop()
291
{
292
  bladerf_enable_module(bdev, BLADERF_MODULE_RX, 0);
293
  bladerf_enable_module(bdev, BLADERF_MODULE_TX, 0);
294
  delete[] data;
295

    
296
  return true;
297
}
298

    
299
double bladeRFDevice::setTxGain(double dB, size_t chan)
300
{
301
    // RAD1 supports only attentuation
302
    dB += maxTxGain();
303

    
304
    if (dB > maxTxGain()) dB = maxTxGain();
305
    if (dB < minTxGain()) dB = minTxGain();
306

    
307
    writeLock.lock();
308
    // bladerf_set_txvga1(bdev, TX_GAIN1);
309
    // int status = bladerf_set_txvga2(bdev, dB);
310
    bladerf_set_txvga1(bdev, -20);
311
    int status = bladerf_set_txvga2(bdev, 0);
312
    writeLock.unlock();
313
    if (status < 0) {
314
        LOG(ERR) << "Error setting TX gain: " << bladerf_strerror(status);
315
        checkHealth(mTxHealth, false);
316
    }
317
    else
318
        LOG(INFO) << "TX gain set to " << dB << " dB.";
319

    
320
    return dB - maxTxGain();
321
}
322

    
323
double bladeRFDevice::setRxGain(double dB, size_t chan)
324
{
325

    
326
    if (dB > maxRxGain()) dB = maxRxGain();
327
    if (dB < minRxGain()) dB = minRxGain();
328

    
329
    writeLock.lock();
330
    mRxMaxOffset = (dB * RX_OFFSET_COEF + RX_OFFSET_ERROR) * RX_AVERAGE_DAMPING;
331
    bladerf_set_rxvga1(bdev, mRxGain1);
332
    int status = bladerf_set_rxvga2(bdev, dB);
333
    // int status = bladerf_set_rxvga2(bdev, 40);
334
    writeLock.unlock();
335
    if (status < 0) {
336
        LOG(ERR) << "Error setting RX gain: " << bladerf_strerror(status);
337
        checkHealth(mRxHealth, false);
338
    }
339
    else
340
        LOG(INFO) << "RX gain set to " << dB << " dB.";
341
    rxGain = dB;
342

    
343
    return dB;
344
}
345

    
346

    
347
// NOTE: Assumes sequential reads
348
int bladeRFDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun,
349
        TIMESTAMP timestamp, bool *underrun, unsigned *RSSI)
350
{
351
    if (len <= 0 || !bdev) return 0;
352

    
353
    if (underrun) *underrun = false;
354
    if (overrun) *overrun = false;
355

    
356
    if (spammy) {
357
        LOG(DEBUG) << ">>> RX len=" << len << " exp=" << timestamp;
358
    }
359
    if (bufs.size() != 1) {
360
        LOG(ALERT) << "BladeRF supports only one channel";
361
    }
362

    
363
    timestamp += RX_TIMESTAMP_OFFSET(sps_rx);
364

    
365
    short *buf = bufs[0];
366
    int rlen = 0;
367
    while (len > 0) {
368
        if (timestamp != rxTimestamp) {
369
            long long delta = (long long)(rxTimestamp - timestamp);
370
            //LOG(DEBUG) << "RX Timestamp difference: " << delta << " at " << rxTimestamp;
371
            if (delta > 0) {
372
                // Pad with zeros
373
                if (delta > len)
374
                    delta = len;
375
                memset(buf, 0, delta * sizeof(uint16_t) * 2);
376
                timestamp += delta;
377
                buf += (2 * delta);
378
                len -= delta;
379
                rlen += delta;
380
                if (len <= 0)
381
                    break;
382
            }
383
            else {
384
                // Discard some data
385
                delta = -delta;
386
                int rxAvail = useSamples() - rxConsumed;
387
                if (rxAvail > 0) {
388
                    if (delta > rxAvail)
389
                        delta = rxAvail;
390
                    rxConsumed += delta;
391
                    rxTimestamp += delta;
392
                    if (rxResyncCandidate)
393
                        rxResyncCandidate += delta;
394
                }
395
                if (overrun)
396
                    *overrun = true;
397
            }
398
        }
399
        int rxLen = useSamples() - rxConsumed;
400
        if (rxLen > 0) {
401
            if (rxLen > len)
402
                rxLen = len;
403
            int16_t* samples = isSuperSpeed ? rxBuffer.superSpeed[rxBufIndex].samples : rxBuffer.highSpeed[rxBufIndex].samples;
404
            memcpy(buf, samples + (rxConsumed * 2), rxLen * sizeof(uint16_t) * 2);
405
            rxConsumed += rxLen;
406
            rxTimestamp += rxLen;
407
            if (rxResyncCandidate)
408
                rxResyncCandidate += rxLen;
409
            timestamp += rxLen;
410
            buf += (2 * rxLen);
411
            len -= rxLen;
412
            rlen += rxLen;
413
            samplesRead += rxLen;
414
            if (len <= 0)
415
                break;
416
        }
417
        if (++rxBufIndex >= rxBufCount) {
418
            // We are out of buffered data so we need to actually read some more
419
            rxBufCount = 0;
420
            rxBufIndex = 0;
421
            int bufCount = (len + useSamples() - 1) / useSamples();
422
            if (bufCount > PKT_BUFFERS)
423
                bufCount = PKT_BUFFERS;
424
            int status = bladerf_sync_rx(bdev, &rxBuffer, rawSamples() * bufCount, NULL, DEFAULT_STREAM_TIMEOUT);
425
            if (status < 0) {
426
                LOG(ERR) << "Samples RX failed at " << rxTimestamp << ": " << bladerf_strerror(status);
427
                checkHealth(mRxHealth, false);
428
                break;
429
            }
430
            checkHealth(mRxHealth, true);
431
            rxBufCount = bufCount;
432
            // Compute averages and peak values
433
            int iMin = 32767;
434
            int iMax = -32767;
435
            int iAvg = 0;
436
            int qMin = 32767;
437
            int qMax = -32767;
438
            int qAvg = 0;
439
            int wPeak = 0;
440
            TIMESTAMP t = rxTimestamp;
441
            TIMESTAMP peak = 0;
442
            for (int b = 0; b < bufCount; b++) {
443
                int16_t* s = isSuperSpeed ? rxBuffer.superSpeed[b].samples : rxBuffer.highSpeed[b].samples;
444
                for (int n = useSamples(); n > 0; n--, t++) {
445
                    int i = *s++;
446
                    int q = *s++;
447
                    iAvg += i;
448
                    qAvg += q;
449
                    if (!rxShowInfo)
450
                        continue;
451
                    if (iMin > i)
452
                        iMin = i;
453
                    if (iMax < i)
454
                        iMax = i;
455
                    if (qMin > q)
456
                        qMin = q;
457
                    if (qMax < q)
458
                        qMax = q;
459
                    if (wPeak < iMax) { wPeak = iMax; peak = t; }
460
                    if (wPeak < -iMin) { wPeak = -iMin; peak = t; }
461
                    if (wPeak < qMax) { wPeak = qMax; peak = t; }
462
                    if (wPeak < -qMin) { wPeak = -qMin; peak = t; }
463
                }
464
            }
465
            iAvg /= (bufCount * useSamples());
466
            qAvg /= (bufCount * useSamples());
467
            if (rxShowInfo) {
468
                if (rxShowInfo > 0)
469
                    rxShowInfo--;
470
                LOG(DEBUG) << "I: " << iMin << "/" << iAvg << "/" << iMax
471
                    << " Q: " << qMin << "/" << qAvg << "/" << qMax
472
                    << " @ " << peak << (wPeak >= 1024 ? " <<<" : "");
473
            }
474
            // DC offsets compensation feedback using an exponential moving average
475
            mRxAverageI = ((RX_AVERAGE_DAMPING - 1) * mRxAverageI / RX_AVERAGE_DAMPING) + iAvg;
476
            mRxAverageQ = ((RX_AVERAGE_DAMPING - 1) * mRxAverageQ / RX_AVERAGE_DAMPING) + qAvg;
477
            int corrI = mRxCorrectionI;
478
            int corrQ = mRxCorrectionQ;
479
            if ((mRxAverageI > mRxMaxOffset) && (corrI < MAX_RX_DC_OFFSET)) {
480
                corrI++;
481
                mRxAverageI = 0;
482
            }
483
            else if ((mRxAverageI < -mRxMaxOffset) && (corrI > -MAX_RX_DC_OFFSET)) {
484
                corrI--;
485
                mRxAverageI = 0;
486
            }
487
            if ((mRxAverageQ > mRxMaxOffset) && (corrQ < MAX_RX_DC_OFFSET)) {
488
                corrQ++;
489
                mRxAverageQ = 0;
490
            }
491
            else if ((mRxAverageQ < -mRxMaxOffset) && (corrQ > -MAX_RX_DC_OFFSET)) {
492
                corrQ--;
493
                mRxAverageQ = 0;
494
            }
495
            if (mDcCorrect && ((corrI != mRxCorrectionI) || (corrQ != mRxCorrectionQ))) {
496
                LOG(INFO) << "Adjusting Rx DC offsets: " << corrI << " " << corrQ;
497
                setRxOffsets(corrI, corrQ);
498
            }
499
        }
500
        rxConsumed = 0;
501
        struct bladerf_timestamp& header = isSuperSpeed ? rxBuffer.superSpeed[rxBufIndex].header : rxBuffer.highSpeed[rxBufIndex].header;
502
        TIMESTAMP tStamp = (((uint64_t)usrp_to_host_u32(header.time_hi)) << 31) | (usrp_to_host_u32(header.time_lo) >> 1);
503
//LOG(DEBUG) << "len=" << len << " exp=" << timestamp << " got=" << tStamp << " idx=" << rxBufIndex << " cnt=" << rxBufCount;
504
        if (tStamp != rxTimestamp) {
505
            long long delta = (long long)(tStamp - rxTimestamp);
506
            if (abs(delta) < 1000 || (tStamp == rxResyncCandidate)) {
507
                LOG(NOTICE) << "RX Timestamp adjusted by " << delta << " to " << tStamp;
508
                rxTimestamp = tStamp;
509
                rxResyncCandidate = 0;
510
                if (overrun && (delta > 0))
511
                    *overrun = true;
512
            }
513
            else {
514
                LOG(WARNING) << "RX Timestamp jumped by " << delta << " at " << rxTimestamp << " in buffer " << rxBufIndex << "/" << rxBufCount;
515
                rxResyncCandidate = tStamp;
516
            }
517
        }
518
        // Rob: disabled temporarily
519
        /*
520
        uint32_t flags = usrp_to_host_u32(header.flags);
521
        if ((flags >> 28) & 0x04) {
522
            if (underrun) *underrun = true;
523
            LOG(DEBUG) << "UNDERRUN in TRX->bladeRF interface";
524
        }
525
        if (RSSI)
526
            *RSSI = (flags >> 21) & 0x3f;
527
        */
528
    }
529

    
530
#ifdef SHOW_COUNTERS
531
    {
532
        static int i = 0;
533
        if (++i >= SHOW_COUNTERS) {
534
            i = 0;
535
            LOG(DEBUG) << rlen << " @ " << rxTimestamp;
536
        }
537
    }
538
#endif
539

    
540
    if (spammy) {
541
        LOG(DEBUG) << "<<< RX len=" << rlen;
542
    }
543
    return rlen;
544
}
545

    
546
//#include <unistd.h>
547
//#include <fcntl.h>
548
//static int bf = -1;
549

    
550
int bladeRFDevice::writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
551
        TIMESTAMP timestamp,
552
        bool isControl)
553
{
554
    if (bufs.size() != 1) {
555
        LOG(ALERT) << "BladeRF supports only one channel";
556
    }
557
    short *buf = bufs[0];
558

    
559
    if (len <= 0 || !bdev) return 0;
560

    
561
    if (txShowInfo) {
562
        if (txShowInfo > 0)
563
            txShowInfo--;
564
        int wMin = 0;
565
        int wMax = 0;
566
        for (int si = 0; si < 2*len; si++) {
567
            if (wMin > buf[si])
568
                wMin = buf[si];
569
            if (wMax < buf[si])
570
                wMax = buf[si];
571
        }
572
        LOG(DEBUG) << "TX min=" << wMin << " max=" << wMax;
573
    }
574

    
575
//if (bf < 0)
576
//    bf = ::open("tx.raw",O_CREAT|O_TRUNC|O_WRONLY);
577
//if (bf >= 0)
578
//    ::write(bf,buf,4*len);
579
    if (spammy) {
580
        LOG(DEBUG) << ">>> TX len=" << len << " tstamp=" << timestamp;
581
    }
582

    
583
    writeLock.lock();
584
    int olen = len;
585

    
586
        // DAVID COMMENT:  The samples in buf[] are assumed to be in the 
587
        // proper scaling.
588
        //
589
    // If there are gaps in timestamp drop the buffer and resynch
590
    TIMESTAMP tStamp = txTimestamp + txBuffered;
591
    if (timestamp != tStamp) {
592
        LOG(WARNING) << "TX Timestamp difference: " << timestamp << " vs " << tStamp;
593
        txBuffered = 0;
594
        txTimestamp = timestamp;
595
    }
596

    
597
    int16_t* samples = isSuperSpeed ? txBuffer.superSpeed.samples : txBuffer.superSpeed.samples;
598
    int bufSpace = useSamples() - txBuffered;
599
    if (bufSpace > 0) {
600
        // There is space left in buffer - fill it
601
        if (bufSpace > len)
602
            bufSpace = len;
603
        if (pulseMode < 0)
604
            memcpy(samples + (txBuffered * 2), buf, bufSpace * sizeof(uint16_t) * 2);
605
        else if (pulseMode < 2)
606
            memset(samples + (txBuffered * 2), 0, bufSpace * sizeof(uint16_t) * 2);
607
        else {
608
            int16_t *p = samples + (txBuffered * 2);
609
            TIMESTAMP t = tStamp;
610
            for (int n = bufSpace; n > 0; n--, p+=2)
611
                switch ((t++) % pulseMode) {
612
                    case 0:
613
                        p[1] = p[0] = 1795;
614
                        break;
615
                    case 1:
616
                        p[1] = p[0] = -1795;
617
                        break;
618
                    default:
619
                        p[1] = p[0] = 0;
620
                }
621
        }
622
        txBuffered += bufSpace;
623
        buf += (2 * bufSpace);
624
        len -= bufSpace;
625
    }
626

    
627
    while (txBuffered >= useSamples()) {
628
        // We have a full buffer - send it
629
        // Each (I,Q) of a sample is counted individually by bladeRF
630
        struct bladerf_timestamp& header = isSuperSpeed ? txBuffer.superSpeed.header : txBuffer.highSpeed.header;
631
        header.time_lo = host_to_usrp_u32(txTimestamp << 1);
632
        header.time_hi = host_to_usrp_u32(txTimestamp >> 31);
633
        header.rsvd = 0xdeadbeef;
634
        header.flags = (uint32_t)-1;
635
        int status = bladerf_sync_tx(bdev, &txBuffer, rawSamples(), NULL, DEFAULT_STREAM_TIMEOUT);
636
        if (status < 0) {
637
            LOG(ERR) << "Samples TX failed at " << txTimestamp << ": " << bladerf_strerror(status);
638
            checkHealth(mTxHealth, false);
639
        }
640
        else {
641
            samplesWritten += useSamples();
642
            checkHealth(mTxHealth, true);
643
        }
644
        txTimestamp += useSamples();
645
        txBuffered = len;
646
        if (!len)
647
            break;
648
        if (txBuffered > useSamples())
649
            txBuffered = useSamples();
650
        if (pulseMode < 0)
651
            memcpy(samples, buf, txBuffered * sizeof(uint16_t) * 2);
652
        else if (pulseMode < 2)
653
            memset(samples, 0, txBuffered * sizeof(uint16_t) * 2);
654
        else {
655
            int16_t *p = samples;
656
            TIMESTAMP t = txTimestamp;
657
            for (int n = txBuffered; n > 0; n--, p+=2)
658
                switch ((t++) % pulseMode) {
659
                    case 0:
660
                        p[1] = p[0] = 1795;
661
                        break;
662
                    case 1:
663
                        p[1] = p[0] = -1795;
664
                        break;
665
                    default:
666
                        p[1] = p[0] = 0;
667
                }
668
        }
669
        buf += (2 * txBuffered);
670
        len -= txBuffered;
671
    }
672
    assert(len == 0);
673

    
674
#ifdef SHOW_COUNTERS
675
    {
676
        static int i = 0;
677
        if (++i >= SHOW_COUNTERS) {
678
            i = 0;
679
            LOG(DEBUG) << olen << " @ " << timestamp << " in future " << (long long)(timestamp - rxTimestamp);
680
        }
681
    }
682
#endif
683
    writeLock.unlock();
684
    // Chances are we underrun if we are less than one buffer ahead
685
    if (underrun && (timestamp <= (olen + rxTimestamp)))
686
        *underrun = true;
687
    if (spammy) {
688
        LOG(DEBUG) << "<<< TX len=" << olen;
689
    }
690
    return olen;
691
}
692

    
693
bool bladeRFDevice::setVCTCXOrad1(unsigned int adj)
694
{
695
    return bladerf_dac_write(bdev, adj << 8) >= 0;
696
}
697

    
698
bool bladeRFDevice::setLoopback(bladerf_loopback loopback)
699
{
700
    writeLock.lock();
701
    int status = bladerf_set_loopback(bdev, loopback);
702
    writeLock.unlock();
703
    if (status < 0) {
704
        LOG(ERR) << "Setting loopback mode failed: " << bladerf_strerror(status);
705
        return false;
706
    }
707
    return true;
708
}
709

    
710
bool bladeRFDevice::setVCTCXO(unsigned int wAdjFreq)
711
{
712
    LOG(INFO) << "set VCTCXO: " << wAdjFreq;
713
    ScopedLock myLock(writeLock);
714
    return setVCTCXOrad1(wAdjFreq);
715
}
716

    
717
bool bladeRFDevice::setRxOffsets(int corrI, int corrQ)
718
{
719
    if ((abs(corrI) > MAX_RX_DC_OFFSET) || (abs(corrQ) > MAX_RX_DC_OFFSET))
720
        return false;
721
    if ((corrI == mRxCorrectionI) && (corrQ == mRxCorrectionQ))
722
        return true;
723
    writeLock.lock();
724
    mRxCorrectionI = corrI;
725
    mRxCorrectionQ = corrQ;
726
    corrI <<= SHIFT_RX_DC;
727
    corrQ <<= SHIFT_RX_DC;
728
    int status = bladerf_set_correction(bdev, BLADERF_MODULE_RX, BLADERF_CORR_LMS_DCOFF_I, corrI);
729
    if (status >= 0)
730
        status = bladerf_set_correction(bdev, BLADERF_MODULE_RX, BLADERF_CORR_LMS_DCOFF_Q, corrQ);
731
    writeLock.unlock();
732
    if (status < 0) {
733
        LOG(ERR) << "Setting RX DC correction failed: " << bladerf_strerror(status);
734
        return false;
735
    }
736
    return true;
737
}
738

    
739
bool bladeRFDevice::setTxOffsets(int corrI, int corrQ)
740
{
741
    if ((abs(corrI) > MAX_TX_DC_OFFSET) || (abs(corrQ) > MAX_TX_DC_OFFSET))
742
        return false;
743
    corrI <<= SHIFT_TX_DC;
744
    corrQ <<= SHIFT_TX_DC;
745
    writeLock.lock();
746
    int status = bladerf_set_correction(bdev, BLADERF_MODULE_TX, BLADERF_CORR_LMS_DCOFF_I, corrI);
747
    if (status >= 0)
748
        status = bladerf_set_correction(bdev, BLADERF_MODULE_TX, BLADERF_CORR_LMS_DCOFF_Q, corrQ);
749
    writeLock.unlock();
750
    if (status < 0) {
751
        LOG(ERR) << "Setting TX DC correction failed: " << bladerf_strerror(status);
752
        return false;
753
    }
754
    return true;
755
}
756

    
757

    
758
bool bladeRFDevice::setTxFreq(double wFreq, size_t chan)
759
{
760
    LOG(INFO) << "set TX freq: " << wFreq;
761
    ScopedLock myLock(writeLock);
762
    return (bladerf_set_frequency(bdev, BLADERF_MODULE_TX, wFreq) >= 0);
763
        // && setVCTCXOrad1((unsigned int)wAdjFreq);
764
}
765

    
766
bool bladeRFDevice::setRxFreq(double wFreq, size_t chan)
767
{
768
    LOG(INFO) << "set RX freq: " << wFreq;
769
    ScopedLock myLock(writeLock);
770
    return (bladerf_set_frequency(bdev, BLADERF_MODULE_RX, wFreq) >= 0);
771
        // && setVCTCXOrad1((unsigned int)wAdjFreq);
772
}
773

    
774

    
775
// Factory calibration handling
776

    
777
unsigned int bladeRFDevice::getFactoryValue(const std::string &name)
778
{
779
    if (name == "freq") {
780
        uint16_t trim = 0x8000;
781
        bladerf_get_vctcxo_trim(bdev, &trim);
782
        trim = trim >> 8;
783
        LOG(INFO) << "get VCTCXO: " << trim;
784
        return trim;
785
    }
786
    // TODO : need a better error condition here
787
    else
788
        return 0;
789
}
790

    
791
bool bladeRFDevice::runCustom(const std::string &command)
792
{
793
    if (command == "normal" || command == "on") {
794
        pulseMode = -1;
795
        setLoopback(BLADERF_LB_NONE);
796
    }
797
    else if (command == "unmodulated" || command == "off")
798
        pulseMode = 0;
799
    else if (command == "modulated")
800
        pulseMode = -1;
801
    else if (command.substr(0,6) == "pulsed") {
802
        if (::sscanf(command.c_str(),"%*s %d",&pulseMode) != 1 || pulseMode < 2)
803
            pulseMode = 2;
804
        else if (pulseMode > 1000000)
805
            pulseMode = 1000000;
806
    }
807
    else if (command == "loopback none")
808
        setLoopback(BLADERF_LB_NONE);
809
    else if (command == "loopback lna1")
810
        setLoopback(BLADERF_LB_RF_LNA1);
811
    else if (command == "loopback lna2")
812
        setLoopback(BLADERF_LB_RF_LNA2);
813
    else if (command == "loopback lna3")
814
        setLoopback(BLADERF_LB_RF_LNA3);
815
    else if (command.substr(0,10) == "tx offsets") {
816
        int corrI = 0;
817
        int corrQ = 0;
818
        if (::sscanf(command.c_str(),"%*s %*s %d %d",&corrI,&corrQ) != 2)
819
            return false;
820
        return setTxOffsets(corrI, corrQ);
821
    }
822
    else if (command == "rx offsets auto")
823
        mDcCorrect = true;
824
    else if (command.substr(0,10) == "rx offsets") {
825
        int corrI = 0;
826
        int corrQ = 0;
827
        if (::sscanf(command.c_str(),"%*s %*s %d %d",&corrI,&corrQ) != 2)
828
            return false;
829
        bool tmp = mDcCorrect;
830
        mDcCorrect = false;
831
        if (setRxOffsets(corrI, corrQ))
832
            return true;
833
        mDcCorrect = tmp;
834
        return false;
835
    }
836
    else if (command.substr(0,8) == "rx gain1") {
837
        int gain = -1;
838
        if (::sscanf(command.c_str(),"%*s %*s %d",&gain) != 1)
839
            return false;
840
        if (BLADERF_RXVGA1_GAIN_MIN > gain || gain > BLADERF_RXVGA1_GAIN_MAX)
841
            return false;
842
        writeLock.lock();
843
        int status = bladerf_set_rxvga1(bdev, gain);
844
        if (status >= 0)
845
            mRxGain1 = gain;
846
        else {
847
            LOG(ERR) << "Error setting RX gain1: " << bladerf_strerror(status);
848
        }
849
        writeLock.unlock();
850
    }
851
    else if (command.substr(0,8) == "tx gain1") {
852
        int gain = -1;
853
        if (::sscanf(command.c_str(),"%*s %*s %d",&gain) != 1)
854
            return false;
855
        if (BLADERF_TXVGA1_GAIN_MIN > gain || gain > BLADERF_TXVGA1_GAIN_MAX)
856
            return false;
857
        writeLock.lock();
858
        int status = bladerf_set_txvga1(bdev, gain);
859
        if (status < 0) {
860
            LOG(ERR) << "Error setting TX gain1: " << bladerf_strerror(status);
861
        }
862
        writeLock.unlock();
863
    }
864
    else if (command.substr(0,8) == "tx gain2") {
865
        int gain = -1;
866
        if (::sscanf(command.c_str(),"%*s %*s %d",&gain) != 1)
867
            return false;
868
        if (BLADERF_TXVGA2_GAIN_MIN > gain || gain > BLADERF_TXVGA2_GAIN_MAX)
869
            return false;
870
        writeLock.lock();
871
        int status = bladerf_set_txvga2(bdev, gain);
872
        if (status < 0) {
873
            LOG(ERR) << "Error setting TX gain2: " << bladerf_strerror(status);
874
        }
875
        writeLock.unlock();
876
    }
877
    else if (command == "gpio read") {
878
        uint32_t val = 0;
879
        int status = bladerf_config_gpio_read(bdev,&val);
880
        if (status >= 0) {
881
            LOG(NOTICE) << "Config GPIO = 0x" << hex << std::setw(8) << std::setfill('0') << val;
882
        }
883
        else {
884
            LOG(ERR) << "Error reading config GPIO: " << bladerf_strerror(status);
885
        }
886
    }
887
    else if (command.substr(0,8) == "lms read") {
888
        int reg = -1;
889
        if (::sscanf(command.c_str(),"%*s %*s %i",&reg) != 1)
890
            return false;
891
        if (reg < 0 || reg > 255)
892
            return false;
893
        uint8_t val = 0;
894
        int status = bladerf_lms_read(bdev,reg,&val);
895
        if (status >= 0) {
896
            LOG(NOTICE) << "LMS register 0x" << hex << std::setw(2) << std::setfill('0') << reg
897
                << " = 0x" << hex << std::setw(2) << std::setfill('0') << (int)val;
898
        }
899
        else {
900
            LOG(ERR) << "Error reading LMS register " << hex << std::setw(2) << std::setfill('0')
901
                << reg << ": " << bladerf_strerror(status);
902
        }
903
    }
904
    else if (command.substr(0,9) == "lms write") {
905
        int reg = -1;
906
        int val = -1;
907
        if (::sscanf(command.c_str(),"%*s %*s %i %i",&reg,&val) != 2)
908
            return false;
909
        if (reg < 0 || reg > 255 || val < 0 || val > 255)
910
            return false;
911
        int status = bladerf_lms_write(bdev,reg,val);
912
        if (status < 0) {
913
            LOG(ERR) << "Error writing " << val << " to LMS register " << reg << ": " << bladerf_strerror(status);
914
        }
915
    }
916
    else if (command.substr(0,7) == "rx freq") {
917
        unsigned int freq = 0;
918
        if (::sscanf(command.c_str(),"%*s %*s %u",&freq) != 1)
919
            return false;
920
        if (freq < 380000000 || freq > 3800000000)
921
            return false;
922
        int status = bladerf_set_frequency(bdev, BLADERF_MODULE_RX, freq);
923
        if (status < 0) {
924
            LOG(ERR) << "Error setting RX frequency " << freq << ": " << bladerf_strerror(status);
925
        }
926
    }
927
    else if (command.substr(0,5) == "rx bw") {
928
        unsigned int bw = 0, bw_out;
929
        if (::sscanf(command.c_str(),"%*s %*s %u", &bw) != 1)
930
            return false;
931
        int status = bladerf_set_bandwidth(bdev, BLADERF_MODULE_RX, bw, &bw);
932
        if (status < 0) {
933
          LOG(ERR) << "Error setting RX bandwidth: " << bladerf_strerror(status);
934
        }
935
    }
936
    else if (command.substr(0,7) == "tx freq") {
937
        unsigned int freq = 0;
938
        if (::sscanf(command.c_str(),"%*s %*s %u",&freq) != 1)
939
            return false;
940
        if (freq < 380000000 || freq > 3800000000)
941
            return false;
942
        int status = bladerf_set_frequency(bdev, BLADERF_MODULE_TX, freq);
943
        if (status < 0) {
944
            LOG(ERR) << "Error setting TX frequency " << freq << ": " << bladerf_strerror(status);
945
        }
946
    }
947
    else if (command.substr(0,5) == "tx bw") {
948
        unsigned int bw = 0, bw_out;
949
        if (::sscanf(command.c_str(),"%*s %*s %u", &bw) != 1)
950
            return false;
951
        int status = bladerf_set_bandwidth(bdev, BLADERF_MODULE_TX, bw, &bw_out);
952
        if (status < 0) {
953
          LOG(ERR) << "Error setting TX bandwidth: " << bladerf_strerror(status);
954
        }
955
    }
956
    else if (command == "rx show on")
957
        rxShowInfo = -1;
958
    else if (command == "rx show off")
959
        rxShowInfo = 0;
960
    else if (command.substr(0,7) == "rx show") {
961
        unsigned int n = 0;
962
        if (::sscanf(command.c_str(),"%*s %*s %u",&n) != 1)
963
            return false;
964
        rxShowInfo = n;
965
    }
966
    else if (command == "tx show on")
967
        txShowInfo = -1;
968
    else if (command == "tx show off")
969
        txShowInfo = 0;
970
    else if (command.substr(0,7) == "tx show") {
971
        unsigned int n = 0;
972
        if (::sscanf(command.c_str(),"%*s %*s %u",&n) != 1)
973
            return false;
974
        txShowInfo = n;
975
    }
976
    else if (command == "spam on")
977
        spammy = true;
978
    else if (command == "spam off")
979
        spammy = false;
980
    else
981
        return false;
982
    return true;
983
}
984

    
985
void bladeRFDevice::checkHealth(int& health, bool ok)
986
{
987
    if (ok) {
988
        if (health < HEALTH_MAX)
989
            health++;
990
    }
991
    else if ((health-=HEALTH_BAD) < 0) {
992
        LOG(CRIT) << "Excessive I/O errors, bailing out";
993
        health = HEALTH_DEF;
994
        kill(getpid(), SIGTERM);
995
    }
996
}
997
/*
998
void RadioDevice::staticInit()
999
{
1000
    ConfigurationKeyMap &map = gConfig.mSchema;
1001
    ConfigurationKey *tmp;
1002

1003
    tmp = new ConfigurationKey("TRX.RX.OffsetI","0",
1004
        "",
1005
        ConfigurationKey::FACTORY,
1006
        ConfigurationKey::VALRANGE,
1007
        "-" STRING(MAX_RX_DC_OFFSET) ":" STRING(MAX_RX_DC_OFFSET),
1008
        true,
1009
        "Correction DC offset for RX DAC component I."
1010
    );
1011
    map[tmp->getName()] = *tmp;
1012
    delete tmp;
1013

1014
    tmp = new ConfigurationKey("TRX.RX.OffsetQ","0",
1015
        "",
1016
        ConfigurationKey::FACTORY,
1017
        ConfigurationKey::VALRANGE,
1018
        "-" STRING(MAX_RX_DC_OFFSET) ":" STRING(MAX_RX_DC_OFFSET),
1019
        true,
1020
        "Correction DC offset for RX DAC component Q."
1021
    );
1022
    map[tmp->getName()] = *tmp;
1023
    delete tmp;
1024

1025
    tmp = new ConfigurationKey("TRX.TX.OffsetI","0",
1026
        "",
1027
        ConfigurationKey::FACTORY,
1028
        ConfigurationKey::VALRANGE,
1029
        "-" STRING(MAX_TX_DC_OFFSET) ":" STRING(MAX_TX_DC_OFFSET),
1030
        true,
1031
        "Correction DC offset for TX DAC component I."
1032
    );
1033
    map[tmp->getName()] = *tmp;
1034
    delete tmp;
1035

1036
    tmp = new ConfigurationKey("TRX.TX.OffsetQ","0",
1037
        "",
1038
        ConfigurationKey::FACTORY,
1039
        ConfigurationKey::VALRANGE,
1040
        "-" STRING(MAX_TX_DC_OFFSET) ":" STRING(MAX_TX_DC_OFFSET),
1041
        true,
1042
        "Correction DC offset for TX DAC component Q."
1043
    );
1044
    map[tmp->getName()] = *tmp;
1045
    delete tmp;
1046

1047
    tmp = new ConfigurationKey("TRX.BladeRF.Debug","4",
1048
        "",
1049
        ConfigurationKey::DEVELOPER,
1050
        ConfigurationKey::VALRANGE,
1051
        "0:6",
1052
        true,
1053
        "Logging level for libbladeRF, 0=silent, 6=verbose."
1054
    );
1055
    map[tmp->getName()] = *tmp;
1056
    delete tmp;
1057
}
1058
*/
1059

    
1060

    
1061

    
1062
RadioDevice *RadioDevice::make(size_t sps_rx, size_t sps_tx, size_t chans,
1063
                               bool diversity, double offset)
1064
{
1065
        return new bladeRFDevice(sps_rx, sps_tx, false);
1066
}
Add picture from clipboard (Maximum size: 48.8 MB)