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