~ubuntu-branches/ubuntu/trusty/gnuradio/trusty-updates

« back to all changes in this revision

Viewing changes to usrp2/host/lib/usrp2_impl.cc

  • Committer: Package Import Robot
  • Author(s): A. Maitland Bottoms
  • Date: 2012-02-26 21:26:16 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20120226212616-vsfkbi1158xshdql
Tags: 3.5.1-1
* new upstream version, re-packaged from scratch with modern tools
    closes: #642716, #645332, #394849, #616832, #590048, #642580,
    #647018, #557050, #559640, #631863
* CMake build

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- c++ -*- */
2
 
/*
3
 
 * Copyright 2008,2009 Free Software Foundation, Inc.
4
 
 *
5
 
 * This program is free software: you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License as published by
7
 
 * the Free Software Foundation, either version 3 of the License, or
8
 
 * (at your option) any later version.
9
 
 *
10
 
 * This program is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 * GNU General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU General Public License
16
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 
 */
18
 
 
19
 
#ifdef HAVE_CONFIG_H
20
 
#include <config.h>
21
 
#endif
22
 
 
23
 
#include <usrp2/usrp2.h>
24
 
#include <usrp2/tune_result.h>
25
 
#include <usrp2/copiers.h>
26
 
#include <gruel/inet.h>
27
 
#include <usrp2_types.h>
28
 
#include "usrp2_impl.h"
29
 
#include "usrp2_thread.h"
30
 
#include "eth_buffer.h"
31
 
#include "pktfilter.h"
32
 
#include "control.h"
33
 
#include "ring.h"
34
 
#include <stdexcept>
35
 
#include <iostream>
36
 
#include <stdio.h>
37
 
#include <stddef.h>
38
 
#include <assert.h>
39
 
#include <string.h>
40
 
 
41
 
#define USRP2_IMPL_DEBUG 0
42
 
#if USRP2_IMPL_DEBUG
43
 
#define DEBUG_LOG(x) ::write(2, x, 1)
44
 
#else
45
 
#define DEBUG_LOG(x)
46
 
#endif
47
 
 
48
 
static const int DEFAULT_RX_SCALE = 1024;
49
 
 
50
 
namespace usrp2 {
51
 
 
52
 
  static const double DEF_CMD_TIMEOUT = 0.1;
53
 
 
54
 
  std::string
55
 
  opcode_to_string(int opcode)
56
 
  {
57
 
    switch(opcode){
58
 
    case OP_EOP: return "OP_EOP";
59
 
    case OP_ID: return "OP_ID";
60
 
    case OP_ID_REPLY: return "OP_ID_REPLY";
61
 
    case OP_BURN_MAC_ADDR: return "OP_BURN_MAC_ADDR";
62
 
    case OP_READ_TIME: return "OP_READ_TIME";
63
 
    case OP_READ_TIME_REPLY: return "OP_READ_TIME_REPLY";
64
 
    case OP_CONFIG_RX_V2: return "OP_CONFIG_RX_V2";
65
 
    case OP_CONFIG_RX_REPLY_V2: return "OP_CONFIG_RX_REPLY_V2";
66
 
    case OP_CONFIG_TX_V2: return "OP_CONFIG_TX_V2";
67
 
    case OP_CONFIG_TX_REPLY_V2: return "OP_CONFIG_TX_REPLY_V2";
68
 
    case OP_START_RX_STREAMING: return "OP_START_RX_STREAMING";
69
 
    case OP_STOP_RX: return "OP_STOP_RX";
70
 
    case OP_CONFIG_MIMO: return "OP_CONFIG_MIMO";
71
 
    case OP_DBOARD_INFO: return "OP_DBOARD_INFO";
72
 
    case OP_DBOARD_INFO_REPLY: return "OP_DBOARD_INFO_REPLY";
73
 
    case OP_SYNC_TO_PPS: return "OP_SYNC_TO_PPS";
74
 
    case OP_PEEK: return "OP_PEEK";
75
 
    case OP_PEEK_REPLY: return "OP_PEEK_REPLY";
76
 
    case OP_SET_TX_LO_OFFSET: return "OP_SET_TX_LO_OFFSET";
77
 
    case OP_SET_TX_LO_OFFSET_REPLY: return "OP_SET_TX_LO_OFFSET_REPLY";
78
 
    case OP_SET_RX_LO_OFFSET: return "OP_SET_RX_LO_OFFSET";
79
 
    case OP_SET_RX_LO_OFFSET_REPLY: return "OP_SET_RX_LO_OFFSET_REPLY";
80
 
    case OP_SYNC_EVERY_PPS: return "OP_SYNC_EVERY_PPS";
81
 
    case OP_SYNC_EVERY_PPS_REPLY: return "OP_SYNC_EVERY_PPS_REPLY";
82
 
 
83
 
    default:
84
 
      char buf[64];
85
 
      snprintf(buf, sizeof(buf), "<unknown opcode: %d>", opcode);
86
 
      return buf;
87
 
    }
88
 
  }
89
 
 
90
 
 
91
 
  /*!
92
 
   * \param p points to fixed header
93
 
   * \param payload_len_in_bytes is length of the fixed hdr and the payload
94
 
   * \param[out] items is set to point to the first uint32 item in the payload
95
 
   * \param[out] nitems is set to the number of uint32 items in the payload
96
 
   * \param[out] md is filled in with the parsed metadata from the frame.
97
 
   */
98
 
  static bool
99
 
  parse_rx_metadata(void *p, size_t payload_len_in_bytes,
100
 
                    uint32_t **items, size_t *nitems_in_uint32s, rx_metadata *md)
101
 
  {
102
 
    if (payload_len_in_bytes < sizeof(u2_fixed_hdr_t))  // invalid format
103
 
      return false;
104
 
 
105
 
    // FIXME deal with the fact that (p % 4) == 2
106
 
    //assert((((uintptr_t) p) % 4) == 0);               // must be 4-byte aligned
107
 
 
108
 
    u2_fixed_hdr_t *fh = static_cast<u2_fixed_hdr_t *>(p);
109
 
    
110
 
    // FIXME unaligned loads!
111
 
    md->word0 = u2p_word0(fh);
112
 
    md->timestamp = u2p_timestamp(fh);
113
 
 
114
 
    // FIXME when we've got more info
115
 
    // md->start_of_burst = (md->word0 & XXX) != 0;
116
 
    // md->end_of_burst =   (md->word0 & XXX) != 0;
117
 
    // md->rx_overrun =     (md->word0 & XXX) != 0;
118
 
    md->start_of_burst = 0;
119
 
    md->end_of_burst =   0;
120
 
    md->rx_overrun =     0;
121
 
 
122
 
    *items = (uint32_t *)(&fh[1]);
123
 
    size_t nbytes = payload_len_in_bytes - sizeof(u2_fixed_hdr_t);
124
 
    assert((nbytes % sizeof(uint32_t)) == 0);
125
 
    *nitems_in_uint32s = nbytes / sizeof(uint32_t);
126
 
 
127
 
    return true;
128
 
  }
129
 
 
130
 
 
131
 
  usrp2::impl::impl(const std::string &ifc, props *p, size_t rx_bufsize)
132
 
    : d_eth_buf(new eth_buffer(rx_bufsize)), d_interface_name(ifc), d_pf(0), d_bg_thread(0),
133
 
      d_bg_running(false), d_rx_seqno(-1), d_tx_seqno(0), d_next_rid(0),
134
 
      d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0), 
135
 
      d_num_enqueued(0), d_enqueued_mutex(), d_bg_pending_cond(&d_enqueued_mutex),
