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