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