136
 
      d_channel_rings(NCHANS), d_tx_interp(0), d_rx_decim(0)
137
 
  {
138
 
    if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE)))
139
 
      throw std::runtime_error("Unable to register USRP2 protocol");
140
 
    
141
 
    d_addr = p->addr;
142
 
 
143
 
    // Create a packet filter for U2_ETHERTYPE packets sourced from target USRP2
144
 
    u2_mac_addr_t usrp_mac;
145
 
    parse_mac_addr(d_addr, &usrp_mac);
146
 
    d_pf = pktfilter::make_ethertype_inbound_target(U2_ETHERTYPE, (const unsigned char*)&(usrp_mac.addr));
147
 
    if (!d_pf || !d_eth_buf->attach_pktfilter(d_pf))
148
 
      throw std::runtime_error("Unable to attach packet filter.");
149
 
    
150
 
    if (USRP2_IMPL_DEBUG)
151
 
      std::cerr << "usrp2 constructor: using USRP2 at " << d_addr << std::endl;
152
 
 
153
 
    memset(d_pending_replies, 0, sizeof(d_pending_replies));
154
 
 
155
 
    d_bg_thread = new usrp2_thread(this);
156
 
    d_bg_thread->start();
157
 
 
158
 
    // In case the USRP2 was left streaming RX
159
 
    // FIXME: only one channel right now
160
 
    stop_rx_streaming(0);
161
 
 
162
 
    if (!dboard_info())         // we're hosed
163
 
      throw std::runtime_error("Unable to retrieve daughterboard info");
164
 
 
165
 
    if (0){
166
 
      int dbid;
167
 
 
168
 
      tx_daughterboard_id(&dbid);
169
 
      fprintf(stderr, "Tx dboard 0x%x\n", dbid);
170
 
      fprintf(stderr, "  freq_min = %g\n", tx_freq_min());
171
 
      fprintf(stderr, "  freq_max = %g\n", tx_freq_max());
172
 
      fprintf(stderr, "  gain_min = %g\n", tx_gain_min());
173
 
      fprintf(stderr, "  gain_max = %g\n", tx_gain_max());
174
 
      fprintf(stderr, "  gain_db_per_step = %g\n", tx_gain_db_per_step());
175
 
 
176
 
      rx_daughterboard_id(&dbid);
177
 
      fprintf(stderr, "Rx dboard 0x%x\n", dbid);
178
 
      fprintf(stderr, "  freq_min = %g\n", rx_freq_min());
179
 
      fprintf(stderr, "  freq_max = %g\n", rx_freq_max());
180
 
      fprintf(stderr, "  gain_min = %g\n", rx_gain_min());
181
 
      fprintf(stderr, "  gain_max = %g\n", rx_gain_max());
182
 
      fprintf(stderr, "  gain_db_per_step = %g\n", rx_gain_db_per_step());
183
 
    }
184
 
 
185
 
    // Ensure any custom values in hardware are cleared
186
 
    if (!reset_db())
187
 
      std::cerr << "usrp2::ctor reset_db failed\n";
188
 
 
189
 
    // default gains to mid point
190
 
    if (!set_tx_gain((tx_gain_min() + tx_gain_max()) / 2))
191
 
      std::cerr << "usrp2::ctor set_tx_gain failed\n";
192
 
 
193
 
    if (!set_rx_gain((rx_gain_min() + rx_gain_max()) / 2))
194
 
      std::cerr << "usrp2::ctor set_rx_gain failed\n";
195
 
 
196
 
    // default interp and decim
197
 
    if (!set_tx_interp(12))
198
 
      std::cerr << "usrp2::ctor set_tx_interp failed\n";
199
 
 
200
 
    if (!set_rx_decim(12))
201
 
      std::cerr << "usrp2::ctor set_rx_decim failed\n";
202
 
      
203
 
    // set workable defaults for scaling
204
 
    if (!set_rx_scale_iq(DEFAULT_RX_SCALE, DEFAULT_RX_SCALE))
205
 
      std::cerr << "usrp2::ctor set_rx_scale_iq failed\n";
206
 
  }
207
 
  
208
 
  usrp2::impl::~impl()
209
 
  {
210
 
    stop_bg();
211
 
    d_bg_thread = 0; // thread class deletes itself
212
 
    delete d_pf;
213
 
    d_eth_buf->close();
214
 
    delete d_eth_buf;
215
 
    
216
 
    if (USRP2_IMPL_DEBUG) {
217
 
      std::cerr << std::endl
218
 
                << "usrp2 destructor: received " << d_num_rx_frames 
219
 
                << " frames, with " << d_num_rx_missing << " lost ("
220
 
                << (d_num_rx_frames == 0 ? 0 : (int)(100.0*d_num_rx_missing/d_num_rx_frames))
221
 
                << "%), totaling " << d_num_rx_bytes
222
 
                << " bytes" << std::endl;
223
 
    }
224
 
  }
225
 
  
226
 
  bool
227
 
  usrp2::impl::parse_mac_addr(const std::string &s, u2_mac_addr_t *p)
228
 
  {
229
 
    p->addr[0] = 0x00;          // Matt's IAB
230
 
    p->addr[1] = 0x50;
231
 
    p->addr[2] = 0xC2;
232
 
    p->addr[3] = 0x85;
233
 
    p->addr[4] = 0x30;
234
 
    p->addr[5] = 0x00;
235
 
    
236
 
    int len = s.size();
237
 
    
238
 
    switch (len){
239
 
      
240
 
    case 5:
241
 
      return sscanf(s.c_str(), "%hhx:%hhx", &p->addr[4], &p->addr[5]) == 2;
242
 
      
243
 
    case 17:
244
 
      return sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
245
 
                    &p->addr[0], &p->addr[1], &p->addr[2],
246
 
                    &p->addr[3], &p->addr[4], &p->addr[5]) == 6;
247
 
    default:
248
 
      return false;
249
 
    }
250
 
  }
251
 
  
252
 
  void
253
 
  usrp2::impl::init_et_hdrs(u2_eth_packet_t *p, const std::string &dst)
254
 
  {
255
 
    p->ehdr.ethertype = htons(U2_ETHERTYPE);
256
 
    parse_mac_addr(dst, &p->ehdr.dst); 
257
 
    memcpy(&p->ehdr.src, d_eth_buf->mac(), 6);
258
 
    p->thdr.flags = 0; // FIXME transport header values?
259
 
    p->thdr.seqno = d_tx_seqno++;
260
 
    p->thdr.ack = 0;
261
 
  }
262
 
  
263
 
  void 
264
 
  usrp2::impl::init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
265
 
                             int word0_flags, int chan, uint32_t timestamp)
266
 
  {
267
 
    init_et_hdrs(p, dst);
268
 
    u2p_set_word0(&p->fixed, word0_flags, chan);
269
 
    u2p_set_timestamp(&p->fixed, timestamp);
270
 
    
271
 
    if (chan == CONTROL_CHAN) { // no sequence numbers, back it out
272
 
      p->thdr.seqno = 0;
273
 
      d_tx_seqno--;
274
 
    }
275
 
  }
276
 
  
277
 
  void
278
 
  usrp2::impl::init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd)
279
 
  {
280
 
    memset(cmd, 0, sizeof(*cmd)); 
281
 
    init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
282
 
    cmd->op.opcode = OP_CONFIG_RX_V2;
283
 
    cmd->op.len = sizeof(cmd->op);
284
 
    cmd->op.rid = d_next_rid++;
285
 
    cmd->eop.opcode = OP_EOP;
286
 
    cmd->eop.len = sizeof(cmd->eop);
287
 
  }
288
 
 
289
 
  void
290
 
  usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd)
