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