3 * Copyright 2008 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 <usrp2_types.h>
28 #include "usrp2_impl.h"
29 #include "usrp2_thread.h"
30 #include "eth_buffer.h"
31 #include "pktfilter.h"
41 #define USRP2_IMPL_DEBUG 0
43 #define DEBUG_LOG(x) ::write(2, x, 1)
48 static const int DEFAULT_RX_SCALE = 1024;
52 static const double DEF_CMD_TIMEOUT = 0.1;
55 opcode_to_string(int 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";
79 snprintf(buf, sizeof(buf), "<unknown opcode: %d>", opcode);
86 * \param p points to fixed header
87 * \param payload_len_in_bytes is length of the fixed hdr and the payload
88 * \param[out] items is set to point to the first uint32 item in the payload
89 * \param[out] nitems is set to the number of uint32 items in the payload
90 * \param[out] md is filled in with the parsed metadata from the frame.
93 parse_rx_metadata(void *p, size_t payload_len_in_bytes,
94 uint32_t **items, size_t *nitems_in_uint32s, rx_metadata *md)
96 if (payload_len_in_bytes < sizeof(u2_fixed_hdr_t)) // invalid format
99 // FIXME deal with the fact that (p % 4) == 2
100 //assert((((uintptr_t) p) % 4) == 0); // must be 4-byte aligned
102 u2_fixed_hdr_t *fh = static_cast<u2_fixed_hdr_t *>(p);
104 // FIXME unaligned loads!
105 md->word0 = u2p_word0(fh);
106 md->timestamp = u2p_timestamp(fh);
108 // FIXME when we've got more info
109 // md->start_of_burst = (md->word0 & XXX) != 0;
110 // md->end_of_burst = (md->word0 & XXX) != 0;
111 // md->rx_overrun = (md->word0 & XXX) != 0;
112 md->start_of_burst = 0;
113 md->end_of_burst = 0;
116 *items = (uint32_t *)(&fh[1]);
117 size_t nbytes = payload_len_in_bytes - sizeof(u2_fixed_hdr_t);
118 assert((nbytes % sizeof(uint32_t)) == 0);
119 *nitems_in_uint32s = nbytes / sizeof(uint32_t);
125 usrp2::impl::impl(const std::string &ifc, props *p)
126 : d_eth_buf(new eth_buffer()), d_pf(0), d_bg_thread(0), d_bg_running(false),
127 d_rx_seqno(-1), d_tx_seqno(0), d_next_rid(0),
128 d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0),
129 d_num_enqueued(0), d_enqueued_mutex(), d_bg_pending_cond(&d_enqueued_mutex),
130 d_channel_rings(NCHANS), d_tx_interp(0), d_rx_decim(0)
132 if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE)))
133 throw std::runtime_error("Unable to register USRP2 protocol");
135 d_pf = pktfilter::make_ethertype_inbound(U2_ETHERTYPE, d_eth_buf->mac());
136 if (!d_pf || !d_eth_buf->attach_pktfilter(d_pf))
137 throw std::runtime_error("Unable to attach packet filter.");
141 if (USRP2_IMPL_DEBUG)
142 std::cerr << "usrp2 constructor: using USRP2 at " << d_addr << std::endl;
144 memset(d_pending_replies, 0, sizeof(d_pending_replies));
146 d_bg_thread = new usrp2_thread(this);
147 d_bg_thread->start();
149 if (!dboard_info()) // we're hosed
150 throw std::runtime_error("Unable to retrieve daughterboard info");
155 tx_daughterboard_id(&dbid);
156 fprintf(stderr, "Tx dboard 0x%x\n", dbid);
157 fprintf(stderr, " freq_min = %g\n", tx_freq_min());
158 fprintf(stderr, " freq_max = %g\n", tx_freq_max());
159 fprintf(stderr, " gain_min = %g\n", tx_gain_min());
160 fprintf(stderr, " gain_max = %g\n", tx_gain_max());
161 fprintf(stderr, " gain_db_per_step = %g\n", tx_gain_db_per_step());
163 rx_daughterboard_id(&dbid);
164 fprintf(stderr, "Rx dboard 0x%x\n", dbid);
165 fprintf(stderr, " freq_min = %g\n", rx_freq_min());
166 fprintf(stderr, " freq_max = %g\n", rx_freq_max());
167 fprintf(stderr, " gain_min = %g\n", rx_gain_min());
168 fprintf(stderr, " gain_max = %g\n", rx_gain_max());
169 fprintf(stderr, " gain_db_per_step = %g\n", rx_gain_db_per_step());
172 // default gains to mid point
173 if (!set_tx_gain((tx_gain_min() + tx_gain_max()) / 2))
174 std::cerr << "usrp2::ctor set_tx_gain failed\n";
176 if (!set_rx_gain((rx_gain_min() + rx_gain_max()) / 2))
177 std::cerr << "usrp2::ctor set_rx_gain failed\n";
179 // default interp and decim
180 if (!set_tx_interp(12))
181 std::cerr << "usrp2::ctor set_tx_interp failed\n";
183 if (!set_rx_decim(12))
184 std::cerr << "usrp2::ctor set_rx_decim failed\n";
186 // set workable defaults for scaling
187 if (!set_rx_scale_iq(DEFAULT_RX_SCALE, DEFAULT_RX_SCALE))
188 std::cerr << "usrp2::ctor set_rx_scale_iq failed\n";
194 d_bg_thread = 0; // thread class deletes itself
199 if (USRP2_IMPL_DEBUG) {
200 std::cerr << std::endl
201 << "usrp2 destructor: received " << d_num_rx_frames
202 << " frames, with " << d_num_rx_missing << " lost ("
203 << (d_num_rx_frames == 0 ? 0 : (int)(100.0*d_num_rx_missing/d_num_rx_frames))
204 << "%), totaling " << d_num_rx_bytes
205 << " bytes" << std::endl;
210 usrp2::impl::parse_mac_addr(const std::string &s, u2_mac_addr_t *p)
212 p->addr[0] = 0x00; // Matt's IAB
224 return sscanf(s.c_str(), "%hhx:%hhx", &p->addr[4], &p->addr[5]) == 2;
227 return sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
228 &p->addr[0], &p->addr[1], &p->addr[2],
229 &p->addr[3], &p->addr[4], &p->addr[5]) == 6;
236 usrp2::impl::init_et_hdrs(u2_eth_packet_t *p, const std::string &dst)
238 p->ehdr.ethertype = htons(U2_ETHERTYPE);
239 parse_mac_addr(dst, &p->ehdr.dst);
240 memcpy(&p->ehdr.src, d_eth_buf->mac(), 6);
241 p->thdr.flags = 0; // FIXME transport header values?
242 p->thdr.seqno = d_tx_seqno++;
247 usrp2::impl::init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
248 int word0_flags, int chan, uint32_t timestamp)
250 init_et_hdrs(p, dst);
251 u2p_set_word0(&p->fixed, word0_flags, chan);
252 u2p_set_timestamp(&p->fixed, timestamp);
254 if (chan == CONTROL_CHAN) { // no sequence numbers, back it out
261 usrp2::impl::init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd)
263 memset(cmd, 0, sizeof(*cmd));
264 init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
265 cmd->op.opcode = OP_CONFIG_RX_V2;
266 cmd->op.len = sizeof(cmd->op);
267 cmd->op.rid = d_next_rid++;
268 cmd->eop.opcode = OP_EOP;
269 cmd->eop.len = sizeof(cmd->eop);
273 usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd)
275 memset(cmd, 0, sizeof(*cmd));
276 init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
277 cmd->op.opcode = OP_CONFIG_TX_V2;
278 cmd->op.len = sizeof(cmd->op);
279 cmd->op.rid = d_next_rid++;
280 cmd->eop.opcode = OP_EOP;
281 cmd->eop.len = sizeof(cmd->eop);
285 usrp2::impl::transmit_cmd(void *cmd, size_t len, pending_reply *p, double secs)
288 d_pending_replies[p->rid()] = p;
291 if (d_eth_buf->tx_frame(cmd, len) != eth_buffer::EB_OK) {
292 d_pending_replies[p->rid()] = 0;
300 d_pending_replies[p->rid()] = 0;
304 // ----------------------------------------------------------------
305 // Background loop: received packet demuxing
306 // ----------------------------------------------------------------
309 usrp2::impl::stop_bg()
311 d_bg_running = false;
312 d_bg_pending_cond.signal();
315 d_bg_thread->join(&dummy_status);
319 usrp2::impl::bg_loop()
322 while(d_bg_running) {
324 // Receive available frames from ethernet buffer. Handler will
325 // process control frames, enqueue data packets in channel
326 // rings, and signal blocked API threads
327 int res = d_eth_buf->rx_frames(this, 100); // FIXME magic timeout
328 if (res == eth_buffer::EB_ERROR)
331 // Wait for user API thread(s) to process all enqueued packets.
332 // The channel ring thread that decrements d_num_enqueued to zero
333 // will signal this thread to continue.
335 omni_mutex_lock l(d_enqueued_mutex);
336 while(d_num_enqueued > 0 && d_bg_running)
337 d_bg_pending_cond.wait();
340 d_bg_running = false;
344 // passed to eth_buffer::rx_frames
347 usrp2::impl::operator()(const void *base, size_t len)
349 u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
351 // FIXME unaligned load!
352 int chan = u2p_chan(&pkt->hdrs.fixed);
354 if (chan == CONTROL_CHAN) { // control packets
356 return handle_control_packet(base, len);
358 else { // data packets
359 return handle_data_packet(base, len);
366 usrp2::impl::handle_control_packet(const void *base, size_t len)
368 // point to beginning of payload (subpackets)
369 unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
371 // FIXME (p % 4) == 2. Not good. Must watch for unaligned loads.
373 // FIXME iterate over payload, handling more than a single subpacket.
376 unsigned int oplen = p[1];
377 unsigned int rid = p[2];
379 pending_reply *rp = d_pending_replies[rid];
381 unsigned int buflen = rp->len();
382 if (oplen != buflen) {
383 std::cerr << "usrp2: mismatched command reply length (expected: "
384 << buflen << " got: " << oplen << "). "
385 << "op = " << opcode_to_string(opcode) << std::endl;
388 // Copy reply into caller's buffer
389 memcpy(rp->buffer(), p, std::min(oplen, buflen));
391 d_pending_replies[rid] = 0;
392 return data_handler::RELEASE;
395 // TODO: handle unsolicited, USRP2 initiated, or late replies
397 return data_handler::RELEASE;
401 usrp2::impl::handle_data_packet(const void *base, size_t len)
403 u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
405 d_num_rx_bytes += len;
407 /* --- FIXME start of fake transport layer handler --- */
409 if (d_rx_seqno != -1) {
410 int expected_seqno = (d_rx_seqno + 1) & 0xFF;
411 int seqno = pkt->hdrs.thdr.seqno;
413 if (seqno != expected_seqno) {
414 ::write(2, "S", 1); // missing sequence number
415 int missing = seqno - expected_seqno;
420 d_num_rx_missing += missing;
424 d_rx_seqno = pkt->hdrs.thdr.seqno;
426 /* --- end of fake transport layer handler --- */
428 // FIXME unaligned load!
429 unsigned int chan = u2p_chan(&pkt->hdrs.fixed);
431 if (!d_channel_rings[chan]) {
433 return data_handler::RELEASE; // discard packet, no channel handler
436 // Strip off ethernet header and transport header and enqueue the rest
438 size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed);
439 if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) {
442 return data_handler::KEEP; // channel ring runner will mark frame done
446 return data_handler::RELEASE; // discard, no room in channel ring
448 return data_handler::RELEASE;
452 // ----------------------------------------------------------------
454 // ----------------------------------------------------------------
457 usrp2::impl::set_rx_gain(double gain)
459 op_config_rx_v2_cmd cmd;
460 op_config_rx_reply_v2_t reply;
462 init_config_rx_v2_cmd(&cmd);
463 cmd.op.valid = htons(CFGV_GAIN);
464 cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
466 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
467 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
470 bool success = (ntohx(reply.ok) == 1);
475 usrp2::impl::set_rx_center_freq(double frequency, tune_result *result)
477 op_config_rx_v2_cmd cmd;
478 op_config_rx_reply_v2_t reply;
480 init_config_rx_v2_cmd(&cmd);
481 cmd.op.valid = htons(CFGV_FREQ);
482 u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
483 cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
484 cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
486 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
487 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
490 bool success = (ntohx(reply.ok) == 1);
491 if (result && success) {
492 result->baseband_freq =
493 u2_fxpt_freq_to_double(
494 u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
495 ntohl(reply.baseband_freq_lo)));
498 u2_fxpt_freq_to_double(
499 u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi),
500 ntohl(reply.ddc_freq_lo)));
502 result->residual_freq =
503 u2_fxpt_freq_to_double(
504 u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
505 ntohl(reply.residual_freq_lo)));
507 result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
514 usrp2::impl::set_rx_decim(int decimation_factor)
516 op_config_rx_v2_cmd cmd;
517 op_config_rx_reply_v2_t reply;
519 init_config_rx_v2_cmd(&cmd);
520 cmd.op.valid = htons(CFGV_INTERP_DECIM);
521 cmd.op.decim = htonl(decimation_factor);
523 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
524 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
527 bool success = (ntohx(reply.ok) == 1);
529 d_rx_decim = decimation_factor;
534 usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
536 op_config_rx_v2_cmd cmd;
537 op_config_rx_reply_v2_t reply;
539 init_config_rx_v2_cmd(&cmd);
540 cmd.op.valid = htons(CFGV_SCALE_IQ);
541 cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
543 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
544 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
547 bool success = (ntohx(reply.ok) == 1);
552 usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
554 if (channel > MAX_CHAN) {
555 std::cerr << "usrp2: invalid channel number (" << channel
560 if (channel > 0) { // until firmware supports multiple streams
561 std::cerr << "usrp2: channel " << channel
562 << " not implemented" << std::endl;
566 if (d_channel_rings[channel]) {
567 std::cerr << "usrp2: channel " << channel
568 << " already streaming" << std::endl;
572 d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
574 if (items_per_frame == 0)
575 items_per_frame = U2_MAX_SAMPLES; // minimize overhead
577 op_start_rx_streaming_cmd cmd;
580 memset(&cmd, 0, sizeof(cmd));
581 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
582 cmd.op.opcode = OP_START_RX_STREAMING;
583 cmd.op.len = sizeof(cmd.op);
584 cmd.op.rid = d_next_rid++;
585 cmd.op.items_per_frame = htonl(items_per_frame);
586 cmd.eop.opcode = OP_EOP;
587 cmd.eop.len = sizeof(cmd.eop);
589 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
590 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
593 bool success = (ntohx(reply.ok) == 1);
598 usrp2::impl::stop_rx_streaming(unsigned int channel)
600 if (channel > MAX_CHAN) {
601 std::cerr << "usrp2: invalid channel number (" << channel
606 if (channel > 0) { // until firmware supports multiple streams
607 std::cerr << "usrp2: channel " << channel
608 << " not implemented" << std::endl;
612 #if 0 // don't be overzealous.
613 if (!d_channel_rings[channel]) {
614 std::cerr << "usrp2: channel " << channel
615 << " not streaming" << std::endl;
623 memset(&cmd, 0, sizeof(cmd));
624 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
625 cmd.op.opcode = OP_STOP_RX;
626 cmd.op.len = sizeof(cmd.op);
627 cmd.op.rid = d_next_rid++;
628 cmd.eop.opcode = OP_EOP;
629 cmd.eop.len = sizeof(cmd.eop);
631 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
632 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
635 bool success = (ntohx(reply.ok) == 1);
637 d_channel_rings[channel].reset();
644 usrp2::impl::rx_samples(unsigned int channel, rx_sample_handler *handler)
646 if (channel > MAX_CHAN) {
647 std::cerr << "usrp2: invalid channel (" << channel
648 << " )" << std::endl;
653 std::cerr << "usrp2: channel " << channel
654 << " not implemented" << std::endl;
658 ring_sptr rp = d_channel_rings[channel];
660 std::cerr << "usrp2: channel " << channel
661 << " not receiving" << std::endl;
665 // Wait for frames available in channel ring
667 rp->wait_for_not_empty();
670 // Iterate through frames and present to user
672 size_t frame_len_in_bytes;
673 while (rp->dequeue(&p, &frame_len_in_bytes)) {
674 uint32_t *items; // points to beginning of data items
675 size_t nitems_in_uint32s;
677 if (!parse_rx_metadata(p, frame_len_in_bytes, &items, &nitems_in_uint32s, &md))
680 bool want_more = (*handler)(items, nitems_in_uint32s, &md);
681 d_eth_buf->release_frame(p);
691 // ----------------------------------------------------------------
693 // ----------------------------------------------------------------
696 usrp2::impl::set_tx_gain(double gain)
698 op_config_tx_v2_cmd cmd;
699 op_config_tx_reply_v2_t reply;
701 init_config_tx_v2_cmd(&cmd);
702 cmd.op.valid = htons(CFGV_GAIN);
703 cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
705 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
706 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
709 bool success = (ntohx(reply.ok) == 1);
714 usrp2::impl::set_tx_center_freq(double frequency, tune_result *result)
716 op_config_tx_v2_cmd cmd;
717 op_config_tx_reply_v2_t reply;
719 init_config_tx_v2_cmd(&cmd);
720 cmd.op.valid = htons(CFGV_FREQ);
721 u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
722 cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
723 cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
725 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
726 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
729 bool success = (ntohx(reply.ok) == 1);
730 if (result && success) {
731 result->baseband_freq =
732 u2_fxpt_freq_to_double(
733 u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
734 ntohl(reply.baseband_freq_lo)));
737 u2_fxpt_freq_to_double(
738 u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi),
739 ntohl(reply.duc_freq_lo)));
741 result->residual_freq =
742 u2_fxpt_freq_to_double(
743 u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
744 ntohl(reply.residual_freq_lo)));
746 result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
753 usrp2::impl::set_tx_interp(int interpolation_factor)
755 op_config_tx_v2_cmd cmd;
756 op_config_tx_reply_v2_t reply;
758 init_config_tx_v2_cmd(&cmd);
759 cmd.op.valid = htons(CFGV_INTERP_DECIM);
760 cmd.op.interp = htonl(interpolation_factor);
762 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
763 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
766 bool success = (ntohx(reply.ok) == 1);
768 d_tx_interp = interpolation_factor;
770 // Auto-set TX scaling based on interpolation rate
771 int scale_i, scale_q;
772 default_tx_scale_iq(d_tx_interp, &scale_i, &scale_q);
773 return set_tx_scale_iq(scale_i, scale_q);
780 usrp2::impl::default_tx_scale_iq(int interpolation_factor, int *scale_i, int *scale_q)
782 // Calculate CIC interpolation (i.e., without halfband interpolators)
783 int i = interpolation_factor;
789 // Calculate dsp_core_tx gain absent scale multipliers
790 float gain = (1.65*i*i*i)/(4096*pow(2, ceil(log2(i*i*i))));
792 // Calculate closest multiplier constant to reverse gain
793 int scale = (int)rint(1.0/gain);
794 // fprintf(stderr, "if=%i i=%i gain=%f scale=%i\n", interpolation_factor, i, gain, scale);
796 // Both I and Q are identical in this case
804 usrp2::impl::set_tx_scale_iq(int scale_i, int scale_q)
806 op_config_tx_v2_cmd cmd;
807 op_config_tx_reply_v2_t reply;
809 init_config_tx_v2_cmd(&cmd);
810 cmd.op.valid = htons(CFGV_SCALE_IQ);
811 cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
813 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
814 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
817 bool success = (ntohx(reply.ok) == 1);
822 usrp2::impl::tx_32fc(unsigned int channel,
823 const std::complex<float> *samples,
825 const tx_metadata *metadata)
827 uint32_t items[nsamples];
828 copy_host_32fc_to_u2_16sc(nsamples, samples, items);
829 return tx_raw(channel, items, nsamples, metadata);
833 usrp2::impl::tx_16sc(unsigned int channel,
834 const std::complex<int16_t> *samples,
836 const tx_metadata *metadata)
838 #ifdef WORDS_BIGENDIAN
840 // Already binary equivalent to 16-bit I/Q on the wire.
841 // No conversion required.
843 assert(sizeof(samples[0]) == sizeof(uint32_t));
844 return tx_raw(channel, (const uint32_t *) samples, nsamples, metadata);
848 uint32_t items[nsamples];
849 copy_host_16sc_to_u2_16sc(nsamples, samples, items);
850 return tx_raw(channel, items, nsamples, metadata);
856 usrp2::impl::tx_raw(unsigned int channel,
857 const uint32_t *items,
859 const tx_metadata *metadata)
864 // FIXME there's the possibility that we send fewer than 9 items in a frame.
865 // That would end up glitching the transmitter, since the ethernet will pad to
866 // 64-bytes total (9 items). We really need some part of the stack to
867 // carry the real length (thdr?).
869 // fragment as necessary then fire away
871 size_t nframes = (nitems + U2_MAX_SAMPLES - 1) / U2_MAX_SAMPLES;
872 size_t last_frame = nframes - 1;
873 u2_eth_packet_t hdrs;
876 for (size_t fn = 0; fn < nframes; fn++){
877 uint32_t timestamp = 0;
881 timestamp = metadata->timestamp;
882 if (metadata->send_now)
883 flags |= U2P_TX_IMMEDIATE;
884 if (metadata->start_of_burst)
885 flags |= U2P_TX_START_OF_BURST;
888 flags |= U2P_TX_IMMEDIATE;
890 if (fn == last_frame){
891 if (metadata->end_of_burst)
892 flags |= U2P_TX_END_OF_BURST;
895 init_etf_hdrs(&hdrs, d_addr, flags, channel, timestamp);
897 size_t i = std::min((size_t) U2_MAX_SAMPLES, nitems - n);
900 iov[0].iov_base = &hdrs;
901 iov[0].iov_len = sizeof(hdrs);
902 iov[1].iov_base = const_cast<uint32_t *>(&items[n]);
903 iov[1].iov_len = i * sizeof(uint32_t);
905 size_t total = iov[0].iov_len + iov[1].iov_len;
907 fprintf(stderr, "usrp2::tx_raw: FIXME: short packet: %zd items (%zd bytes)\n", i, total);
909 if (d_eth_buf->tx_framev(iov, 2) != eth_buffer::EB_OK){
919 // ----------------------------------------------------------------
921 // ----------------------------------------------------------------
924 usrp2::impl::config_mimo(int flags)
926 op_config_mimo_cmd cmd;
929 memset(&cmd, 0, sizeof(cmd));
930 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
931 cmd.op.opcode = OP_CONFIG_MIMO;
932 cmd.op.len = sizeof(cmd.op);
933 cmd.op.rid = d_next_rid++;
934 cmd.eop.opcode = OP_EOP;
935 cmd.eop.len = sizeof(cmd.eop);
937 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
938 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
941 return ntohx(reply.ok) == 1;
945 usrp2::impl::fpga_master_clock_freq(long *freq)
947 *freq = 100000000L; // 100 MHz
952 usrp2::impl::adc_rate(long *rate)
954 return fpga_master_clock_freq(rate);
958 usrp2::impl::dac_rate(long *rate)
960 return fpga_master_clock_freq(rate);
964 usrp2::impl::tx_daughterboard_id(int *dbid)
966 *dbid = d_tx_db_info.dbid;
971 usrp2::impl::rx_daughterboard_id(int *dbid)
973 *dbid = d_rx_db_info.dbid;
978 // ----------------------------------------------------------------
979 // low-level commands
980 // ----------------------------------------------------------------
983 usrp2::impl::burn_mac_addr(const std::string &new_addr)
985 op_burn_mac_addr_cmd cmd;
988 memset(&cmd, 0, sizeof(cmd));
989 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
990 cmd.op.opcode = OP_BURN_MAC_ADDR;
991 cmd.op.len = sizeof(cmd.op);
992 cmd.op.rid = d_next_rid++;
993 if (!parse_mac_addr(new_addr, &cmd.op.addr))
996 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
997 if (!transmit_cmd(&cmd, sizeof(cmd), &p, 4*DEF_CMD_TIMEOUT))
1000 bool success = (ntohx(reply.ok) == 1);
1005 fill_dboard_info(db_info *dst, const u2_db_info_t *src)
1007 dst->dbid = ntohl(src->dbid);
1010 u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi),
1011 ntohl(src->freq_min_lo)));
1013 u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi),
1014 ntohl(src->freq_max_lo)));
1016 dst->gain_min = u2_fxpt_gain_to_double(ntohs(src->gain_min));
1017 dst->gain_max = u2_fxpt_gain_to_double(ntohs(src->gain_max));
1018 dst->gain_step_size = u2_fxpt_gain_to_double(ntohs(src->gain_step_size));
1022 usrp2::impl::dboard_info()
1024 op_dboard_info_cmd cmd;
1025 op_dboard_info_reply_t reply;
1027 memset(&cmd, 0, sizeof(cmd));
1028 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1029 cmd.op.opcode = OP_DBOARD_INFO;
1030 cmd.op.len = sizeof(cmd.op);
1031 cmd.op.rid = d_next_rid++;
1032 cmd.eop.opcode = OP_EOP;
1033 cmd.eop.len = sizeof(cmd.eop);
1035 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1036 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1039 bool success = (ntohx(reply.ok) == 1);
1041 fill_dboard_info(&d_tx_db_info, &reply.tx_db_info);
1042 fill_dboard_info(&d_rx_db_info, &reply.rx_db_info);
1049 usrp2::impl::sync_to_pps()
1054 memset(&cmd, 0, sizeof(cmd));
1055 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1056 cmd.op.opcode = OP_SYNC_TO_PPS;
1057 cmd.op.len = sizeof(cmd.op);
1058 cmd.op.rid = d_next_rid++;
1059 cmd.eop.opcode = OP_EOP;
1060 cmd.eop.len = sizeof(cmd.eop);
1062 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
1063 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
1066 return ntohx(reply.ok) == 1;
1069 std::vector<uint32_t>
1070 usrp2::impl::peek32(uint32_t addr, uint32_t words)
1072 std::vector<uint32_t> result; // zero sized on error return
1073 // fprintf(stderr, "usrp2::peek: addr=%08X words=%u\n", addr, words);
1075 if (addr % 4 != 0) {
1076 fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr);
1084 op_generic_t *reply;
1086 int wlen = sizeof(uint32_t);
1087 int rlen = sizeof(op_generic_t);
1088 size_t bytes = words*wlen;
1090 memset(&cmd, 0, sizeof(cmd));
1091 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
1092 cmd.op.opcode = OP_PEEK;
1093 cmd.op.len = sizeof(cmd.op);
1094 cmd.op.rid = d_next_rid++;
1095 cmd.eop.opcode = OP_EOP;
1096 cmd.eop.len = sizeof(cmd.eop);
1098 cmd.op.addr = htonl(addr);
1099 cmd.op.bytes = htonl(bytes);
1101 reply = (op_generic_t *)malloc(rlen+bytes);
1102 pending_reply p(cmd.op.rid, reply, rlen+bytes);
1103 if (transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) {
1104 uint32_t nwords = (reply->len-rlen)/sizeof(uint32_t);
1105 uint32_t *data = (uint32_t *)(reply+rlen/wlen);
1106 for (unsigned int i = 0; i < nwords; i++)
1107 result.push_back(ntohl(data[i]));
1115 usrp2::impl::poke32(uint32_t addr, const std::vector<uint32_t> &data)
1117 if (addr % 4 != 0) {
1118 fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr);
1122 int plen = sizeof(op_poke_cmd);
1123 int wlen = sizeof(uint32_t);
1124 int max_words = (MAX_SUBPKT_LEN-plen)/wlen;
1125 int words = data.size();
1127 if (words > max_words) {
1128 fprintf(stderr, "usrp2::poke32: write size (=%u) exceeds maximum of %u words\n",
1133 //fprintf(stderr, "usrp2::poke32: addr=%08X words=%u\n", addr, words);
1141 // Allocate, clear, and initialize command packet
1142 int bytes = words*wlen;
1143 int l = plen+bytes+sizeof(*eop); // op_poke_cmd+data+eop
1144 cmd = (op_poke_cmd *)malloc(l);
1145 //fprintf(stderr, "cmd=%p l=%i\n", cmd, l);
1147 init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
1148 cmd->op.opcode = OP_POKE;
1149 cmd->op.len = sizeof(cmd->op)+bytes;
1150 cmd->op.rid = d_next_rid++;
1151 cmd->op.addr = htonl(addr);
1153 // Copy data from vector into packet space
1154 uint32_t *dest = (uint32_t *)((uint8_t *)cmd+plen);
1155 for (unsigned int i = 0; i < words; i++) {
1156 //fprintf(stderr, "%03i@%p\n", i, dest);
1157 *dest++ = htonl(data[i]);
1160 // Write end-of-packet subpacket
1161 eop = (op_generic_t *)dest;
1162 eop->opcode = OP_EOP;
1163 eop->len = sizeof(*eop);
1164 //fprintf(stderr, "eop=%p len=%i\n", eop, eop->len);
1166 // Send command to device and retrieve reply
1169 pending_reply p(cmd->op.rid, &reply, sizeof(reply));
1170 if (transmit_cmd(cmd, l, &p, DEF_CMD_TIMEOUT))
1171 ok = (ntohx(reply.ok) == 1);
1177 } // namespace usrp2