291
 
  {
292
 
    memset(cmd, 0, sizeof(*cmd)); 
293
 
    init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
294
 
    cmd->op.opcode = OP_CONFIG_TX_V2;
295
 
    cmd->op.len = sizeof(cmd->op);
296
 
    cmd->op.rid = d_next_rid++;
297
 
    cmd->eop.opcode = OP_EOP;
298
 
    cmd->eop.len = sizeof(cmd->eop);
299
 
  }
300
 
 
301
 
  bool
302
 
  usrp2::impl::transmit_cmd(void *cmd, size_t len, pending_reply *p, double secs)
303
 
  {
304
 
    if (p)    
305
 
      d_pending_replies[p->rid()] = p;
306
 
    
307
 
    // Transmit command
308
 
    if (d_eth_buf->tx_frame(cmd, len) != eth_buffer::EB_OK) {
309
 
      d_pending_replies[p->rid()] = 0;
310
 
      return false;
311
 
    }
312
 
 
313
 
    int res = 1;
314
 
    if (p)
315
 
      res = p->wait(secs);
316
 
      
317
 
    d_pending_replies[p->rid()] = 0;
318
 
    return res == 1;
319
 
  }
320
 
 
321
 
  // ----------------------------------------------------------------
322
 
  //        Background loop: received packet demuxing
323
 
  // ----------------------------------------------------------------
324
 
 
325
 
  void
326
 
  usrp2::impl::stop_bg()
327
 
  {
328
 
    d_bg_running = false;
329
 
    d_bg_pending_cond.signal();
330
 
    
331
 
    void *dummy_status;
332
 
    d_bg_thread->join(&dummy_status);  
333
 
  }
334
 
  
335
 
  void
336
 
  usrp2::impl::bg_loop()
337
 
  {
338
 
    d_bg_running = true;
339
 
    while(d_bg_running) {
340
 
      DEBUG_LOG(":");
341
 
      // Receive available frames from ethernet buffer.  Handler will
342
 
      // process control frames, enqueue data packets in channel
343
 
      // rings, and signal blocked API threads
344
 
      int res = d_eth_buf->rx_frames(this, 100); // FIXME magic timeout
345
 
      if (res == eth_buffer::EB_ERROR)
346
 
        break;  
347
 
 
348
 
      // Wait for user API thread(s) to process all enqueued packets.
349
 
      // The channel ring thread that decrements d_num_enqueued to zero 
350
 
      // will signal this thread to continue.
351
 
      {
352
 
        omni_mutex_lock l(d_enqueued_mutex);
353
 
        while(d_num_enqueued > 0 && d_bg_running)
354
 
          d_bg_pending_cond.wait();
355
 
      }
356
 
    }
357
 
    d_bg_running = false;
358
 
  }
359
 
  
360
 
  //
361
 
  // passed to eth_buffer::rx_frames
362
 
  //
363
 
  data_handler::result
364
 
  usrp2::impl::operator()(const void *base, size_t len)
365
 
  {
366
 
    u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
367
 
 
368
 
    // FIXME unaligned load!
369
 
    int chan = u2p_chan(&pkt->hdrs.fixed);
370
 
 
371
 
    if (chan == CONTROL_CHAN) {         // control packets
372
 
      DEBUG_LOG("c");
373
 
      return handle_control_packet(base, len);
374
 
    }
375
 
    else {                              // data packets
376
 
      return handle_data_packet(base, len);
377
 
    }
378
 
 
379
 
    // not reached
380
 
  }
381
 
 
382
 
  data_handler::result
383
 
  usrp2::impl::handle_control_packet(const void *base, size_t len)
384
 
  {
385
 
    // point to beginning of payload (subpackets)
386
 
    unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
387
 
    
388
 
    // FIXME (p % 4) == 2.  Not good.  Must watch for unaligned loads.
389
 
 
390
 
    // FIXME iterate over payload, handling more than a single subpacket.
391
 
    
392
 
    int opcode = p[0];
393
 
    unsigned int oplen = p[1];
394
 
    unsigned int rid = p[2];
395
 
 
396
 
    pending_reply *rp = d_pending_replies[rid];
397
 
    if (rp) {
398
 
      unsigned int buflen = rp->len();
399
 
      if (oplen != buflen) {
400
 
        std::cerr << "usrp2: mismatched command reply length (expected: "
401
 
                  << buflen << " got: " << oplen << "). "
402
 
                  << "op = " << opcode_to_string(opcode) << std::endl;
403
 
      }     
404
 
    
405
 
      // Copy reply into caller's buffer
406
 
      memcpy(rp->buffer(), p, std::min(oplen, buflen));
407
 
      rp->signal();
408
 
      d_pending_replies[rid] = 0;
409
 
      return data_handler::RELEASE;
410
 
    }
411
 
 
412
 
    // TODO: handle unsolicited, USRP2 initiated, or late replies
413
 
    DEBUG_LOG("l");
414
 
    return data_handler::RELEASE;
415
 
  }
416
 
  
417
 
  data_handler::result
418
 
  usrp2::impl::handle_data_packet(const void *base, size_t len)
419
 
  {
420
 
    u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
421
 
    d_num_rx_frames++;
422
 
    d_num_rx_bytes += len;
423
 
    
424
 
    /* --- FIXME start of fake transport layer handler --- */
425
 
 
426
 
    if (d_rx_seqno != -1) {
427
 
      int expected_seqno = (d_rx_seqno + 1) & 0xFF;
428
 
      int seqno = pkt->hdrs.thdr.seqno; 
429
 
      
430
 
      if (seqno != expected_seqno) {
431
 
        ::write(2, "S", 1); // missing sequence number
432
 
        int missing = seqno - expected_seqno;
433
 
        if (missing < 0)
434
 
          missing += 256;
435
 
        
436
 
        d_num_rx_overruns++;
437
 
        d_num_rx_missing += missing;
438
 
      }
439
 
    }
440
 
 
441
 
    d_rx_seqno = pkt->hdrs.thdr.seqno;
442
 
 
443
 
    /* --- end of fake transport layer handler --- */
444
 
 
445
 
    // FIXME unaligned load!
446
 
    unsigned int chan = u2p_chan(&pkt->hdrs.fixed);
447
 
 
448
 
    {
449
 
      omni_mutex_lock l(d_channel_rings_mutex);
450
 
 
451
 
      if (!d_channel_rings[chan]) {
452
 
        DEBUG_LOG("!");
453
 
        return data_handler::RELEASE;   // discard packet, no channel handler
454
 
      }
455
 
      
456
 
      // Strip off ethernet header and transport header and enqueue the rest
457
 
      
458
 
      size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed);
459
 
      if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) {
460
 
        inc_enqueued();
461
 
        DEBUG_LOG("+");
462
 
        return data_handler::KEEP;      // channel ring runner will mark frame done
463
 
      }
464
 
      else {
465
 
        DEBUG_LOG("!");
466
 
        return data_handler::RELEASE;   // discard, no room in channel ring
467
 
      }         
468
 
      return data_handler::RELEASE;
469
 
    }
470
 
  }
471
 
 
472
 
 
473
 
  // ----------------------------------------------------------------
474
 
  //                           Receive
475
 
  // ----------------------------------------------------------------
476
 
 
477
 
  bool 
478
 
  usrp2::impl::set_rx_gain(double gain)
479
 
  {
480
 
    op_config_rx_v2_cmd cmd;
481
 
    op_config_rx_reply_v2_t reply;
482
 
 
483
 
    init_config_rx_v2_cmd(&cmd);
484
 
    cmd.op.valid = htons(CFGV_GAIN);
485
 
    cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
486
 
    
487
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
488
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
489
 
      return false;
490
 
 
491
 
    bool success = (ntohx(reply.ok) == 1);
492
 
    return success;
493
 
  }
