Cleanup, changed ifc_name() to interface_name()
[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)
132     : d_eth_buf(new eth_buffer()), d_interface_name(ifc), d_pf(0), d_bg_thread(0),
133       d_bg_running(false), d_rx_seqno(-1), d_tx_seqno(0), d_next_rid(0),
134       d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0), 
135       d_num_enqueued(0), d_enqueued_mutex(), d_bg_pending_cond(&d_enqueued_mutex),
136       d_channel_rings(NCHANS), d_tx_interp(0), d_rx_decim(0)
137   {
138     if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE)))
139       throw std::runtime_error("Unable to register USRP2 protocol");
140     
141     d_pf = pktfilter::make_ethertype_inbound(U2_ETHERTYPE, d_eth_buf->mac());
142     if (!d_pf || !d_eth_buf->attach_pktfilter(d_pf))
143       throw std::runtime_error("Unable to attach packet filter.");
144     
145     d_addr = p->addr;
146     
147     if (USRP2_IMPL_DEBUG)
148       std::cerr << "usrp2 constructor: using USRP2 at " << d_addr << std::endl;
149
150     memset(d_pending_replies, 0, sizeof(d_pending_replies));
151
152     d_bg_thread = new usrp2_thread(this);
153     d_bg_thread->start();
154
155     if (!dboard_info())         // we're hosed
156       throw std::runtime_error("Unable to retrieve daughterboard info");
157
158     if (0){
159       int dbid;
160
161       tx_daughterboard_id(&dbid);
162       fprintf(stderr, "Tx dboard 0x%x\n", dbid);
163       fprintf(stderr, "  freq_min = %g\n", tx_freq_min());
164       fprintf(stderr, "  freq_max = %g\n", tx_freq_max());
165       fprintf(stderr, "  gain_min = %g\n", tx_gain_min());
166       fprintf(stderr, "  gain_max = %g\n", tx_gain_max());
167       fprintf(stderr, "  gain_db_per_step = %g\n", tx_gain_db_per_step());
168
169       rx_daughterboard_id(&dbid);
170       fprintf(stderr, "Rx dboard 0x%x\n", dbid);
171       fprintf(stderr, "  freq_min = %g\n", rx_freq_min());
172       fprintf(stderr, "  freq_max = %g\n", rx_freq_max());
173       fprintf(stderr, "  gain_min = %g\n", rx_gain_min());
174       fprintf(stderr, "  gain_max = %g\n", rx_gain_max());
175       fprintf(stderr, "  gain_db_per_step = %g\n", rx_gain_db_per_step());
176     }
177
178     // Ensure any custom values in hardware are cleared
179     if (!reset_db())
180       std::cerr << "usrp2::ctor reset_db failed\n";
181
182     // default gains to mid point
183     if (!set_tx_gain((tx_gain_min() + tx_gain_max()) / 2))
184       std::cerr << "usrp2::ctor set_tx_gain failed\n";
185
186     if (!set_rx_gain((rx_gain_min() + rx_gain_max()) / 2))
187       std::cerr << "usrp2::ctor set_rx_gain failed\n";
188
189     // default interp and decim
190     if (!set_tx_interp(12))
191       std::cerr << "usrp2::ctor set_tx_interp failed\n";
192
193     if (!set_rx_decim(12))
194       std::cerr << "usrp2::ctor set_rx_decim failed\n";
195       
196     // set workable defaults for scaling
197     if (!set_rx_scale_iq(DEFAULT_RX_SCALE, DEFAULT_RX_SCALE))
198       std::cerr << "usrp2::ctor set_rx_scale_iq failed\n";
199   }
200   
201   usrp2::impl::~impl()
202   {
203     stop_bg();
204     d_bg_thread = 0; // thread class deletes itself
205     delete d_pf;
206     d_eth_buf->close();
207     delete d_eth_buf;
208     
209     if (USRP2_IMPL_DEBUG) {
210       std::cerr << std::endl
211                 << "usrp2 destructor: received " << d_num_rx_frames 
212                 << " frames, with " << d_num_rx_missing << " lost ("
213                 << (d_num_rx_frames == 0 ? 0 : (int)(100.0*d_num_rx_missing/d_num_rx_frames))
214                 << "%), totaling " << d_num_rx_bytes
215                 << " bytes" << std::endl;
216     }
217   }
218   
219   bool
220   usrp2::impl::parse_mac_addr(const std::string &s, u2_mac_addr_t *p)
221   {
222     p->addr[0] = 0x00;          // Matt's IAB
223     p->addr[1] = 0x50;
224     p->addr[2] = 0xC2;
225     p->addr[3] = 0x85;
226     p->addr[4] = 0x30;
227     p->addr[5] = 0x00;
228     
229     int len = s.size();
230     
231     switch (len){
232       
233     case 5:
234       return sscanf(s.c_str(), "%hhx:%hhx", &p->addr[4], &p->addr[5]) == 2;
235       
236     case 17:
237       return sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
238                     &p->addr[0], &p->addr[1], &p->addr[2],
239                     &p->addr[3], &p->addr[4], &p->addr[5]) == 6;
240     default:
241       return false;
242     }
243   }
244   
245   void
246   usrp2::impl::init_et_hdrs(u2_eth_packet_t *p, const std::string &dst)
247   {
248     p->ehdr.ethertype = htons(U2_ETHERTYPE);
249     parse_mac_addr(dst, &p->ehdr.dst); 
250     memcpy(&p->ehdr.src, d_eth_buf->mac(), 6);
251     p->thdr.flags = 0; // FIXME transport header values?
252     p->thdr.seqno = d_tx_seqno++;
253     p->thdr.ack = 0;
254   }
255   
256   void 
257   usrp2::impl::init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
258                              int word0_flags, int chan, uint32_t timestamp)
259   {
260     init_et_hdrs(p, dst);
261     u2p_set_word0(&p->fixed, word0_flags, chan);
262     u2p_set_timestamp(&p->fixed, timestamp);
263     
264     if (chan == CONTROL_CHAN) { // no sequence numbers, back it out
265       p->thdr.seqno = 0;
266       d_tx_seqno--;
267     }
268   }
269   
270   void
271   usrp2::impl::init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd)
272   {
273     memset(cmd, 0, sizeof(*cmd)); 
274     init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
275     cmd->op.opcode = OP_CONFIG_RX_V2;
276     cmd->op.len = sizeof(cmd->op);
277     cmd->op.rid = d_next_rid++;
278     cmd->eop.opcode = OP_EOP;
279     cmd->eop.len = sizeof(cmd->eop);
280   }
281
282   void
283   usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd)
284   {
285     memset(cmd, 0, sizeof(*cmd)); 
286     init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
287     cmd->op.opcode = OP_CONFIG_TX_V2;
288     cmd->op.len = sizeof(cmd->op);
289     cmd->op.rid = d_next_rid++;
290     cmd->eop.opcode = OP_EOP;
291     cmd->eop.len = sizeof(cmd->eop);
292   }
293
294   bool
295   usrp2::impl::transmit_cmd(void *cmd, size_t len, pending_reply *p, double secs)
296   {
297     if (p)    
298       d_pending_replies[p->rid()] = p;
299     
300     // Transmit command
301     if (d_eth_buf->tx_frame(cmd, len) != eth_buffer::EB_OK) {
302       d_pending_replies[p->rid()] = 0;
303       return false;
304     }
305
306     int res = 1;
307     if (p)
308       res = p->wait(secs);
309       
310     d_pending_replies[p->rid()] = 0;
311     return res == 1;
312   }
313
314   // ----------------------------------------------------------------
315   //        Background loop: received packet demuxing
316   // ----------------------------------------------------------------
317
318   void
319   usrp2::impl::stop_bg()
320   {
321     d_bg_running = false;
322     d_bg_pending_cond.signal();
323     
324     void *dummy_status;
325     d_bg_thread->join(&dummy_status);  
326   }
327   
328   void
329   usrp2::impl::bg_loop()
330   {
331     d_bg_running = true;
332     while(d_bg_running) {
333       DEBUG_LOG(":");
334       // Receive available frames from ethernet buffer.  Handler will
335       // process control frames, enqueue data packets in channel
336       // rings, and signal blocked API threads
337       int res = d_eth_buf->rx_frames(this, 100); // FIXME magic timeout
338       if (res == eth_buffer::EB_ERROR)
339         break;  
340
341       // Wait for user API thread(s) to process all enqueued packets.
342       // The channel ring thread that decrements d_num_enqueued to zero 
343       // will signal this thread to continue.
344       {
345         omni_mutex_lock l(d_enqueued_mutex);
346         while(d_num_enqueued > 0 && d_bg_running)
347           d_bg_pending_cond.wait();
348       }
349     }
350     d_bg_running = false;
351   }
352   
353   //
354   // passed to eth_buffer::rx_frames
355   //
356   data_handler::result
357   usrp2::impl::operator()(const void *base, size_t len)
358   {
359     u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
360
361     // FIXME unaligned load!
362     int chan = u2p_chan(&pkt->hdrs.fixed);
363
364     if (chan == CONTROL_CHAN) {         // control packets
365       DEBUG_LOG("c");
366       return handle_control_packet(base, len);
367     }
368     else {                              // data packets
369       return handle_data_packet(base, len);
370     }
371
372     // not reached
373   }
374
375   data_handler::result
376   usrp2::impl::handle_control_packet(const void *base, size_t len)
377   {
378     // point to beginning of payload (subpackets)
379     unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
380     
381     // FIXME (p % 4) == 2.  Not good.  Must watch for unaligned loads.
382
383     // FIXME iterate over payload, handling more than a single subpacket.
384     
385     int opcode = p[0];
386     unsigned int oplen = p[1];
387     unsigned int rid = p[2];
388
389     pending_reply *rp = d_pending_replies[rid];
390     if (rp) {
391       unsigned int buflen = rp->len();
392       if (oplen != buflen) {
393         std::cerr << "usrp2: mismatched command reply length (expected: "
394                   << buflen << " got: " << oplen << "). "
395                   << "op = " << opcode_to_string(opcode) << std::endl;
396       }     
397     
398       // Copy reply into caller's buffer
399       memcpy(rp->buffer(), p, std::min(oplen, buflen));
400       rp->signal();
401       d_pending_replies[rid] = 0;
402       return data_handler::RELEASE;
403     }
404
405     // TODO: handle unsolicited, USRP2 initiated, or late replies
406     DEBUG_LOG("l");
407     return data_handler::RELEASE;
408   }
409   
410   data_handler::result
411   usrp2::impl::handle_data_packet(const void *base, size_t len)
412   {
413     u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
414     d_num_rx_frames++;
415     d_num_rx_bytes += len;
416     
417     /* --- FIXME start of fake transport layer handler --- */
418
419     if (d_rx_seqno != -1) {
420       int expected_seqno = (d_rx_seqno + 1) & 0xFF;
421       int seqno = pkt->hdrs.thdr.seqno; 
422       
423       if (seqno != expected_seqno) {
424         ::write(2, "S", 1); // missing sequence number
425         int missing = seqno - expected_seqno;
426         if (missing < 0)
427           missing += 256;
428         
429         d_num_rx_overruns++;
430         d_num_rx_missing += missing;
431       }
432     }
433
434     d_rx_seqno = pkt->hdrs.thdr.seqno;
435
436     /* --- end of fake transport layer handler --- */
437
438     // FIXME unaligned load!
439     unsigned int chan = u2p_chan(&pkt->hdrs.fixed);
440
441     if (!d_channel_rings[chan]) {
442       DEBUG_LOG("!");
443       return data_handler::RELEASE;     // discard packet, no channel handler
444     }
445
446     // Strip off ethernet header and transport header and enqueue the rest
447
448     size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed);
449     if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) {
450       inc_enqueued();
451       DEBUG_LOG("+");
452       return data_handler::KEEP;        // channel ring runner will mark frame done
453     }
454     else {
455       DEBUG_LOG("!");
456       return data_handler::RELEASE;     // discard, no room in channel ring
457     }   
458     return data_handler::RELEASE;
459   }
460
461
462   // ----------------------------------------------------------------
463   //                           Receive
464   // ----------------------------------------------------------------
465
466   bool 
467   usrp2::impl::set_rx_gain(double gain)
468   {
469     op_config_rx_v2_cmd cmd;
470     op_config_rx_reply_v2_t reply;
471
472     init_config_rx_v2_cmd(&cmd);
473     cmd.op.valid = htons(CFGV_GAIN);
474     cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
475     
476     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
477     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
478       return false;
479
480     bool success = (ntohx(reply.ok) == 1);
481     return success;
482   }
483   
484   bool
485   usrp2::impl::set_rx_lo_offset(double frequency)
486   {
487     op_freq_cmd cmd;
488     op_generic_t reply;
489
490     memset(&cmd, 0, sizeof(cmd));
491     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
492     cmd.op.opcode = OP_SET_RX_LO_OFFSET;
493     cmd.op.len = sizeof(cmd.op);
494     cmd.op.rid = d_next_rid++;
495
496     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
497     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
498     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
499
500     cmd.eop.opcode = OP_EOP;
501     cmd.eop.len = sizeof(cmd.eop);
502     
503     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
504     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
505       return false;
506
507     bool success = (ntohx(reply.ok) == 1);
508     return success;
509   }
510
511   bool
512   usrp2::impl::set_rx_center_freq(double frequency, tune_result *result)
513   {
514     op_config_rx_v2_cmd cmd;
515     op_config_rx_reply_v2_t reply;
516
517     init_config_rx_v2_cmd(&cmd);
518     cmd.op.valid = htons(CFGV_FREQ);
519     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
520     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
521     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
522     
523     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
524     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
525       return false;
526
527     bool success = (ntohx(reply.ok) == 1);
528     if (result && success) {
529       result->baseband_freq =
530         u2_fxpt_freq_to_double( 
531           u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi), 
532                                  ntohl(reply.baseband_freq_lo)));
533
534       result->dxc_freq =
535         u2_fxpt_freq_to_double( 
536           u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi), 
537                                  ntohl(reply.ddc_freq_lo)));
538
539       result->residual_freq =
540         u2_fxpt_freq_to_double( 
541          u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi), 
542                                 ntohl(reply.residual_freq_lo)));
543
544       result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
545     }
546
547     return success;
548   }
549   
550   bool
551   usrp2::impl::set_rx_decim(int decimation_factor)
552   {
553     op_config_rx_v2_cmd cmd;
554     op_config_rx_reply_v2_t reply;
555
556     init_config_rx_v2_cmd(&cmd);
557     cmd.op.valid = htons(CFGV_INTERP_DECIM);
558     cmd.op.decim = htonl(decimation_factor);
559     
560     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
561     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
562       return false;
563
564     bool success = (ntohx(reply.ok) == 1);
565     if (success)
566       d_rx_decim = decimation_factor;
567     return success;
568   }
569   
570   bool
571   usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
572   {
573     op_config_rx_v2_cmd cmd;
574     op_config_rx_reply_v2_t reply;
575
576     init_config_rx_v2_cmd(&cmd);
577     cmd.op.valid = htons(CFGV_SCALE_IQ);
578     cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
579     
580     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
581     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
582       return false;
583
584     bool success = (ntohx(reply.ok) == 1);
585     return success;
586   }
587   
588   bool
589   usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
590   {
591     if (channel > MAX_CHAN) {
592       std::cerr << "usrp2: invalid channel number (" << channel
593                 << ")" << std::endl;
594       return false;
595     }
596
597     if (channel > 0) { // until firmware supports multiple streams
598       std::cerr << "usrp2: channel " << channel
599                 << " not implemented" << std::endl;
600       return false;
601     }
602
603     if (d_channel_rings[channel]) {
604       std::cerr << "usrp2: channel " << channel
605                 << " already streaming" << std::endl;
606       return false;
607     }
608
609     d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
610
611     if (items_per_frame == 0)
612       items_per_frame = U2_MAX_SAMPLES;         // minimize overhead
613     
614     op_start_rx_streaming_cmd cmd;
615     op_generic_t reply;
616
617     memset(&cmd, 0, sizeof(cmd));
618     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
619     cmd.op.opcode = OP_START_RX_STREAMING;
620     cmd.op.len = sizeof(cmd.op);
621     cmd.op.rid = d_next_rid++;
622     cmd.op.items_per_frame = htonl(items_per_frame);
623     cmd.eop.opcode = OP_EOP;
624     cmd.eop.len = sizeof(cmd.eop);
625     
626     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
627     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
628       return false;
629
630     bool success = (ntohx(reply.ok) == 1);
631     return success;
632   }
633   
634   bool
635   usrp2::impl::stop_rx_streaming(unsigned int channel)
636   {
637     if (channel > MAX_CHAN) {
638       std::cerr << "usrp2: invalid channel number (" << channel
639                 << ")" << std::endl;
640       return false;
641     }
642
643     if (channel > 0) { // until firmware supports multiple streams
644       std::cerr << "usrp2: channel " << channel
645                 << " not implemented" << std::endl;
646       return false;
647     }
648
649 #if 0 // don't be overzealous.    
650     if (!d_channel_rings[channel]) {
651       std::cerr << "usrp2: channel " << channel
652                 << " not streaming" << std::endl;
653       return false;
654     }
655 #endif
656
657     op_stop_rx_cmd cmd;
658     op_generic_t reply;
659
660     memset(&cmd, 0, sizeof(cmd));
661     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
662     cmd.op.opcode = OP_STOP_RX;
663     cmd.op.len = sizeof(cmd.op);
664     cmd.op.rid = d_next_rid++;
665     cmd.eop.opcode = OP_EOP;
666     cmd.eop.len = sizeof(cmd.eop);
667     
668     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
669     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
670       return false;
671
672     bool success = (ntohx(reply.ok) == 1);
673     if (success)
674       d_channel_rings[channel].reset();
675
676     return success;
677   }
678   
679
680   bool
681   usrp2::impl::rx_samples(unsigned int channel, rx_sample_handler *handler)
682   {
683     if (channel > MAX_CHAN) {
684       std::cerr << "usrp2: invalid channel (" << channel
685                 << " )" << std::endl;
686       return false;
687     }
688     
689     if (channel > 0) {
690       std::cerr << "usrp2: channel " << channel
691                 << " not implemented" << std::endl;
692       return false;
693     }
694     
695     ring_sptr rp = d_channel_rings[channel];
696     if (!rp){
697       std::cerr << "usrp2: channel " << channel
698                 << " not receiving" << std::endl;
699       return false;
700     }
701     
702     // Wait for frames available in channel ring
703     DEBUG_LOG("W");
704     rp->wait_for_not_empty();
705     DEBUG_LOG("s");
706     
707     // Iterate through frames and present to user
708     void *p;
709     size_t frame_len_in_bytes;
710     while (rp->dequeue(&p, &frame_len_in_bytes)) {
711       uint32_t         *items;                  // points to beginning of data items
712       size_t            nitems_in_uint32s;
713       rx_metadata       md;
714       if (!parse_rx_metadata(p, frame_len_in_bytes, &items, &nitems_in_uint32s, &md))
715         return false;
716
717       bool want_more = (*handler)(items, nitems_in_uint32s, &md);
718       d_eth_buf->release_frame(p);
719       DEBUG_LOG("-");
720       dec_enqueued();
721
722       if (!want_more)
723         break;
724     }
725     return true;
726   }
727
728   // ----------------------------------------------------------------
729   //                            Transmit
730   // ----------------------------------------------------------------
731
732   bool 
733   usrp2::impl::set_tx_gain(double gain)
734   {
735     op_config_tx_v2_cmd cmd;
736     op_config_tx_reply_v2_t reply;
737
738     init_config_tx_v2_cmd(&cmd);
739     cmd.op.valid = htons(CFGV_GAIN);
740     cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
741     
742     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
743     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
744       return false;
745
746     bool success = (ntohx(reply.ok) == 1);
747     return success;
748   }
749   
750   bool
751   usrp2::impl::set_tx_lo_offset(double frequency)
752   {
753     op_freq_cmd cmd;
754     op_generic_t reply;
755
756     memset(&cmd, 0, sizeof(cmd));
757     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
758     cmd.op.opcode = OP_SET_TX_LO_OFFSET;
759     cmd.op.len = sizeof(cmd.op);
760     cmd.op.rid = d_next_rid++;
761
762     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
763     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
764     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
765
766     cmd.eop.opcode = OP_EOP;
767     cmd.eop.len = sizeof(cmd.eop);
768     
769     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
770     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
771       return false;
772
773     bool success = (ntohx(reply.ok) == 1);
774     return success;
775   }
776
777   bool
778   usrp2::impl::set_tx_center_freq(double frequency, tune_result *result)
779   {
780     op_config_tx_v2_cmd cmd;
781     op_config_tx_reply_v2_t reply;
782
783     init_config_tx_v2_cmd(&cmd);
784     cmd.op.valid = htons(CFGV_FREQ);
785     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
786     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
787     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
788     
789     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
790     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
791       return false;
792
793     bool success = (ntohx(reply.ok) == 1);
794     if (result && success) {
795       result->baseband_freq =
796         u2_fxpt_freq_to_double( 
797           u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi), 
798                                  ntohl(reply.baseband_freq_lo)));
799
800       result->dxc_freq =
801         u2_fxpt_freq_to_double( 
802           u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi), 
803                                  ntohl(reply.duc_freq_lo)));
804
805       result->residual_freq =
806         u2_fxpt_freq_to_double( 
807          u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi), 
808                                 ntohl(reply.residual_freq_lo)));
809
810       result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
811     }
812
813     return success;
814   }
815   
816   bool
817   usrp2::impl::set_tx_interp(int interpolation_factor)
818   {
819     op_config_tx_v2_cmd cmd;
820     op_config_tx_reply_v2_t reply;
821
822     init_config_tx_v2_cmd(&cmd);
823     cmd.op.valid = htons(CFGV_INTERP_DECIM);
824     cmd.op.interp = htonl(interpolation_factor);
825     
826     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
827     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
828       return false;
829
830     bool success = (ntohx(reply.ok) == 1);
831     if (success) {
832       d_tx_interp = interpolation_factor;
833
834       // Auto-set TX scaling based on interpolation rate
835       int scale_i, scale_q;
836       default_tx_scale_iq(d_tx_interp, &scale_i, &scale_q);
837       return set_tx_scale_iq(scale_i, scale_q);
838     }
839
840     return success;
841   }
842   
843   void
844   usrp2::impl::default_tx_scale_iq(int interpolation_factor, int *scale_i, int *scale_q)
845   {
846     // Calculate CIC interpolation (i.e., without halfband interpolators)
847     int i = interpolation_factor;
848     if (i > 128)
849       i = i >> 1;
850     if (i > 128)
851       i = i >> 1;
852
853     // Calculate dsp_core_tx gain absent scale multipliers
854     float gain = (1.65*i*i*i)/(4096*pow(2, ceil(log2(i*i*i))));
855     
856     // Calculate closest multiplier constant to reverse gain
857     int scale = (int)rint(1.0/gain);
858     // fprintf(stderr, "if=%i i=%i gain=%f scale=%i\n", interpolation_factor, i, gain, scale);
859
860     // Both I and Q are identical in this case
861     if (scale_i)
862       *scale_i = scale;
863     if (scale_q)
864       *scale_q = scale;
865   }
866
867   bool
868   usrp2::impl::set_tx_scale_iq(int scale_i, int scale_q)
869   {
870     op_config_tx_v2_cmd cmd;
871     op_config_tx_reply_v2_t reply;
872
873     init_config_tx_v2_cmd(&cmd);
874     cmd.op.valid = htons(CFGV_SCALE_IQ);
875     cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
876     
877     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
878     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
879       return false;
880
881     bool success = (ntohx(reply.ok) == 1);
882     return success;
883   }
884
885   bool
886   usrp2::impl::tx_32fc(unsigned int channel,
887                        const std::complex<float> *samples,
888                        size_t nsamples,
889                        const tx_metadata *metadata)
890   {
891     uint32_t items[nsamples];
892     copy_host_32fc_to_u2_16sc(nsamples, samples, items);
893     return tx_raw(channel, items, nsamples, metadata);
894   }
895
896   bool
897   usrp2::impl::tx_16sc(unsigned int channel,
898                        const std::complex<int16_t> *samples,
899                        size_t nsamples,
900                        const tx_metadata *metadata)
901   {
902 #ifdef WORDS_BIGENDIAN
903
904     // Already binary equivalent to 16-bit I/Q on the wire.
905     // No conversion required.
906
907     assert(sizeof(samples[0]) == sizeof(uint32_t));
908     return tx_raw(channel, (const uint32_t *) samples, nsamples, metadata);
909
910 #else
911
912     uint32_t items[nsamples];
913     copy_host_16sc_to_u2_16sc(nsamples, samples, items);
914     return tx_raw(channel, items, nsamples, metadata);
915
916 #endif
917   }
918
919   bool
920   usrp2::impl::tx_raw(unsigned int channel,
921                       const uint32_t *items,
922                       size_t nitems,
923                       const tx_metadata *metadata)
924   {
925     if (nitems == 0)
926       return true;
927
928     // FIXME there's the possibility that we send fewer than 9 items in a frame.
929     // That would end up glitching the transmitter, since the ethernet will pad to
930     // 64-bytes total (9 items).  We really need some part of the stack to
931     // carry the real length (thdr?).
932
933     // fragment as necessary then fire away
934
935     size_t nframes = (nitems + U2_MAX_SAMPLES - 1) / U2_MAX_SAMPLES;
936     size_t last_frame = nframes - 1;
937     u2_eth_packet_t     hdrs;
938
939     size_t n = 0;
940     for (size_t fn = 0; fn < nframes; fn++){
941       uint32_t timestamp = 0;
942       uint32_t flags = 0;
943
944       if (fn == 0){
945         timestamp = metadata->timestamp;
946         if (metadata->send_now)
947           flags |= U2P_TX_IMMEDIATE;
948         if (metadata->start_of_burst)
949           flags |= U2P_TX_START_OF_BURST;
950       }
951       if (fn > 0){
952         flags |= U2P_TX_IMMEDIATE;
953       }
954       if (fn == last_frame){
955         if (metadata->end_of_burst)
956           flags |= U2P_TX_END_OF_BURST;
957       }
958
959       init_etf_hdrs(&hdrs, d_addr, flags, channel, timestamp);
960
961       size_t i = std::min((size_t) U2_MAX_SAMPLES, nitems - n);
962
963       eth_iovec iov[2];
964       iov[0].iov_base = &hdrs;
965       iov[0].iov_len = sizeof(hdrs);
966       iov[1].iov_base = const_cast<uint32_t *>(&items[n]);
967       iov[1].iov_len = i * sizeof(uint32_t);
968
969       size_t total = iov[0].iov_len + iov[1].iov_len;
970       if (total < 64)
971         fprintf(stderr, "usrp2::tx_raw: FIXME: short packet: %zd items (%zd bytes)\n", i, total);
972
973       if (d_eth_buf->tx_framev(iov, 2) != eth_buffer::EB_OK){
974         return false;
975       }
976
977       n += i;
978     }
979
980     return true;
981   }
982
983   // ----------------------------------------------------------------
984   //                       misc commands
985   // ----------------------------------------------------------------
986
987   bool
988   usrp2::impl::config_mimo(int flags)
989   {
990     op_config_mimo_cmd cmd;
991     op_generic_t reply;
992
993     memset(&cmd, 0, sizeof(cmd));
994     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
995     cmd.op.opcode = OP_CONFIG_MIMO;
996     cmd.op.len = sizeof(cmd.op);
997     cmd.op.rid = d_next_rid++;
998     cmd.op.flags = flags;
999     cmd.eop.opcode = OP_EOP;
1000     cmd.eop.len = sizeof(cmd.eop);
1001     
1002     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1003     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1004       return false;
1005
1006     return ntohx(reply.ok) == 1;
1007   }
1008
1009   bool
1010   usrp2::impl::fpga_master_clock_freq(long *freq)
1011   {
1012     *freq = 100000000L;         // 100 MHz
1013     return true;
1014   }
1015
1016   bool
1017   usrp2::impl::adc_rate(long *rate)
1018   {
1019     return fpga_master_clock_freq(rate);
1020   }
1021
1022   bool
1023   usrp2::impl::dac_rate(long *rate)
1024   {
1025     return fpga_master_clock_freq(rate);
1026   }
1027
1028   bool
1029   usrp2::impl::tx_daughterboard_id(int *dbid)
1030   {
1031     *dbid = d_tx_db_info.dbid;
1032     return true;
1033   }
1034
1035   bool
1036   usrp2::impl::rx_daughterboard_id(int *dbid)
1037   {
1038     *dbid = d_rx_db_info.dbid;
1039     return true;
1040   }
1041
1042
1043   // ----------------------------------------------------------------
1044   //                    low-level commands
1045   // ----------------------------------------------------------------
1046
1047   bool
1048   usrp2::impl::burn_mac_addr(const std::string &new_addr)
1049   {
1050     op_burn_mac_addr_cmd cmd;
1051     op_generic_t reply;
1052
1053     memset(&cmd, 0, sizeof(cmd));
1054     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1055     cmd.op.opcode = OP_BURN_MAC_ADDR;
1056     cmd.op.len = sizeof(cmd.op);
1057     cmd.op.rid = d_next_rid++;
1058     if (!parse_mac_addr(new_addr, &cmd.op.addr))
1059       return false;
1060
1061     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1062     if (!transmit_cmd(&cmd, sizeof(cmd), &p, 4*DEF_CMD_TIMEOUT))
1063       return false;
1064
1065     bool success = (ntohx(reply.ok) == 1);
1066     return success;
1067   }
1068
1069   static void
1070   fill_dboard_info(db_info *dst, const u2_db_info_t *src)
1071   {
1072     dst->dbid = ntohl(src->dbid);
1073
1074     dst->freq_min =
1075       u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi), 
1076                                                     ntohl(src->freq_min_lo)));
1077     dst->freq_max =
1078       u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi), 
1079                                                     ntohl(src->freq_max_lo)));
1080
1081     dst->gain_min = u2_fxpt_gain_to_double(ntohs(src->gain_min));
1082     dst->gain_max = u2_fxpt_gain_to_double(ntohs(src->gain_max));
1083     dst->gain_step_size = u2_fxpt_gain_to_double(ntohs(src->gain_step_size));
1084   }
1085
1086   bool
1087   usrp2::impl::dboard_info()
1088   {
1089     op_dboard_info_cmd          cmd;
1090     op_dboard_info_reply_t      reply;
1091
1092     memset(&cmd, 0, sizeof(cmd));
1093     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1094     cmd.op.opcode = OP_DBOARD_INFO;
1095     cmd.op.len = sizeof(cmd.op);
1096     cmd.op.rid = d_next_rid++;
1097     cmd.eop.opcode = OP_EOP;
1098     cmd.eop.len = sizeof(cmd.eop);
1099     
1100     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1101     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1102       return false;
1103
1104     bool success = (ntohx(reply.ok) == 1);
1105     if (success){
1106       fill_dboard_info(&d_tx_db_info, &reply.tx_db_info);
1107       fill_dboard_info(&d_rx_db_info, &reply.rx_db_info);
1108     }
1109     return success;
1110   }
1111
1112
1113   bool
1114   usrp2::impl::sync_to_pps()
1115   {
1116     op_generic_cmd cmd;
1117     op_generic_t   reply;
1118
1119     memset(&cmd, 0, sizeof(cmd));
1120     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1121     cmd.op.opcode = OP_SYNC_TO_PPS;
1122     cmd.op.len = sizeof(cmd.op);
1123     cmd.op.rid = d_next_rid++;
1124     cmd.eop.opcode = OP_EOP;
1125     cmd.eop.len = sizeof(cmd.eop);
1126     
1127     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1128     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1129       return false;
1130
1131     return ntohx(reply.ok) == 1;
1132   }
1133
1134   bool
1135   usrp2::impl::sync_every_pps(bool enable)
1136   {
1137     op_generic_cmd cmd;
1138     op_generic_t   reply;
1139
1140     memset(&cmd, 0, sizeof(cmd));
1141     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1142     cmd.op.opcode = OP_SYNC_EVERY_PPS;
1143     cmd.op.len = sizeof(cmd.op);
1144     cmd.op.rid = d_next_rid++;
1145     cmd.op.ok = enable ? 1 : 0;
1146     cmd.eop.opcode = OP_EOP;
1147     cmd.eop.len = sizeof(cmd.eop);
1148     
1149     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1150     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1151       return false;
1152
1153     return ntohx(reply.ok) == 1;
1154   }
1155
1156   std::vector<uint32_t>
1157   usrp2::impl::peek32(uint32_t addr, uint32_t words)
1158   {
1159     std::vector<uint32_t> result; // zero sized on error return
1160     // fprintf(stderr, "usrp2::peek: addr=%08X words=%u\n", addr, words);
1161
1162     if (addr % 4 != 0) {
1163       fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr); 
1164       return result;
1165     }
1166
1167     if (words == 0)
1168       return result;
1169
1170     op_peek_cmd   cmd;
1171     op_generic_t *reply;
1172
1173     int wlen = sizeof(uint32_t);
1174     int rlen = sizeof(op_generic_t);
1175     size_t bytes = words*wlen;
1176
1177     memset(&cmd, 0, sizeof(cmd));
1178     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1179     cmd.op.opcode = OP_PEEK;
1180     cmd.op.len = sizeof(cmd.op);
1181     cmd.op.rid = d_next_rid++;
1182     cmd.eop.opcode = OP_EOP;
1183     cmd.eop.len = sizeof(cmd.eop);
1184
1185     cmd.op.addr = htonl(addr);
1186     cmd.op.bytes = htonl(bytes);
1187
1188     reply = (op_generic_t *)malloc(rlen+bytes);
1189     pending_reply p(cmd.op.rid, reply, rlen+bytes);
1190     if (transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) {
1191       uint32_t nwords = (reply->len-rlen)/sizeof(uint32_t);
1192       uint32_t *data = (uint32_t *)(reply+rlen/wlen);
1193       for (unsigned int i = 0; i < nwords; i++)
1194         result.push_back(ntohl(data[i]));
1195     }
1196
1197     free(reply);
1198     return result;
1199   }
1200
1201   bool
1202   usrp2::impl::poke32(uint32_t addr, const std::vector<uint32_t> &data)
1203   {
1204     if (addr % 4 != 0) {
1205       fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr); 
1206       return false;
1207     }
1208
1209     int plen = sizeof(op_poke_cmd);
1210     int wlen = sizeof(uint32_t);
1211     int max_words = (MAX_SUBPKT_LEN-plen)/wlen;
1212     int words = data.size();
1213
1214     if (words > max_words) {
1215       fprintf(stderr, "usrp2::poke32: write size (=%u) exceeds maximum of %u words\n",
1216               words, max_words);
1217       return false;
1218     }
1219
1220     //fprintf(stderr, "usrp2::poke32: addr=%08X words=%u\n", addr, words);
1221
1222     if (words == 0)
1223       return true; // NOP
1224
1225     op_poke_cmd  *cmd;
1226     op_generic_t *eop;
1227
1228     // Allocate, clear, and initialize command packet
1229     int bytes = words*wlen;
1230     int l = plen+bytes+sizeof(*eop); // op_poke_cmd+data+eop
1231     cmd = (op_poke_cmd *)malloc(l);
1232     //fprintf(stderr, "cmd=%p l=%i\n", cmd, l);
1233     memset(cmd, 0, l);
1234     init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
1235     cmd->op.opcode = OP_POKE;
1236     cmd->op.len = sizeof(cmd->op)+bytes;
1237     cmd->op.rid = d_next_rid++;
1238     cmd->op.addr = htonl(addr);
1239
1240     // Copy data from vector into packet space
1241     uint32_t *dest = (uint32_t *)((uint8_t *)cmd+plen);
1242     for (int i = 0; i < words; i++) {
1243       //fprintf(stderr, "%03i@%p\n", i, dest);
1244       *dest++ = htonl(data[i]);
1245     }
1246
1247     // Write end-of-packet subpacket
1248     eop = (op_generic_t *)dest;
1249     eop->opcode = OP_EOP;
1250     eop->len = sizeof(*eop);
1251     //fprintf(stderr, "eop=%p len=%i\n", eop, eop->len);
1252
1253     // Send command to device and retrieve reply
1254     bool ok = false;
1255     op_generic_t reply;
1256     pending_reply p(cmd->op.rid, &reply, sizeof(reply));
1257     if (transmit_cmd(cmd, l, &p, DEF_CMD_TIMEOUT))
1258       ok = (ntohx(reply.ok) == 1);
1259
1260     free(cmd);
1261     return ok;
1262   }
1263
1264   bool
1265   usrp2::impl::reset_db()
1266   {
1267     op_generic_cmd cmd;
1268     op_generic_t reply;
1269
1270     memset(&cmd, 0, sizeof(cmd));
1271     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1272     cmd.op.opcode = OP_RESET_DB;
1273     cmd.op.len = sizeof(cmd.op);
1274     cmd.op.rid = d_next_rid++;
1275     cmd.eop.opcode = OP_EOP;
1276     cmd.eop.len = sizeof(cmd.eop);
1277     
1278     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1279     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1280       return false;
1281
1282     bool success = (ntohx(reply.ok) == 1);
1283     return success;
1284   }
1285
1286 } // namespace usrp2