Fix problem with commands timing out (specifically stop_rx_streaming)
[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), d_dont_enqueue(true)
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
302   bool
303   usrp2::impl::transmit_cmd(void *cmd, size_t len)
304   {
305     return d_eth_buf->tx_frame(cmd, len) == eth_buffer::EB_OK;
306   }
307
308   bool
309   usrp2::impl::transmit_cmd_and_wait(void *cmd, size_t len, pending_reply *p, double secs)
310   {
311     d_pending_replies[p->rid()] = p;
312     
313     if (!transmit_cmd(cmd, len)){
314       d_pending_replies[p->rid()] = 0;
315       return false;
316     }
317
318     int res = p->wait_for_completion(secs);
319     d_pending_replies[p->rid()] = 0;
320     return res == 1;
321   }
322
323   // ----------------------------------------------------------------
324   //        Background loop: received packet demuxing
325   // ----------------------------------------------------------------
326
327   void
328   usrp2::impl::stop_bg()
329   {
330     d_bg_running = false;
331     d_bg_pending_cond.signal();
332     
333     void *dummy_status;
334     d_bg_thread->join(&dummy_status);  
335   }
336   
337   void
338   usrp2::impl::bg_loop()
339   {
340     d_bg_running = true;
341     while(d_bg_running) {
342       DEBUG_LOG(":");
343       // Receive available frames from ethernet buffer.  Handler will
344       // process control frames, enqueue data packets in channel
345       // rings, and signal blocked API threads
346       int res = d_eth_buf->rx_frames(this, 100); // FIXME magic timeout
347       if (res == eth_buffer::EB_ERROR)
348         break;  
349
350       // Wait for user API thread(s) to process all enqueued packets.
351       // The channel ring thread that decrements d_num_enqueued to zero 
352       // will signal this thread to continue.
353       {
354         omni_mutex_lock l(d_enqueued_mutex);
355         while(d_num_enqueued > 0 && d_bg_running)
356           d_bg_pending_cond.wait();
357       }
358     }
359     d_bg_running = false;
360   }
361   
362   //
363   // passed to eth_buffer::rx_frames
364   //
365   data_handler::result
366   usrp2::impl::operator()(const void *base, size_t len)
367   {
368     u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
369
370     // FIXME unaligned load!
371     int chan = u2p_chan(&pkt->hdrs.fixed);
372
373     if (chan == CONTROL_CHAN) {         // control packets
374       DEBUG_LOG("c");
375       return handle_control_packet(base, len);
376     }
377     else {                              // data packets
378
379       if (d_dont_enqueue)               // toss packet
380         return data_handler::RELEASE;
381
382       return handle_data_packet(base, len);
383     }
384
385     // not reached
386   }
387
388   data_handler::result
389   usrp2::impl::handle_control_packet(const void *base, size_t len)
390   {
391     // point to beginning of payload (subpackets)
392     unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
393     
394     // FIXME (p % 4) == 2.  Not good.  Must watch for unaligned loads.
395
396     // FIXME iterate over payload, handling more than a single subpacket.
397     
398     int opcode = p[0];
399     unsigned int oplen = p[1];
400     unsigned int rid = p[2];
401
402     pending_reply *rp = d_pending_replies[rid];
403     if (rp) {
404       unsigned int buflen = rp->len();
405       if (oplen != buflen) {
406         std::cerr << "usrp2: mismatched command reply length (expected: "
407                   << buflen << " got: " << oplen << "). "
408                   << "op = " << opcode_to_string(opcode) << std::endl;
409       }     
410     
411       // Copy reply into caller's buffer
412       memcpy(rp->buffer(), p, std::min(oplen, buflen));
413       rp->notify_completion();
414       d_pending_replies[rid] = 0;
415       return data_handler::RELEASE;
416     }
417
418     // TODO: handle unsolicited, USRP2 initiated, or late replies
419     DEBUG_LOG("l");
420     return data_handler::RELEASE;
421   }
422   
423   data_handler::result
424   usrp2::impl::handle_data_packet(const void *base, size_t len)
425   {
426     u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
427     d_num_rx_frames++;
428     d_num_rx_bytes += len;
429     
430     /* --- FIXME start of fake transport layer handler --- */
431
432     if (d_rx_seqno != -1) {
433       int expected_seqno = (d_rx_seqno + 1) & 0xFF;
434       int seqno = pkt->hdrs.thdr.seqno; 
435       
436       if (seqno != expected_seqno) {
437         ::write(2, "S", 1); // missing sequence number
438         int missing = seqno - expected_seqno;
439         if (missing < 0)
440           missing += 256;
441         
442         d_num_rx_overruns++;
443         d_num_rx_missing += missing;
444       }
445     }
446
447     d_rx_seqno = pkt->hdrs.thdr.seqno;
448
449     /* --- end of fake transport layer handler --- */
450
451     // FIXME unaligned load!
452     unsigned int chan = u2p_chan(&pkt->hdrs.fixed);
453
454     {
455       omni_mutex_lock l(d_channel_rings_mutex);
456
457       if (!d_channel_rings[chan]) {
458         DEBUG_LOG("!");
459         return data_handler::RELEASE;   // discard packet, no channel handler
460       }
461       
462       // Strip off ethernet header and transport header and enqueue the rest
463       
464       size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed);
465       if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) {
466         inc_enqueued();
467         DEBUG_LOG("+");
468         return data_handler::KEEP;      // channel ring runner will mark frame done
469       }
470       else {
471         DEBUG_LOG("!");
472         return data_handler::RELEASE;   // discard, no room in channel ring
473       }         
474       return data_handler::RELEASE;
475     }
476   }
477
478
479   // ----------------------------------------------------------------
480   //                           Receive
481   // ----------------------------------------------------------------
482
483   bool 
484   usrp2::impl::set_rx_gain(double gain)
485   {
486     op_config_rx_v2_cmd cmd;
487     op_config_rx_reply_v2_t reply;
488
489     init_config_rx_v2_cmd(&cmd);
490     cmd.op.valid = htons(CFGV_GAIN);
491     cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
492     
493     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
494     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
495       return false;
496
497     bool success = (ntohx(reply.ok) == 1);
498     return success;
499   }
500   
501   bool
502   usrp2::impl::set_rx_lo_offset(double frequency)
503   {
504     op_freq_cmd cmd;
505     op_generic_t reply;
506
507     memset(&cmd, 0, sizeof(cmd));
508     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
509     cmd.op.opcode = OP_SET_RX_LO_OFFSET;
510     cmd.op.len = sizeof(cmd.op);
511     cmd.op.rid = d_next_rid++;
512
513     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
514     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
515     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
516
517     cmd.eop.opcode = OP_EOP;
518     cmd.eop.len = sizeof(cmd.eop);
519     
520     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
521     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
522       return false;
523
524     bool success = (ntohx(reply.ok) == 1);
525     return success;
526   }
527
528   bool
529   usrp2::impl::set_rx_center_freq(double frequency, tune_result *result)
530   {
531     op_config_rx_v2_cmd cmd;
532     op_config_rx_reply_v2_t reply;
533
534     init_config_rx_v2_cmd(&cmd);
535     cmd.op.valid = htons(CFGV_FREQ);
536     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
537     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
538     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
539     
540     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
541     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
542       return false;
543
544     bool success = (ntohx(reply.ok) == 1);
545     if (result && success) {
546       result->baseband_freq =
547         u2_fxpt_freq_to_double( 
548           u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi), 
549                                  ntohl(reply.baseband_freq_lo)));
550
551       result->dxc_freq =
552         u2_fxpt_freq_to_double( 
553           u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi), 
554                                  ntohl(reply.ddc_freq_lo)));
555
556       result->residual_freq =
557         u2_fxpt_freq_to_double( 
558          u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi), 
559                                 ntohl(reply.residual_freq_lo)));
560
561       result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
562     }
563
564     return success;
565   }
566   
567   bool
568   usrp2::impl::set_rx_decim(int decimation_factor)
569   {
570     op_config_rx_v2_cmd cmd;
571     op_config_rx_reply_v2_t reply;
572
573     init_config_rx_v2_cmd(&cmd);
574     cmd.op.valid = htons(CFGV_INTERP_DECIM);
575     cmd.op.decim = htonl(decimation_factor);
576     
577     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
578     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
579       return false;
580
581     bool success = (ntohx(reply.ok) == 1);
582     if (success)
583       d_rx_decim = decimation_factor;
584     return success;
585   }
586   
587   bool
588   usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
589   {
590     op_config_rx_v2_cmd cmd;
591     op_config_rx_reply_v2_t reply;
592
593     init_config_rx_v2_cmd(&cmd);
594     cmd.op.valid = htons(CFGV_SCALE_IQ);
595     cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
596     
597     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
598     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
599       return false;
600
601     bool success = (ntohx(reply.ok) == 1);
602     return success;
603   }
604   
605   bool
606   usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
607   {
608     if (channel > MAX_CHAN) {
609       std::cerr << "usrp2: invalid channel number (" << channel
610                 << ")" << std::endl;
611       return false;
612     }
613
614     if (channel > 0) { // until firmware supports multiple streams
615       std::cerr << "usrp2: channel " << channel
616                 << " not implemented" << std::endl;
617       return false;
618     }
619
620     {
621       omni_mutex_lock l(d_channel_rings_mutex);
622       if (d_channel_rings[channel]) {
623         std::cerr << "usrp2: channel " << channel
624                   << " already streaming" << std::endl;
625         return false;
626       }
627       
628       if (items_per_frame == 0)
629         items_per_frame = U2_MAX_SAMPLES;               // minimize overhead
630       
631       op_start_rx_streaming_cmd cmd;
632       op_generic_t reply;
633
634       memset(&cmd, 0, sizeof(cmd));
635       init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
636       cmd.op.opcode = OP_START_RX_STREAMING;
637       cmd.op.len = sizeof(cmd.op);
638       cmd.op.rid = d_next_rid++;
639       cmd.op.items_per_frame = htonl(items_per_frame);
640       cmd.eop.opcode = OP_EOP;
641       cmd.eop.len = sizeof(cmd.eop);
642     
643       d_dont_enqueue = false;
644       bool success = false;
645       pending_reply p(cmd.op.rid, &reply, sizeof(reply));
646       success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
647       success = success && (ntohx(reply.ok) == 1);
648       
649       if (success)
650         d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
651       else
652         d_dont_enqueue = true;
653
654       //fprintf(stderr, "usrp2::start_rx_streaming: success = %d\n", success);
655       return success;
656     }
657   }
658   
659   bool
660   usrp2::impl::stop_rx_streaming(unsigned int channel)
661   {
662     if (channel > MAX_CHAN) {
663       std::cerr << "usrp2: invalid channel number (" << channel
664                 << ")" << std::endl;
665       return false;
666     }
667
668     if (channel > 0) { // until firmware supports multiple streams
669       std::cerr << "usrp2: channel " << channel
670                 << " not implemented" << std::endl;
671       return false;
672     }
673
674     d_dont_enqueue = true;      // no new samples
675     flush_rx_samples(channel);  // dump any we may already have
676
677     op_stop_rx_cmd cmd;
678     op_generic_t reply;
679
680     {
681       omni_mutex_lock l(d_channel_rings_mutex);
682
683       memset(&cmd, 0, sizeof(cmd));
684       init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
685       cmd.op.opcode = OP_STOP_RX;
686       cmd.op.len = sizeof(cmd.op);
687       cmd.op.rid = d_next_rid++;
688       cmd.eop.opcode = OP_EOP;
689       cmd.eop.len = sizeof(cmd.eop);
690     
691       bool success = false;
692       pending_reply p(cmd.op.rid, &reply, sizeof(reply));
693       success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
694       success = success && (ntohx(reply.ok) == 1);
695       d_channel_rings[channel].reset();
696       //fprintf(stderr, "usrp2::stop_rx_streaming:  success = %d\n", success);
697       return success;
698     }
699   }
700
701   bool
702   usrp2::impl::rx_samples(unsigned int channel, rx_sample_handler *handler)
703   {
704     if (channel > MAX_CHAN) {
705       std::cerr << "usrp2: invalid channel (" << channel
706                 << " )" << std::endl;
707       return false;
708     }
709     
710     if (channel > 0) {
711       std::cerr << "usrp2: channel " << channel
712                 << " not implemented" << std::endl;
713       return false;
714     }
715     
716     ring_sptr rp = d_channel_rings[channel];
717     if (!rp){
718       std::cerr << "usrp2: channel " << channel
719                 << " not receiving" << std::endl;
720       return false;
721     }
722     
723     // Wait for frames available in channel ring
724     DEBUG_LOG("W");
725     rp->wait_for_not_empty();
726     DEBUG_LOG("s");
727     
728     // Iterate through frames and present to user
729     void *p;
730     size_t frame_len_in_bytes;
731     while (rp->dequeue(&p, &frame_len_in_bytes)) {
732       uint32_t         *items;                  // points to beginning of data items
733       size_t            nitems_in_uint32s;
734       rx_metadata       md;
735       if (!parse_rx_metadata(p, frame_len_in_bytes, &items, &nitems_in_uint32s, &md))
736         return false;
737
738       bool want_more = (*handler)(items, nitems_in_uint32s, &md);
739       d_eth_buf->release_frame(p);
740       DEBUG_LOG("-");
741       dec_enqueued();
742
743       if (!want_more)
744         break;
745     }
746     return true;
747   }
748
749   bool
750   usrp2::impl::flush_rx_samples(unsigned int channel)
751   {
752     if (channel > MAX_CHAN) {
753       std::cerr << "usrp2: invalid channel (" << channel
754                 << " )" << std::endl;
755       return false;
756     }
757
758     if (channel > 0) {
759       std::cerr << "usrp2: channel " << channel
760                 << " not implemented" << std::endl;
761       return false;
762     }
763
764     ring_sptr rp = d_channel_rings[channel];
765     if (!rp){
766       return false;
767     }
768
769     // Iterate through frames and drop them
770     void *p;
771     size_t frame_len_in_bytes;
772     while (rp->dequeue(&p, &frame_len_in_bytes)) {
773       d_eth_buf->release_frame(p);
774       dec_enqueued();
775     }
776     return true;
777   }
778
779   // ----------------------------------------------------------------
780   //                            Transmit
781   // ----------------------------------------------------------------
782
783   bool 
784   usrp2::impl::set_tx_gain(double gain)
785   {
786     op_config_tx_v2_cmd cmd;
787     op_config_tx_reply_v2_t reply;
788
789     init_config_tx_v2_cmd(&cmd);
790     cmd.op.valid = htons(CFGV_GAIN);
791     cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
792     
793     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
794     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
795       return false;
796
797     bool success = (ntohx(reply.ok) == 1);
798     return success;
799   }
800   
801   bool
802   usrp2::impl::set_tx_lo_offset(double frequency)
803   {
804     op_freq_cmd cmd;
805     op_generic_t reply;
806
807     memset(&cmd, 0, sizeof(cmd));
808     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
809     cmd.op.opcode = OP_SET_TX_LO_OFFSET;
810     cmd.op.len = sizeof(cmd.op);
811     cmd.op.rid = d_next_rid++;
812
813     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
814     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
815     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
816
817     cmd.eop.opcode = OP_EOP;
818     cmd.eop.len = sizeof(cmd.eop);
819     
820     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
821     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
822       return false;
823
824     bool success = (ntohx(reply.ok) == 1);
825     return success;
826   }
827
828   bool
829   usrp2::impl::set_tx_center_freq(double frequency, tune_result *result)
830   {
831     op_config_tx_v2_cmd cmd;
832     op_config_tx_reply_v2_t reply;
833
834     init_config_tx_v2_cmd(&cmd);
835     cmd.op.valid = htons(CFGV_FREQ);
836     u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
837     cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
838     cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
839     
840     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
841     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
842       return false;
843
844     bool success = (ntohx(reply.ok) == 1);
845     if (result && success) {
846       result->baseband_freq =
847         u2_fxpt_freq_to_double( 
848           u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi), 
849                                  ntohl(reply.baseband_freq_lo)));
850
851       result->dxc_freq =
852         u2_fxpt_freq_to_double( 
853           u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi), 
854                                  ntohl(reply.duc_freq_lo)));
855
856       result->residual_freq =
857         u2_fxpt_freq_to_double( 
858          u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi), 
859                                 ntohl(reply.residual_freq_lo)));
860
861       result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
862     }
863
864     return success;
865   }
866   
867   bool
868   usrp2::impl::set_tx_interp(int interpolation_factor)
869   {
870     op_config_tx_v2_cmd cmd;
871     op_config_tx_reply_v2_t reply;
872
873     init_config_tx_v2_cmd(&cmd);
874     cmd.op.valid = htons(CFGV_INTERP_DECIM);
875     cmd.op.interp = htonl(interpolation_factor);
876     
877     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
878     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
879       return false;
880
881     bool success = (ntohx(reply.ok) == 1);
882     if (success) {
883       d_tx_interp = interpolation_factor;
884
885       // Auto-set TX scaling based on interpolation rate
886       int scale_i, scale_q;
887       default_tx_scale_iq(d_tx_interp, &scale_i, &scale_q);
888       return set_tx_scale_iq(scale_i, scale_q);
889     }
890
891     return success;
892   }
893   
894   void
895   usrp2::impl::default_tx_scale_iq(int interpolation_factor, int *scale_i, int *scale_q)
896   {
897     // Calculate CIC interpolation (i.e., without halfband interpolators)
898     int i = interpolation_factor;
899     if (i > 128)
900       i = i >> 1;
901     if (i > 128)
902       i = i >> 1;
903
904     // Calculate dsp_core_tx gain absent scale multipliers
905     float gain = (1.65*i*i*i)/(4096*pow(2, ceil(log2(i*i*i))));
906     
907     // Calculate closest multiplier constant to reverse gain
908     int scale = (int)rint(1.0/gain);
909     // fprintf(stderr, "if=%i i=%i gain=%f scale=%i\n", interpolation_factor, i, gain, scale);
910
911     // Both I and Q are identical in this case
912     if (scale_i)
913       *scale_i = scale;
914     if (scale_q)
915       *scale_q = scale;
916   }
917
918   bool
919   usrp2::impl::set_tx_scale_iq(int scale_i, int scale_q)
920   {
921     op_config_tx_v2_cmd cmd;
922     op_config_tx_reply_v2_t reply;
923
924     init_config_tx_v2_cmd(&cmd);
925     cmd.op.valid = htons(CFGV_SCALE_IQ);
926     cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
927     
928     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
929     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
930       return false;
931
932     bool success = (ntohx(reply.ok) == 1);
933     return success;
934   }
935
936   bool
937   usrp2::impl::tx_32fc(unsigned int channel,
938                        const std::complex<float> *samples,
939                        size_t nsamples,
940                        const tx_metadata *metadata)
941   {
942     uint32_t items[nsamples];
943     copy_host_32fc_to_u2_16sc(nsamples, samples, items);
944     return tx_raw(channel, items, nsamples, metadata);
945   }
946
947   bool
948   usrp2::impl::tx_16sc(unsigned int channel,
949                        const std::complex<int16_t> *samples,
950                        size_t nsamples,
951                        const tx_metadata *metadata)
952   {
953 #ifdef WORDS_BIGENDIAN
954
955     // Already binary equivalent to 16-bit I/Q on the wire.
956     // No conversion required.
957
958     assert(sizeof(samples[0]) == sizeof(uint32_t));
959     return tx_raw(channel, (const uint32_t *) samples, nsamples, metadata);
960
961 #else
962
963     uint32_t items[nsamples];
964     copy_host_16sc_to_u2_16sc(nsamples, samples, items);
965     return tx_raw(channel, items, nsamples, metadata);
966
967 #endif
968   }
969
970   bool
971   usrp2::impl::tx_raw(unsigned int channel,
972                       const uint32_t *items,
973                       size_t nitems,
974                       const tx_metadata *metadata)
975   {
976     if (nitems == 0)
977       return true;
978
979     // FIXME can't deal with nitems < U2_MIN_SAMPLES (will be fixed in VRT)
980     // FIXME need to check the MTU instead of assuming 1500 bytes
981
982     // fragment as necessary then fire away
983
984     size_t nframes = (nitems + U2_MAX_SAMPLES - 1) / U2_MAX_SAMPLES;
985     size_t last_frame = nframes - 1;
986     u2_eth_packet_t     hdrs;
987
988     size_t n = 0;
989     for (size_t fn = 0; fn < nframes; fn++){
990       uint32_t timestamp = 0;
991       uint32_t flags = 0;
992
993       if (fn == 0){
994         timestamp = metadata->timestamp;
995         if (metadata->send_now)
996           flags |= U2P_TX_IMMEDIATE;
997         if (metadata->start_of_burst)
998           flags |= U2P_TX_START_OF_BURST;
999       }
1000       if (fn > 0){
1001         flags |= U2P_TX_IMMEDIATE;
1002       }
1003       if (fn == last_frame){
1004         if (metadata->end_of_burst)
1005           flags |= U2P_TX_END_OF_BURST;
1006       }
1007
1008       init_etf_hdrs(&hdrs, d_addr, flags, channel, timestamp);
1009
1010       // Avoid short packet by splitting last two packets if reqd
1011       size_t i;
1012       if ((nitems - n) > U2_MAX_SAMPLES && (nitems - n) < (U2_MAX_SAMPLES + U2_MIN_SAMPLES))
1013         i = (nitems - n) / 2;
1014       else
1015         i = std::min((size_t) U2_MAX_SAMPLES, nitems - n);
1016
1017       eth_iovec iov[2];
1018       iov[0].iov_base = &hdrs;
1019       iov[0].iov_len = sizeof(hdrs);
1020       iov[1].iov_base = const_cast<uint32_t *>(&items[n]);
1021       iov[1].iov_len = i * sizeof(uint32_t);
1022
1023       size_t total = iov[0].iov_len + iov[1].iov_len;
1024       if (total < 64)
1025         fprintf(stderr, "usrp2::tx_raw: FIXME: short packet: %zd items (%zd bytes)\n", i, total);
1026
1027       if (d_eth_buf->tx_framev(iov, 2) != eth_buffer::EB_OK){
1028         return false;
1029       }
1030
1031       n += i;
1032     }
1033
1034     return true;
1035   }
1036
1037   // ----------------------------------------------------------------
1038   //                       misc commands
1039   // ----------------------------------------------------------------
1040
1041   bool
1042   usrp2::impl::config_mimo(int flags)
1043   {
1044     op_config_mimo_cmd cmd;
1045     op_generic_t reply;
1046
1047     memset(&cmd, 0, sizeof(cmd));
1048     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1049     cmd.op.opcode = OP_CONFIG_MIMO;
1050     cmd.op.len = sizeof(cmd.op);
1051     cmd.op.rid = d_next_rid++;
1052     cmd.op.flags = flags;
1053     cmd.eop.opcode = OP_EOP;
1054     cmd.eop.len = sizeof(cmd.eop);
1055     
1056     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1057     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1058       return false;
1059
1060     return ntohx(reply.ok) == 1;
1061   }
1062
1063   bool
1064   usrp2::impl::fpga_master_clock_freq(long *freq)
1065   {
1066     *freq = 100000000L;         // 100 MHz
1067     return true;
1068   }
1069
1070   bool
1071   usrp2::impl::adc_rate(long *rate)
1072   {
1073     return fpga_master_clock_freq(rate);
1074   }
1075
1076   bool
1077   usrp2::impl::dac_rate(long *rate)
1078   {
1079     return fpga_master_clock_freq(rate);
1080   }
1081
1082   bool
1083   usrp2::impl::tx_daughterboard_id(int *dbid)
1084   {
1085     *dbid = d_tx_db_info.dbid;
1086     return true;
1087   }
1088
1089   bool
1090   usrp2::impl::rx_daughterboard_id(int *dbid)
1091   {
1092     *dbid = d_rx_db_info.dbid;
1093     return true;
1094   }
1095
1096
1097   // ----------------------------------------------------------------
1098   //                    low-level commands
1099   // ----------------------------------------------------------------
1100
1101   bool
1102   usrp2::impl::burn_mac_addr(const std::string &new_addr)
1103   {
1104     op_burn_mac_addr_cmd cmd;
1105     op_generic_t reply;
1106
1107     memset(&cmd, 0, sizeof(cmd));
1108     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1109     cmd.op.opcode = OP_BURN_MAC_ADDR;
1110     cmd.op.len = sizeof(cmd.op);
1111     cmd.op.rid = d_next_rid++;
1112     if (!parse_mac_addr(new_addr, &cmd.op.addr))
1113       return false;
1114
1115     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1116     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, 4*DEF_CMD_TIMEOUT))
1117       return false;
1118
1119     bool success = (ntohx(reply.ok) == 1);
1120     return success;
1121   }
1122
1123   static void
1124   fill_dboard_info(db_info *dst, const u2_db_info_t *src)
1125   {
1126     dst->dbid = ntohl(src->dbid);
1127
1128     dst->freq_min =
1129       u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi), 
1130                                                     ntohl(src->freq_min_lo)));
1131     dst->freq_max =
1132       u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi), 
1133                                                     ntohl(src->freq_max_lo)));
1134
1135     dst->gain_min = u2_fxpt_gain_to_double(ntohs(src->gain_min));
1136     dst->gain_max = u2_fxpt_gain_to_double(ntohs(src->gain_max));
1137     dst->gain_step_size = u2_fxpt_gain_to_double(ntohs(src->gain_step_size));
1138   }
1139
1140   bool
1141   usrp2::impl::dboard_info()
1142   {
1143     op_dboard_info_cmd          cmd;
1144     op_dboard_info_reply_t      reply;
1145
1146     memset(&cmd, 0, sizeof(cmd));
1147     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1148     cmd.op.opcode = OP_DBOARD_INFO;
1149     cmd.op.len = sizeof(cmd.op);
1150     cmd.op.rid = d_next_rid++;
1151     cmd.eop.opcode = OP_EOP;
1152     cmd.eop.len = sizeof(cmd.eop);
1153     
1154     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1155     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1156       return false;
1157
1158     bool success = (ntohx(reply.ok) == 1);
1159     if (success){
1160       fill_dboard_info(&d_tx_db_info, &reply.tx_db_info);
1161       fill_dboard_info(&d_rx_db_info, &reply.rx_db_info);
1162     }
1163     return success;
1164   }
1165
1166
1167   bool
1168   usrp2::impl::sync_to_pps()
1169   {
1170     op_generic_cmd cmd;
1171     op_generic_t   reply;
1172
1173     memset(&cmd, 0, sizeof(cmd));
1174     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1175     cmd.op.opcode = OP_SYNC_TO_PPS;
1176     cmd.op.len = sizeof(cmd.op);
1177     cmd.op.rid = d_next_rid++;
1178     cmd.eop.opcode = OP_EOP;
1179     cmd.eop.len = sizeof(cmd.eop);
1180     
1181     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1182     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1183       return false;
1184
1185     return ntohx(reply.ok) == 1;
1186   }
1187
1188   bool
1189   usrp2::impl::sync_every_pps(bool enable)
1190   {
1191     op_generic_cmd cmd;
1192     op_generic_t   reply;
1193
1194     memset(&cmd, 0, sizeof(cmd));
1195     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1196     cmd.op.opcode = OP_SYNC_EVERY_PPS;
1197     cmd.op.len = sizeof(cmd.op);
1198     cmd.op.rid = d_next_rid++;
1199     cmd.op.ok = enable ? 1 : 0;
1200     cmd.eop.opcode = OP_EOP;
1201     cmd.eop.len = sizeof(cmd.eop);
1202     
1203     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1204     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1205       return false;
1206
1207     return ntohx(reply.ok) == 1;
1208   }
1209
1210   std::vector<uint32_t>
1211   usrp2::impl::peek32(uint32_t addr, uint32_t words)
1212   {
1213     std::vector<uint32_t> result; // zero sized on error return
1214     // fprintf(stderr, "usrp2::peek: addr=%08X words=%u\n", addr, words);
1215
1216     if (addr % 4 != 0) {
1217       fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr); 
1218       return result;
1219     }
1220
1221     if (words == 0)
1222       return result;
1223
1224     op_peek_cmd   cmd;
1225     op_generic_t *reply;
1226
1227     int wlen = sizeof(uint32_t);
1228     int rlen = sizeof(op_generic_t);
1229     size_t bytes = words*wlen;
1230
1231     memset(&cmd, 0, sizeof(cmd));
1232     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1233     cmd.op.opcode = OP_PEEK;
1234     cmd.op.len = sizeof(cmd.op);
1235     cmd.op.rid = d_next_rid++;
1236     cmd.eop.opcode = OP_EOP;
1237     cmd.eop.len = sizeof(cmd.eop);
1238
1239     cmd.op.addr = htonl(addr);
1240     cmd.op.bytes = htonl(bytes);
1241
1242     reply = (op_generic_t *)malloc(rlen+bytes);
1243     pending_reply p(cmd.op.rid, reply, rlen+bytes);
1244     if (transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) {
1245       uint32_t nwords = (reply->len-rlen)/sizeof(uint32_t);
1246       uint32_t *data = (uint32_t *)(reply+rlen/wlen);
1247       for (unsigned int i = 0; i < nwords; i++)
1248         result.push_back(ntohl(data[i]));
1249     }
1250
1251     free(reply);
1252     return result;
1253   }
1254
1255   bool
1256   usrp2::impl::poke32(uint32_t addr, const std::vector<uint32_t> &data)
1257   {
1258     if (addr % 4 != 0) {
1259       fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr); 
1260       return false;
1261     }
1262
1263     int plen = sizeof(op_poke_cmd);
1264     int wlen = sizeof(uint32_t);
1265     int max_words = (MAX_SUBPKT_LEN-plen)/wlen;
1266     int words = data.size();
1267
1268     if (words > max_words) {
1269       fprintf(stderr, "usrp2::poke32: write size (=%u) exceeds maximum of %u words\n",
1270               words, max_words);
1271       return false;
1272     }
1273
1274     //fprintf(stderr, "usrp2::poke32: addr=%08X words=%u\n", addr, words);
1275
1276     if (words == 0)
1277       return true; // NOP
1278
1279     op_poke_cmd  *cmd;
1280     op_generic_t *eop;
1281
1282     // Allocate, clear, and initialize command packet
1283     int bytes = words*wlen;
1284     int l = plen+bytes+sizeof(*eop); // op_poke_cmd+data+eop
1285     cmd = (op_poke_cmd *)malloc(l);
1286     //fprintf(stderr, "cmd=%p l=%i\n", cmd, l);
1287     memset(cmd, 0, l);
1288     init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
1289     cmd->op.opcode = OP_POKE;
1290     cmd->op.len = sizeof(cmd->op)+bytes;
1291     cmd->op.rid = d_next_rid++;
1292     cmd->op.addr = htonl(addr);
1293
1294     // Copy data from vector into packet space
1295     uint32_t *dest = (uint32_t *)((uint8_t *)cmd+plen);
1296     for (int i = 0; i < words; i++) {
1297       //fprintf(stderr, "%03i@%p\n", i, dest);
1298       *dest++ = htonl(data[i]);
1299     }
1300
1301     // Write end-of-packet subpacket
1302     eop = (op_generic_t *)dest;
1303     eop->opcode = OP_EOP;
1304     eop->len = sizeof(*eop);
1305     //fprintf(stderr, "eop=%p len=%i\n", eop, eop->len);
1306
1307     // Send command to device and retrieve reply
1308     bool ok = false;
1309     op_generic_t reply;
1310     pending_reply p(cmd->op.rid, &reply, sizeof(reply));
1311     if (transmit_cmd_and_wait(cmd, l, &p, DEF_CMD_TIMEOUT))
1312       ok = (ntohx(reply.ok) == 1);
1313
1314     free(cmd);
1315     return ok;
1316   }
1317
1318   bool
1319   usrp2::impl::reset_db()
1320   {
1321     op_generic_cmd cmd;
1322     op_generic_t reply;
1323
1324     memset(&cmd, 0, sizeof(cmd));
1325     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1326     cmd.op.opcode = OP_RESET_DB;
1327     cmd.op.len = sizeof(cmd.op);
1328     cmd.op.rid = d_next_rid++;
1329     cmd.eop.opcode = OP_EOP;
1330     cmd.eop.len = sizeof(cmd.eop);
1331     
1332     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1333     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1334       return false;
1335
1336     bool success = (ntohx(reply.ok) == 1);
1337     return success;
1338   }
1339
1340   bool usrp2::impl::set_gpio_ddr(int bank, uint16_t value, uint16_t mask)
1341   {
1342     if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1343       fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1344       return false;
1345     }
1346
1347     op_gpio_cmd cmd;
1348     op_generic_t reply;
1349
1350     memset(&cmd, 0, sizeof(cmd));
1351     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1352     cmd.op.opcode = OP_GPIO_SET_DDR;
1353     cmd.op.len = sizeof(cmd.op);
1354     cmd.op.rid = d_next_rid++;
1355     cmd.op.bank = static_cast<uint8_t>(bank);
1356     cmd.op.value = htons(value);
1357     cmd.op.mask = htons(mask);
1358     cmd.eop.opcode = OP_EOP;
1359     cmd.eop.len = sizeof(cmd.eop);
1360     
1361     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1362     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1363       return false;
1364
1365     bool success = (ntohx(reply.ok) == 1);
1366     return success;
1367   }
1368
1369   bool usrp2::impl::set_gpio_sels(int bank, std::string sels)
1370   {
1371     if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1372       fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1373       return false;
1374     }
1375
1376     if (sels.size() != 16) {
1377       fprintf(stderr, "set_gpio_sels: sels must be exactly 16 bytes\n");
1378       return false;
1379     }
1380
1381     op_gpio_set_sels_cmd cmd;
1382     op_generic_t reply;
1383
1384     memset(&cmd, 0, sizeof(cmd));
1385     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1386     cmd.op.opcode = OP_GPIO_SET_SELS;
1387     cmd.op.len = sizeof(cmd.op);
1388     cmd.op.rid = d_next_rid++;
1389     cmd.op.bank = static_cast<uint8_t>(bank);
1390     memcpy(&cmd.op.sels, sels.c_str(), 16);
1391     cmd.eop.opcode = OP_EOP;
1392     cmd.eop.len = sizeof(cmd.eop);
1393     
1394     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1395     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1396       return false;
1397
1398     bool success = (ntohx(reply.ok) == 1);
1399     return success;
1400   }
1401
1402   bool usrp2::impl::write_gpio(int bank, uint16_t value, uint16_t mask)
1403   {
1404     if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1405       fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1406       return false;
1407     }
1408
1409     op_gpio_cmd cmd;
1410     op_generic_t reply;
1411
1412     memset(&cmd, 0, sizeof(cmd));
1413     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1414     cmd.op.opcode = OP_GPIO_WRITE;
1415     cmd.op.len = sizeof(cmd.op);
1416     cmd.op.rid = d_next_rid++;
1417     cmd.op.bank = static_cast<uint8_t>(bank);
1418     cmd.op.value = htons(value);
1419     cmd.op.mask = htons(mask);
1420     cmd.eop.opcode = OP_EOP;
1421     cmd.eop.len = sizeof(cmd.eop);
1422     
1423     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1424     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1425       return false;
1426
1427     bool success = (ntohx(reply.ok) == 1);
1428     return success;
1429   }
1430
1431   bool usrp2::impl::read_gpio(int bank, uint16_t *value)
1432   {
1433     if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1434       fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1435       return false;
1436     }
1437
1438     op_gpio_cmd cmd;
1439     op_gpio_read_reply_t reply;
1440
1441     memset(&cmd, 0, sizeof(cmd));
1442     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1443     cmd.op.opcode = OP_GPIO_READ;
1444     cmd.op.len = sizeof(cmd.op);
1445     cmd.op.rid = d_next_rid++;
1446     cmd.op.bank = static_cast<uint8_t>(bank);
1447     cmd.op.value = 0; // not used
1448     cmd.op.mask = 0;  // not used
1449     cmd.eop.opcode = OP_EOP;
1450     cmd.eop.len = sizeof(cmd.eop);
1451     
1452     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1453     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1454       return false;
1455
1456     bool success = (ntohx(reply.ok) == 1);
1457     if (success && (value != NULL))
1458       *value = ntohs(reply.value);
1459
1460     return success;
1461   }
1462
1463   bool usrp2::impl::enable_gpio_streaming(int bank, int enable)
1464   {
1465     if (bank != GPIO_RX_BANK) {
1466       fprintf(stderr, "enable_gpio_streaming: only RX streaming is currently implemented\n");
1467       return false;
1468     }
1469
1470     if ((enable & ~0x03) != 0) {
1471       fprintf(stderr, "enable_gpio_streaming: invalid enable format\n");
1472       return false;
1473     }
1474
1475     op_gpio_cmd cmd;
1476     op_generic_t reply;
1477
1478     memset(&cmd, 0, sizeof(cmd));
1479     init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1480     cmd.op.opcode = OP_GPIO_STREAM;
1481     cmd.op.len = sizeof(cmd.op);
1482     cmd.op.rid = d_next_rid++;
1483     cmd.op.bank = static_cast<uint8_t>(bank);
1484     cmd.op.value = htons((uint16_t)enable);
1485     cmd.op.mask = 0;  // not used
1486     cmd.eop.opcode = OP_EOP;
1487     cmd.eop.len = sizeof(cmd.eop);
1488     
1489     pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1490     if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1491       return false;
1492
1493     bool success = (ntohx(reply.ok) == 1);
1494     return success;
1495   }
1496
1497 } // namespace usrp2