494
 
  
495
 
  bool
496
 
  usrp2::impl::set_rx_lo_offset(double frequency)
497
 
  {
498
 
    op_freq_cmd cmd;
499
 
    op_generic_t reply;
500
 
 
501
 
    memset(&cmd, 0, sizeof(cmd));
502
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
503
 
    cmd.op.opcode = OP_SET_RX_LO_OFFSET;
504
 
    cmd.op.len = sizeof(cmd.op);
505
 
    cmd.op.rid = d_next_rid++;
506
 
 
507
 
    u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
508
 
    cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
509
 
    cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
510
 
 
511
 
    cmd.eop.opcode = OP_EOP;
512
 
    cmd.eop.len = sizeof(cmd.eop);
513
 
    
514
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
515
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
516
 
      return false;
517
 
 
518
 
    bool success = (ntohx(reply.ok) == 1);
519
 
    return success;
520
 
  }
521
 
 
522
 
  bool
523
 
  usrp2::impl::set_rx_center_freq(double frequency, tune_result *result)
524
 
  {
525
 
    op_config_rx_v2_cmd cmd;
526
 
    op_config_rx_reply_v2_t reply;
527
 
 
528
 
    init_config_rx_v2_cmd(&cmd);
529
 
    cmd.op.valid = htons(CFGV_FREQ);
530
 
    u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
531
 
    cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
532
 
    cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
533
 
    
534
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
535
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
536
 
      return false;
537
 
 
538
 
    bool success = (ntohx(reply.ok) == 1);
539
 
    if (result && success) {
540
 
      result->baseband_freq =
541
 
        u2_fxpt_freq_to_double( 
542
 
          u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi), 
543
 
                                 ntohl(reply.baseband_freq_lo)));
544
 
 
545
 
      result->dxc_freq =
546
 
        u2_fxpt_freq_to_double( 
547
 
          u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi), 
548
 
                                 ntohl(reply.ddc_freq_lo)));
549
 
 
550
 
      result->residual_freq =
551
 
        u2_fxpt_freq_to_double( 
552
 
         u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi), 
553
 
                                ntohl(reply.residual_freq_lo)));
554
 
 
555
 
      result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
556
 
    }
557
 
 
558
 
    return success;
559
 
  }
560
 
  
561
 
  bool
562
 
  usrp2::impl::set_rx_decim(int decimation_factor)
563
 
  {
564
 
    op_config_rx_v2_cmd cmd;
565
 
    op_config_rx_reply_v2_t reply;
566
 
 
567
 
    init_config_rx_v2_cmd(&cmd);
568
 
    cmd.op.valid = htons(CFGV_INTERP_DECIM);
569
 
    cmd.op.decim = htonl(decimation_factor);
570
 
    
571
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
572
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
573
 
      return false;
574
 
 
575
 
    bool success = (ntohx(reply.ok) == 1);
576
 
    if (success)
577
 
      d_rx_decim = decimation_factor;
578
 
    return success;
579
 
  }
580
 
  
581
 
  bool
582
 
  usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
583
 
  {
584
 
    op_config_rx_v2_cmd cmd;
585
 
    op_config_rx_reply_v2_t reply;
586
 
 
587
 
    init_config_rx_v2_cmd(&cmd);
588
 
    cmd.op.valid = htons(CFGV_SCALE_IQ);
589
 
    cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
590
 
    
591
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
592
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
593
 
      return false;
594
 
 
595
 
    bool success = (ntohx(reply.ok) == 1);
596
 
    return success;
597
 
  }
598
 
  
599
 
  bool
600
 
  usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
601
 
  {
602
 
    if (channel > MAX_CHAN) {
603
 
      std::cerr << "usrp2: invalid channel number (" << channel
604
 
                << ")" << std::endl;
605
 
      return false;
606
 
    }
607
 
 
608
 
    if (channel > 0) { // until firmware supports multiple streams
609
 
      std::cerr << "usrp2: channel " << channel
610
 
                << " not implemented" << std::endl;
611
 
      return false;
612
 
    }
613
 
 
614
 
    {
615
 
      omni_mutex_lock l(d_channel_rings_mutex);
616
 
      if (d_channel_rings[channel]) {
617
 
        std::cerr << "usrp2: channel " << channel
618
 
                  << " already streaming" << std::endl;
619
 
        return false;
620
 
      }
621
 
      
622
 
      if (items_per_frame == 0)
623
 
        items_per_frame = U2_MAX_SAMPLES;               // minimize overhead
624
 
      
625
 
      op_start_rx_streaming_cmd cmd;
626
 
      op_generic_t reply;
627
 
 
628
 
      memset(&cmd, 0, sizeof(cmd));
629
 
      init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
630
 
      cmd.op.opcode = OP_START_RX_STREAMING;
631
 
      cmd.op.len = sizeof(cmd.op);
632
 
      cmd.op.rid = d_next_rid++;
633
 
      cmd.op.items_per_frame = htonl(items_per_frame);
634
 
      cmd.eop.opcode = OP_EOP;
635
 
      cmd.eop.len = sizeof(cmd.eop);
636
 
    
637
 
      bool success = false;
638
 
      pending_reply p(cmd.op.rid, &reply, sizeof(reply));
639
 
      success = transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
640
 
      success = success && (ntohx(reply.ok) == 1);
641
 
      
642
 
      if (success)
643
 
        d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
644
 
 
645
 
      return success;
646
 
    }
647
 
  }
648
 
  
649
 
  bool
650
 
  usrp2::impl::stop_rx_streaming(unsigned int channel)
651
 
  {
652
 
    if (channel > MAX_CHAN) {
653
 
      std::cerr << "usrp2: invalid channel number (" << channel
654
 
                << ")" << std::endl;
655
 
      return false;
656
 
    }
657
 
 
658
 
    if (channel > 0) { // until firmware supports multiple streams
659
 
      std::cerr << "usrp2: channel " << channel
660
 
                << " not implemented" << std::endl;
661
 
      return false;
662
 
    }
663
 
 
664
 
    op_stop_rx_cmd cmd;
665
 
    op_generic_t reply;
666
 
 
667
 
    {
668
 
      omni_mutex_lock l(d_channel_rings_mutex);
669
 
 
670
 
      memset(&cmd, 0, sizeof(cmd));
671
 
      init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
672
 
      cmd.op.opcode = OP_STOP_RX;
673
 
      cmd.op.len = sizeof(cmd.op);
674
 
      cmd.op.rid = d_next_rid++;
675
 
      cmd.eop.opcode = OP_EOP;
676
 
      cmd.eop.len = sizeof(cmd.eop);
677
 
    
678
 
      bool success = false;
679
 
      pending_reply p(cmd.op.rid, &reply, sizeof(reply));
680
 
      success = transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
681
 
      success = success && (ntohx(reply.ok) == 1);
682
 
      d_channel_rings[channel].reset();
683
 
      return success;
684
 
    }
685
 
  }
686
 
 
687
 
  bool
688
 
  usrp2::impl::rx_samples(unsigned int channel, rx_sample_handler *handler)
