3
* Copyright 2008,2009 Free Software Foundation, Inc.
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.
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.
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/>.
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"
41
#define USRP2_IMPL_DEBUG 0
43
#define DEBUG_LOG(x) ::write(2, x, 1)
48
static const int DEFAULT_RX_SCALE = 1024;
52
static const double DEF_CMD_TIMEOUT = 0.1;
55
opcode_to_string(int 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";
85
snprintf(buf, sizeof(buf), "<unknown opcode: %d>", opcode);
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.
99
parse_rx_metadata(void *p, size_t payload_len_in_bytes,
100
uint32_t **items, size_t *nitems_in_uint32s, rx_metadata *md)
102
if (payload_len_in_bytes < sizeof(u2_fixed_hdr_t)) // invalid format
105
// FIXME deal with the fact that (p % 4) == 2
106
//assert((((uintptr_t) p) % 4) == 0); // must be 4-byte aligned
108
u2_fixed_hdr_t *fh = static_cast<u2_fixed_hdr_t *>(p);
110
// FIXME unaligned loads!
111
md->word0 = u2p_word0(fh);
112
md->timestamp = u2p_timestamp(fh);
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;
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);
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)
138
if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE)))
139
throw std::runtime_error("Unable to register USRP2 protocol");
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.");
150
if (USRP2_IMPL_DEBUG)
151
std::cerr << "usrp2 constructor: using USRP2 at " << d_addr << std::endl;
153
memset(d_pending_replies, 0, sizeof(d_pending_replies));
155
d_bg_thread = new usrp2_thread(this);
156
d_bg_thread->start();
158
// In case the USRP2 was left streaming RX
159
// FIXME: only one channel right now
160
stop_rx_streaming(0);
162
if (!dboard_info()) // we're hosed
163
throw std::runtime_error("Unable to retrieve daughterboard info");
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());
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());
185
// Ensure any custom values in hardware are cleared
187
std::cerr << "usrp2::ctor reset_db failed\n";
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";
193
if (!set_rx_gain((rx_gain_min() + rx_gain_max()) / 2))
194
std::cerr << "usrp2::ctor set_rx_gain failed\n";
196
// default interp and decim
197
if (!set_tx_interp(12))
198
std::cerr << "usrp2::ctor set_tx_interp failed\n";
200
if (!set_rx_decim(12))
201
std::cerr << "usrp2::ctor set_rx_decim failed\n";
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";
211
d_bg_thread = 0; // thread class deletes itself
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;
227
usrp2::impl::parse_mac_addr(const std::string &s, u2_mac_addr_t *p)
229
p->addr[0] = 0x00; // Matt's IAB
241
return sscanf(s.c_str(), "%hhx:%hhx", &p->addr[4], &p->addr[5]) == 2;
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;
253
usrp2::impl::init_et_hdrs(u2_eth_packet_t *p, const std::string &dst)
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++;
264
usrp2::impl::init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
265
int word0_flags, int chan, uint32_t timestamp)
267
init_et_hdrs(p, dst);
268
u2p_set_word0(&p->fixed, word0_flags, chan);
269
u2p_set_timestamp(&p->fixed, timestamp);
271
if (chan == CONTROL_CHAN) { // no sequence numbers, back it out
278
usrp2::impl::init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd)
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);
290
usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd)
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);
302
usrp2::impl::transmit_cmd(void *cmd, size_t len, pending_reply *p, double secs)
305
d_pending_replies[p->rid()] = p;
308
if (d_eth_buf->tx_frame(cmd, len) != eth_buffer::EB_OK) {
309
d_pending_replies[p->rid()] = 0;
317
d_pending_replies[p->rid()] = 0;
321
// ----------------------------------------------------------------
322
// Background loop: received packet demuxing
323
// ----------------------------------------------------------------
326
usrp2::impl::stop_bg()
328
d_bg_running = false;
329
d_bg_pending_cond.signal();
332
d_bg_thread->join(&dummy_status);
336
usrp2::impl::bg_loop()
339
while(d_bg_running) {
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)
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.
352
omni_mutex_lock l(d_enqueued_mutex);
353
while(d_num_enqueued > 0 && d_bg_running)
354
d_bg_pending_cond.wait();
357
d_bg_running = false;
361
// passed to eth_buffer::rx_frames
364
usrp2::impl::operator()(const void *base, size_t len)
366
u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
368
// FIXME unaligned load!
369
int chan = u2p_chan(&pkt->hdrs.fixed);
371
if (chan == CONTROL_CHAN) { // control packets
373
return handle_control_packet(base, len);
375
else { // data packets
376
return handle_data_packet(base, len);
383
usrp2::impl::handle_control_packet(const void *base, size_t len)
385
// point to beginning of payload (subpackets)
386
unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
388
// FIXME (p % 4) == 2. Not good. Must watch for unaligned loads.
390
// FIXME iterate over payload, handling more than a single subpacket.
393
unsigned int oplen = p[1];
394
unsigned int rid = p[2];
396
pending_reply *rp = d_pending_replies[rid];
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;
405
// Copy reply into caller's buffer
406
memcpy(rp->buffer(), p, std::min(oplen, buflen));
408
d_pending_replies[rid] = 0;
409
return data_handler::RELEASE;
412
// TODO: handle unsolicited, USRP2 initiated, or late replies
414
return data_handler::RELEASE;
418
usrp2::impl::handle_data_packet(const void *base, size_t len)
420
u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
422
d_num_rx_bytes += len;
424
/* --- FIXME start of fake transport layer handler --- */
426
if (d_rx_seqno != -1) {
427
int expected_seqno = (d_rx_seqno + 1) & 0xFF;
428
int seqno = pkt->hdrs.thdr.seqno;
430
if (seqno != expected_seqno) {
431
::write(2, "S", 1); // missing sequence number
432
int missing = seqno - expected_seqno;
437
d_num_rx_missing += missing;
441
d_rx_seqno = pkt->hdrs.thdr.seqno;
443
/* --- end of fake transport layer handler --- */
445
// FIXME unaligned load!
446
unsigned int chan = u2p_chan(&pkt->hdrs.fixed);
449
omni_mutex_lock l(d_channel_rings_mutex);
451
if (!d_channel_rings[chan]) {
453
return data_handler::RELEASE; // discard packet, no channel handler
456
// Strip off ethernet header and transport header and enqueue the rest
458
size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed);
459
if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) {
462
return data_handler::KEEP; // channel ring runner will mark frame done
466
return data_handler::RELEASE; // discard, no room in channel ring
468
return data_handler::RELEASE;
473
// ----------------------------------------------------------------
475
// ----------------------------------------------------------------
478
usrp2::impl::set_rx_gain(double gain)
480
op_config_rx_v2_cmd cmd;
481
op_config_rx_reply_v2_t reply;
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));
487
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
488
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
491
bool success = (ntohx(reply.ok) == 1);
496
usrp2::impl::set_rx_lo_offset(double frequency)
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++;
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));
511
cmd.eop.opcode = OP_EOP;
512
cmd.eop.len = sizeof(cmd.eop);
514
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
515
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
518
bool success = (ntohx(reply.ok) == 1);
523
usrp2::impl::set_rx_center_freq(double frequency, tune_result *result)
525
op_config_rx_v2_cmd cmd;
526
op_config_rx_reply_v2_t reply;
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));
534
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
535
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
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)));
546
u2_fxpt_freq_to_double(
547
u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi),
548
ntohl(reply.ddc_freq_lo)));
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)));
555
result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
562
usrp2::impl::set_rx_decim(int decimation_factor)
564
op_config_rx_v2_cmd cmd;
565
op_config_rx_reply_v2_t reply;
567
init_config_rx_v2_cmd(&cmd);
568
cmd.op.valid = htons(CFGV_INTERP_DECIM);
569
cmd.op.decim = htonl(decimation_factor);
571
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
572
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
575
bool success = (ntohx(reply.ok) == 1);
577
d_rx_decim = decimation_factor;
582
usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
584
op_config_rx_v2_cmd cmd;
585
op_config_rx_reply_v2_t reply;
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));
591
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
592
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
595
bool success = (ntohx(reply.ok) == 1);
600
usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
602
if (channel > MAX_CHAN) {
603
std::cerr << "usrp2: invalid channel number (" << channel
608
if (channel > 0) { // until firmware supports multiple streams
609
std::cerr << "usrp2: channel " << channel
610
<< " not implemented" << std::endl;
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;
622
if (items_per_frame == 0)
623
items_per_frame = U2_MAX_SAMPLES; // minimize overhead
625
op_start_rx_streaming_cmd cmd;
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);
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);
643
d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
650
usrp2::impl::stop_rx_streaming(unsigned int channel)
652
if (channel > MAX_CHAN) {
653
std::cerr << "usrp2: invalid channel number (" << channel
658
if (channel > 0) { // until firmware supports multiple streams
659
std::cerr << "usrp2: channel " << channel
660
<< " not implemented" << std::endl;
668
omni_mutex_lock l(d_channel_rings_mutex);
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);
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();
688
usrp2::impl::rx_samples(unsigned int channel, rx_sample_handler *handler)
690
if (channel > MAX_CHAN) {
691
std::cerr << "usrp2: invalid channel (" << channel
692
<< " )" << std::endl;
697
std::cerr << "usrp2: channel " << channel
698
<< " not implemented" << std::endl;
702
ring_sptr rp = d_channel_rings[channel];
704
std::cerr << "usrp2: channel " << channel
705
<< " not receiving" << std::endl;
709
// Wait for frames available in channel ring
711
rp->wait_for_not_empty();
714
// Iterate through frames and present to user
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;
721
if (!parse_rx_metadata(p, frame_len_in_bytes, &items, &nitems_in_uint32s, &md))
724
bool want_more = (*handler)(items, nitems_in_uint32s, &md);
725
d_eth_buf->release_frame(p);
735
// ----------------------------------------------------------------
737
// ----------------------------------------------------------------
740
usrp2::impl::set_tx_gain(double gain)
742
op_config_tx_v2_cmd cmd;
743
op_config_tx_reply_v2_t reply;
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));
749
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
750
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
753
bool success = (ntohx(reply.ok) == 1);
758
usrp2::impl::set_tx_lo_offset(double frequency)
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++;
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));
773
cmd.eop.opcode = OP_EOP;
774
cmd.eop.len = sizeof(cmd.eop);
776
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
777
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
780
bool success = (ntohx(reply.ok) == 1);
785
usrp2::impl::set_tx_center_freq(double frequency, tune_result *result)
787
op_config_tx_v2_cmd cmd;
788
op_config_tx_reply_v2_t reply;
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));
796
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
797
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
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)));
808
u2_fxpt_freq_to_double(
809
u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi),
810
ntohl(reply.duc_freq_lo)));
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)));
817
result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
824
usrp2::impl::set_tx_interp(int interpolation_factor)
826
op_config_tx_v2_cmd cmd;
827
op_config_tx_reply_v2_t reply;
829
init_config_tx_v2_cmd(&cmd);
830
cmd.op.valid = htons(CFGV_INTERP_DECIM);
831
cmd.op.interp = htonl(interpolation_factor);
833
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
834
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
837
bool success = (ntohx(reply.ok) == 1);
839
d_tx_interp = interpolation_factor;
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);
851
usrp2::impl::default_tx_scale_iq(int interpolation_factor, int *scale_i, int *scale_q)
853
// Calculate CIC interpolation (i.e., without halfband interpolators)
854
int i = interpolation_factor;
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))));
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);
867
// Both I and Q are identical in this case
875
usrp2::impl::set_tx_scale_iq(int scale_i, int scale_q)
877
op_config_tx_v2_cmd cmd;
878
op_config_tx_reply_v2_t reply;
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));
884
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
885
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
888
bool success = (ntohx(reply.ok) == 1);
893
usrp2::impl::tx_32fc(unsigned int channel,
894
const std::complex<float> *samples,
896
const tx_metadata *metadata)
898
uint32_t items[nsamples];
899
copy_host_32fc_to_u2_16sc(nsamples, samples, items);
900
return tx_raw(channel, items, nsamples, metadata);
904
usrp2::impl::tx_16sc(unsigned int channel,
905
const std::complex<int16_t> *samples,
907
const tx_metadata *metadata)
909
#ifdef WORDS_BIGENDIAN
911
// Already binary equivalent to 16-bit I/Q on the wire.
912
// No conversion required.
914
assert(sizeof(samples[0]) == sizeof(uint32_t));
915
return tx_raw(channel, (const uint32_t *) samples, nsamples, metadata);
919
uint32_t items[nsamples];
920
copy_host_16sc_to_u2_16sc(nsamples, samples, items);
921
return tx_raw(channel, items, nsamples, metadata);
927
usrp2::impl::tx_raw(unsigned int channel,
928
const uint32_t *items,
930
const tx_metadata *metadata)
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
938
// fragment as necessary then fire away
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;
945
for (size_t fn = 0; fn < nframes; fn++){
946
uint32_t timestamp = 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;
957
flags |= U2P_TX_IMMEDIATE;
959
if (fn == last_frame){
960
if (metadata->end_of_burst)
961
flags |= U2P_TX_END_OF_BURST;
964
init_etf_hdrs(&hdrs, d_addr, flags, channel, timestamp);
966
// Avoid short packet by splitting last two packets if reqd
968
if ((nitems - n) > U2_MAX_SAMPLES && (nitems - n) < (U2_MAX_SAMPLES + U2_MIN_SAMPLES))
969
i = (nitems - n) / 2;
971
i = std::min((size_t) U2_MAX_SAMPLES, nitems - n);
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);
979
size_t total = iov[0].iov_len + iov[1].iov_len;
981
fprintf(stderr, "usrp2::tx_raw: FIXME: short packet: %zd items (%zd bytes)\n", i, total);
983
if (d_eth_buf->tx_framev(iov, 2) != eth_buffer::EB_OK){
993
// ----------------------------------------------------------------
995
// ----------------------------------------------------------------
998
usrp2::impl::config_mimo(int flags)
1000
op_config_mimo_cmd cmd;
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);
1012
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1013
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1016
return ntohx(reply.ok) == 1;
1020
usrp2::impl::fpga_master_clock_freq(long *freq)
1022
*freq = 100000000L; // 100 MHz
1027
usrp2::impl::adc_rate(long *rate)
1029
return fpga_master_clock_freq(rate);
1033
usrp2::impl::dac_rate(long *rate)
1035
return fpga_master_clock_freq(rate);
1039
usrp2::impl::tx_daughterboard_id(int *dbid)
1041
*dbid = d_tx_db_info.dbid;
1046
usrp2::impl::rx_daughterboard_id(int *dbid)
1048
*dbid = d_rx_db_info.dbid;
1053
// ----------------------------------------------------------------
1054
// low-level commands
1055
// ----------------------------------------------------------------
1058
usrp2::impl::burn_mac_addr(const std::string &new_addr)
1060
op_burn_mac_addr_cmd cmd;
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))
1071
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1072
if (!transmit_cmd(&cmd, sizeof(cmd), &p, 4*DEF_CMD_TIMEOUT))
1075
bool success = (ntohx(reply.ok) == 1);
1080
fill_dboard_info(db_info *dst, const u2_db_info_t *src)
1082
dst->dbid = ntohl(src->dbid);
1085
u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi),
1086
ntohl(src->freq_min_lo)));
1088
u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi),
1089
ntohl(src->freq_max_lo)));
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));
1097
usrp2::impl::dboard_info()
1099
op_dboard_info_cmd cmd;
1100
op_dboard_info_reply_t reply;
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);
1110
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1111
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1114
bool success = (ntohx(reply.ok) == 1);
1116
fill_dboard_info(&d_tx_db_info, &reply.tx_db_info);
1117
fill_dboard_info(&d_rx_db_info, &reply.rx_db_info);
1124
usrp2::impl::sync_to_pps()
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);
1137
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1138
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1141
return ntohx(reply.ok) == 1;
1145
usrp2::impl::sync_every_pps(bool enable)
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);
1159
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1160
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1163
return ntohx(reply.ok) == 1;
1166
std::vector<uint32_t>
1167
usrp2::impl::peek32(uint32_t addr, uint32_t words)
1169
std::vector<uint32_t> result; // zero sized on error return
1170
// fprintf(stderr, "usrp2::peek: addr=%08X words=%u\n", addr, words);
1172
if (addr % 4 != 0) {
1173
fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr);
1181
op_generic_t *reply;
1183
int wlen = sizeof(uint32_t);
1184
int rlen = sizeof(op_generic_t);
1185
size_t bytes = words*wlen;
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);
1195
cmd.op.addr = htonl(addr);
1196
cmd.op.bytes = htonl(bytes);
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]));
1212
usrp2::impl::poke32(uint32_t addr, const std::vector<uint32_t> &data)
1214
if (addr % 4 != 0) {
1215
fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr);
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();
1224
if (words > max_words) {
1225
fprintf(stderr, "usrp2::poke32: write size (=%u) exceeds maximum of %u words\n",
1230
//fprintf(stderr, "usrp2::poke32: addr=%08X words=%u\n", addr, words);
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);
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);
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]);
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);
1263
// Send command to device and retrieve 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);
1275
usrp2::impl::reset_db()
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);
1288
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1289
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1292
bool success = (ntohx(reply.ok) == 1);
1296
bool usrp2::impl::set_gpio_ddr(int bank, uint16_t value, uint16_t mask)
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");
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);
1317
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1318
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1321
bool success = (ntohx(reply.ok) == 1);
1325
bool usrp2::impl::set_gpio_sels(int bank, std::string sels)
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");
1332
if (sels.size() != 16) {
1333
fprintf(stderr, "set_gpio_sels: sels must be exactly 16 bytes\n");
1337
op_gpio_set_sels_cmd cmd;
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);
1350
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1351
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1354
bool success = (ntohx(reply.ok) == 1);
1358
bool usrp2::impl::write_gpio(int bank, uint16_t value, uint16_t mask)
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");
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);
1379
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1380
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1383
bool success = (ntohx(reply.ok) == 1);
1387
bool usrp2::impl::read_gpio(int bank, uint16_t *value)
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");
1395
op_gpio_read_reply_t reply;
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);
1408
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1409
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1412
bool success = (ntohx(reply.ok) == 1);
1413
if (success && (value != NULL))
1414
*value = ntohs(reply.value);
1419
bool usrp2::impl::enable_gpio_streaming(int bank, int enable)
1421
if (bank != GPIO_RX_BANK) {
1422
fprintf(stderr, "enable_gpio_streaming: only RX streaming is currently implemented\n");
1426
if ((enable & ~0x03) != 0) {
1427
fprintf(stderr, "enable_gpio_streaming: invalid enable format\n");
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);
1445
pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1446
if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1449
bool success = (ntohx(reply.ok) == 1);
1453
} // namespace usrp2