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