689
 
  {
690
 
    if (channel > MAX_CHAN) {
691
 
      std::cerr << "usrp2: invalid channel (" << channel
692
 
                << " )" << std::endl;
693
 
      return false;
694
 
    }
695
 
    
696
 
    if (channel > 0) {
697
 
      std::cerr << "usrp2: channel " << channel
698
 
                << " not implemented" << std::endl;
699
 
      return false;
700
 
    }
701
 
    
702
 
    ring_sptr rp = d_channel_rings[channel];
703
 
    if (!rp){
704
 
      std::cerr << "usrp2: channel " << channel
705
 
                << " not receiving" << std::endl;
706
 
      return false;
707
 
    }
708
 
    
709
 
    // Wait for frames available in channel ring
710
 
    DEBUG_LOG("W");
711
 
    rp->wait_for_not_empty();
712
 
    DEBUG_LOG("s");
713
 
    
714
 
    // Iterate through frames and present to user
715
 
    void *p;
716
 
    size_t frame_len_in_bytes;
717
 
    while (rp->dequeue(&p, &frame_len_in_bytes)) {
718
 
      uint32_t         *items;                  // points to beginning of data items
719
 
      size_t            nitems_in_uint32s;
720
 
      rx_metadata       md;
721
 
      if (!parse_rx_metadata(p, frame_len_in_bytes, &items, &nitems_in_uint32s, &md))
722
 
        return false;
723
 
 
724
 
      bool want_more = (*handler)(items, nitems_in_uint32s, &md);
725
 
      d_eth_buf->release_frame(p);
726
 
      DEBUG_LOG("-");
727
 
      dec_enqueued();
728
 
 
729
 
      if (!want_more)
730
 
        break;
731
 
    }
732
 
    return true;
733
 
  }
734
 
 
735
 
  // ----------------------------------------------------------------
736
 
  //                            Transmit
737
 
  // ----------------------------------------------------------------
738
 
 
739
 
  bool 
740
 
  usrp2::impl::set_tx_gain(double gain)
741
 
  {
742
 
    op_config_tx_v2_cmd cmd;
743
 
    op_config_tx_reply_v2_t reply;
744
 
 
745
 
    init_config_tx_v2_cmd(&cmd);
746
 
    cmd.op.valid = htons(CFGV_GAIN);
747
 
    cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
748
 
    
749
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
750
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
751
 
      return false;
752
 
 
753
 
    bool success = (ntohx(reply.ok) == 1);
754
 
    return success;
755
 
  }
756
 
  
757
 
  bool
758
 
  usrp2::impl::set_tx_lo_offset(double frequency)
759
 
  {
760
 
    op_freq_cmd cmd;
761
 
    op_generic_t reply;
762
 
 
763
 
    memset(&cmd, 0, sizeof(cmd));
764
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
765
 
    cmd.op.opcode = OP_SET_TX_LO_OFFSET;
766
 
    cmd.op.len = sizeof(cmd.op);
767
 
    cmd.op.rid = d_next_rid++;
768
 
 
769
 
    u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
770
 
    cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
771
 
    cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
772
 
 
773
 
    cmd.eop.opcode = OP_EOP;
774
 
    cmd.eop.len = sizeof(cmd.eop);
775
 
    
776
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
777
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
778
 
      return false;
779
 
 
780
 
    bool success = (ntohx(reply.ok) == 1);
781
 
    return success;
782
 
  }
783
 
 
784
 
  bool
785
 
  usrp2::impl::set_tx_center_freq(double frequency, tune_result *result)
786
 
  {
787
 
    op_config_tx_v2_cmd cmd;
788
 
    op_config_tx_reply_v2_t reply;
789
 
 
790
 
    init_config_tx_v2_cmd(&cmd);
791
 
    cmd.op.valid = htons(CFGV_FREQ);
792
 
    u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
793
 
    cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
794
 
    cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
795
 
    
796
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
797
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
798
 
      return false;
799
 
 
800
 
    bool success = (ntohx(reply.ok) == 1);
801
 
    if (result && success) {
802
 
      result->baseband_freq =
803
 
        u2_fxpt_freq_to_double( 
804
 
          u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi), 
805
 
                                 ntohl(reply.baseband_freq_lo)));
806
 
 
807
 
      result->dxc_freq =
808
 
        u2_fxpt_freq_to_double( 
809
 
          u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi), 
810
 
                                 ntohl(reply.duc_freq_lo)));
811
 
 
812
 
      result->residual_freq =
813
 
        u2_fxpt_freq_to_double( 
814
 
         u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi), 
815
 
                                ntohl(reply.residual_freq_lo)));
816
 
 
817
 
      result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
818
 
    }
819
 
 
820
 
    return success;
821
 
  }
822
 
  
823
 
  bool
824
 
  usrp2::impl::set_tx_interp(int interpolation_factor)
825
 
  {
826
 
    op_config_tx_v2_cmd cmd;
827
 
    op_config_tx_reply_v2_t reply;
828
 
 
829
 
    init_config_tx_v2_cmd(&cmd);
830
 
    cmd.op.valid = htons(CFGV_INTERP_DECIM);
831
 
    cmd.op.interp = htonl(interpolation_factor);
832
 
    
833
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
834
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
835
 
      return false;
836
 
 
837
 
    bool success = (ntohx(reply.ok) == 1);
838
 
    if (success) {
839
 
      d_tx_interp = interpolation_factor;
840
 
 
841
 
      // Auto-set TX scaling based on interpolation rate
842
 
      int scale_i, scale_q;
843
 
      default_tx_scale_iq(d_tx_interp, &scale_i, &scale_q);
844
 
      return set_tx_scale_iq(scale_i, scale_q);
845
 
    }
846
 
 
847
 
    return success;
848
 
  }
849
 
  
850
 
  void
851
 
  usrp2::impl::default_tx_scale_iq(int interpolation_factor, int *scale_i, int *scale_q)
852
 
  {
853
 
    // Calculate CIC interpolation (i.e., without halfband interpolators)
854
 
    int i = interpolation_factor;
855
 
    if (i > 128)
856
 
      i = i >> 1;
857
 
    if (i > 128)
858
 
      i = i >> 1;
859
 
 
860
 
    // Calculate dsp_core_tx gain absent scale multipliers
861
 
    float gain = (1.65*i*i*i)/(4096*pow(2, ceil(log2(i*i*i))));
862
 
    
863
 
    // Calculate closest multiplier constant to reverse gain
864
 
    int scale = (int)rint(1.0/gain);
865
 
    // fprintf(stderr, "if=%i i=%i gain=%f scale=%i\n", interpolation_factor, i, gain, scale);
866
 
 
867
 
    // Both I and Q are identical in this case
868
 
    if (scale_i)
869
 
      *scale_i = scale;
870
 
    if (scale_q)
871
 
      *scale_q = scale;
872
 
  }
873
 
 
874
 
  bool
875
 
  usrp2::impl::set_tx_scale_iq(int scale_i, int scale_q)
876
 
  {
877
 
    op_config_tx_v2_cmd cmd;
878
 
    op_config_tx_reply_v2_t reply;
879
 
 
880
 
    init_config_tx_v2_cmd(&cmd);
881
 
    cmd.op.valid = htons(CFGV_SCALE_IQ);
882
 
    cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
883
 
    
884
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
885
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
886
 
      return false;
887
 
 
888
 
    bool success = (ntohx(reply.ok) == 1);
889
 
    return success;
890
 
  }
891
 
 
892
 
  bool
893
 
  usrp2::impl::tx_32fc(unsigned int channel,
894
 
                       const std::complex<float> *samples,
895
 
                       size_t nsamples,
896
 
                       const tx_metadata *metadata)
897
 
  {
898
 
    uint32_t items[nsamples];
899
 
    copy_host_32fc_to_u2_16sc(nsamples, samples, items);
900
 
    return tx_raw(channel, items, nsamples, metadata);
901
 
  }
902
 
 
903
 
  bool
904
 
  usrp2::impl::tx_16sc(unsigned int channel,
905
 
                       const std::complex<int16_t> *samples,
906
 
                       size_t nsamples,
907
 
                       const tx_metadata *metadata)
