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