Imported Upstream version 3.2.2
[debian/gnuradio] / usrp2 / host / lib / usrp2_impl.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2008,2009 Free Software Foundation, Inc.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <usrp2/usrp2.h>
24 #include <usrp2/tune_result.h>
25 #include <usrp2/copiers.h>
26 #include <gruel/inet.h>
27 #include <usrp2_types.h>
28 #include "usrp2_impl.h"
29 #include "usrp2_thread.h"
30 #include "eth_buffer.h"
31 #include "pktfilter.h"
32 #include "control.h"
33 #include "ring.h"
34 #include <stdexcept>
35 #include <iostream>
36 #include <stdio.h>
37 #include <stddef.h>
38 #include <assert.h>
39 #include <string.h>
40
41 #define USRP2_IMPL_DEBUG 0
42 #if USRP2_IMPL_DEBUG
43 #define DEBUG_LOG(x) ::write(2, x, 1)
44 #else
45 #define DEBUG_LOG(x)
46 #endif
47
48 static const int DEFAULT_RX_SCALE = 1024;
49
50 namespace usrp2 {
51
52   static const double DEF_CMD_TIMEOUT = 0.1;
53
54   std::string
55   opcode_to_string(int opcode)
56   {
57     switch(opcode){
58     case OP_EOP: return "OP_EOP";
59     case OP_ID: return "OP_ID";
60     case OP_ID_REPLY: return "OP_ID_REPLY";
61     case OP_BURN_MAC_ADDR: return "OP_BURN_MAC_ADDR";
62     case OP_READ_TIME: return "OP_READ_TIME";
63     case OP_READ_TIME_REPLY: return "OP_READ_TIME_REPLY";
64     case OP_CONFIG_RX_V2: return "OP_CONFIG_RX_V2";
65     case OP_CONFIG_RX_REPLY_V2: return "OP_CONFIG_RX_REPLY_V2";
66     case OP_CONFIG_TX_V2: return "OP_CONFIG_TX_V2";
67     case OP_CONFIG_TX_REPLY_V2: return "OP_CONFIG_TX_REPLY_V2";
68     case OP_START_RX_STREAMING: return "OP_START_RX_STREAMING";
69     case OP_STOP_RX: return "OP_STOP_RX";
70     case OP_CONFIG_MIMO: return "OP_CONFIG_MIMO";
71     case OP_DBOARD_INFO: return "OP_DBOARD_INFO";
72     case OP_DBOARD_INFO_REPLY: return "OP_DBOARD_INFO_REPLY";
73     case OP_SYNC_TO_PPS: return "OP_SYNC_TO_PPS";
74     case OP_PEEK: return "OP_PEEK";
75     case OP_PEEK_REPLY: return "OP_PEEK_REPLY";
76     case OP_SET_TX_LO_OFFSET: return "OP_SET_TX_LO_OFFSET";
77     case OP_SET_TX_LO_OFFSET_REPLY: return "OP_SET_TX_LO_OFFSET_REPLY";
78     case OP_SET_RX_LO_OFFSET: return "OP_SET_RX_LO_OFFSET";
79     case OP_SET_RX_LO_OFFSET_REPLY: return "OP_SET_RX_LO_OFFSET_REPLY";
80     case OP_SYNC_EVERY_PPS: return "OP_SYNC_EVERY_PPS";
81     case OP_SYNC_EVERY_PPS_REPLY: return "OP_SYNC_EVERY_PPS_REPLY";
82
83     default:
84       char buf[64];
85       snprintf(buf, sizeof(buf), "<unknown opcode: %d>", opcode);
86       return buf;
87     }
88   }
89
90
91   /*!
92    * \param p points to fixed header
93    * \param payload_len_in_bytes is length of the fixed hdr and the payload
94    * \param[out] items is set to point to the first uint32 item in the payload
95    * \param[out] nitems is set to the number of uint32 items in the payload
96    * \param[out] md is filled in with the parsed metadata from the frame.
97    */
98   static bool
99   parse_rx_metadata(void *p, size_t payload_len_in_bytes,
100                     uint32_t **items, size_t *nitems_in_uint32s, rx_metadata *md)
101   {
102     if (payload_len_in_bytes < sizeof(u2_fixed_hdr_t))  // invalid format
103       return false;
104
105     // FIXME deal with the fact that (p % 4) == 2
106     //assert((((uintptr_t) p) % 4) == 0);               // must be 4-byte aligned
107
108     u2_fixed_hdr_t *fh = static_cast<u2_fixed_hdr_t *>(p);
109     
110     // FIXME unaligned loads!
111     md->word0 = u2p_word0(fh);
112     md->timestamp = u2p_timestamp(fh);
113
114     // FIXME when we've got more info
115     // md->start_of_burst = (md->word0 & XXX) != 0;
116     // md->end_of_burst =   (md->word0 & XXX) != 0;
117     // md->rx_overrun =     (md->word0 & XXX) != 0;
118     md->start_of_burst = 0;
119     md->end_of_burst =   0;
120     md->rx_overrun =     0;
121
122     *items = (uint32_t *)(&fh[1]);
123     size_t nbytes = payload_len_in_bytes - sizeof(u2_fixed_hdr_t);
124     assert((nbytes % sizeof(uint32_t)) == 0);
125     *nitems_in_uint32s = nbytes / sizeof(uint32_t);
126
127     return true;
128   }
129
130
131   usrp2::impl::impl(const std::string &ifc, props *p, size_t rx_bufsize)
132     : d_eth_buf(new eth_buffer(rx_bufsize)), d_interface_name(ifc), d_pf(0), d_bg_thread(0),
133       d_bg_running(false), d_rx_seqno(-1), d_tx_seqno(0), d_next_rid(0),
134       d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0), 
135       d_num_enqueued(0), d_enqueued_mutex(), d_bg_pending_cond(&d_enqueued_mutex),
136       d_channel_rings(NCHANS), d_tx_interp(0), d_rx_decim(0)
137   {
138     if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE)))
139       throw std::runtime_error("Unable to register USRP2 protocol");
140     
141     d_addr = p->addr;
142
143     // Create a packet filter for U2_ETHERTYPE packets sourced from target USRP2
144     u2_mac_addr_t usrp_mac;
145     parse_mac_addr(d_addr, &usrp_mac);
146     d_pf = pktfilter::make_ethertype_inbound_target(U2_ETHERTYPE, (const unsigned char*)&(usrp_mac.addr));
147     if (!d_pf || !d_eth_buf->attach_pktfilter(d_pf))
148       throw std::runtime_error("Unable to attach packet filter.");
149     
150     if (USRP2_IMPL_DEBUG)
151       std::cerr << "usrp2 constructor: using USRP2 at " << d_addr << std::endl;
152
153     memset(d_pending_replies, 0, sizeof(d_pending_replies));
154
155     d_bg_thread = new usrp2_thread(this);
156     d_bg_thread->start();
157
158     // In case the USRP2 was left streaming RX
159     // FIXME: only one channel right now
160     stop_rx_streaming(0);
161
162     if (!dboard_info())         // we're hosed
163       throw std::runtime_error("Unable to retrieve daughterboard info");
164
165     if (0){
166       int dbid;
167
168       tx_daughterboard_id(&dbid);
169       fprintf(stderr, "Tx dboard 0x%x\n", dbid);
170       fprintf(stderr, "  freq_min = %g\n", tx_freq_min());
171       fprintf(stderr, "  freq_max = %g\n", tx_freq_max());
172       fprintf(stderr, "  gain_min = %g\n", tx_gain_min());
173       fprintf(stderr, "  gain_max = %g\n", tx_gain_max());
174       fprintf(stderr, "  gain_db_per_step = %g\n", tx_gain_db_per_step());
175
176       rx_daughterboard_id(&dbid);
177       fprintf(stderr, "Rx dboard 0x%x\n", dbid);
178       fprintf(stderr, "  freq_min = %g\n", rx_freq_min());
179       fprintf(stderr, "  freq_max = %g\n", rx_freq_max());
180       fprintf(stderr, "  gain_min = %g\n", rx_gain_min());
181       fprintf(stderr, "  gain_max = %g\n", rx_gain_max());
182       fprintf(stderr, "  gain_db_per_step = %g\n", rx_gain_db_per_step());
183     }
184
185     // Ensure any custom values in hardware are cleared
186     if (!reset_db())
187       std::cerr << "usrp2::ctor reset_db failed\n";
188
189     // default gains to mid point
190     if (!set_tx_gain((tx_gain_min() + tx_gain_max()) / 2))
191       std::cerr << "usrp2::ctor set_tx_gain failed\n";
192
193     if (!set_rx_gain((rx_gain_min() + rx_gain_max()) / 2))
194       std::cerr << "usrp2::ctor set_rx_gain failed\n";
195
196     // default interp and decim
197     if (!set_tx_interp(12))
198       std::cerr << "usrp2::ctor set_tx_interp failed\n";
199
200     if (!set_rx_decim(12))
201       std::cerr << "usrp2::ctor set_rx_decim failed\n";
202       
203     // set workable defaults for scaling
204     if (!set_rx_scale_iq(DEFAULT_RX_SCALE, DEFAULT_RX_SCALE))
205       std::cerr << "usrp2::ctor set_rx_scale_iq failed\n";
206   }
207   
208   usrp2::impl::~impl()
209   {
210     stop_bg();
211     d_bg_thread = 0; // thread class deletes itself
212     delete d_pf;
213     d_eth_buf->close();
214     delete d_eth_buf;
215     
216     if (USRP2_IMPL_DEBUG) {
217       std::cerr << std::endl
218                 << "usrp2 destructor: received " << d_num_rx_frames 
219                 << " frames, with " << d_num_rx_missing << " lost ("
220                 << (d_num_rx_frames == 0 ? 0 : (int)(100.0*d_num_rx_missing/d_num_rx_frames))
221                 << "%), totaling " << d_num_rx_bytes
222                 << " bytes" << std::endl;
223     }
224   }
225   
226   bool
227   usrp2::impl::parse_mac_addr(const std::string &s, u2_mac_addr_t *p)
228   {
229     p->addr[0] = 0x00;          // Matt's IAB
230     p->addr[1] = 0x50;
231     p->addr[2] = 0xC2;
232     p->addr[3] = 0x85;
233     p->addr[4] = 0x30;
234     p->addr[5] = 0x00;
235     
236     int len = s.size();
237     
238     switch (len){
239       
240     case 5:
241       return sscanf(s.c_str(), "%hhx:%hhx", &p->addr[4], &p->addr[5]) == 2;
242       
243     case 17:
244       return sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
245                     &p->addr[0], &p->addr[1], &p->addr[2],
246                     &p->addr[3], &p->addr[4], &p->addr[5]) == 6;
247     default:
248       return false;
249     }
250   }
251   
252   void
253   usrp2::impl::init_et_hdrs(u2_eth_packet_t *p, const std::string &dst)
254   {
255     p->ehdr.ethertype = htons(U2_ETHERTYPE);
256     parse_mac_addr(dst, &p->ehdr.dst); 
257     memcpy(&p->ehdr.src, d_eth_buf->mac(), 6);
258     p->thdr.flags = 0; // FIXME transport header values?
259     p->thdr.seqno = d_tx_seqno++;
260     p->thdr.ack = 0;
261   }
262   
263   void 
264   usrp2::impl::init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
265                              int word0_flags, int chan, uint32_t timestamp)
266   {
267     init_et_hdrs(p, dst);
268     u2p_set_word0(&p->fixed, word0_flags, chan);
269     u2p_set_timestamp(&p->fixed, timestamp);
270     
271     if (chan == CONTROL_CHAN) { // no sequence numbers, back it out
272       p->thdr.seqno = 0;
273       d_tx_seqno--;
274     }
275   }
276   
277   void
278   usrp2::impl::init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd)
279   {
280     memset(cmd, 0, sizeof(*cmd)); 
281     init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
282     cmd->op.opcode = OP_CONFIG_RX_V2;
283     cmd->op.len = sizeof(cmd->op);
284     cmd->op.rid = d_next_rid++;
285     cmd->eop.opcode = OP_EOP;
286     cmd->eop.len = sizeof(cmd->eop);
287   }
288
289   void
290   usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd)
291   {
292     memset(cmd, 0, sizeof(*cmd)); 
293     init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
294     cmd->op.opcode = OP_CONFIG_TX_V2;
295     cmd->op.len = sizeof(cmd->op);
296     cmd->op.rid = d_next_rid++;
297     cmd->eop.opcode = OP_EOP;
298     cmd->eop.len = sizeof(cmd->eop);
299   }
300
301   bool
302   usrp2::impl::transmit_cmd(void *cmd, size_t len, pending_reply *p, double secs)
303   {
304     if (p)    
305       d_pending_replies[p->rid()] = p;
306     
307     // Transmit command
308     if (d_eth_buf->tx_frame(cmd, len) != eth_buffer::EB_OK) {
309       d_pending_replies[p->rid()] = 0;
310       return false;
311     }
312
313     int res = 1;
314     if (p)
315       res = p->wait(secs);
316       
317     d_pending_replies[p->rid()] = 0;
318     return res == 1;
319   }
320
321   // ----------------------------------------------------------------
322   //        Background loop: received packet demuxing
323   // ----------------------------------------------------------------
324
325   void
326   usrp2::impl::stop_bg()
327   {
328     d_bg_running = false;
329     d_bg_pending_cond.signal();
330     
331     void *dummy_status;
332     d_bg_thread->join(&dummy_status);  
333   }
334   
335   void
336   usrp2::impl::bg_loop()
337   {
338     d_bg_running = true;
339     while(d_bg_running) {
340       DEBUG_LOG(":");
341       // Receive available frames from ethernet buffer.  Handler will
342       // process control frames, enqueue data packets in channel
343       // rings, and signal blocked API threads
344       int res = d_eth_buf->rx_frames(this, 100); // FIXME magic timeout
345       if (res == eth_buffer::EB_ERROR)
346         break;  
347
348       // Wait for user API thread(s) to process all enqueued packets.
349       // The channel ring thread that decrements d_num_enqueued to zero 
350       // will signal this thread to continue.
351       {
352         omni_mutex_lock l(d_enqueued_mutex);
353         while(d_num_enqueued > 0 && d_bg_running)
354           d_bg_pending_cond.wait();
355       }
356     }
357     d_bg_running = false;
358   }
359   
360   //
361   // passed to eth_buffer::rx_frames
362   //
363   data_handler::result
364   usrp2::impl::operator()(const void *base, size_t len)
365   {
366     u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
367
368     // FIXME unaligned load!
369     int chan = u2p_chan(&pkt->hdrs.fixed);
370
371     if (chan == CONTROL_CHAN) {         // control packets
372       DEBUG_LOG("c");
373       return handle_control_packet(base, len);
374     }
375     else {                              // data packets
376       return handle_data_packet(base, len);
377     }
378
379     // not reached
380   }
381
382   data_handler::result
383   usrp2::impl::handle_control_packet(const void *base, size_t len)
384   {
385     // point to beginning of payload (subpackets)
386     unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
387     
388     // FIXME (p % 4) == 2.  Not good.  Must watch for unaligned loads.
389
390     // FIXME iterate over payload, handling more than a single subpacket.
391     
392     int opcode = p[0];
393     unsigned int oplen = p[1];
394     unsigned int rid = p[2];
395
396     pending_reply *rp = d_pending_replies[rid];
397     if (rp) {
398       unsigned int buflen = rp->len();
399       if (oplen != buflen) {
400         std::cerr << "usrp2: mismatched command reply length (expected: "
401                   << buflen << " got: " << oplen << "). "
402                   << "op = " << opcode_to_string(opcode) << std::endl;
403       }     
404     
405       // Copy reply into caller's buffer
406       memcpy(rp->buffer(), p, std::min(oplen, buflen));
407       rp->signal();
408       d_pending_replies[rid] = 0;
409       return data_handler::RELEASE;
410     }
411
412     // TODO: handle unsolicited, USRP2 initiated, or late replies
413     DEBUG_LOG("l");
414     return data_handler::RELEASE;
415   }
416   
417   data_handler::result
418   usrp2::impl::handle_data_packet(const void *base, size_t len)
419   {
420     u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
421     d_num_rx_frames++;
422     d_num_rx_bytes += len;
423     
424     /* --- FIXME start of fake transport layer handler --- */
425
426     if (d_rx_seqno != -1) {
427       int expected_seqno = (d_rx_seqno + 1) & 0xFF;
428       int seqno = pkt->hdrs.thdr.seqno; 
429       
430       if (seqno != expected_seqno) {
431         ::write(2, "S", 1); // missing sequence number
432         int missing = seqno - expected_seqno;
433         if (missing < 0)
434           missing += 256;
435         
436         d_num_rx_overruns++;
437         d_num_rx_missing += missing;
438       }
439     }
440
441     d_rx_seqno = pkt->hdrs.thdr.seqno;
442
443     /* --- end of fake transport layer handler --- */
444
445     // FIXME unaligned load!
446     unsigned int chan = u2p_chan(&pkt->hdrs.fixed);
447
448     {
449       omni_mutex_lock l(d_channel_rings_mutex);
450
451       if (!d_channel_rings[chan]) {
452         DEBUG_LOG("!");
453         return data_handler::RELEASE;   // discard packet, no channel handler
454       }
455       
456       // Strip off ethernet header and transport header and enqueue the rest
457       
458       size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed);
459       if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) {
460         inc_enqueued();
461         DEBUG_LOG("+");
462         return data_handler::KEEP;      // channel ring runner will mark frame done
463       }
464       else {
465         DEBUG_LOG("!");
466         return data_handler::RELEASE;   // discard, no room in channel ring
467       }         
468       return data_handler::RELEASE;
469     }
470   }
471
472
473   // ----------------------------------------------------------------
474   //                           Receive
475   // ----------------------------------------------------------------
476
477   bool 
478   usrp2::impl::set_rx_gain(double gain)
479   {
480     op_config_rx_v2_cmd cmd;
481     op_config_rx_reply_v2_t reply;
482
483     init_config_rx_v2_cmd(&cmd);
484     cmd.op.valid = htons(CFGV_GAIN);
485     cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
486     
487     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
488     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
489       return false;
490
491     bool success = (ntohx(reply.ok) == 1);
492     return success;
493   }
494   
495   bool
496   usrp2::impl::set_rx_lo_offset(double frequency)
497   {
498     op_freq_cmd cmd;
499     op_generic_t reply;
500
501     memset(&cmd, 0, sizeof(cmd));
502     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
503     cmd.op.opcode = OP_SET_RX_LO_OFFSET;
504     cmd.op.len = sizeof(cmd.op);
505     cmd.op.rid = d_next_rid++;
506
507     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
508     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
509     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
510
511     cmd.eop.opcode = OP_EOP;
512     cmd.eop.len = sizeof(cmd.eop);
513     
514     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
515     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
516       return false;
517
518     bool success = (ntohx(reply.ok) == 1);
519     return success;
520   }
521
522   bool
523   usrp2::impl::set_rx_center_freq(double frequency, tune_result *result)
524   {
525     op_config_rx_v2_cmd cmd;
526     op_config_rx_reply_v2_t reply;
527
528     init_config_rx_v2_cmd(&cmd);
529     cmd.op.valid = htons(CFGV_FREQ);
530     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
531     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
532     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
533     
534     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
535     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
536       return false;
537
538     bool success = (ntohx(reply.ok) == 1);
539     if (result && success) {
540       result->baseband_freq =
541         u2_fxpt_freq_to_double( 
542           u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi), 
543                                  ntohl(reply.baseband_freq_lo)));
544
545       result->dxc_freq =
546         u2_fxpt_freq_to_double( 
547           u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi), 
548                                  ntohl(reply.ddc_freq_lo)));
549
550       result->residual_freq =
551         u2_fxpt_freq_to_double( 
552          u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi), 
553                                 ntohl(reply.residual_freq_lo)));
554
555       result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
556     }
557
558     return success;
559   }
560   
561   bool
562   usrp2::impl::set_rx_decim(int decimation_factor)
563   {
564     op_config_rx_v2_cmd cmd;
565     op_config_rx_reply_v2_t reply;
566
567     init_config_rx_v2_cmd(&cmd);
568     cmd.op.valid = htons(CFGV_INTERP_DECIM);
569     cmd.op.decim = htonl(decimation_factor);
570     
571     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
572     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
573       return false;
574
575     bool success = (ntohx(reply.ok) == 1);
576     if (success)
577       d_rx_decim = decimation_factor;
578     return success;
579   }
580   
581   bool
582   usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
583   {
584     op_config_rx_v2_cmd cmd;
585     op_config_rx_reply_v2_t reply;
586
587     init_config_rx_v2_cmd(&cmd);
588     cmd.op.valid = htons(CFGV_SCALE_IQ);
589     cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
590     
591     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
592     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
593       return false;
594
595     bool success = (ntohx(reply.ok) == 1);
596     return success;
597   }
598   
599   bool
600   usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
601   {
602     if (channel > MAX_CHAN) {
603       std::cerr << "usrp2: invalid channel number (" << channel
604                 << ")" << std::endl;
605       return false;
606     }
607
608     if (channel > 0) { // until firmware supports multiple streams
609       std::cerr << "usrp2: channel " << channel
610                 << " not implemented" << std::endl;
611       return false;
612     }
613
614     {
615       omni_mutex_lock l(d_channel_rings_mutex);
616       if (d_channel_rings[channel]) {
617         std::cerr << "usrp2: channel " << channel
618                   << " already streaming" << std::endl;
619         return false;
620       }
621       
622       if (items_per_frame == 0)
623         items_per_frame = U2_MAX_SAMPLES;               // minimize overhead
624       
625       op_start_rx_streaming_cmd cmd;
626       op_generic_t reply;
627
628       memset(&cmd, 0, sizeof(cmd));
629       init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
630       cmd.op.opcode = OP_START_RX_STREAMING;
631       cmd.op.len = sizeof(cmd.op);
632       cmd.op.rid = d_next_rid++;
633       cmd.op.items_per_frame = htonl(items_per_frame);
634       cmd.eop.opcode = OP_EOP;
635       cmd.eop.len = sizeof(cmd.eop);
636     
637       bool success = false;
638       pending_reply p(cmd.op.rid, &reply, sizeof(reply));
639       success = transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
640       success = success && (ntohx(reply.ok) == 1);
641       
642       if (success)
643         d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
644
645       return success;
646     }
647   }
648   
649   bool
650   usrp2::impl::stop_rx_streaming(unsigned int channel)
651   {
652     if (channel > MAX_CHAN) {
653       std::cerr << "usrp2: invalid channel number (" << channel
654                 << ")" << std::endl;
655       return false;
656     }
657
658     if (channel > 0) { // until firmware supports multiple streams
659       std::cerr << "usrp2: channel " << channel
660                 << " not implemented" << std::endl;
661       return false;
662     }
663
664     op_stop_rx_cmd cmd;
665     op_generic_t reply;
666
667     {
668       omni_mutex_lock l(d_channel_rings_mutex);
669
670       memset(&cmd, 0, sizeof(cmd));
671       init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
672       cmd.op.opcode = OP_STOP_RX;
673       cmd.op.len = sizeof(cmd.op);
674       cmd.op.rid = d_next_rid++;
675       cmd.eop.opcode = OP_EOP;
676       cmd.eop.len = sizeof(cmd.eop);
677     
678       bool success = false;
679       pending_reply p(cmd.op.rid, &reply, sizeof(reply));
680       success = transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
681       success = success && (ntohx(reply.ok) == 1);
682       d_channel_rings[channel].reset();
683       return success;
684     }
685   }
686
687   bool
688   usrp2::impl::rx_samples(unsigned int channel, rx_sample_handler *handler)
689   {
690     if (channel > MAX_CHAN) {
691       std::cerr << "usrp2: invalid channel (" << channel
692                 << " )" << std::endl;
693       return false;
694     }
695     
696     if (channel > 0) {
697       std::cerr << "usrp2: channel " << channel
698                 << " not implemented" << std::endl;
699       return false;
700     }
701     
702     ring_sptr rp = d_channel_rings[channel];
703     if (!rp){
704       std::cerr << "usrp2: channel " << channel
705                 << " not receiving" << std::endl;
706       return false;
707     }
708     
709     // Wait for frames available in channel ring
710     DEBUG_LOG("W");
711     rp->wait_for_not_empty();
712     DEBUG_LOG("s");
713     
714     // Iterate through frames and present to user
715     void *p;
716     size_t frame_len_in_bytes;
717     while (rp->dequeue(&p, &frame_len_in_bytes)) {
718       uint32_t         *items;                  // points to beginning of data items
719       size_t            nitems_in_uint32s;
720       rx_metadata       md;
721       if (!parse_rx_metadata(p, frame_len_in_bytes, &items, &nitems_in_uint32s, &md))
722         return false;
723
724       bool want_more = (*handler)(items, nitems_in_uint32s, &md);
725       d_eth_buf->release_frame(p);
726       DEBUG_LOG("-");
727       dec_enqueued();
728
729       if (!want_more)
730         break;
731     }
732     return true;
733   }
734
735   // ----------------------------------------------------------------
736   //                            Transmit
737   // ----------------------------------------------------------------
738
739   bool 
740   usrp2::impl::set_tx_gain(double gain)
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_GAIN);
747     cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
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_lo_offset(double frequency)
759   {
760     op_freq_cmd cmd;
761     op_generic_t reply;
762
763     memset(&cmd, 0, sizeof(cmd));
764     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
765     cmd.op.opcode = OP_SET_TX_LO_OFFSET;
766     cmd.op.len = sizeof(cmd.op);
767     cmd.op.rid = d_next_rid++;
768
769     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
770     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
771     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
772
773     cmd.eop.opcode = OP_EOP;
774     cmd.eop.len = sizeof(cmd.eop);
775     
776     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
777     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
778       return false;
779
780     bool success = (ntohx(reply.ok) == 1);
781     return success;
782   }
783
784   bool
785   usrp2::impl::set_tx_center_freq(double frequency, tune_result *result)
786   {
787     op_config_tx_v2_cmd cmd;
788     op_config_tx_reply_v2_t reply;
789
790     init_config_tx_v2_cmd(&cmd);
791     cmd.op.valid = htons(CFGV_FREQ);
792     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
793     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
794     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
795     
796     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
797     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
798       return false;
799
800     bool success = (ntohx(reply.ok) == 1);
801     if (result && success) {
802       result->baseband_freq =
803         u2_fxpt_freq_to_double( 
804           u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi), 
805                                  ntohl(reply.baseband_freq_lo)));
806
807       result->dxc_freq =
808         u2_fxpt_freq_to_double( 
809           u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi), 
810                                  ntohl(reply.duc_freq_lo)));
811
812       result->residual_freq =
813         u2_fxpt_freq_to_double( 
814          u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi), 
815                                 ntohl(reply.residual_freq_lo)));
816
817       result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
818     }
819
820     return success;
821   }
822   
823   bool
824   usrp2::impl::set_tx_interp(int interpolation_factor)
825   {
826     op_config_tx_v2_cmd cmd;
827     op_config_tx_reply_v2_t reply;
828
829     init_config_tx_v2_cmd(&cmd);
830     cmd.op.valid = htons(CFGV_INTERP_DECIM);
831     cmd.op.interp = htonl(interpolation_factor);
832     
833     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
834     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
835       return false;
836
837     bool success = (ntohx(reply.ok) == 1);
838     if (success) {
839       d_tx_interp = interpolation_factor;
840
841       // Auto-set TX scaling based on interpolation rate
842       int scale_i, scale_q;
843       default_tx_scale_iq(d_tx_interp, &scale_i, &scale_q);
844       return set_tx_scale_iq(scale_i, scale_q);
845     }
846
847     return success;
848   }
849   
850   void
851   usrp2::impl::default_tx_scale_iq(int interpolation_factor, int *scale_i, int *scale_q)
852   {
853     // Calculate CIC interpolation (i.e., without halfband interpolators)
854     int i = interpolation_factor;
855     if (i > 128)
856       i = i >> 1;
857     if (i > 128)
858       i = i >> 1;
859
860     // Calculate dsp_core_tx gain absent scale multipliers
861     float gain = (1.65*i*i*i)/(4096*pow(2, ceil(log2(i*i*i))));
862     
863     // Calculate closest multiplier constant to reverse gain
864     int scale = (int)rint(1.0/gain);
865     // fprintf(stderr, "if=%i i=%i gain=%f scale=%i\n", interpolation_factor, i, gain, scale);
866
867     // Both I and Q are identical in this case
868     if (scale_i)
869       *scale_i = scale;
870     if (scale_q)
871       *scale_q = scale;
872   }
873
874   bool
875   usrp2::impl::set_tx_scale_iq(int scale_i, int scale_q)
876   {
877     op_config_tx_v2_cmd cmd;
878     op_config_tx_reply_v2_t reply;
879
880     init_config_tx_v2_cmd(&cmd);
881     cmd.op.valid = htons(CFGV_SCALE_IQ);
882     cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
883     
884     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
885     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
886       return false;
887
888     bool success = (ntohx(reply.ok) == 1);
889     return success;
890   }
891
892   bool
893   usrp2::impl::tx_32fc(unsigned int channel,
894                        const std::complex<float> *samples,
895                        size_t nsamples,
896                        const tx_metadata *metadata)
897   {
898     uint32_t items[nsamples];
899     copy_host_32fc_to_u2_16sc(nsamples, samples, items);
900     return tx_raw(channel, items, nsamples, metadata);
901   }
902
903   bool
904   usrp2::impl::tx_16sc(unsigned int channel,
905                        const std::complex<int16_t> *samples,
906                        size_t nsamples,
907                        const tx_metadata *metadata)
908   {
909 #ifdef WORDS_BIGENDIAN
910
911     // Already binary equivalent to 16-bit I/Q on the wire.
912     // No conversion required.
913
914     assert(sizeof(samples[0]) == sizeof(uint32_t));
915     return tx_raw(channel, (const uint32_t *) samples, nsamples, metadata);
916
917 #else
918
919     uint32_t items[nsamples];
920     copy_host_16sc_to_u2_16sc(nsamples, samples, items);
921     return tx_raw(channel, items, nsamples, metadata);
922
923 #endif
924   }
925
926   bool
927   usrp2::impl::tx_raw(unsigned int channel,
928                       const uint32_t *items,
929                       size_t nitems,
930                       const tx_metadata *metadata)
931   {
932     if (nitems == 0)
933       return true;
934
935     // FIXME can't deal with nitems < U2_MIN_SAMPLES (will be fixed in VRT)
936     // FIXME need to check the MTU instead of assuming 1500 bytes
937
938     // fragment as necessary then fire away
939
940     size_t nframes = (nitems + U2_MAX_SAMPLES - 1) / U2_MAX_SAMPLES;
941     size_t last_frame = nframes - 1;
942     u2_eth_packet_t     hdrs;
943
944     size_t n = 0;
945     for (size_t fn = 0; fn < nframes; fn++){
946       uint32_t timestamp = 0;
947       uint32_t flags = 0;
948
949       if (fn == 0){
950         timestamp = metadata->timestamp;
951         if (metadata->send_now)
952           flags |= U2P_TX_IMMEDIATE;
953         if (metadata->start_of_burst)
954           flags |= U2P_TX_START_OF_BURST;
955       }
956       if (fn > 0){
957         flags |= U2P_TX_IMMEDIATE;
958       }
959       if (fn == last_frame){
960         if (metadata->end_of_burst)
961           flags |= U2P_TX_END_OF_BURST;
962       }
963
964       init_etf_hdrs(&hdrs, d_addr, flags, channel, timestamp);
965
966       // Avoid short packet by splitting last two packets if reqd
967       size_t i;
968       if ((nitems - n) > U2_MAX_SAMPLES && (nitems - n) < (U2_MAX_SAMPLES + U2_MIN_SAMPLES))
969         i = (nitems - n) / 2;
970       else
971         i = std::min((size_t) U2_MAX_SAMPLES, nitems - n);
972
973       eth_iovec iov[2];
974       iov[0].iov_base = &hdrs;
975       iov[0].iov_len = sizeof(hdrs);
976       iov[1].iov_base = const_cast<uint32_t *>(&items[n]);
977       iov[1].iov_len = i * sizeof(uint32_t);
978
979       size_t total = iov[0].iov_len + iov[1].iov_len;
980       if (total < 64)
981         fprintf(stderr, "usrp2::tx_raw: FIXME: short packet: %zd items (%zd bytes)\n", i, total);
982
983       if (d_eth_buf->tx_framev(iov, 2) != eth_buffer::EB_OK){
984         return false;
985       }
986
987       n += i;
988     }
989
990     return true;
991   }
992
993   // ----------------------------------------------------------------
994   //                       misc commands
995   // ----------------------------------------------------------------
996
997   bool
998   usrp2::impl::config_mimo(int flags)
999   {
1000     op_config_mimo_cmd cmd;
1001     op_generic_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_CONFIG_MIMO;
1006     cmd.op.len = sizeof(cmd.op);
1007     cmd.op.rid = d_next_rid++;
1008     cmd.op.flags = flags;
1009     cmd.eop.opcode = OP_EOP;
1010     cmd.eop.len = sizeof(cmd.eop);
1011     
1012     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1013     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1014       return false;
1015
1016     return ntohx(reply.ok) == 1;
1017   }
1018
1019   bool
1020   usrp2::impl::fpga_master_clock_freq(long *freq)
1021   {
1022     *freq = 100000000L;         // 100 MHz
1023     return true;
1024   }
1025
1026   bool
1027   usrp2::impl::adc_rate(long *rate)
1028   {
1029     return fpga_master_clock_freq(rate);
1030   }
1031
1032   bool
1033   usrp2::impl::dac_rate(long *rate)
1034   {
1035     return fpga_master_clock_freq(rate);
1036   }
1037
1038   bool
1039   usrp2::impl::tx_daughterboard_id(int *dbid)
1040   {
1041     *dbid = d_tx_db_info.dbid;
1042     return true;
1043   }
1044
1045   bool
1046   usrp2::impl::rx_daughterboard_id(int *dbid)
1047   {
1048     *dbid = d_rx_db_info.dbid;
1049     return true;
1050   }
1051
1052
1053   // ----------------------------------------------------------------
1054   //                    low-level commands
1055   // ----------------------------------------------------------------
1056
1057   bool
1058   usrp2::impl::burn_mac_addr(const std::string &new_addr)
1059   {
1060     op_burn_mac_addr_cmd cmd;
1061     op_generic_t reply;
1062
1063     memset(&cmd, 0, sizeof(cmd));
1064     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1065     cmd.op.opcode = OP_BURN_MAC_ADDR;
1066     cmd.op.len = sizeof(cmd.op);
1067     cmd.op.rid = d_next_rid++;
1068     if (!parse_mac_addr(new_addr, &cmd.op.addr))
1069       return false;
1070
1071     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1072     if (!transmit_cmd(&cmd, sizeof(cmd), &p, 4*DEF_CMD_TIMEOUT))
1073       return false;
1074
1075     bool success = (ntohx(reply.ok) == 1);
1076     return success;
1077   }
1078
1079   static void
1080   fill_dboard_info(db_info *dst, const u2_db_info_t *src)
1081   {
1082     dst->dbid = ntohl(src->dbid);
1083
1084     dst->freq_min =
1085       u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi), 
1086                                                     ntohl(src->freq_min_lo)));
1087     dst->freq_max =
1088       u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi), 
1089                                                     ntohl(src->freq_max_lo)));
1090
1091     dst->gain_min = u2_fxpt_gain_to_double(ntohs(src->gain_min));
1092     dst->gain_max = u2_fxpt_gain_to_double(ntohs(src->gain_max));
1093     dst->gain_step_size = u2_fxpt_gain_to_double(ntohs(src->gain_step_size));
1094   }
1095
1096   bool
1097   usrp2::impl::dboard_info()
1098   {
1099     op_dboard_info_cmd          cmd;
1100     op_dboard_info_reply_t      reply;
1101
1102     memset(&cmd, 0, sizeof(cmd));
1103     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1104     cmd.op.opcode = OP_DBOARD_INFO;
1105     cmd.op.len = sizeof(cmd.op);
1106     cmd.op.rid = d_next_rid++;
1107     cmd.eop.opcode = OP_EOP;
1108     cmd.eop.len = sizeof(cmd.eop);
1109     
1110     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1111     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1112       return false;
1113
1114     bool success = (ntohx(reply.ok) == 1);
1115     if (success){
1116       fill_dboard_info(&d_tx_db_info, &reply.tx_db_info);
1117       fill_dboard_info(&d_rx_db_info, &reply.rx_db_info);
1118     }
1119     return success;
1120   }
1121
1122
1123   bool
1124   usrp2::impl::sync_to_pps()
1125   {
1126     op_generic_cmd cmd;
1127     op_generic_t   reply;
1128
1129     memset(&cmd, 0, sizeof(cmd));
1130     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1131     cmd.op.opcode = OP_SYNC_TO_PPS;
1132     cmd.op.len = sizeof(cmd.op);
1133     cmd.op.rid = d_next_rid++;
1134     cmd.eop.opcode = OP_EOP;
1135     cmd.eop.len = sizeof(cmd.eop);
1136     
1137     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1138     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1139       return false;
1140
1141     return ntohx(reply.ok) == 1;
1142   }
1143
1144   bool
1145   usrp2::impl::sync_every_pps(bool enable)
1146   {
1147     op_generic_cmd cmd;
1148     op_generic_t   reply;
1149
1150     memset(&cmd, 0, sizeof(cmd));
1151     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1152     cmd.op.opcode = OP_SYNC_EVERY_PPS;
1153     cmd.op.len = sizeof(cmd.op);
1154     cmd.op.rid = d_next_rid++;
1155     cmd.op.ok = enable ? 1 : 0;
1156     cmd.eop.opcode = OP_EOP;
1157     cmd.eop.len = sizeof(cmd.eop);
1158     
1159     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1160     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1161       return false;
1162
1163     return ntohx(reply.ok) == 1;
1164   }
1165
1166   std::vector<uint32_t>
1167   usrp2::impl::peek32(uint32_t addr, uint32_t words)
1168   {
1169     std::vector<uint32_t> result; // zero sized on error return
1170     // fprintf(stderr, "usrp2::peek: addr=%08X words=%u\n", addr, words);
1171
1172     if (addr % 4 != 0) {
1173       fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr); 
1174       return result;
1175     }
1176
1177     if (words == 0)
1178       return result;
1179
1180     op_peek_cmd   cmd;
1181     op_generic_t *reply;
1182
1183     int wlen = sizeof(uint32_t);
1184     int rlen = sizeof(op_generic_t);
1185     size_t bytes = words*wlen;
1186
1187     memset(&cmd, 0, sizeof(cmd));
1188     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1189     cmd.op.opcode = OP_PEEK;
1190     cmd.op.len = sizeof(cmd.op);
1191     cmd.op.rid = d_next_rid++;
1192     cmd.eop.opcode = OP_EOP;
1193     cmd.eop.len = sizeof(cmd.eop);
1194
1195     cmd.op.addr = htonl(addr);
1196     cmd.op.bytes = htonl(bytes);
1197
1198     reply = (op_generic_t *)malloc(rlen+bytes);
1199     pending_reply p(cmd.op.rid, reply, rlen+bytes);
1200     if (transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) {
1201       uint32_t nwords = (reply->len-rlen)/sizeof(uint32_t);
1202       uint32_t *data = (uint32_t *)(reply+rlen/wlen);
1203       for (unsigned int i = 0; i < nwords; i++)
1204         result.push_back(ntohl(data[i]));
1205     }
1206
1207     free(reply);
1208     return result;
1209   }
1210
1211   bool
1212   usrp2::impl::poke32(uint32_t addr, const std::vector<uint32_t> &data)
1213   {
1214     if (addr % 4 != 0) {
1215       fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr); 
1216       return false;
1217     }
1218
1219     int plen = sizeof(op_poke_cmd);
1220     int wlen = sizeof(uint32_t);
1221     int max_words = (MAX_SUBPKT_LEN-plen)/wlen;
1222     int words = data.size();
1223
1224     if (words > max_words) {
1225       fprintf(stderr, "usrp2::poke32: write size (=%u) exceeds maximum of %u words\n",
1226               words, max_words);
1227       return false;
1228     }
1229
1230     //fprintf(stderr, "usrp2::poke32: addr=%08X words=%u\n", addr, words);
1231
1232     if (words == 0)
1233       return true; // NOP
1234
1235     op_poke_cmd  *cmd;
1236     op_generic_t *eop;
1237
1238     // Allocate, clear, and initialize command packet
1239     int bytes = words*wlen;
1240     int l = plen+bytes+sizeof(*eop); // op_poke_cmd+data+eop
1241     cmd = (op_poke_cmd *)malloc(l);
1242     //fprintf(stderr, "cmd=%p l=%i\n", cmd, l);
1243     memset(cmd, 0, l);
1244     init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
1245     cmd->op.opcode = OP_POKE;
1246     cmd->op.len = sizeof(cmd->op)+bytes;
1247     cmd->op.rid = d_next_rid++;
1248     cmd->op.addr = htonl(addr);
1249
1250     // Copy data from vector into packet space
1251     uint32_t *dest = (uint32_t *)((uint8_t *)cmd+plen);
1252     for (int i = 0; i < words; i++) {
1253       //fprintf(stderr, "%03i@%p\n", i, dest);
1254       *dest++ = htonl(data[i]);
1255     }
1256
1257     // Write end-of-packet subpacket
1258     eop = (op_generic_t *)dest;
1259     eop->opcode = OP_EOP;
1260     eop->len = sizeof(*eop);
1261     //fprintf(stderr, "eop=%p len=%i\n", eop, eop->len);
1262
1263     // Send command to device and retrieve reply
1264     bool ok = false;
1265     op_generic_t reply;
1266     pending_reply p(cmd->op.rid, &reply, sizeof(reply));
1267     if (transmit_cmd(cmd, l, &p, DEF_CMD_TIMEOUT))
1268       ok = (ntohx(reply.ok) == 1);
1269
1270     free(cmd);
1271     return ok;
1272   }
1273
1274   bool
1275   usrp2::impl::reset_db()
1276   {
1277     op_generic_cmd cmd;
1278     op_generic_t reply;
1279
1280     memset(&cmd, 0, sizeof(cmd));
1281     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1282     cmd.op.opcode = OP_RESET_DB;
1283     cmd.op.len = sizeof(cmd.op);
1284     cmd.op.rid = d_next_rid++;
1285     cmd.eop.opcode = OP_EOP;
1286     cmd.eop.len = sizeof(cmd.eop);
1287     
1288     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1289     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1290       return false;
1291
1292     bool success = (ntohx(reply.ok) == 1);
1293     return success;
1294   }
1295
1296   bool usrp2::impl::set_gpio_ddr(int bank, uint16_t value, uint16_t mask)
1297   {
1298     if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1299       fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1300       return false;
1301     }
1302
1303     op_gpio_cmd cmd;
1304     op_generic_t reply;
1305
1306     memset(&cmd, 0, sizeof(cmd));
1307     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1308     cmd.op.opcode = OP_GPIO_SET_DDR;
1309     cmd.op.len = sizeof(cmd.op);
1310     cmd.op.rid = d_next_rid++;
1311     cmd.op.bank = static_cast<uint8_t>(bank);
1312     cmd.op.value = htons(value);
1313     cmd.op.mask = htons(mask);
1314     cmd.eop.opcode = OP_EOP;
1315     cmd.eop.len = sizeof(cmd.eop);
1316     
1317     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1318     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1319       return false;
1320
1321     bool success = (ntohx(reply.ok) == 1);
1322     return success;
1323   }
1324
1325   bool usrp2::impl::set_gpio_sels(int bank, std::string sels)
1326   {
1327     if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1328       fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1329       return false;
1330     }
1331
1332     if (sels.size() != 16) {
1333       fprintf(stderr, "set_gpio_sels: sels must be exactly 16 bytes\n");
1334       return false;
1335     }
1336
1337     op_gpio_set_sels_cmd cmd;
1338     op_generic_t reply;
1339
1340     memset(&cmd, 0, sizeof(cmd));
1341     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1342     cmd.op.opcode = OP_GPIO_SET_SELS;
1343     cmd.op.len = sizeof(cmd.op);
1344     cmd.op.rid = d_next_rid++;
1345     cmd.op.bank = static_cast<uint8_t>(bank);
1346     memcpy(&cmd.op.sels, sels.c_str(), 16);
1347     cmd.eop.opcode = OP_EOP;
1348     cmd.eop.len = sizeof(cmd.eop);
1349     
1350     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1351     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1352       return false;
1353
1354     bool success = (ntohx(reply.ok) == 1);
1355     return success;
1356   }
1357
1358   bool usrp2::impl::write_gpio(int bank, uint16_t value, uint16_t mask)
1359   {
1360     if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1361       fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1362       return false;
1363     }
1364
1365     op_gpio_cmd cmd;
1366     op_generic_t reply;
1367
1368     memset(&cmd, 0, sizeof(cmd));
1369     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1370     cmd.op.opcode = OP_GPIO_WRITE;
1371     cmd.op.len = sizeof(cmd.op);
1372     cmd.op.rid = d_next_rid++;
1373     cmd.op.bank = static_cast<uint8_t>(bank);
1374     cmd.op.value = htons(value);
1375     cmd.op.mask = htons(mask);
1376     cmd.eop.opcode = OP_EOP;
1377     cmd.eop.len = sizeof(cmd.eop);
1378     
1379     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1380     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1381       return false;
1382
1383     bool success = (ntohx(reply.ok) == 1);
1384     return success;
1385   }
1386
1387   bool usrp2::impl::read_gpio(int bank, uint16_t *value)
1388   {
1389     if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1390       fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1391       return false;
1392     }
1393
1394     op_gpio_cmd cmd;
1395     op_gpio_read_reply_t reply;
1396
1397     memset(&cmd, 0, sizeof(cmd));
1398     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1399     cmd.op.opcode = OP_GPIO_READ;
1400     cmd.op.len = sizeof(cmd.op);
1401     cmd.op.rid = d_next_rid++;
1402     cmd.op.bank = static_cast<uint8_t>(bank);
1403     cmd.op.value = 0; // not used
1404     cmd.op.mask = 0;  // not used
1405     cmd.eop.opcode = OP_EOP;
1406     cmd.eop.len = sizeof(cmd.eop);
1407     
1408     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1409     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1410       return false;
1411
1412     bool success = (ntohx(reply.ok) == 1);
1413     if (success && (value != NULL))
1414       *value = ntohs(reply.value);
1415
1416     return success;
1417   }
1418
1419   bool usrp2::impl::enable_gpio_streaming(int bank, int enable)
1420   {
1421     if (bank != GPIO_RX_BANK) {
1422       fprintf(stderr, "enable_gpio_streaming: only RX streaming is currently implemented\n");
1423       return false;
1424     }
1425
1426     if ((enable & ~0x03) != 0) {
1427       fprintf(stderr, "enable_gpio_streaming: invalid enable format\n");
1428       return false;
1429     }
1430
1431     op_gpio_cmd cmd;
1432     op_generic_t reply;
1433
1434     memset(&cmd, 0, sizeof(cmd));
1435     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1436     cmd.op.opcode = OP_GPIO_STREAM;
1437     cmd.op.len = sizeof(cmd.op);
1438     cmd.op.rid = d_next_rid++;
1439     cmd.op.bank = static_cast<uint8_t>(bank);
1440     cmd.op.value = htons((uint16_t)enable);
1441     cmd.op.mask = 0;  // not used
1442     cmd.eop.opcode = OP_EOP;
1443     cmd.eop.len = sizeof(cmd.eop);
1444     
1445     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1446     if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1447       return false;
1448
1449     bool success = (ntohx(reply.ok) == 1);
1450     return success;
1451   }
1452
1453 } // namespace usrp2