908
 
  {
909
 
#ifdef WORDS_BIGENDIAN
910
 
 
911
 
    // Already binary equivalent to 16-bit I/Q on the wire.
912
 
    // No conversion required.
913
 
 
914
 
    assert(sizeof(samples[0]) == sizeof(uint32_t));
915
 
    return tx_raw(channel, (const uint32_t *) samples, nsamples, metadata);
916
 
 
917
 
#else
918
 
 
919
 
    uint32_t items[nsamples];
920
 
    copy_host_16sc_to_u2_16sc(nsamples, samples, items);
921
 
    return tx_raw(channel, items, nsamples, metadata);
922
 
 
923
 
#endif
924
 
  }
925
 
 
926
 
  bool
927
 
  usrp2::impl::tx_raw(unsigned int channel,
928
 
                      const uint32_t *items,
929
 
                      size_t nitems,
930
 
                      const tx_metadata *metadata)
931
 
  {
932
 
    if (nitems == 0)
933
 
      return true;
934
 
 
935
 
    // FIXME can't deal with nitems < U2_MIN_SAMPLES (will be fixed in VRT)
936
 
    // FIXME need to check the MTU instead of assuming 1500 bytes
937
 
 
938
 
    // fragment as necessary then fire away
939
 
 
940
 
    size_t nframes = (nitems + U2_MAX_SAMPLES - 1) / U2_MAX_SAMPLES;
941
 
    size_t last_frame = nframes - 1;
942
 
    u2_eth_packet_t     hdrs;
943
 
 
944
 
    size_t n = 0;
945
 
    for (size_t fn = 0; fn < nframes; fn++){
946
 
      uint32_t timestamp = 0;
947
 
      uint32_t flags = 0;
948
 
 
949
 
      if (fn == 0){
950
 
        timestamp = metadata->timestamp;
951
 
        if (metadata->send_now)
952
 
          flags |= U2P_TX_IMMEDIATE;
953
 
        if (metadata->start_of_burst)
954
 
          flags |= U2P_TX_START_OF_BURST;
955
 
      }
956
 
      if (fn > 0){
957
 
        flags |= U2P_TX_IMMEDIATE;
958
 
      }
959
 
      if (fn == last_frame){
960
 
        if (metadata->end_of_burst)
961
 
          flags |= U2P_TX_END_OF_BURST;
962
 
      }
963
 
 
964
 
      init_etf_hdrs(&hdrs, d_addr, flags, channel, timestamp);
965
 
 
966
 
      // Avoid short packet by splitting last two packets if reqd
967
 
      size_t i;
968
 
      if ((nitems - n) > U2_MAX_SAMPLES && (nitems - n) < (U2_MAX_SAMPLES + U2_MIN_SAMPLES))
969
 
        i = (nitems - n) / 2;
970
 
      else
971
 
        i = std::min((size_t) U2_MAX_SAMPLES, nitems - n);
972
 
 
973
 
      eth_iovec iov[2];
974
 
      iov[0].iov_base = &hdrs;
975
 
      iov[0].iov_len = sizeof(hdrs);
976
 
      iov[1].iov_base = const_cast<uint32_t *>(&items[n]);
977
 
      iov[1].iov_len = i * sizeof(uint32_t);
978
 
 
979
 
      size_t total = iov[0].iov_len + iov[1].iov_len;
980
 
      if (total < 64)
981
 
        fprintf(stderr, "usrp2::tx_raw: FIXME: short packet: %zd items (%zd bytes)\n", i, total);
982
 
 
983
 
      if (d_eth_buf->tx_framev(iov, 2) != eth_buffer::EB_OK){
984
 
        return false;
985
 
      }
986
 
 
987
 
      n += i;
988
 
    }
989
 
 
990
 
    return true;
991
 
  }
992
 
 
993
 
  // ----------------------------------------------------------------
994
 
  //                       misc commands
995
 
  // ----------------------------------------------------------------
996
 
 
997
 
  bool
998
 
  usrp2::impl::config_mimo(int flags)
999
 
  {
1000
 
    op_config_mimo_cmd cmd;
1001
 
    op_generic_t reply;
1002
 
 
1003
 
    memset(&cmd, 0, sizeof(cmd));
1004
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1005
 
    cmd.op.opcode = OP_CONFIG_MIMO;
1006
 
    cmd.op.len = sizeof(cmd.op);
1007
 
    cmd.op.rid = d_next_rid++;
1008
 
    cmd.op.flags = flags;
1009
 
    cmd.eop.opcode = OP_EOP;
1010
 
    cmd.eop.len = sizeof(cmd.eop);
1011
 
    
1012
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1013
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1014
 
      return false;
1015
 
 
1016
 
    return ntohx(reply.ok) == 1;
1017
 
  }
1018
 
 
1019
 
  bool
1020
 
  usrp2::impl::fpga_master_clock_freq(long *freq)
1021
 
  {
1022
 
    *freq = 100000000L;         // 100 MHz
1023
 
    return true;
1024
 
  }
1025
 
 
1026
 
  bool
1027
 
  usrp2::impl::adc_rate(long *rate)
1028
 
  {
1029
 
    return fpga_master_clock_freq(rate);
1030
 
  }
1031
 
 
1032
 
  bool
1033
 
  usrp2::impl::dac_rate(long *rate)
1034
 
  {
1035
 
    return fpga_master_clock_freq(rate);
1036
 
  }
1037
 
 
1038
 
  bool
1039
 
  usrp2::impl::tx_daughterboard_id(int *dbid)
1040
 
  {
1041
 
    *dbid = d_tx_db_info.dbid;
1042
 
    return true;
1043
 
  }
1044
 
 
1045
 
  bool
1046
 
  usrp2::impl::rx_daughterboard_id(int *dbid)
1047
 
  {
1048
 
    *dbid = d_rx_db_info.dbid;
1049
 
    return true;
1050
 
  }
1051
 
 
1052
 
 
1053
 
  // ----------------------------------------------------------------
1054
 
  //                    low-level commands
1055
 
  // ----------------------------------------------------------------
1056
 
 
1057
 
  bool
1058
 
  usrp2::impl::burn_mac_addr(const std::string &new_addr)
1059
 
  {
1060
 
    op_burn_mac_addr_cmd cmd;
1061
 
    op_generic_t reply;
1062
 
 
1063
 
    memset(&cmd, 0, sizeof(cmd));
1064
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1065
 
    cmd.op.opcode = OP_BURN_MAC_ADDR;
1066
 
    cmd.op.len = sizeof(cmd.op);
1067
 
    cmd.op.rid = d_next_rid++;
1068
 
    if (!parse_mac_addr(new_addr, &cmd.op.addr))
1069
 
      return false;
1070
 
 
1071
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1072
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, 4*DEF_CMD_TIMEOUT))
1073
 
      return false;
1074
 
 
1075
 
    bool success = (ntohx(reply.ok) == 1);
1076
 
    return success;
1077
 
  }
1078
 
 
1079
 
  static void
1080
 
  fill_dboard_info(db_info *dst, const u2_db_info_t *src)
1081
 
  {
1082
 
    dst->dbid = ntohl(src->dbid);
1083
 
 
1084
 
    dst->freq_min =
1085
 
      u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi), 
1086
 
                                                    ntohl(src->freq_min_lo)));
1087
 
    dst->freq_max =
1088
 
      u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi), 
1089
 
                                                    ntohl(src->freq_max_lo)));
1090
 
 
1091
 
    dst->gain_min = u2_fxpt_gain_to_double(ntohs(src->gain_min));
