3 * Copyright 2008,2009,2010 Free Software Foundation, Inc.
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.
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.
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/>.
23 #include <usrp2/usrp2.h>
24 #include <usrp2/tune_result.h>
25 #include <usrp2/copiers.h>
26 #include <gruel/inet.h>
27 #include <gruel/realtime.h>
28 #include <boost/bind.hpp>
29 #include <usrp2_types.h>
30 #include "usrp2_impl.h"
31 #include "eth_buffer.h"
32 #include "pktfilter.h"
42 #define USRP2_IMPL_DEBUG 0
44 #define DEBUG_LOG(x) ::write(2, x, 1)
49 static const int DEFAULT_RX_SCALE = 1024;
53 static const double DEF_CMD_TIMEOUT = 0.1;
56 opcode_to_string(int opcode)
59 case OP_EOP: return "OP_EOP";
60 case OP_ID: return "OP_ID";
61 case OP_ID_REPLY: return "OP_ID_REPLY";
62 case OP_BURN_MAC_ADDR: return "OP_BURN_MAC_ADDR";
63 case OP_READ_TIME: return "OP_READ_TIME";
64 case OP_READ_TIME_REPLY: return "OP_READ_TIME_REPLY";
65 case OP_CONFIG_RX_V2: return "OP_CONFIG_RX_V2";
66 case OP_CONFIG_RX_REPLY_V2: return "OP_CONFIG_RX_REPLY_V2";
67 case OP_CONFIG_TX_V2: return "OP_CONFIG_TX_V2";
68 case OP_CONFIG_TX_REPLY_V2: return "OP_CONFIG_TX_REPLY_V2";
69 case OP_START_RX_STREAMING: return "OP_START_RX_STREAMING";
70 case OP_STOP_RX: return "OP_STOP_RX";
71 case OP_CONFIG_MIMO: return "OP_CONFIG_MIMO";
72 case OP_DBOARD_INFO: return "OP_DBOARD_INFO";
73 case OP_DBOARD_INFO_REPLY: return "OP_DBOARD_INFO_REPLY";
74 case OP_SYNC_TO_PPS: return "OP_SYNC_TO_PPS";
75 case OP_PEEK: return "OP_PEEK";
76 case OP_PEEK_REPLY: return "OP_PEEK_REPLY";
77 case OP_SET_TX_LO_OFFSET: return "OP_SET_TX_LO_OFFSET";
78 case OP_SET_TX_LO_OFFSET_REPLY: return "OP_SET_TX_LO_OFFSET_REPLY";
79 case OP_SET_RX_LO_OFFSET: return "OP_SET_RX_LO_OFFSET";
80 case OP_SET_RX_LO_OFFSET_REPLY: return "OP_SET_RX_LO_OFFSET_REPLY";
81 case OP_SYNC_EVERY_PPS: return "OP_SYNC_EVERY_PPS";
82 case OP_SYNC_EVERY_PPS_REPLY: return "OP_SYNC_EVERY_PPS_REPLY";
86 snprintf(buf, sizeof(buf), "<unknown opcode: %d>", opcode);
93 * \param p points to fixed header
94 * \param payload_len_in_bytes is length of the fixed hdr and the payload
95 * \param[out] items is set to point to the first uint32 item in the payload
96 * \param[out] nitems is set to the number of uint32 items in the payload
97 * \param[out] md is filled in with the parsed metadata from the frame.
100 parse_rx_metadata(void *p, size_t payload_len_in_bytes,
101 uint32_t **items, size_t *nitems_in_uint32s, rx_metadata *md)
103 if (payload_len_in_bytes < sizeof(u2_fixed_hdr_t)) // invalid format
106 // FIXME deal with the fact that (p % 4) == 2
107 //assert((((uintptr_t) p) % 4) == 0); // must be 4-byte aligned
109 u2_fixed_hdr_t *fh = static_cast<u2_fixed_hdr_t *>(p);
111 // FIXME unaligned loads!
112 md->word0 = u2p_word0(fh);
113 md->timestamp = u2p_timestamp(fh);
115 // FIXME when we've got more info
116 // md->start_of_burst = (md->word0 & XXX) != 0;
117 // md->end_of_burst = (md->word0 & XXX) != 0;
118 // md->rx_overrun = (md->word0 & XXX) != 0;
119 md->start_of_burst = 0;
120 md->end_of_burst = 0;
123 *items = (uint32_t *)(&fh[1]);
124 size_t nbytes = payload_len_in_bytes - sizeof(u2_fixed_hdr_t);
125 assert((nbytes % sizeof(uint32_t)) == 0);
126 *nitems_in_uint32s = nbytes / sizeof(uint32_t);
132 usrp2::impl::impl(const std::string &ifc, props *p, size_t rx_bufsize)
133 : d_eth_buf(new eth_buffer(rx_bufsize)), d_interface_name(ifc), d_pf(0),
134 d_bg_running(false), d_rx_seqno(-1), d_tx_seqno(0), d_next_rid(0),
135 d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0),
136 d_num_enqueued(0), d_enqueued_mutex(), d_bg_pending_cond(),
137 d_channel_rings(NCHANS), d_tx_interp(0), d_rx_decim(0), d_dont_enqueue(true)
139 if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE)))
140 throw std::runtime_error("Unable to register USRP2 protocol");
144 // Create a packet filter for U2_ETHERTYPE packets sourced from target USRP2
145 u2_mac_addr_t usrp_mac;
146 parse_mac_addr(d_addr, &usrp_mac);
147 d_pf = pktfilter::make_ethertype_inbound_target(U2_ETHERTYPE, (const unsigned char*)&(usrp_mac.addr));
148 if (!d_pf || !d_eth_buf->attach_pktfilter(d_pf))
149 throw std::runtime_error("Unable to attach packet filter.");
151 if (USRP2_IMPL_DEBUG)
152 std::cerr << "usrp2 constructor: using USRP2 at " << d_addr << std::endl;
154 memset(d_pending_replies, 0, sizeof(d_pending_replies));
156 // Kick off receive thread
159 // In case the USRP2 was left streaming RX
160 // FIXME: only one channel right now
161 stop_rx_streaming(0);
163 if (!dboard_info()) // we're hosed
164 throw std::runtime_error("Unable to retrieve daughterboard info");
169 tx_daughterboard_id(&dbid);
170 fprintf(stderr, "Tx dboard 0x%x\n", dbid);
171 fprintf(stderr, " freq_min = %g\n", tx_freq_min());
172 fprintf(stderr, " freq_max = %g\n", tx_freq_max());
173 fprintf(stderr, " gain_min = %g\n", tx_gain_min());
174 fprintf(stderr, " gain_max = %g\n", tx_gain_max());
175 fprintf(stderr, " gain_db_per_step = %g\n", tx_gain_db_per_step());
177 rx_daughterboard_id(&dbid);
178 fprintf(stderr, "Rx dboard 0x%x\n", dbid);
179 fprintf(stderr, " freq_min = %g\n", rx_freq_min());
180 fprintf(stderr, " freq_max = %g\n", rx_freq_max());
181 fprintf(stderr, " gain_min = %g\n", rx_gain_min());
182 fprintf(stderr, " gain_max = %g\n", rx_gain_max());
183 fprintf(stderr, " gain_db_per_step = %g\n", rx_gain_db_per_step());
186 // Ensure any custom values in hardware are cleared
188 std::cerr << "usrp2::ctor reset_db failed\n";
190 // default gains to mid point
191 if (!set_tx_gain((tx_gain_min() + tx_gain_max()) / 2))
192 std::cerr << "usrp2::ctor set_tx_gain failed\n";
194 if (!set_rx_gain((rx_gain_min() + rx_gain_max()) / 2))
195 std::cerr << "usrp2::ctor set_rx_gain failed\n";
197 // default interp and decim
198 if (!set_tx_interp(12))
199 std::cerr << "usrp2::ctor set_tx_interp failed\n";
201 if (!set_rx_decim(12))
202 std::cerr << "usrp2::ctor set_rx_decim failed\n";
204 // set workable defaults for scaling
205 if (!set_rx_scale_iq(DEFAULT_RX_SCALE, DEFAULT_RX_SCALE))
206 std::cerr << "usrp2::ctor set_rx_scale_iq failed\n";
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;
227 usrp2::impl::parse_mac_addr(const std::string &s, u2_mac_addr_t *p)
229 p->addr[0] = 0x00; // Matt's IAB
241 return sscanf(s.c_str(), "%hhx:%hhx", &p->addr[4], &p->addr[5]) == 2;
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;
253 usrp2::impl::init_et_hdrs(u2_eth_packet_t *p, const std::string &dst)
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++;
264 usrp2::impl::init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
265 int word0_flags, int chan, uint32_t timestamp)
267 init_et_hdrs(p, dst);
268 u2p_set_word0(&p->fixed, word0_flags, chan);
269 u2p_set_timestamp(&p->fixed, timestamp);
271 if (chan == CONTROL_CHAN) { // no sequence numbers, back it out
278 usrp2::impl::init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd)
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);
290 usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd)
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);
303 usrp2::impl::transmit_cmd(void *cmd_, size_t len_)
305 const void *cmd = cmd_;
307 unsigned char tmp[64];
309 if (len_ < 64){ // pad to minimum ethernet frame size
310 memset(tmp, 0, sizeof(tmp));
311 memcpy(tmp, cmd_, len_);
316 return d_eth_buf->tx_frame(cmd, len) == eth_buffer::EB_OK;
320 usrp2::impl::transmit_cmd_and_wait(void *cmd, size_t len, pending_reply *p, double secs)
322 d_pending_replies[p->rid()] = p;
324 if (!transmit_cmd(cmd, len)){
325 d_pending_replies[p->rid()] = 0;
329 int res = p->wait_for_completion(secs);
330 d_pending_replies[p->rid()] = 0;
334 // ----------------------------------------------------------------
335 // Background loop: received packet demuxing
336 // ----------------------------------------------------------------
339 usrp2::impl::start_bg()
341 d_rx_tg.create_thread(boost::bind(&usrp2::impl::bg_loop, this));
345 usrp2::impl::stop_bg()
347 d_bg_running = false;
348 d_bg_pending_cond.notify_one(); // FIXME: check if needed
353 usrp2::impl::bg_loop()
355 gruel::enable_realtime_scheduling();
358 while(d_bg_running) {
360 // Receive available frames from ethernet buffer. Handler will
361 // process control frames, enqueue data packets in channel
362 // rings, and signal blocked API threads
363 int res = d_eth_buf->rx_frames(this, 100); // FIXME magic timeout
364 if (res == eth_buffer::EB_ERROR)
367 // Wait for user API thread(s) to process all enqueued packets.
368 // The channel ring thread that decrements d_num_enqueued to zero
369 // will signal this thread to continue.
371 gruel::scoped_lock l(d_enqueued_mutex);
372 while(d_num_enqueued > 0 && d_bg_running)
373 d_bg_pending_cond.wait(l);
376 d_bg_running = false;
380 // passed to eth_buffer::rx_frames
383 usrp2::impl::operator()(const void *base, size_t len)
385 u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
387 // FIXME unaligned load!
388 int chan = u2p_chan(&pkt->hdrs.fixed);
390 if (chan == CONTROL_CHAN) { // control packets
392 return handle_control_packet(base, len);
394 else { // data packets
396 if (d_dont_enqueue) // toss packet
397 return data_handler::RELEASE;
399 return handle_data_packet(base, len);
406 usrp2::impl::handle_control_packet(const void *base, size_t len)
408 // point to beginning of payload (subpackets)
409 unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
411 // FIXME (p % 4) == 2. Not good. Must watch for unaligned loads.
413 // FIXME iterate over payload, handling more than a single subpacket.
416 unsigned int oplen = p[1];
417 unsigned int rid = p[2];
419 pending_reply *rp = d_pending_replies[rid];
421 unsigned int buflen = rp->len();
422 if (oplen != buflen) {
423 std::cerr << "usrp2: mismatched command reply length (expected: "
424 << buflen << " got: " << oplen << "). "
425 << "op = " << opcode_to_string(opcode) << std::endl;
428 // Copy reply into caller's buffer
429 memcpy(rp->buffer(), p, std::min(oplen, buflen));
430 rp->notify_completion();
431 d_pending_replies[rid] = 0;
432 return data_handler::RELEASE;
435 // TODO: handle unsolicited, USRP2 initiated, or late replies
437 return data_handler::RELEASE;
441 usrp2::impl::handle_data_packet(const void *base, size_t len)
443 u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
445 d_num_rx_bytes += len;
447 /* --- FIXME start of fake transport layer handler --- */
449 if (d_rx_seqno != -1) {
450 int expected_seqno = (d_rx_seqno + 1) & 0xFF;
451 int seqno = pkt->hdrs.thdr.seqno;
453 if (seqno != expected_seqno) {
454 ::write(2, "S", 1); // missing sequence number
455 int missing = seqno - expected_seqno;
460 d_num_rx_missing += missing;
464 d_rx_seqno = pkt->hdrs.thdr.seqno;
466 /* --- end of fake transport layer handler --- */
468 // FIXME unaligned load!
469 unsigned int chan = u2p_chan(&pkt->hdrs.fixed);
472 gruel::scoped_lock l(d_channel_rings_mutex);
474 if (!d_channel_rings[chan]) {
476 return data_handler::RELEASE; // discard packet, no channel handler
479 // Strip off ethernet header and transport header and enqueue the rest
481 size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed);
482 if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) {
485 return data_handler::KEEP; // channel ring runner will mark frame done
489 return data_handler::RELEASE; // discard, no room in channel ring
491 return data_handler::RELEASE;
496 // ----------------------------------------------------------------
498 // ----------------------------------------------------------------
501 usrp2::impl::set_rx_antenna(int ant){
502 op_config_mimo_cmd cmd;
505 memset(&cmd, 0, sizeof(cmd));
506 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
507 cmd.op.opcode = OP_RX_ANTENNA;
508 cmd.op.len = sizeof(cmd.op);
509 cmd.op.rid = d_next_rid++;
511 cmd.eop.opcode = OP_EOP;
512 cmd.eop.len = sizeof(cmd.eop);
514 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
515 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
518 return ntohx(reply.ok) == 1;
522 usrp2::impl::set_rx_gain(double gain)
524 op_config_rx_v2_cmd cmd;
525 op_config_rx_reply_v2_t reply;
527 init_config_rx_v2_cmd(&cmd);
528 cmd.op.valid = htons(CFGV_GAIN);
529 cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
531 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
532 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
535 bool success = (ntohx(reply.ok) == 1);
540 usrp2::impl::set_rx_lo_offset(double frequency)
545 memset(&cmd, 0, sizeof(cmd));
546 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
547 cmd.op.opcode = OP_SET_RX_LO_OFFSET;
548 cmd.op.len = sizeof(cmd.op);
549 cmd.op.rid = d_next_rid++;
551 u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
552 cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
553 cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
555 cmd.eop.opcode = OP_EOP;
556 cmd.eop.len = sizeof(cmd.eop);
558 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
559 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
562 bool success = (ntohx(reply.ok) == 1);
567 usrp2::impl::set_rx_center_freq(double frequency, tune_result *result)
569 op_config_rx_v2_cmd cmd;
570 op_config_rx_reply_v2_t reply;
572 init_config_rx_v2_cmd(&cmd);
573 cmd.op.valid = htons(CFGV_FREQ);
574 u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
575 cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
576 cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
578 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
579 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
582 bool success = (ntohx(reply.ok) == 1);
583 if (result && success) {
584 result->baseband_freq =
585 u2_fxpt_freq_to_double(
586 u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
587 ntohl(reply.baseband_freq_lo)));
590 u2_fxpt_freq_to_double(
591 u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi),
592 ntohl(reply.ddc_freq_lo)));
594 result->residual_freq =
595 u2_fxpt_freq_to_double(
596 u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
597 ntohl(reply.residual_freq_lo)));
599 result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
606 usrp2::impl::set_rx_decim(int decimation_factor)
608 op_config_rx_v2_cmd cmd;
609 op_config_rx_reply_v2_t reply;
611 init_config_rx_v2_cmd(&cmd);
612 cmd.op.valid = htons(CFGV_INTERP_DECIM);
613 cmd.op.decim = htonl(decimation_factor);
615 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
616 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
619 bool success = (ntohx(reply.ok) == 1);
621 d_rx_decim = decimation_factor;
626 usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
628 op_config_rx_v2_cmd cmd;
629 op_config_rx_reply_v2_t reply;
631 init_config_rx_v2_cmd(&cmd);
632 cmd.op.valid = htons(CFGV_SCALE_IQ);
633 cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
635 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
636 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
639 bool success = (ntohx(reply.ok) == 1);
644 usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
646 if (channel > MAX_CHAN) {
647 std::cerr << "usrp2: invalid channel number (" << channel
652 if (channel > 0) { // until firmware supports multiple streams
653 std::cerr << "usrp2: channel " << channel
654 << " not implemented" << std::endl;
659 gruel::scoped_lock l(d_channel_rings_mutex);
660 if (d_channel_rings[channel]) {
661 std::cerr << "usrp2: channel " << channel
662 << " already streaming" << std::endl;
666 if (items_per_frame == 0)
667 items_per_frame = U2_MAX_SAMPLES; // minimize overhead
669 op_start_rx_streaming_cmd cmd;
672 memset(&cmd, 0, sizeof(cmd));
673 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
674 cmd.op.opcode = OP_START_RX_STREAMING;
675 cmd.op.len = sizeof(cmd.op);
676 cmd.op.rid = d_next_rid++;
677 cmd.op.items_per_frame = htonl(items_per_frame);
678 cmd.eop.opcode = OP_EOP;
679 cmd.eop.len = sizeof(cmd.eop);
681 d_dont_enqueue = false;
682 bool success = false;
683 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
684 success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
685 success = success && (ntohx(reply.ok) == 1);
688 d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
690 d_dont_enqueue = true;
692 //fprintf(stderr, "usrp2::start_rx_streaming: success = %d\n", success);
698 usrp2::impl::start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time)
700 if (channel > MAX_CHAN) {
701 std::cerr << "usrp2: invalid channel number (" << channel
706 if (channel > 0) { // until firmware supports multiple streams
707 std::cerr << "usrp2: channel " << channel
708 << " not implemented" << std::endl;
713 gruel::scoped_lock guard(d_channel_rings_mutex);
714 if (d_channel_rings[channel]) {
715 std::cerr << "usrp2: channel " << channel
716 << " already streaming" << std::endl;
720 if (items_per_frame == 0)
721 items_per_frame = U2_MAX_SAMPLES; // minimize overhead
723 op_start_rx_streaming_cmd cmd;
726 memset(&cmd, 0, sizeof(cmd));
727 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, time);
728 cmd.op.opcode = OP_START_RX_STREAMING;
729 cmd.op.len = sizeof(cmd.op);
730 cmd.op.rid = d_next_rid++;
731 cmd.op.items_per_frame = htonl(items_per_frame);
732 cmd.eop.opcode = OP_EOP;
733 cmd.eop.len = sizeof(cmd.eop);
735 d_dont_enqueue = false;
736 bool success = false;
737 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
738 success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
739 success = success && (ntohx(reply.ok) == 1);
742 d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
744 d_dont_enqueue = true;
751 usrp2::impl::sync_and_start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time)
754 if (channel > MAX_CHAN) {
755 std::cerr << "usrp2: invalid channel number (" << channel
760 if (channel > 0) { // until firmware supports multiple streams
761 std::cerr << "usrp2: channel " << channel
762 << " not implemented" << std::endl;
767 gruel::scoped_lock guard(d_channel_rings_mutex);
768 if (d_channel_rings[channel]) {
769 std::cerr << "usrp2: channel " << channel
770 << " already streaming" << std::endl;
774 if (items_per_frame == 0)
775 items_per_frame = U2_MAX_SAMPLES; // minimize overhead
777 op_sync_and_start_rx_streaming_cmd cmd;
780 memset(&cmd, 0, sizeof(cmd));
781 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, time);
782 cmd.sync_op.opcode = OP_SYNC_TO_PPS;
783 cmd.sync_op.len = sizeof(cmd.sync_op);
784 cmd.sync_op.rid = d_next_rid++;
785 cmd.rx_op.opcode = OP_START_RX_STREAMING;
786 cmd.rx_op.len = sizeof(cmd.rx_op);
787 cmd.rx_op.rid = d_next_rid++;
788 cmd.rx_op.items_per_frame = htonl(items_per_frame);
789 cmd.eop.opcode = OP_EOP;
790 cmd.eop.len = sizeof(cmd.eop);
792 d_dont_enqueue = false;
793 bool success = false;
794 pending_reply p(cmd.sync_op.rid, &reply, sizeof(reply));
795 success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
796 success = success && (ntohx(reply.ok) == 1);
799 d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
801 d_dont_enqueue = true;
808 usrp2::impl::stop_rx_streaming(unsigned int channel)
810 if (channel > MAX_CHAN) {
811 std::cerr << "usrp2: invalid channel number (" << channel
816 if (channel > 0) { // until firmware supports multiple streams
817 std::cerr << "usrp2: channel " << channel
818 << " not implemented" << std::endl;
822 d_dont_enqueue = true; // no new samples
823 flush_rx_samples(channel); // dump any we may already have
829 gruel::scoped_lock l(d_channel_rings_mutex);
831 memset(&cmd, 0, sizeof(cmd));
832 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
833 cmd.op.opcode = OP_STOP_RX;
834 cmd.op.len = sizeof(cmd.op);
835 cmd.op.rid = d_next_rid++;
836 cmd.eop.opcode = OP_EOP;
837 cmd.eop.len = sizeof(cmd.eop);
839 bool success = false;
840 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
841 success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT);
842 success = success && (ntohx(reply.ok) == 1);
843 d_channel_rings[channel].reset();
845 //fprintf(stderr, "usrp2::stop_rx_streaming: success = %d\n", success);
851 usrp2::impl::rx_samples(unsigned int channel, rx_sample_handler *handler)
853 if (channel > MAX_CHAN) {
854 std::cerr << "usrp2: invalid channel (" << channel
855 << " )" << std::endl;
860 std::cerr << "usrp2: channel " << channel
861 << " not implemented" << std::endl;
865 ring_sptr rp = d_channel_rings[channel];
867 std::cerr << "usrp2: channel " << channel
868 << " not receiving" << std::endl;
872 // Wait for frames available in channel ring
874 rp->wait_for_not_empty();
877 // Iterate through frames and present to user
879 size_t frame_len_in_bytes;
880 while (rp->dequeue(&p, &frame_len_in_bytes)) {
881 uint32_t *items; // points to beginning of data items
882 size_t nitems_in_uint32s;
884 if (!parse_rx_metadata(p, frame_len_in_bytes, &items, &nitems_in_uint32s, &md))
887 bool want_more = (*handler)(items, nitems_in_uint32s, &md);
888 d_eth_buf->release_frame(p);
899 usrp2::impl::flush_rx_samples(unsigned int channel)
901 if (channel > MAX_CHAN) {
902 std::cerr << "usrp2: invalid channel (" << channel
903 << " )" << std::endl;
908 std::cerr << "usrp2: channel " << channel
909 << " not implemented" << std::endl;
913 ring_sptr rp = d_channel_rings[channel];
918 // Iterate through frames and drop them
920 size_t frame_len_in_bytes;
921 while (rp->dequeue(&p, &frame_len_in_bytes)) {
922 d_eth_buf->release_frame(p);
928 // ----------------------------------------------------------------
930 // ----------------------------------------------------------------
933 usrp2::impl::set_tx_antenna(int ant){
934 op_config_mimo_cmd cmd;
937 memset(&cmd, 0, sizeof(cmd));
938 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
939 cmd.op.opcode = OP_TX_ANTENNA;
940 cmd.op.len = sizeof(cmd.op);
941 cmd.op.rid = d_next_rid++;
943 cmd.eop.opcode = OP_EOP;
944 cmd.eop.len = sizeof(cmd.eop);
946 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
947 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
950 return ntohx(reply.ok) == 1;
954 usrp2::impl::set_tx_gain(double gain)
956 op_config_tx_v2_cmd cmd;
957 op_config_tx_reply_v2_t reply;
959 init_config_tx_v2_cmd(&cmd);
960 cmd.op.valid = htons(CFGV_GAIN);
961 cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
963 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
964 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
967 bool success = (ntohx(reply.ok) == 1);
972 usrp2::impl::set_tx_lo_offset(double frequency)
977 memset(&cmd, 0, sizeof(cmd));
978 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
979 cmd.op.opcode = OP_SET_TX_LO_OFFSET;
980 cmd.op.len = sizeof(cmd.op);
981 cmd.op.rid = d_next_rid++;
983 u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
984 cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
985 cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
987 cmd.eop.opcode = OP_EOP;
988 cmd.eop.len = sizeof(cmd.eop);
990 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
991 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
994 bool success = (ntohx(reply.ok) == 1);
999 usrp2::impl::set_tx_center_freq(double frequency, tune_result *result)
1001 op_config_tx_v2_cmd cmd;
1002 op_config_tx_reply_v2_t reply;
1004 init_config_tx_v2_cmd(&cmd);
1005 cmd.op.valid = htons(CFGV_FREQ);
1006 u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
1007 cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
1008 cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
1010 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1011 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1014 bool success = (ntohx(reply.ok) == 1);
1015 if (result && success) {
1016 result->baseband_freq =
1017 u2_fxpt_freq_to_double(
1018 u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
1019 ntohl(reply.baseband_freq_lo)));
1022 u2_fxpt_freq_to_double(
1023 u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi),
1024 ntohl(reply.duc_freq_lo)));
1026 result->residual_freq =
1027 u2_fxpt_freq_to_double(
1028 u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
1029 ntohl(reply.residual_freq_lo)));
1031 result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
1038 usrp2::impl::set_tx_interp(int interpolation_factor)
1040 op_config_tx_v2_cmd cmd;
1041 op_config_tx_reply_v2_t reply;
1043 init_config_tx_v2_cmd(&cmd);
1044 cmd.op.valid = htons(CFGV_INTERP_DECIM);
1045 cmd.op.interp = htonl(interpolation_factor);
1047 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1048 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1051 bool success = (ntohx(reply.ok) == 1);
1053 d_tx_interp = interpolation_factor;
1055 // Auto-set TX scaling based on interpolation rate
1056 int scale_i, scale_q;
1057 default_tx_scale_iq(d_tx_interp, &scale_i, &scale_q);
1058 return set_tx_scale_iq(scale_i, scale_q);
1065 usrp2::impl::default_tx_scale_iq(int interpolation_factor, int *scale_i, int *scale_q)
1067 // Calculate CIC interpolation (i.e., without halfband interpolators)
1068 int i = interpolation_factor;
1074 // Calculate dsp_core_tx gain absent scale multipliers
1075 float gain = (1.65*i*i*i)/(4096*pow(2, ceil(log2(i*i*i))));
1077 // Calculate closest multiplier constant to reverse gain
1078 int scale = (int)rint(1.0/gain);
1079 // fprintf(stderr, "if=%i i=%i gain=%f scale=%i\n", interpolation_factor, i, gain, scale);
1081 // Both I and Q are identical in this case
1089 usrp2::impl::set_tx_scale_iq(int scale_i, int scale_q)
1091 op_config_tx_v2_cmd cmd;
1092 op_config_tx_reply_v2_t reply;
1094 init_config_tx_v2_cmd(&cmd);
1095 cmd.op.valid = htons(CFGV_SCALE_IQ);
1096 cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
1098 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1099 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1102 bool success = (ntohx(reply.ok) == 1);
1107 usrp2::impl::tx_32fc(unsigned int channel,
1108 const std::complex<float> *samples,
1110 const tx_metadata *metadata)
1112 uint32_t items[nsamples];
1113 copy_host_32fc_to_u2_16sc(nsamples, samples, items);
1114 return tx_raw(channel, items, nsamples, metadata);
1118 usrp2::impl::tx_16sc(unsigned int channel,
1119 const std::complex<int16_t> *samples,
1121 const tx_metadata *metadata)
1123 #ifdef WORDS_BIGENDIAN
1125 // Already binary equivalent to 16-bit I/Q on the wire.
1126 // No conversion required.
1128 assert(sizeof(samples[0]) == sizeof(uint32_t));
1129 return tx_raw(channel, (const uint32_t *) samples, nsamples, metadata);
1133 uint32_t items[nsamples];
1134 copy_host_16sc_to_u2_16sc(nsamples, samples, items);
1135 return tx_raw(channel, items, nsamples, metadata);
1141 usrp2::impl::tx_raw(unsigned int channel,
1142 const uint32_t *items,
1144 const tx_metadata *metadata)
1149 // FIXME can't deal with nitems < U2_MIN_SAMPLES (will be fixed in VRT)
1150 // FIXME need to check the MTU instead of assuming 1500 bytes
1152 // fragment as necessary then fire away
1154 size_t nframes = (nitems + U2_MAX_SAMPLES - 1) / U2_MAX_SAMPLES;
1155 size_t last_frame = nframes - 1;
1156 u2_eth_packet_t hdrs;
1159 for (size_t fn = 0; fn < nframes; fn++){
1160 uint32_t timestamp = 0;
1164 timestamp = metadata->timestamp;
1165 if (metadata->send_now)
1166 flags |= U2P_TX_IMMEDIATE;
1167 if (metadata->start_of_burst)
1168 flags |= U2P_TX_START_OF_BURST;
1171 flags |= U2P_TX_IMMEDIATE;
1173 if (fn == last_frame){
1174 if (metadata->end_of_burst)
1175 flags |= U2P_TX_END_OF_BURST;
1178 init_etf_hdrs(&hdrs, d_addr, flags, channel, timestamp);
1180 // Avoid short packet by splitting last two packets if reqd
1182 if ((nitems - n) > U2_MAX_SAMPLES && (nitems - n) < (U2_MAX_SAMPLES + U2_MIN_SAMPLES))
1183 i = (nitems - n) / 2;
1185 i = std::min((size_t) U2_MAX_SAMPLES, nitems - n);
1188 iov[0].iov_base = &hdrs;
1189 iov[0].iov_len = sizeof(hdrs);
1190 iov[1].iov_base = const_cast<uint32_t *>(&items[n]);
1191 iov[1].iov_len = i * sizeof(uint32_t);
1193 size_t total = iov[0].iov_len + iov[1].iov_len;
1195 fprintf(stderr, "usrp2::tx_raw: FIXME: short packet: %zd items (%zd bytes)\n", i, total);
1197 if (d_eth_buf->tx_framev(iov, 2) != eth_buffer::EB_OK){
1207 // ----------------------------------------------------------------
1209 // ----------------------------------------------------------------
1212 usrp2::impl::config_mimo(int flags)
1214 op_config_mimo_cmd cmd;
1217 memset(&cmd, 0, sizeof(cmd));
1218 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1219 cmd.op.opcode = OP_CONFIG_MIMO;
1220 cmd.op.len = sizeof(cmd.op);
1221 cmd.op.rid = d_next_rid++;
1222 cmd.op.flags = flags;
1223 cmd.eop.opcode = OP_EOP;
1224 cmd.eop.len = sizeof(cmd.eop);
1226 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1227 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1230 return ntohx(reply.ok) == 1;
1234 usrp2::impl::fpga_master_clock_freq(long *freq)
1236 *freq = 100000000L; // 100 MHz
1241 usrp2::impl::adc_rate(long *rate)
1243 return fpga_master_clock_freq(rate);
1247 usrp2::impl::dac_rate(long *rate)
1249 return fpga_master_clock_freq(rate);
1253 usrp2::impl::tx_daughterboard_id(int *dbid)
1255 *dbid = d_tx_db_info.dbid;
1260 usrp2::impl::rx_daughterboard_id(int *dbid)
1262 *dbid = d_rx_db_info.dbid;
1267 // ----------------------------------------------------------------
1268 // low-level commands
1269 // ----------------------------------------------------------------
1272 usrp2::impl::burn_mac_addr(const std::string &new_addr)
1274 op_burn_mac_addr_cmd cmd;
1277 memset(&cmd, 0, sizeof(cmd));
1278 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1279 cmd.op.opcode = OP_BURN_MAC_ADDR;
1280 cmd.op.len = sizeof(cmd.op);
1281 cmd.op.rid = d_next_rid++;
1282 if (!parse_mac_addr(new_addr, &cmd.op.addr))
1285 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1286 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, 4*DEF_CMD_TIMEOUT))
1289 bool success = (ntohx(reply.ok) == 1);
1294 fill_dboard_info(db_info *dst, const u2_db_info_t *src)
1296 dst->dbid = ntohl(src->dbid);
1299 u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi),
1300 ntohl(src->freq_min_lo)));
1302 u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi),
1303 ntohl(src->freq_max_lo)));
1305 dst->gain_min = u2_fxpt_gain_to_double(ntohs(src->gain_min));
1306 dst->gain_max = u2_fxpt_gain_to_double(ntohs(src->gain_max));
1307 dst->gain_step_size = u2_fxpt_gain_to_double(ntohs(src->gain_step_size));
1311 usrp2::impl::dboard_info()
1313 op_dboard_info_cmd cmd;
1314 op_dboard_info_reply_t reply;
1316 memset(&cmd, 0, sizeof(cmd));
1317 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1318 cmd.op.opcode = OP_DBOARD_INFO;
1319 cmd.op.len = sizeof(cmd.op);
1320 cmd.op.rid = d_next_rid++;
1321 cmd.eop.opcode = OP_EOP;
1322 cmd.eop.len = sizeof(cmd.eop);
1324 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1325 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1328 bool success = (ntohx(reply.ok) == 1);
1330 fill_dboard_info(&d_tx_db_info, &reply.tx_db_info);
1331 fill_dboard_info(&d_rx_db_info, &reply.rx_db_info);
1338 usrp2::impl::sync_to_pps()
1343 memset(&cmd, 0, sizeof(cmd));
1344 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1345 cmd.op.opcode = OP_SYNC_TO_PPS;
1346 cmd.op.len = sizeof(cmd.op);
1347 cmd.op.rid = d_next_rid++;
1348 cmd.eop.opcode = OP_EOP;
1349 cmd.eop.len = sizeof(cmd.eop);
1351 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1352 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1355 return ntohx(reply.ok) == 1;
1359 usrp2::impl::sync_every_pps(bool enable)
1364 memset(&cmd, 0, sizeof(cmd));
1365 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1366 cmd.op.opcode = OP_SYNC_EVERY_PPS;
1367 cmd.op.len = sizeof(cmd.op);
1368 cmd.op.rid = d_next_rid++;
1369 cmd.op.ok = enable ? 1 : 0;
1370 cmd.eop.opcode = OP_EOP;
1371 cmd.eop.len = sizeof(cmd.eop);
1373 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1374 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1377 return ntohx(reply.ok) == 1;
1380 std::vector<uint32_t>
1381 usrp2::impl::peek32(uint32_t addr, uint32_t words)
1383 std::vector<uint32_t> result; // zero sized on error return
1384 // fprintf(stderr, "usrp2::peek: addr=%08X words=%u\n", addr, words);
1386 if (addr % 4 != 0) {
1387 fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr);
1395 op_generic_t *reply;
1397 int wlen = sizeof(uint32_t);
1398 int rlen = sizeof(op_generic_t);
1399 size_t bytes = words*wlen;
1401 memset(&cmd, 0, sizeof(cmd));
1402 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1403 cmd.op.opcode = OP_PEEK;
1404 cmd.op.len = sizeof(cmd.op);
1405 cmd.op.rid = d_next_rid++;
1406 cmd.eop.opcode = OP_EOP;
1407 cmd.eop.len = sizeof(cmd.eop);
1409 cmd.op.addr = htonl(addr);
1410 cmd.op.bytes = htonl(bytes);
1412 reply = (op_generic_t *)malloc(rlen+bytes);
1413 pending_reply p(cmd.op.rid, reply, rlen+bytes);
1414 if (transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) {
1415 uint32_t nwords = (reply->len-rlen)/sizeof(uint32_t);
1416 uint32_t *data = (uint32_t *)(reply+rlen/wlen);
1417 for (unsigned int i = 0; i < nwords; i++)
1418 result.push_back(ntohl(data[i]));
1426 usrp2::impl::poke32(uint32_t addr, const std::vector<uint32_t> &data)
1428 if (addr % 4 != 0) {
1429 fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr);
1433 int plen = sizeof(op_poke_cmd);
1434 int wlen = sizeof(uint32_t);
1435 int max_words = (MAX_SUBPKT_LEN-plen)/wlen;
1436 int words = data.size();
1438 if (words > max_words) {
1439 fprintf(stderr, "usrp2::poke32: write size (=%u) exceeds maximum of %u words\n",
1444 //fprintf(stderr, "usrp2::poke32: addr=%08X words=%u\n", addr, words);
1452 // Allocate, clear, and initialize command packet
1453 int bytes = words*wlen;
1454 int l = plen+bytes+sizeof(*eop); // op_poke_cmd+data+eop
1455 cmd = (op_poke_cmd *)malloc(l);
1456 //fprintf(stderr, "cmd=%p l=%i\n", cmd, l);
1458 init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
1459 cmd->op.opcode = OP_POKE;
1460 cmd->op.len = sizeof(cmd->op)+bytes;
1461 cmd->op.rid = d_next_rid++;
1462 cmd->op.addr = htonl(addr);
1464 // Copy data from vector into packet space
1465 uint32_t *dest = (uint32_t *)((uint8_t *)cmd+plen);
1466 for (int i = 0; i < words; i++) {
1467 //fprintf(stderr, "%03i@%p\n", i, dest);
1468 *dest++ = htonl(data[i]);
1471 // Write end-of-packet subpacket
1472 eop = (op_generic_t *)dest;
1473 eop->opcode = OP_EOP;
1474 eop->len = sizeof(*eop);
1475 //fprintf(stderr, "eop=%p len=%i\n", eop, eop->len);
1477 // Send command to device and retrieve reply
1480 pending_reply p(cmd->op.rid, &reply, sizeof(reply));
1481 if (transmit_cmd_and_wait(cmd, l, &p, DEF_CMD_TIMEOUT))
1482 ok = (ntohx(reply.ok) == 1);
1489 usrp2::impl::reset_db()
1494 memset(&cmd, 0, sizeof(cmd));
1495 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1496 cmd.op.opcode = OP_RESET_DB;
1497 cmd.op.len = sizeof(cmd.op);
1498 cmd.op.rid = d_next_rid++;
1499 cmd.eop.opcode = OP_EOP;
1500 cmd.eop.len = sizeof(cmd.eop);
1502 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1503 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1506 bool success = (ntohx(reply.ok) == 1);
1510 bool usrp2::impl::set_gpio_ddr(int bank, uint16_t value, uint16_t mask)
1512 if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1513 fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1520 memset(&cmd, 0, sizeof(cmd));
1521 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1522 cmd.op.opcode = OP_GPIO_SET_DDR;
1523 cmd.op.len = sizeof(cmd.op);
1524 cmd.op.rid = d_next_rid++;
1525 cmd.op.bank = static_cast<uint8_t>(bank);
1526 cmd.op.value = htons(value);
1527 cmd.op.mask = htons(mask);
1528 cmd.eop.opcode = OP_EOP;
1529 cmd.eop.len = sizeof(cmd.eop);
1531 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1532 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1535 bool success = (ntohx(reply.ok) == 1);
1539 bool usrp2::impl::set_gpio_sels(int bank, std::string sels)
1541 if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1542 fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1546 if (sels.size() != 16) {
1547 fprintf(stderr, "set_gpio_sels: sels must be exactly 16 bytes\n");
1551 op_gpio_set_sels_cmd cmd;
1554 memset(&cmd, 0, sizeof(cmd));
1555 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1556 cmd.op.opcode = OP_GPIO_SET_SELS;
1557 cmd.op.len = sizeof(cmd.op);
1558 cmd.op.rid = d_next_rid++;
1559 cmd.op.bank = static_cast<uint8_t>(bank);
1560 memcpy(&cmd.op.sels, sels.c_str(), 16);
1561 cmd.eop.opcode = OP_EOP;
1562 cmd.eop.len = sizeof(cmd.eop);
1564 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1565 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1568 bool success = (ntohx(reply.ok) == 1);
1572 bool usrp2::impl::write_gpio(int bank, uint16_t value, uint16_t mask)
1574 if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1575 fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1582 memset(&cmd, 0, sizeof(cmd));
1583 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1584 cmd.op.opcode = OP_GPIO_WRITE;
1585 cmd.op.len = sizeof(cmd.op);
1586 cmd.op.rid = d_next_rid++;
1587 cmd.op.bank = static_cast<uint8_t>(bank);
1588 cmd.op.value = htons(value);
1589 cmd.op.mask = htons(mask);
1590 cmd.eop.opcode = OP_EOP;
1591 cmd.eop.len = sizeof(cmd.eop);
1593 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1594 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1597 bool success = (ntohx(reply.ok) == 1);
1601 bool usrp2::impl::read_gpio(int bank, uint16_t *value)
1603 if (bank != GPIO_TX_BANK && bank != GPIO_RX_BANK) {
1604 fprintf(stderr, "set_gpio_ddr: bank must be one of GPIO_RX_BANK or GPIO_TX_BANK\n");
1609 op_gpio_read_reply_t reply;
1611 memset(&cmd, 0, sizeof(cmd));
1612 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1613 cmd.op.opcode = OP_GPIO_READ;
1614 cmd.op.len = sizeof(cmd.op);
1615 cmd.op.rid = d_next_rid++;
1616 cmd.op.bank = static_cast<uint8_t>(bank);
1617 cmd.op.value = 0; // not used
1618 cmd.op.mask = 0; // not used
1619 cmd.eop.opcode = OP_EOP;
1620 cmd.eop.len = sizeof(cmd.eop);
1622 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1623 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1626 bool success = (ntohx(reply.ok) == 1);
1627 if (success && (value != NULL))
1628 *value = ntohs(reply.value);
1633 bool usrp2::impl::enable_gpio_streaming(int bank, int enable)
1635 if (bank != GPIO_RX_BANK) {
1636 fprintf(stderr, "enable_gpio_streaming: only RX streaming is currently implemented\n");
1640 if ((enable & ~0x03) != 0) {
1641 fprintf(stderr, "enable_gpio_streaming: invalid enable format\n");
1648 memset(&cmd, 0, sizeof(cmd));
1649 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1650 cmd.op.opcode = OP_GPIO_STREAM;
1651 cmd.op.len = sizeof(cmd.op);
1652 cmd.op.rid = d_next_rid++;
1653 cmd.op.bank = static_cast<uint8_t>(bank);
1654 cmd.op.value = htons((uint16_t)enable);
1655 cmd.op.mask = 0; // not used
1656 cmd.eop.opcode = OP_EOP;
1657 cmd.eop.len = sizeof(cmd.eop);
1659 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1660 if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1663 bool success = (ntohx(reply.ok) == 1);
1667 } // namespace usrp2