882ad7414ad15bea9f26bf902c3fcfe062ac86cd
[debian/gnuradio] / usrp2 / host / lib / usrp2_impl.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2008,2009,2010 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 <gruel/realtime.h>
28 #include <usrp2_types.h>
29 #include "usrp2_impl.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),
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(),
136       d_channel_rings(NCHANS), d_tx_interp(0), d_rx_decim(0), d_dont_enqueue(true)
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     // Kick off receive thread
156     start_bg();
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     delete d_pf;
212     d_eth_buf->close();
213     delete d_eth_buf;
214
215     if (USRP2_IMPL_DEBUG) {
216       std::cerr << std::endl
217                 << "usrp2 destructor: received " << d_num_rx_frames
218                 << " frames, with " << d_num_rx_missing << " lost ("
219                 << (d_num_rx_frames == 0 ? 0 : (int)(100.0*d_num_rx_missing/d_num_rx_frames))
220                 << "%), totaling " << d_num_rx_bytes
221                 << " bytes" << std::endl;
222     }
223   }
224
225   bool
226   usrp2::impl::parse_mac_addr(const std::string &s, u2_mac_addr_t *p)
227   {
228     p->addr[0] = 0x00;          // Matt's IAB
229     p->addr[1] = 0x50;
230     p->addr[2] = 0xC2;
231     p->addr[3] = 0x85;
232     p->addr[4] = 0x30;
233     p->addr[5] = 0x00;
234
235     int len = s.size();
236
237     switch (len){
238
239     case 5:
240       return sscanf(s.c_str(), "%hhx:%hhx", &p->addr[4], &p->addr[5]) == 2;
241
242     case 17:
243       return sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
244                     &p->addr[0], &p->addr[1], &p->addr[2],
245                     &p->addr[3], &p->addr[4], &p->addr[5]) == 6;
246     default:
247       return false;
248     }
249   }
250
251   void
252   usrp2::impl::init_et_hdrs(u2_eth_packet_t *p, const std::string &dst)
253   {
254     p->ehdr.ethertype = htons(U2_ETHERTYPE);
255     parse_mac_addr(dst, &p->ehdr.dst);
256     memcpy(&p->ehdr.src, d_eth_buf->mac(), 6);
257     p->thdr.flags = 0; // FIXME transport header values?
258     p->thdr.seqno = d_tx_seqno++;
259     p->thdr.ack = 0;
260   }
261
262   void
263   usrp2::impl::init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
264                              int word0_flags, int chan, uint32_t timestamp)
265   {
266     init_et_hdrs(p, dst);
267     u2p_set_word0(&p->fixed, word0_flags, chan);
268     u2p_set_timestamp(&p->fixed, timestamp);
269
270     if (chan == CONTROL_CHAN) { // no sequence numbers, back it out
271       p->thdr.seqno = 0;
272       d_tx_seqno--;
273     }
274   }
275
276   void
277   usrp2::impl::init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd)
278   {
279     memset(cmd, 0, sizeof(*cmd));
280     init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
281     cmd->op.opcode = OP_CONFIG_RX_V2;
282     cmd->op.len = sizeof(cmd->op);
283     cmd->op.rid = d_next_rid++;
284     cmd->eop.opcode = OP_EOP;
285     cmd->eop.len = sizeof(cmd->eop);
286   }
287
288   void
289   usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd)
290   {
291     memset(cmd, 0, sizeof(*cmd));
292     init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
293     cmd->op.opcode = OP_CONFIG_TX_V2;
294     cmd->op.len = sizeof(cmd->op);
295     cmd->op.rid = d_next_rid++;
296     cmd->eop.opcode = OP_EOP;
297     cmd->eop.len = sizeof(cmd->eop);
298   }
299
300
301   bool
302   usrp2::impl::transmit_cmd(void *cmd_, size_t len_)
303   {
304     const void *cmd = cmd_;
305     int len = len_;
306     unsigned char tmp[64];
307
308     if (len_ < 64){             // pad to minimum ethernet frame size
309       memset(tmp, 0, sizeof(tmp));
310       memcpy(tmp, cmd_, len_);
311       cmd = tmp;
312       len = sizeof(tmp);
313     }
314
315     return d_eth_buf->tx_frame(cmd, len) == eth_buffer::EB_OK;
316   }
317
318   bool
319   usrp2::impl::transmit_cmd_and_wait(void *cmd, size_t len, pending_reply *p, double secs)
320   {
321     d_pending_replies[p->rid()] = p;
322
323     if (!transmit_cmd(cmd, len)){
324       d_pending_replies[p->rid()] = 0;
325       return false;
326     }
327
328     int res = p->wait_for_completion(secs);
329     d_pending_replies[p->rid()] = 0;
330     return res == 1;
331   }
332
333   // ----------------------------------------------------------------
334   //        Background loop: received packet demuxing
335   // ----------------------------------------------------------------
336
337   void
338   usrp2::impl::start_bg()
339   {
340     d_rx_tg.create_thread(boost::bind(&usrp2::impl::bg_loop, this));
341   }
342
343   void
344   usrp2::impl::stop_bg()
345   {
346     d_bg_running = false;
347     d_bg_pending_cond.notify_one(); // FIXME: check if needed
348     d_rx_tg.join_all();
349   }
350
351   void
352   usrp2::impl::bg_loop()
353   {
354     gruel::enable_realtime_scheduling();
355
356     d_bg_running = true;
357     while(d_bg_running) {
358       DEBUG_LOG(":");
359       // Receive available frames from ethernet buffer.  Handler will
360       // process control frames, enqueue data packets in channel
361       // rings, and signal blocked API threads
362       int res = d_eth_buf->rx_frames(this, 100); // FIXME magic timeout
363       if (res == eth_buffer::EB_ERROR)
364         break;
365
366       // Wait for user API thread(s) to process all enqueued packets.
367       // The channel ring thread that decrements d_num_enqueued to zero
368       // will signal this thread to continue.
369       {
370         gruel::scoped_lock l(d_enqueued_mutex);
371         while(d_num_enqueued > 0 && d_bg_running)
372           d_bg_pending_cond.wait(l);
373       }
374     }
375     d_bg_running = false;
376   }
377
378   //
379   // passed to eth_buffer::rx_frames
380   //
381   data_handler::result
382   usrp2::impl::operator()(const void *base, size_t len)
383   {
384     u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
385
386     // FIXME unaligned load!
387     int chan = u2p_chan(&pkt->hdrs.fixed);
388
389     if (chan == CONTROL_CHAN) {         // control packets
390       DEBUG_LOG("c");
391       return handle_control_packet(base, len);
392     }
393     else {                              // data packets
394
395       if (d_dont_enqueue)               // toss packet
396         return data_handler::RELEASE;
397
398       return handle_data_packet(base, len);
399     }
400
401     // not reached
402   }
403
404   data_handler::result
405   usrp2::impl::handle_control_packet(const void *base, size_t len)
406   {
407     // point to beginning of payload (subpackets)
408     unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
409
410     // FIXME (p % 4) == 2.  Not good.  Must watch for unaligned loads.
411
412     // FIXME iterate over payload, handling more than a single subpacket.
413
414     int opcode = p[0];
415     unsigned int oplen = p[1];
416     unsigned int rid = p[2];
417
418     pending_reply *rp = d_pending_replies[rid];
419     if (rp) {
420       unsigned int buflen = rp->len();
421       if (oplen != buflen) {
422         std::cerr << "usrp2: mismatched command reply length (expected: "
423                   << buflen << " got: " << oplen << "). "
424                   << "op = " << opcode_to_string(opcode) << std::endl;
425       }
426
427       // Copy reply into caller's buffer
428       memcpy(rp->buffer(), p, std::min(oplen, buflen));
429       rp->notify_completion();
430       d_pending_replies[rid] = 0;
431       return data_handler::RELEASE;
432     }
433
434     // TODO: handle unsolicited, USRP2 initiated, or late replies
435     DEBUG_LOG("l");
436     return data_handler::RELEASE;
437   }
438
439   data_handler::result
440   usrp2::impl::handle_data_packet(const void *base, size_t len)
441   {
442     u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
443     d_num_rx_frames++;
444     d_num_rx_bytes += len;
445
446     /* --- FIXME start of fake transport layer handler --- */
447
448     if (d_rx_seqno != -1) {
449       int expected_seqno = (d_rx_seqno + 1) & 0xFF;
450       int seqno = pkt->hdrs.thdr.seqno;
451
452       if (seqno != expected_seqno) {
453         ::write(2, "S", 1); // missing sequence number
454         int missing = seqno - expected_seqno;
455         if (missing < 0)
456           missing += 256;
457
458         d_num_rx_overruns++;
459         d_num_rx_missing += missing;
460       }
461     }
462
463     d_rx_seqno = pkt->hdrs.thdr.seqno;
464
465     /* --- end of fake transport layer handler --- */
466
467     // FIXME unaligned load!
468     unsigned int chan = u2p_chan(&pkt->hdrs.fixed);
469
470     {
471       gruel::scoped_lock l(d_channel_rings_mutex);
472
473       if (!d_channel_rings[chan]) {
474         DEBUG_LOG("!");
475         return data_handler::RELEASE;   // discard packet, no channel handler
476       }
477
478       // Strip off ethernet header and transport header and enqueue the rest
479
480       size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed);
481       if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) {
482         inc_enqueued();
483         DEBUG_LOG("+");
484         return data_handler::KEEP;      // channel ring runner will mark frame done
485       }
486       else {
487         DEBUG_LOG("!");
488         return data_handler::RELEASE;   // discard, no room in channel ring
489       }
490       return data_handler::RELEASE;
491     }
492   }
493
494
495   // ----------------------------------------------------------------
496   //                           Receive
497   // ----------------------------------------------------------------
498
499   bool
500   usrp2::impl::set_rx_antenna(int ant){
501     op_config_mimo_cmd cmd;
502     op_generic_t reply;
503
504     memset(&cmd, 0, sizeof(cmd));
505     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
506     cmd.op.opcode = OP_RX_ANTENNA;
507     cmd.op.len = sizeof(cmd.op);
508     cmd.op.rid = d_next_rid++;
509     cmd.op.flags = ant;
510     cmd.eop.opcode = OP_EOP;
511     cmd.eop.len = sizeof(cmd.eop);
512
513     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
514     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
515       return false;
516
517     return ntohx(reply.ok) == 1;
518   }
519
520   bool
521   usrp2::impl::set_rx_gain(double gain)
522   {
523     op_config_rx_v2_cmd cmd;
524     op_config_rx_reply_v2_t reply;
525
526     init_config_rx_v2_cmd(&cmd);
527     cmd.op.valid = htons(CFGV_GAIN);
528     cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
529
530     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
531     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
532       return false;
533
534     bool success = (ntohx(reply.ok) == 1);
535     return success;
536   }
537
538   bool
539   usrp2::impl::set_rx_lo_offset(double frequency)
540   {
541     op_freq_cmd cmd;
542     op_generic_t reply;
543
544     memset(&cmd, 0, sizeof(cmd));
545     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
546     cmd.op.opcode = OP_SET_RX_LO_OFFSET;
547     cmd.op.len = sizeof(cmd.op);
548     cmd.op.rid = d_next_rid++;
549
550     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
551     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
552     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
553
554     cmd.eop.opcode = OP_EOP;
555     cmd.eop.len = sizeof(cmd.eop);
556
557     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
558     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
559       return false;
560
561     bool success = (ntohx(reply.ok) == 1);
562     return success;
563   }
564
565   bool
566   usrp2::impl::set_rx_center_freq(double frequency, tune_result *result)
567   {
568     op_config_rx_v2_cmd cmd;
569     op_config_rx_reply_v2_t reply;
570
571     init_config_rx_v2_cmd(&cmd);
572     cmd.op.valid = htons(CFGV_FREQ);
573     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
574     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
575     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
576
577     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
578     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
579       return false;
580
581     bool success = (ntohx(reply.ok) == 1);
582     if (result && success) {
583       result->baseband_freq =
584         u2_fxpt_freq_to_double(
585           u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
586                                  ntohl(reply.baseband_freq_lo)));
587
588       result->dxc_freq =
589         u2_fxpt_freq_to_double(
590           u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi),
591                                  ntohl(reply.ddc_freq_lo)));
592
593       result->residual_freq =
594         u2_fxpt_freq_to_double(
595          u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
596                                 ntohl(reply.residual_freq_lo)));
597
598       result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
599     }
600
601     return success;
602   }
603
604   bool
605   usrp2::impl::set_rx_decim(int decimation_factor)
606   {
607     op_config_rx_v2_cmd cmd;
608     op_config_rx_reply_v2_t reply;
609
610     init_config_rx_v2_cmd(&cmd);
611     cmd.op.valid = htons(CFGV_INTERP_DECIM);
612     cmd.op.decim = htonl(decimation_factor);
613
614     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
615     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
616       return false;
617
618     bool success = (ntohx(reply.ok) == 1);
619     if (success)
620       d_rx_decim = decimation_factor;
621     return success;
622   }
623
624   bool
625   usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
626   {
627     op_config_rx_v2_cmd cmd;
628     op_config_rx_reply_v2_t reply;
629
630     init_config_rx_v2_cmd(&cmd);
631     cmd.op.valid = htons(CFGV_SCALE_IQ);
632     cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
633
634     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
635     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
636       return false;
637
638     bool success = (ntohx(reply.ok) == 1);
639     return success;
640   }
641
642   bool
643   usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
644   {
645     if (channel > MAX_CHAN) {
646       std::cerr << "usrp2: invalid channel number (" << channel
647                 << ")" << std::endl;
648       return false;
649     }
650
651     if (channel > 0) { // until firmware supports multiple streams
652       std::cerr << "usrp2: channel " << channel
653                 << " not implemented" << std::endl;
654       return false;
655     }
656
657     {
658       gruel::scoped_lock l(d_channel_rings_mutex);
659       if (d_channel_rings[channel]) {
660         std::cerr << "usrp2: channel " << channel
661                   << " already streaming" << std::endl;
662         return false;
663       }
664
665       if (items_per_frame == 0)
666         items_per_frame = U2_MAX_SAMPLES;               // minimize overhead
667
668       op_start_rx_streaming_cmd cmd;
669       op_generic_t reply;
670
671       memset(&cmd, 0, sizeof(cmd));
672       init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
673       cmd.op.opcode = OP_START_RX_STREAMING;
674       cmd.op.len = sizeof(cmd.op);
675       cmd.op.rid = d_next_rid++;
676       cmd.op.items_per_frame = htonl(items_per_frame);
677       cmd.eop.opcode = OP_EOP;
678       cmd.eop.len = sizeof(cmd.eop);
679
680       d_dont_enqueue = false;
681       bool success = false;
682       pending_reply p(cmd.op.rid, &reply, sizeof(reply));
683       success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
684       success = success && (ntohx(reply.ok) == 1);
685
686       if (success)
687         d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
688       else
689         d_dont_enqueue = true;
690
691       //fprintf(stderr, "usrp2::start_rx_streaming: success = %d\n", success);
692       return success;
693     }
694   }
695
696   bool
697   usrp2::impl::start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time)
698   {
699     if (channel > MAX_CHAN) {
700       std::cerr << "usrp2: invalid channel number (" << channel
701                 << ")" << std::endl;
702       return false;
703     }
704
705     if (channel > 0) { // until firmware supports multiple streams
706       std::cerr << "usrp2: channel " << channel
707                 << " not implemented" << std::endl;
708       return false;
709     }
710
711     {
712       gruel::scoped_lock guard(d_channel_rings_mutex);
713       if (d_channel_rings[channel]) {
714         std::cerr << "usrp2: channel " << channel
715                   << " already streaming" << std::endl;
716         return false;
717       }
718
719       if (items_per_frame == 0)
720         items_per_frame = U2_MAX_SAMPLES;               // minimize overhead
721
722       op_start_rx_streaming_cmd cmd;
723       op_generic_t reply;
724
725       memset(&cmd, 0, sizeof(cmd));
726       init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, time);
727       cmd.op.opcode = OP_START_RX_STREAMING;
728       cmd.op.len = sizeof(cmd.op);
729       cmd.op.rid = d_next_rid++;
730       cmd.op.items_per_frame = htonl(items_per_frame);
731       cmd.eop.opcode = OP_EOP;
732       cmd.eop.len = sizeof(cmd.eop);
733
734       d_dont_enqueue = false;
735       bool success = false;
736       pending_reply p(cmd.op.rid, &reply, sizeof(reply));
737       success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
738       success = success && (ntohx(reply.ok) == 1);
739
740       if (success)
741         d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
742       else
743         d_dont_enqueue = true;
744
745       return success;
746     }
747   }
748
749   bool
750   usrp2::impl::sync_and_start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time)
751   {
752
753     if (channel > MAX_CHAN) {
754       std::cerr << "usrp2: invalid channel number (" << channel
755                 << ")" << std::endl;
756       return false;
757     }
758
759     if (channel > 0) { // until firmware supports multiple streams
760       std::cerr << "usrp2: channel " << channel
761                 << " not implemented" << std::endl;
762       return false;
763     }
764
765     {
766       gruel::scoped_lock guard(d_channel_rings_mutex);
767       if (d_channel_rings[channel]) {
768         std::cerr << "usrp2: channel " << channel
769                   << " already streaming" << std::endl;
770         return false;
771       }
772
773       if (items_per_frame == 0)
774         items_per_frame = U2_MAX_SAMPLES;               // minimize overhead
775
776       op_sync_and_start_rx_streaming_cmd cmd;
777       op_generic_t reply;
778
779       memset(&cmd, 0, sizeof(cmd));
780       init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, time);
781       cmd.sync_op.opcode = OP_SYNC_TO_PPS;
782       cmd.sync_op.len = sizeof(cmd.sync_op);
783       cmd.sync_op.rid = d_next_rid++;
784       cmd.rx_op.opcode = OP_START_RX_STREAMING;
785       cmd.rx_op.len = sizeof(cmd.rx_op);
786       cmd.rx_op.rid = d_next_rid++;
787       cmd.rx_op.items_per_frame = htonl(items_per_frame);
788       cmd.eop.opcode = OP_EOP;
789       cmd.eop.len = sizeof(cmd.eop);
790
791       d_dont_enqueue = false;
792       bool success = false;
793       pending_reply p(cmd.sync_op.rid, &reply, sizeof(reply));
794       success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
795       success = success && (ntohx(reply.ok) == 1);
796
797       if (success)
798         d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
799       else
800         d_dont_enqueue = true;
801
802       return success;
803     }
804   }
805
806   bool
807   usrp2::impl::stop_rx_streaming(unsigned int channel)
808   {
809     if (channel > MAX_CHAN) {
810       std::cerr << "usrp2: invalid channel number (" << channel
811                 << ")" << std::endl;
812       return false;
813     }
814
815     if (channel > 0) { // until firmware supports multiple streams
816       std::cerr << "usrp2: channel " << channel
817                 << " not implemented" << std::endl;
818       return false;
819     }
820
821     d_dont_enqueue = true;      // no new samples
822     flush_rx_samples(channel);  // dump any we may already have
823
824     op_stop_rx_cmd cmd;
825     op_generic_t reply;
826
827     {
828       gruel::scoped_lock l(d_channel_rings_mutex);
829
830       memset(&cmd, 0, sizeof(cmd));
831       init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
832       cmd.op.opcode = OP_STOP_RX;
833       cmd.op.len = sizeof(cmd.op);
834       cmd.op.rid = d_next_rid++;
835       cmd.eop.opcode = OP_EOP;
836       cmd.eop.len = sizeof(cmd.eop);
837
838       bool success = false;
839       pending_reply p(cmd.op.rid, &reply, sizeof(reply));
840       success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
841       success = success && (ntohx(reply.ok) == 1);
842       d_channel_rings[channel].reset();
843       d_rx_seqno = -1;
844       //fprintf(stderr, "usrp2::stop_rx_streaming:  success = %d\n", success);
845       return success;
846     }
847   }
848
849   bool
850   usrp2::impl::rx_samples(unsigned int channel, rx_sample_handler *handler)
851   {
852     if (channel > MAX_CHAN) {
853       std::cerr << "usrp2: invalid channel (" << channel
854                 << " )" << std::endl;
855       return false;
856     }
857
858     if (channel > 0) {
859       std::cerr << "usrp2: channel " << channel
860                 << " not implemented" << std::endl;
861       return false;
862     }
863
864     ring_sptr rp = d_channel_rings[channel];
865     if (!rp){
866       std::cerr << "usrp2: channel " << channel
867                 << " not receiving" << std::endl;
868       return false;
869     }
870
871     // Wait for frames available in channel ring
872     DEBUG_LOG("W");
873     rp->wait_for_not_empty();
874     DEBUG_LOG("s");
875
876     // Iterate through frames and present to user
877     void *p;
878     size_t frame_len_in_bytes;
879     while (rp->dequeue(&p, &frame_len_in_bytes)) {
880       uint32_t         *items;                  // points to beginning of data items
881       size_t            nitems_in_uint32s;
882       rx_metadata       md;
883       if (!parse_rx_metadata(p, frame_len_in_bytes, &items, &nitems_in_uint32s, &md))
884         return false;
885
886       bool want_more = (*handler)(items, nitems_in_uint32s, &md);
887       d_eth_buf->release_frame(p);
888       DEBUG_LOG("-");
889       dec_enqueued();
890
891       if (!want_more)
892         break;
893     }
894     return true;
895   }
896
897   bool
898   usrp2::impl::flush_rx_samples(unsigned int channel)
899   {
900     if (channel > MAX_CHAN) {
901       std::cerr << "usrp2: invalid channel (" << channel
902                 << " )" << std::endl;
903       return false;
904     }
905
906     if (channel > 0) {
907       std::cerr << "usrp2: channel " << channel
908                 << " not implemented" << std::endl;
909       return false;
910     }
911
912     ring_sptr rp = d_channel_rings[channel];
913     if (!rp){
914       return false;
915     }
916
917     // Iterate through frames and drop them
918     void *p;
919     size_t frame_len_in_bytes;
920     while (rp->dequeue(&p, &frame_len_in_bytes)) {
921       d_eth_buf->release_frame(p);
922       dec_enqueued();
923     }
924     return true;
925   }
926
927   // ----------------------------------------------------------------
928   //                            Transmit
929   // ----------------------------------------------------------------
930
931   bool
932   usrp2::impl::set_tx_antenna(int ant){
933     op_config_mimo_cmd cmd;
934     op_generic_t reply;
935
936     memset(&cmd, 0, sizeof(cmd));
937     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
938     cmd.op.opcode = OP_TX_ANTENNA;
939     cmd.op.len = sizeof(cmd.op);
940     cmd.op.rid = d_next_rid++;
941     cmd.op.flags = ant;
942     cmd.eop.opcode = OP_EOP;
943     cmd.eop.len = sizeof(cmd.eop);
944
945     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
946     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
947       return false;
948
949     return ntohx(reply.ok) == 1;
950   }
951
952   bool
953   usrp2::impl::set_tx_gain(double gain)
954   {
955     op_config_tx_v2_cmd cmd;
956     op_config_tx_reply_v2_t reply;
957
958     init_config_tx_v2_cmd(&cmd);
959     cmd.op.valid = htons(CFGV_GAIN);
960     cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
961
962     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
963     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
964       return false;
965
966     bool success = (ntohx(reply.ok) == 1);
967     return success;
968   }
969
970   bool
971   usrp2::impl::set_tx_lo_offset(double frequency)
972   {
973     op_freq_cmd cmd;
974     op_generic_t reply;
975
976     memset(&cmd, 0, sizeof(cmd));
977     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
978     cmd.op.opcode = OP_SET_TX_LO_OFFSET;
979     cmd.op.len = sizeof(cmd.op);
980     cmd.op.rid = d_next_rid++;
981
982     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
983     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
984     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
985
986     cmd.eop.opcode = OP_EOP;
987     cmd.eop.len = sizeof(cmd.eop);
988
989     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
990     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
991       return false;
992
993     bool success = (ntohx(reply.ok) == 1);
994     return success;
995   }
996
997   bool
998   usrp2::impl::set_tx_center_freq(double frequency, tune_result *result)
999   {
1000     op_config_tx_v2_cmd cmd;
1001     op_config_tx_reply_v2_t reply;
1002
1003     init_config_tx_v2_cmd(&cmd);
1004     cmd.op.valid = htons(CFGV_FREQ);
1005     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
1006     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
1007     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
1008
1009     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1010     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1011       return false;
1012
1013     bool success = (ntohx(reply.ok) == 1);
1014     if (result && success) {
1015       result->baseband_freq =
1016         u2_fxpt_freq_to_double(
1017           u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
1018                                  ntohl(reply.baseband_freq_lo)));
1019
1020       result->dxc_freq =
1021         u2_fxpt_freq_to_double(
1022           u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi),
1023                                  ntohl(reply.duc_freq_lo)));
1024
1025       result->residual_freq =
1026         u2_fxpt_freq_to_double(
1027          u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
1028                                 ntohl(reply.residual_freq_lo)));
1029
1030       result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
1031     }
1032
1033     return success;
1034   }
1035
1036   bool
1037   usrp2::impl::set_tx_interp(int interpolation_factor)
1038   {
1039     op_config_tx_v2_cmd cmd;
1040     op_config_tx_reply_v2_t reply;
1041
1042     init_config_tx_v2_cmd(&cmd);
1043     cmd.op.valid = htons(CFGV_INTERP_DECIM);
1044     cmd.op.interp = htonl(interpolation_factor);
1045
1046     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1047     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1048       return false;
1049
1050     bool success = (ntohx(reply.ok) == 1);
1051     if (success) {
1052       d_tx_interp = interpolation_factor;
1053
1054       // Auto-set TX scaling based on interpolation rate
1055       int scale_i, scale_q;
1056       default_tx_scale_iq(d_tx_interp, &scale_i, &scale_q);
1057       return set_tx_scale_iq(scale_i, scale_q);
1058     }
1059
1060     return success;
1061   }
1062
1063   void
1064   usrp2::impl::default_tx_scale_iq(int interpolation_factor, int *scale_i, int *scale_q)
1065   {
1066     // Calculate CIC interpolation (i.e., without halfband interpolators)
1067     int i = interpolation_factor;
1068     if (i > 128)
1069       i = i >> 1;
1070     if (i > 128)
1071       i = i >> 1;
1072
1073     // Calculate dsp_core_tx gain absent scale multipliers
1074     float gain = (1.65*i*i*i)/(4096*pow(2, ceil(log2(i*i*i))));
1075
1076     // Calculate closest multiplier constant to reverse gain
1077     int scale = (int)rint(1.0/gain);
1078     // fprintf(stderr, "if=%i i=%i gain=%f scale=%i\n", interpolation_factor, i, gain, scale);
1079
1080     // Both I and Q are identical in this case
1081     if (scale_i)
1082       *scale_i = scale;
1083     if (scale_q)
1084       *scale_q = scale;
1085   }
1086
1087   bool
1088   usrp2::impl::set_tx_scale_iq(int scale_i, int scale_q)
1089   {
1090     op_config_tx_v2_cmd cmd;
1091     op_config_tx_reply_v2_t reply;
1092
1093     init_config_tx_v2_cmd(&cmd);
1094     cmd.op.valid = htons(CFGV_SCALE_IQ);
1095     cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
1096
1097     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1098     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1099       return false;
1100
1101     bool success = (ntohx(reply.ok) == 1);
1102     return success;
1103   }
1104
1105   bool
1106   usrp2::impl::tx_32fc(unsigned int channel,
1107                        const std::complex<float> *samples,
1108                        size_t nsamples,
1109                        const tx_metadata *metadata)
1110   {
1111     uint32_t items[nsamples];
1112     copy_host_32fc_to_u2_16sc(nsamples, samples, items);
1113     return tx_raw(channel, items, nsamples, metadata);
1114   }
1115
1116   bool
1117   usrp2::impl::tx_16sc(unsigned int channel,
1118                        const std::complex<int16_t> *samples,
1119                        size_t nsamples,
1120                        const tx_metadata *metadata)
1121   {
1122 #ifdef WORDS_BIGENDIAN
1123
1124     // Already binary equivalent to 16-bit I/Q on the wire.
1125     // No conversion required.
1126
1127     assert(sizeof(samples[0]) == sizeof(uint32_t));
1128     return tx_raw(channel, (const uint32_t *) samples, nsamples, metadata);
1129
1130 #else
1131
1132     uint32_t items[nsamples];
1133     copy_host_16sc_to_u2_16sc(nsamples, samples, items);
1134     return tx_raw(channel, items, nsamples, metadata);
1135
1136 #endif
1137   }
1138
1139   bool
1140   usrp2::impl::tx_raw(unsigned int channel,
1141                       const uint32_t *items,
1142                       size_t nitems,
1143                       const tx_metadata *metadata)
1144   {
1145     if (nitems == 0)
1146       return true;
1147
1148     // FIXME can't deal with nitems < U2_MIN_SAMPLES (will be fixed in VRT)
1149     // FIXME need to check the MTU instead of assuming 1500 bytes
1150
1151     // fragment as necessary then fire away
1152
1153     size_t nframes = (nitems + U2_MAX_SAMPLES - 1) / U2_MAX_SAMPLES;
1154     size_t last_frame = nframes - 1;
1155     u2_eth_packet_t     hdrs;
1156
1157     size_t n = 0;
1158     for (size_t fn = 0; fn < nframes; fn++){
1159       uint32_t timestamp = 0;
1160       uint32_t flags = 0;
1161
1162       if (fn == 0){
1163         timestamp = metadata->timestamp;
1164         if (metadata->send_now)
1165           flags |= U2P_TX_IMMEDIATE;
1166         if (metadata->start_of_burst)
1167           flags |= U2P_TX_START_OF_BURST;
1168       }
1169       if (fn > 0){
1170         flags |= U2P_TX_IMMEDIATE;
1171       }
1172       if (fn == last_frame){
1173         if (metadata->end_of_burst)
1174           flags |= U2P_TX_END_OF_BURST;
1175       }
1176
1177       init_etf_hdrs(&hdrs, d_addr, flags, channel, timestamp);
1178
1179       // Avoid short packet by splitting last two packets if reqd
1180       size_t i;
1181       if ((nitems - n) > U2_MAX_SAMPLES && (nitems - n) < (U2_MAX_SAMPLES + U2_MIN_SAMPLES))
1182         i = (nitems - n) / 2;
1183       else
1184         i = std::min((size_t) U2_MAX_SAMPLES, nitems - n);
1185
1186       eth_iovec iov[2];
1187       iov[0].iov_base = &hdrs;
1188       iov[0].iov_len = sizeof(hdrs);
1189       iov[1].iov_base = const_cast<uint32_t *>(&items[n]);
1190       iov[1].iov_len = i * sizeof(uint32_t);
1191
1192       size_t total = iov[0].iov_len + iov[1].iov_len;
1193       if (total < 64)
1194         fprintf(stderr, "usrp2::tx_raw: FIXME: short packet: %zd items (%zd bytes)\n", i, total);
1195
1196       if (d_eth_buf->tx_framev(iov, 2) != eth_buffer::EB_OK){
1197         return false;
1198       }
1199
1200       n += i;
1201     }
1202
1203     return true;
1204   }
1205
1206   // ----------------------------------------------------------------
1207   //                       misc commands
1208   // ----------------------------------------------------------------
1209
1210   bool
1211   usrp2::impl::config_mimo(int flags)
1212   {
1213     op_config_mimo_cmd cmd;
1214     op_generic_t reply;
1215
1216     memset(&cmd, 0, sizeof(cmd));
1217     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1218     cmd.op.opcode = OP_CONFIG_MIMO;
1219     cmd.op.len = sizeof(cmd.op);
1220     cmd.op.rid = d_next_rid++;
1221     cmd.op.flags = flags;
1222     cmd.eop.opcode = OP_EOP;
1223     cmd.eop.len = sizeof(cmd.eop);
1224
1225     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1226     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1227       return false;
1228
1229     return ntohx(reply.ok) == 1;
1230   }
1231
1232   bool
1233   usrp2::impl::fpga_master_clock_freq(long *freq)
1234   {
1235     *freq = 100000000L;         // 100 MHz
1236     return true;
1237   }
1238
1239   bool
1240   usrp2::impl::adc_rate(long *rate)
1241   {
1242     return fpga_master_clock_freq(rate);
1243   }
1244
1245   bool
1246   usrp2::impl::dac_rate(long *rate)
1247   {
1248     return fpga_master_clock_freq(rate);
1249   }
1250
1251   bool
1252   usrp2::impl::tx_daughterboard_id(int *dbid)
1253   {
1254     *dbid = d_tx_db_info.dbid;
1255     return true;
1256   }
1257
1258   bool
1259   usrp2::impl::rx_daughterboard_id(int *dbid)
1260   {
1261     *dbid = d_rx_db_info.dbid;
1262     return true;
1263   }
1264
1265
1266   // ----------------------------------------------------------------
1267   //                    low-level commands
1268   // ----------------------------------------------------------------
1269
1270   bool
1271   usrp2::impl::burn_mac_addr(const std::string &new_addr)
1272   {
1273     op_burn_mac_addr_cmd cmd;
1274     op_generic_t reply;
1275
1276     memset(&cmd, 0, sizeof(cmd));
1277     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1278     cmd.op.opcode = OP_BURN_MAC_ADDR;
1279     cmd.op.len = sizeof(cmd.op);
1280     cmd.op.rid = d_next_rid++;
1281     if (!parse_mac_addr(new_addr, &cmd.op.addr))
1282       return false;
1283
1284     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1285     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, 4*DEF_CMD_TIMEOUT))
1286       return false;
1287
1288     bool success = (ntohx(reply.ok) == 1);
1289     return success;
1290   }
1291
1292   static void
1293   fill_dboard_info(db_info *dst, const u2_db_info_t *src)
1294   {
1295     dst->dbid = ntohl(src->dbid);
1296
1297     dst->freq_min =
1298       u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi),
1299                                                     ntohl(src->freq_min_lo)));
1300     dst->freq_max =
1301       u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi),
1302                                                     ntohl(src->freq_max_lo)));
1303
1304     dst->gain_min = u2_fxpt_gain_to_double(ntohs(src->gain_min));
1305     dst->gain_max = u2_fxpt_gain_to_double(ntohs(src->gain_max));
1306     dst->gain_step_size = u2_fxpt_gain_to_double(ntohs(src->gain_step_size));
1307   }
1308
1309   bool
1310   usrp2::impl::dboard_info()
1311   {
1312     op_dboard_info_cmd          cmd;
1313     op_dboard_info_reply_t      reply;
1314
1315     memset(&cmd, 0, sizeof(cmd));
1316     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1317     cmd.op.opcode = OP_DBOARD_INFO;
1318     cmd.op.len = sizeof(cmd.op);
1319     cmd.op.rid = d_next_rid++;
1320     cmd.eop.opcode = OP_EOP;
1321     cmd.eop.len = sizeof(cmd.eop);
1322
1323     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1324     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1325       return false;
1326
1327     bool success = (ntohx(reply.ok) == 1);
1328     if (success){
1329       fill_dboard_info(&d_tx_db_info, &reply.tx_db_info);
1330       fill_dboard_info(&d_rx_db_info, &reply.rx_db_info);
1331     }
1332     return success;
1333   }
1334
1335
1336   bool
1337   usrp2::impl::sync_to_pps()
1338   {
1339     op_generic_cmd cmd;
1340     op_generic_t   reply;
1341
1342     memset(&cmd, 0, sizeof(cmd));
1343     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1344     cmd.op.opcode = OP_SYNC_TO_PPS;
1345     cmd.op.len = sizeof(cmd.op);
1346     cmd.op.rid = d_next_rid++;
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_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1352       return false;
1353
1354     return ntohx(reply.ok) == 1;
1355   }
1356
1357   bool
1358   usrp2::impl::sync_every_pps(bool enable)
1359   {
1360     op_generic_cmd cmd;
1361     op_generic_t   reply;
1362
1363     memset(&cmd, 0, sizeof(cmd));
1364     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1365     cmd.op.opcode = OP_SYNC_EVERY_PPS;
1366     cmd.op.len = sizeof(cmd.op);
1367     cmd.op.rid = d_next_rid++;
1368     cmd.op.ok = enable ? 1 : 0;
1369     cmd.eop.opcode = OP_EOP;
1370     cmd.eop.len = sizeof(cmd.eop);
1371
1372     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1373     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1374       return false;
1375
1376     return ntohx(reply.ok) == 1;
1377   }
1378
1379   std::vector<uint32_t>
1380   usrp2::impl::peek32(uint32_t addr, uint32_t words)
1381   {
1382     std::vector<uint32_t> result; // zero sized on error return
1383     // fprintf(stderr, "usrp2::peek: addr=%08X words=%u\n", addr, words);
1384
1385     if (addr % 4 != 0) {
1386       fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr);
1387       return result;
1388     }
1389
1390     if (words == 0)
1391       return result;
1392
1393     op_peek_cmd   cmd;
1394     op_generic_t *reply;
1395
1396     int wlen = sizeof(uint32_t);
1397     int rlen = sizeof(op_generic_t);
1398     size_t bytes = words*wlen;
1399
1400     memset(&cmd, 0, sizeof(cmd));
1401     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1402     cmd.op.opcode = OP_PEEK;
1403     cmd.op.len = sizeof(cmd.op);
1404     cmd.op.rid = d_next_rid++;
1405     cmd.eop.opcode = OP_EOP;
1406     cmd.eop.len = sizeof(cmd.eop);
1407
1408     cmd.op.addr = htonl(addr);
1409     cmd.op.bytes = htonl(bytes);
1410
1411     reply = (op_generic_t *)malloc(rlen+bytes);
1412     pending_reply p(cmd.op.rid, reply, rlen+bytes);
1413     if (transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) {
1414       uint32_t nwords = (reply->len-rlen)/sizeof(uint32_t);
1415       uint32_t *data = (uint32_t *)(reply+rlen/wlen);
1416       for (unsigned int i = 0; i < nwords; i++)
1417         result.push_back(ntohl(data[i]));
1418     }
1419
1420     free(reply);
1421     return result;
1422   }
1423
1424   bool
1425   usrp2::impl::poke32(uint32_t addr, const std::vector<uint32_t> &data)
1426   {
1427     if (addr % 4 != 0) {
1428       fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr);
1429       return false;
1430     }
1431
1432     int plen = sizeof(op_poke_cmd);
1433     int wlen = sizeof(uint32_t);
1434     int max_words = (MAX_SUBPKT_LEN-plen)/wlen;
1435     int words = data.size();
1436
1437     if (words > max_words) {
1438       fprintf(stderr, "usrp2::poke32: write size (=%u) exceeds maximum of %u words\n",
1439               words, max_words);
1440       return false;
1441     }
1442
1443     //fprintf(stderr, "usrp2::poke32: addr=%08X words=%u\n", addr, words);
1444
1445     if (words == 0)
1446       return true; // NOP
1447
1448     op_poke_cmd  *cmd;
1449     op_generic_t *eop;
1450
1451     // Allocate, clear, and initialize command packet
1452     int bytes = words*wlen;
1453     int l = plen+bytes+sizeof(*eop); // op_poke_cmd+data+eop
1454     cmd = (op_poke_cmd *)malloc(l);
1455     //fprintf(stderr, "cmd=%p l=%i\n", cmd, l);
1456     memset(cmd, 0, l);
1457     init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
1458     cmd->op.opcode = OP_POKE;
1459     cmd->op.len = sizeof(cmd->op)+bytes;
1460     cmd->op.rid = d_next_rid++;
1461     cmd->op.addr = htonl(addr);
1462
1463     // Copy data from vector into packet space
1464     uint32_t *dest = (uint32_t *)((uint8_t *)cmd+plen);
1465     for (int i = 0; i < words; i++) {
1466       //fprintf(stderr, "%03i@%p\n", i, dest);
1467       *dest++ = htonl(data[i]);
1468     }
1469
1470     // Write end-of-packet subpacket
1471     eop = (op_generic_t *)dest;
1472     eop->opcode = OP_EOP;
1473     eop->len = sizeof(*eop);
1474     //fprintf(stderr, "eop=%p len=%i\n", eop, eop->len);
1475
1476     // Send command to device and retrieve reply
1477     bool ok = false;
1478     op_generic_t reply;
1479     pending_reply p(cmd->op.rid, &reply, sizeof(reply));
1480     if (transmit_cmd_and_wait(cmd, l, &p, DEF_CMD_TIMEOUT))
1481       ok = (ntohx(reply.ok) == 1);
1482
1483     free(cmd);
1484     return ok;
1485   }
1486
1487   bool
1488   usrp2::impl::reset_db()
1489   {
1490     op_generic_cmd cmd;
1491     op_generic_t reply;
1492
1493     memset(&cmd, 0, sizeof(cmd));
1494     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1495     cmd.op.opcode = OP_RESET_DB;
1496     cmd.op.len = sizeof(cmd.op);
1497     cmd.op.rid = d_next_rid++;
1498     cmd.eop.opcode = OP_EOP;
1499     cmd.eop.len = sizeof(cmd.eop);
1500
1501     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1502     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1503       return false;
1504
1505     bool success = (ntohx(reply.ok) == 1);
1506     return success;
1507   }
1508
1509   bool usrp2::impl::set_gpio_ddr(int bank, uint16_t value, uint16_t mask)
1510   {
1511     if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1512       fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1513       return false;
1514     }
1515
1516     op_gpio_cmd cmd;
1517     op_generic_t reply;
1518
1519     memset(&cmd, 0, sizeof(cmd));
1520     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1521     cmd.op.opcode = OP_GPIO_SET_DDR;
1522     cmd.op.len = sizeof(cmd.op);
1523     cmd.op.rid = d_next_rid++;
1524     cmd.op.bank = static_cast<uint8_t>(bank);
1525     cmd.op.value = htons(value);
1526     cmd.op.mask = htons(mask);
1527     cmd.eop.opcode = OP_EOP;
1528     cmd.eop.len = sizeof(cmd.eop);
1529
1530     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1531     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1532       return false;
1533
1534     bool success = (ntohx(reply.ok) == 1);
1535     return success;
1536   }
1537
1538   bool usrp2::impl::set_gpio_sels(int bank, std::string sels)
1539   {
1540     if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1541       fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1542       return false;
1543     }
1544
1545     if (sels.size() != 16) {
1546       fprintf(stderr, "set_gpio_sels: sels must be exactly 16 bytes\n");
1547       return false;
1548     }
1549
1550     op_gpio_set_sels_cmd cmd;
1551     op_generic_t reply;
1552
1553     memset(&cmd, 0, sizeof(cmd));
1554     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1555     cmd.op.opcode = OP_GPIO_SET_SELS;
1556     cmd.op.len = sizeof(cmd.op);
1557     cmd.op.rid = d_next_rid++;
1558     cmd.op.bank = static_cast<uint8_t>(bank);
1559     memcpy(&cmd.op.sels, sels.c_str(), 16);
1560     cmd.eop.opcode = OP_EOP;
1561     cmd.eop.len = sizeof(cmd.eop);
1562
1563     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1564     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1565       return false;
1566
1567     bool success = (ntohx(reply.ok) == 1);
1568     return success;
1569   }
1570
1571   bool usrp2::impl::write_gpio(int bank, uint16_t value, uint16_t mask)
1572   {
1573     if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1574       fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1575       return false;
1576     }
1577
1578     op_gpio_cmd cmd;
1579     op_generic_t reply;
1580
1581     memset(&cmd, 0, sizeof(cmd));
1582     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1583     cmd.op.opcode = OP_GPIO_WRITE;
1584     cmd.op.len = sizeof(cmd.op);
1585     cmd.op.rid = d_next_rid++;
1586     cmd.op.bank = static_cast<uint8_t>(bank);
1587     cmd.op.value = htons(value);
1588     cmd.op.mask = htons(mask);
1589     cmd.eop.opcode = OP_EOP;
1590     cmd.eop.len = sizeof(cmd.eop);
1591
1592     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1593     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1594       return false;
1595
1596     bool success = (ntohx(reply.ok) == 1);
1597     return success;
1598   }
1599
1600   bool usrp2::impl::read_gpio(int bank, uint16_t *value)
1601   {
1602     if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1603       fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1604       return false;
1605     }
1606
1607     op_gpio_cmd cmd;
1608     op_gpio_read_reply_t reply;
1609
1610     memset(&cmd, 0, sizeof(cmd));
1611     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1612     cmd.op.opcode = OP_GPIO_READ;
1613     cmd.op.len = sizeof(cmd.op);
1614     cmd.op.rid = d_next_rid++;
1615     cmd.op.bank = static_cast<uint8_t>(bank);
1616     cmd.op.value = 0; // not used
1617     cmd.op.mask = 0;  // not used
1618     cmd.eop.opcode = OP_EOP;
1619     cmd.eop.len = sizeof(cmd.eop);
1620
1621     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1622     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1623       return false;
1624
1625     bool success = (ntohx(reply.ok) == 1);
1626     if (success && (value != NULL))
1627       *value = ntohs(reply.value);
1628
1629     return success;
1630   }
1631
1632   bool usrp2::impl::enable_gpio_streaming(int bank, int enable)
1633   {
1634     if (bank != GPIO_RX_BANK) {
1635       fprintf(stderr, "enable_gpio_streaming: only RX streaming is currently implemented\n");
1636       return false;
1637     }
1638
1639     if ((enable & ~0x03) != 0) {
1640       fprintf(stderr, "enable_gpio_streaming: invalid enable format\n");
1641       return false;
1642     }
1643
1644     op_gpio_cmd cmd;
1645     op_generic_t reply;
1646
1647     memset(&cmd, 0, sizeof(cmd));
1648     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1649     cmd.op.opcode = OP_GPIO_STREAM;
1650     cmd.op.len = sizeof(cmd.op);
1651     cmd.op.rid = d_next_rid++;
1652     cmd.op.bank = static_cast<uint8_t>(bank);
1653     cmd.op.value = htons((uint16_t)enable);
1654     cmd.op.mask = 0;  // not used
1655     cmd.eop.opcode = OP_EOP;
1656     cmd.eop.len = sizeof(cmd.eop);
1657
1658     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1659     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1660       return false;
1661
1662     bool success = (ntohx(reply.ok) == 1);
1663     return success;
1664   }
1665
1666 } // namespace usrp2