1092
 
    dst->gain_max = u2_fxpt_gain_to_double(ntohs(src->gain_max));
1093
 
    dst->gain_step_size = u2_fxpt_gain_to_double(ntohs(src->gain_step_size));
1094
 
  }
1095
 
 
1096
 
  bool
1097
 
  usrp2::impl::dboard_info()
1098
 
  {
1099
 
    op_dboard_info_cmd          cmd;
1100
 
    op_dboard_info_reply_t      reply;
1101
 
 
1102
 
    memset(&cmd, 0, sizeof(cmd));
1103
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1104
 
    cmd.op.opcode = OP_DBOARD_INFO;
1105
 
    cmd.op.len = sizeof(cmd.op);
1106
 
    cmd.op.rid = d_next_rid++;
1107
 
    cmd.eop.opcode = OP_EOP;
1108
 
    cmd.eop.len = sizeof(cmd.eop);
1109
 
    
1110
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1111
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1112
 
      return false;
1113
 
 
1114
 
    bool success = (ntohx(reply.ok) == 1);
1115
 
    if (success){
1116
 
      fill_dboard_info(&d_tx_db_info, &reply.tx_db_info);
1117
 
      fill_dboard_info(&d_rx_db_info, &reply.rx_db_info);
1118
 
    }
1119
 
    return success;
1120
 
  }
1121
 
 
1122
 
 
1123
 
  bool
1124
 
  usrp2::impl::sync_to_pps()
1125
 
  {
1126
 
    op_generic_cmd cmd;
1127
 
    op_generic_t   reply;
1128
 
 
1129
 
    memset(&cmd, 0, sizeof(cmd));
1130
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1131
 
    cmd.op.opcode = OP_SYNC_TO_PPS;
1132
 
    cmd.op.len = sizeof(cmd.op);
1133
 
    cmd.op.rid = d_next_rid++;
1134
 
    cmd.eop.opcode = OP_EOP;
1135
 
    cmd.eop.len = sizeof(cmd.eop);
1136
 
    
1137
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1138
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1139
 
      return false;
1140
 
 
1141
 
    return ntohx(reply.ok) == 1;
1142
 
  }
1143
 
 
1144
 
  bool
1145
 
  usrp2::impl::sync_every_pps(bool enable)
1146
 
  {
1147
 
    op_generic_cmd cmd;
1148
 
    op_generic_t   reply;
1149
 
 
1150
 
    memset(&cmd, 0, sizeof(cmd));
1151
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1152
 
    cmd.op.opcode = OP_SYNC_EVERY_PPS;
1153
 
    cmd.op.len = sizeof(cmd.op);
1154
 
    cmd.op.rid = d_next_rid++;
1155
 
    cmd.op.ok = enable ? 1 : 0;
1156
 
    cmd.eop.opcode = OP_EOP;
1157
 
    cmd.eop.len = sizeof(cmd.eop);
1158
 
    
1159
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1160
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1161
 
      return false;
1162
 
 
1163
 
    return ntohx(reply.ok) == 1;
1164
 
  }
1165
 
 
1166
 
  std::vector<uint32_t>
1167
 
  usrp2::impl::peek32(uint32_t addr, uint32_t words)
1168
 
  {
1169
 
    std::vector<uint32_t> result; // zero sized on error return
1170
 
    // fprintf(stderr, "usrp2::peek: addr=%08X words=%u\n", addr, words);
1171
 
 
1172
 
    if (addr % 4 != 0) {
1173
 
      fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr); 
1174
 
      return result;
1175
 
    }
1176
 
 
1177
 
    if (words == 0)
1178
 
      return result;
1179
 
 
1180
 
    op_peek_cmd   cmd;
1181
 
    op_generic_t *reply;
1182
 
 
1183
 
    int wlen = sizeof(uint32_t);
1184
 
    int rlen = sizeof(op_generic_t);
1185
 
    size_t bytes = words*wlen;
1186
 
 
1187
 
    memset(&cmd, 0, sizeof(cmd));
1188
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1189
 
    cmd.op.opcode = OP_PEEK;
1190
 
    cmd.op.len = sizeof(cmd.op);
1191
 
    cmd.op.rid = d_next_rid++;
1192
 
    cmd.eop.opcode = OP_EOP;
1193
 
    cmd.eop.len = sizeof(cmd.eop);
1194
 
 
1195
 
    cmd.op.addr = htonl(addr);
1196
 
    cmd.op.bytes = htonl(bytes);
1197
 
 
1198
 
    reply = (op_generic_t *)malloc(rlen+bytes);
1199
 
    pending_reply p(cmd.op.rid, reply, rlen+bytes);
1200
 
    if (transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) {
1201
 
      uint32_t nwords = (reply->len-rlen)/sizeof(uint32_t);
1202
 
      uint32_t *data = (uint32_t *)(reply+rlen/wlen);
1203
 
      for (unsigned int i = 0; i < nwords; i++)
1204
 
        result.push_back(ntohl(data[i]));
1205
 
    }
1206
 
 
1207
 
    free(reply);
1208
 
    return result;
1209
 
  }
1210
 
 
1211
 
  bool
1212
 
  usrp2::impl::poke32(uint32_t addr, const std::vector<uint32_t> &data)
1213
 
  {
1214
 
    if (addr % 4 != 0) {
1215
 
      fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr); 
1216
 
      return false;
1217
 
    }
1218
 
 
1219
 
    int plen = sizeof(op_poke_cmd);
1220
 
    int wlen = sizeof(uint32_t);
1221
 
    int max_words = (MAX_SUBPKT_LEN-plen)/wlen;
1222
 
    int words = data.size();
1223
 
 
1224
 
    if (words > max_words) {
1225
 
      fprintf(stderr, "usrp2::poke32: write size (=%u) exceeds maximum of %u words\n",
1226
 
              words, max_words);
1227
 
      return false;
1228
 
    }
1229
 
 
1230
 
    //fprintf(stderr, "usrp2::poke32: addr=%08X words=%u\n", addr, words);
1231
 
 
1232
 
    if (words == 0)
1233
 
      return true; // NOP
1234
 
 
1235
 
    op_poke_cmd  *cmd;
1236
 
    op_generic_t *eop;
1237
 
 
1238
 
    // Allocate, clear, and initialize command packet
1239
 
    int bytes = words*wlen;
1240
 
    int l = plen+bytes+sizeof(*eop); // op_poke_cmd+data+eop
1241
 
    cmd = (op_poke_cmd *)malloc(l);
1242
 
    //fprintf(stderr, "cmd=%p l=%i\n", cmd, l);
1243
 
    memset(cmd, 0, l);
1244
 
    init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
1245
 
    cmd->op.opcode = OP_POKE;
1246
 
    cmd->op.len = sizeof(cmd->op)+bytes;
1247
 
    cmd->op.rid = d_next_rid++;
1248
 
    cmd->op.addr = htonl(addr);
1249
 
 
1250
 
    // Copy data from vector into packet space
1251
 
    uint32_t *dest = (uint32_t *)((uint8_t *)cmd+plen);
1252
 
    for (int i = 0; i < words; i++) {
1253
 
      //fprintf(stderr, "%03i@%p\n", i, dest);
1254
 
      *dest++ = htonl(data[i]);
1255
 
    }
1256
 
 
1257
 
    // Write end-of-packet subpacket
1258
 
    eop = (op_generic_t *)dest;
1259
 
    eop->opcode = OP_EOP;
1260
 
    eop->len = sizeof(*eop);
1261
 
    //fprintf(stderr, "eop=%p len=%i\n", eop, eop->len);
1262
 
 
1263
 
    // Send command to device and retrieve reply
