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