1264
 
    bool ok = false;
1265
 
    op_generic_t reply;
1266
 
    pending_reply p(cmd->op.rid, &reply, sizeof(reply));
1267
 
    if (transmit_cmd(cmd, l, &p, DEF_CMD_TIMEOUT))
1268
 
      ok = (ntohx(reply.ok) == 1);
1269
 
 
1270
 
    free(cmd);
1271
 
    return ok;
1272
 
  }
1273
 
 
1274
 
  bool
1275
 
  usrp2::impl::reset_db()
1276
 
  {
1277
 
    op_generic_cmd cmd;
1278
 
    op_generic_t reply;
1279
 
 
1280
 
    memset(&cmd, 0, sizeof(cmd));
1281
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1282
 
    cmd.op.opcode = OP_RESET_DB;
1283
 
    cmd.op.len = sizeof(cmd.op);
1284
 
    cmd.op.rid = d_next_rid++;
1285
 
    cmd.eop.opcode = OP_EOP;
1286
 
    cmd.eop.len = sizeof(cmd.eop);
1287
 
    
1288
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1289
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1290
 
      return false;
1291
 
 
1292
 
    bool success = (ntohx(reply.ok) == 1);
1293
 
    return success;
1294
 
  }
1295
 
 
1296
 
  bool usrp2::impl::set_gpio_ddr(int bank, uint16_t value, uint16_t mask)
1297
 
  {
1298
 
    if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1299
 
      fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1300
 
      return false;
1301
 
    }
1302
 
 
1303
 
    op_gpio_cmd cmd;
1304
 
    op_generic_t reply;
1305
 
 
1306
 
    memset(&cmd, 0, sizeof(cmd));
1307
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1308
 
    cmd.op.opcode = OP_GPIO_SET_DDR;
1309
 
    cmd.op.len = sizeof(cmd.op);
1310
 
    cmd.op.rid = d_next_rid++;
1311
 
    cmd.op.bank = static_cast<uint8_t>(bank);
1312
 
    cmd.op.value = htons(value);
1313
 
    cmd.op.mask = htons(mask);
1314
 
    cmd.eop.opcode = OP_EOP;
1315
 
    cmd.eop.len = sizeof(cmd.eop);
1316
 
    
1317
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1318
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1319
 
      return false;
1320
 
 
1321
 
    bool success = (ntohx(reply.ok) == 1);
1322
 
    return success;
1323
 
  }
1324
 
 
1325
 
  bool usrp2::impl::set_gpio_sels(int bank, std::string sels)
1326
 
  {
1327
 
    if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1328
 
      fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1329
 
      return false;
1330
 
    }
1331
 
 
1332
 
    if (sels.size() != 16) {
1333
 
      fprintf(stderr, "set_gpio_sels: sels must be exactly 16 bytes\n");
1334
 
      return false;
1335
 
    }
1336
 
 
1337
 
    op_gpio_set_sels_cmd cmd;
1338
 
    op_generic_t reply;
1339
 
 
1340
 
    memset(&cmd, 0, sizeof(cmd));
1341
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1342
 
    cmd.op.opcode = OP_GPIO_SET_SELS;
1343
 
    cmd.op.len = sizeof(cmd.op);
1344
 
    cmd.op.rid = d_next_rid++;
1345
 
    cmd.op.bank = static_cast<uint8_t>(bank);
1346
 
    memcpy(&cmd.op.sels, sels.c_str(), 16);
1347
 
    cmd.eop.opcode = OP_EOP;
1348
 
    cmd.eop.len = sizeof(cmd.eop);
1349
 
    
1350
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1351
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1352
 
      return false;
1353
 
 
1354
 
    bool success = (ntohx(reply.ok) == 1);
1355
 
    return success;
1356
 
  }
1357
 
 
1358
 
  bool usrp2::impl::write_gpio(int bank, uint16_t value, uint16_t mask)
1359
 
  {
1360
 
    if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1361
 
      fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1362
 
      return false;
1363
 
    }
1364
 
 
1365
 
    op_gpio_cmd cmd;
1366
 
    op_generic_t reply;
1367
 
 
1368
 
    memset(&cmd, 0, sizeof(cmd));
1369
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1370
 
    cmd.op.opcode = OP_GPIO_WRITE;
1371
 
    cmd.op.len = sizeof(cmd.op);
1372
 
    cmd.op.rid = d_next_rid++;
1373
 
    cmd.op.bank = static_cast<uint8_t>(bank);
1374
 
    cmd.op.value = htons(value);
1375
 
    cmd.op.mask = htons(mask);
1376
 
    cmd.eop.opcode = OP_EOP;
1377
 
    cmd.eop.len = sizeof(cmd.eop);
1378
 
    
1379
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1380
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1381
 
      return false;
1382
 
 
1383
 
    bool success = (ntohx(reply.ok) == 1);
1384
 
    return success;
1385
 
  }
1386
 
 
1387
 
  bool usrp2::impl::read_gpio(int bank, uint16_t *value)
1388
 
  {
1389
 
    if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1390
 
      fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1391
 
      return false;
1392
 
    }
1393
 
 
1394
 
    op_gpio_cmd cmd;
1395
 
    op_gpio_read_reply_t reply;
1396
 
 
1397
 
    memset(&cmd, 0, sizeof(cmd));
1398
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1399
 
    cmd.op.opcode = OP_GPIO_READ;
1400
 
    cmd.op.len = sizeof(cmd.op);
1401
 
    cmd.op.rid = d_next_rid++;
1402
 
    cmd.op.bank = static_cast<uint8_t>(bank);
1403
 
    cmd.op.value = 0; // not used
1404
 
    cmd.op.mask = 0;  // not used
1405
 
    cmd.eop.opcode = OP_EOP;
1406
 
    cmd.eop.len = sizeof(cmd.eop);
1407
 
    
1408
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1409
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1410
 
      return false;
1411
 
 
1412
 
    bool success = (ntohx(reply.ok) == 1);
1413
 
    if (success && (value != NULL))
1414
 
      *value = ntohs(reply.value);
1415
 
 
1416
 
    return success;
1417
 
  }
1418
 
 
1419
 
  bool usrp2::impl::enable_gpio_streaming(int bank, int enable)
1420
 
  {
1421
 
    if (bank != GPIO_RX_BANK) {
1422
 
      fprintf(stderr, "enable_gpio_streaming: only RX streaming is currently implemented\n");
1423
 
      return false;
1424
 
    }
1425
 
 
1426
 
    if ((enable & ~0x03) != 0) {
1427
 
      fprintf(stderr, "enable_gpio_streaming: invalid enable format\n");
1428
 
      return false;
1429
 
    }
1430
 
 
1431
 
    op_gpio_cmd cmd;
1432
 
    op_generic_t reply;
1433
 
 
1434
 
    memset(&cmd, 0, sizeof(cmd));
1435
 
    init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1436
 
    cmd.op.opcode = OP_GPIO_STREAM;
1437
 
    cmd.op.len = sizeof(cmd.op);
1438
 
    cmd.op.rid = d_next_rid++;
1439
 
    cmd.op.bank = static_cast<uint8_t>(bank);
1440
 
    cmd.op.value = htons((uint16_t)enable);
1441
 
    cmd.op.mask = 0;  // not used
1442
 
    cmd.eop.opcode = OP_EOP;
1443
 
    cmd.eop.len = sizeof(cmd.eop);
1444
 
    
1445
 
    pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1446
 
    if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1447
 
      return false;
1448
 
 
1449
 
    bool success = (ntohx(reply.ok) == 1);
1450
 
    return success;
1451
 
  }
1452
 
 
1453
 
} // namespace usrp2