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;
49 static const int DEFAULT_TX_SCALE = 3000;
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";
72 case OP_WRITE_REG: return "OP_WRITE_REG";
73 case OP_WRITE_REG_MASKED: return "OP_WRITE_REG_MASKED";
74 case OP_READ_REG: return "OP_READ_REG";
75 case OP_READ_REG_REPLY: return "OP_READ_REG_REPLY";
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 // md->start_of_burst = (md->word0 & XXX) != 0;
109 // md->end_of_burst = (md->word0 & XXX) != 0;
110 // md->rx_overrun = (md->word0 & XXX) != 0;
112 *items = (uint32_t *)(&fh[1]);
113 size_t nbytes = payload_len_in_bytes - sizeof(u2_fixed_hdr_t);
114 assert((nbytes % sizeof(uint32_t)) == 0);
115 *nitems_in_uint32s = nbytes / sizeof(uint32_t);
121 usrp2::impl::impl(const std::string &ifc, props *p)
122 : d_eth_buf(new eth_buffer()), d_pf(0), d_bg_thread(0), d_bg_running(false),
123 d_rx_decim(0), d_rx_seqno(-1), d_tx_seqno(0), d_next_rid(0),
124 d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0),
125 d_num_enqueued(0), d_enqueued_mutex(), d_bg_pending_cond(&d_enqueued_mutex),
126 d_channel_rings(NCHANS)
128 if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE)))
129 throw std::runtime_error("Unable to register USRP2 protocol");
131 d_pf = pktfilter::make_ethertype_inbound(U2_ETHERTYPE, d_eth_buf->mac());
132 if (!d_pf || !d_eth_buf->attach_pktfilter(d_pf))
133 throw std::runtime_error("Unable to attach packet filter.");
137 if (USRP2_IMPL_DEBUG)
138 std::cerr << "usrp2 constructor: using USRP2 at " << d_addr << std::endl;
140 memset(d_pending_replies, 0, sizeof(d_pending_replies));
142 d_bg_thread = new usrp2_thread(this);
143 d_bg_thread->start();
145 // set workable defaults for scaling
146 if (!set_rx_scale_iq(DEFAULT_RX_SCALE, DEFAULT_RX_SCALE))
147 std::cerr << "usrp2::ctor set_rx_scale_iq failed\n";
149 if (!set_tx_scale_iq(DEFAULT_TX_SCALE, DEFAULT_TX_SCALE))
150 std::cerr << "usrp2::ctor set_tx_scale_iq failed\n";
156 d_bg_thread = 0; // thread class deletes itself
161 if (USRP2_IMPL_DEBUG) {
162 std::cerr << std::endl
163 << "usrp2 destructor: received " << d_num_rx_frames
164 << " frames, with " << d_num_rx_missing << " lost ("
165 << (d_num_rx_frames == 0 ? 0 : (int)(100.0*d_num_rx_missing/d_num_rx_frames))
166 << "%), totaling " << d_num_rx_bytes
167 << " bytes" << std::endl;
172 usrp2::impl::parse_mac_addr(const std::string &s, u2_mac_addr_t *p)
174 p->addr[0] = 0x00; // Matt's IAB
186 return sscanf(s.c_str(), "%hhx:%hhx", &p->addr[4], &p->addr[5]) == 2;
189 return sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
190 &p->addr[0], &p->addr[1], &p->addr[2],
191 &p->addr[3], &p->addr[4], &p->addr[5]) == 6;
198 usrp2::impl::init_et_hdrs(u2_eth_packet_t *p, const std::string &dst)
200 p->ehdr.ethertype = htons(U2_ETHERTYPE);
201 parse_mac_addr(dst, &p->ehdr.dst);
202 memcpy(&p->ehdr.src, d_eth_buf->mac(), 6);
203 p->thdr.flags = 0; // FIXME transport header values?
204 p->thdr.seqno = d_tx_seqno++;
209 usrp2::impl::init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst,
210 int word0_flags, int chan, uint32_t timestamp)
212 init_et_hdrs(p, dst);
213 u2p_set_word0(&p->fixed, word0_flags, chan);
214 u2p_set_timestamp(&p->fixed, timestamp);
216 if (chan == CONTROL_CHAN) { // no sequence numbers, back it out
223 usrp2::impl::init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd)
225 memset(cmd, 0, sizeof(*cmd));
226 init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
227 cmd->op.opcode = OP_CONFIG_RX_V2;
228 cmd->op.len = sizeof(cmd->op);
229 cmd->op.rid = d_next_rid++;
230 cmd->eop.opcode = OP_EOP;
231 cmd->eop.len = sizeof(cmd->eop);
235 usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd)
237 memset(cmd, 0, sizeof(*cmd));
238 init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1);
239 cmd->op.opcode = OP_CONFIG_TX_V2;
240 cmd->op.len = sizeof(cmd->op);
241 cmd->op.rid = d_next_rid++;
242 cmd->eop.opcode = OP_EOP;
243 cmd->eop.len = sizeof(cmd->eop);
247 usrp2::impl::transmit_cmd(void *cmd, size_t len, pending_reply *p, double secs)
250 d_pending_replies[p->rid()] = p;
253 if (d_eth_buf->tx_frame(cmd, len) != eth_buffer::EB_OK) {
254 d_pending_replies[p->rid()] = 0;
262 d_pending_replies[p->rid()] = 0;
266 // ----------------------------------------------------------------
267 // Background loop: received packet demuxing
268 // ----------------------------------------------------------------
271 usrp2::impl::stop_bg()
273 d_bg_running = false;
274 d_bg_pending_cond.signal();
277 d_bg_thread->join(&dummy_status);
281 usrp2::impl::bg_loop()
284 while(d_bg_running) {
286 // Receive available frames from ethernet buffer. Handler will
287 // process control frames, enqueue data packets in channel
288 // rings, and signal blocked API threads
289 int res = d_eth_buf->rx_frames(this, 100); // FIXME magic timeout
290 if (res == eth_buffer::EB_ERROR)
293 // Wait for user API thread(s) to process all enqueued packets.
294 // The channel ring thread that decrements d_num_enqueued to zero
295 // will signal this thread to continue.
297 omni_mutex_lock l(d_enqueued_mutex);
298 while(d_num_enqueued > 0 && d_bg_running)
299 d_bg_pending_cond.wait();
302 d_bg_running = false;
306 // passed to eth_buffer::rx_frames
309 usrp2::impl::operator()(const void *base, size_t len)
311 u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
313 // FIXME unaligned load!
314 int chan = u2p_chan(&pkt->hdrs.fixed);
316 if (chan == CONTROL_CHAN) { // control packets
318 return handle_control_packet(base, len);
320 else { // data packets
321 return handle_data_packet(base, len);
328 usrp2::impl::handle_control_packet(const void *base, size_t len)
330 // point to beginning of payload (subpackets)
331 unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t);
333 // FIXME (p % 4) == 2. Not good. Must watch for unaligned loads.
335 // FIXME iterate over payload, handling more than a single subpacket.
338 unsigned int oplen = p[1];
339 unsigned int rid = p[2];
341 pending_reply *rp = d_pending_replies[rid];
343 unsigned int buflen = rp->len();
344 if (oplen != buflen) {
345 std::cerr << "usrp2: mismatched command reply length (expected: "
346 << buflen << " got: " << oplen << "). "
347 << "op = " << opcode_to_string(opcode) << std::endl;
350 // Copy reply into caller's buffer
351 memcpy(rp->buffer(), p, std::min(oplen, buflen));
353 d_pending_replies[rid] = 0;
354 return data_handler::RELEASE;
357 // TODO: handle unsolicited, USRP2 initiated, or late replies
359 return data_handler::RELEASE;
363 usrp2::impl::handle_data_packet(const void *base, size_t len)
365 u2_eth_samples_t *pkt = (u2_eth_samples_t *)base;
367 d_num_rx_bytes += len;
369 /* --- FIXME start of fake transport layer handler --- */
371 if (d_rx_seqno != -1) {
372 int expected_seqno = (d_rx_seqno + 1) & 0xFF;
373 int seqno = pkt->hdrs.thdr.seqno;
375 if (seqno != expected_seqno) {
376 ::write(2, "S", 1); // missing sequence number
377 int missing = seqno - expected_seqno;
382 d_num_rx_missing += missing;
386 d_rx_seqno = pkt->hdrs.thdr.seqno;
388 /* --- end of fake transport layer handler --- */
390 // FIXME unaligned load!
391 unsigned int chan = u2p_chan(&pkt->hdrs.fixed);
393 if (!d_channel_rings[chan]) {
395 return data_handler::RELEASE; // discard packet, no channel handler
398 // Strip off ethernet header and transport header and enqueue the rest
400 size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed);
401 if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) {
404 return data_handler::KEEP; // channel ring runner will mark frame done
408 return data_handler::RELEASE; // discard, no room in channel ring
410 return data_handler::RELEASE;
414 // ----------------------------------------------------------------
416 // ----------------------------------------------------------------
419 usrp2::impl::burn_mac_addr(const std::string &new_addr)
421 op_burn_mac_addr_cmd cmd;
424 memset(&cmd, 0, sizeof(cmd));
425 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
426 cmd.op.opcode = OP_BURN_MAC_ADDR;
427 cmd.op.len = sizeof(cmd.op);
428 cmd.op.rid = d_next_rid++;
429 if (!parse_mac_addr(new_addr, &cmd.op.addr))
432 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
433 if (!transmit_cmd(&cmd, sizeof(cmd), &p, 4*DEF_CMD_TIMEOUT))
436 bool success = (ntohx(reply.ok) == 1);
441 // ----------------------------------------------------------------
443 // ----------------------------------------------------------------
446 usrp2::impl::set_rx_gain(double gain)
448 op_config_rx_v2_cmd cmd;
449 op_config_rx_reply_v2_t reply;
451 init_config_rx_v2_cmd(&cmd);
452 cmd.op.valid = htons(CFGV_GAIN);
453 cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
455 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
456 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
459 bool success = (ntohx(reply.ok) == 1);
464 usrp2::impl::set_rx_center_freq(double frequency, tune_result *result)
466 op_config_rx_v2_cmd cmd;
467 op_config_rx_reply_v2_t reply;
469 init_config_rx_v2_cmd(&cmd);
470 cmd.op.valid = htons(CFGV_FREQ);
471 u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
472 cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
473 cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
475 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
476 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
479 bool success = (ntohx(reply.ok) == 1);
480 if (result && success) {
481 result->baseband_freq =
482 u2_fxpt_freq_to_double(
483 u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
484 ntohl(reply.baseband_freq_lo)));
487 u2_fxpt_freq_to_double(
488 u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi),
489 ntohl(reply.ddc_freq_lo)));
491 result->residual_freq =
492 u2_fxpt_freq_to_double(
493 u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
494 ntohl(reply.residual_freq_lo)));
496 result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
503 usrp2::impl::set_rx_decim(int decimation_factor)
505 op_config_rx_v2_cmd cmd;
506 op_config_rx_reply_v2_t reply;
508 init_config_rx_v2_cmd(&cmd);
509 cmd.op.valid = htons(CFGV_INTERP_DECIM);
510 cmd.op.decim = htonl(decimation_factor);
512 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
513 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
516 bool success = (ntohx(reply.ok) == 1);
521 usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q)
523 op_config_rx_v2_cmd cmd;
524 op_config_rx_reply_v2_t reply;
526 init_config_rx_v2_cmd(&cmd);
527 cmd.op.valid = htons(CFGV_SCALE_IQ);
528 cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
530 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
531 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
534 bool success = (ntohx(reply.ok) == 1);
539 usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
541 if (channel > MAX_CHAN) {
542 std::cerr << "usrp2: invalid channel number (" << channel
547 if (channel > 0) { // until firmware supports multiple streams
548 std::cerr << "usrp2: channel " << channel
549 << " not implemented" << std::endl;
553 if (d_channel_rings[channel]) {
554 std::cerr << "usrp2: channel " << channel
555 << " already streaming" << std::endl;
559 d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames()));
561 if (items_per_frame == 0)
562 items_per_frame = U2_MAX_SAMPLES; // minimize overhead
564 op_start_rx_streaming_cmd cmd;
567 memset(&cmd, 0, sizeof(cmd));
568 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
569 cmd.op.opcode = OP_START_RX_STREAMING;
570 cmd.op.len = sizeof(cmd.op);
571 cmd.op.rid = d_next_rid++;
572 cmd.op.items_per_frame = htonl(items_per_frame);
573 cmd.eop.opcode = OP_EOP;
574 cmd.eop.len = sizeof(cmd.eop);
576 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
577 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
580 bool success = (ntohx(reply.ok) == 1);
585 usrp2::impl::stop_rx_streaming(unsigned int channel)
587 if (channel > MAX_CHAN) {
588 std::cerr << "usrp2: invalid channel number (" << channel
593 if (channel > 0) { // until firmware supports multiple streams
594 std::cerr << "usrp2: channel " << channel
595 << " not implemented" << std::endl;
599 #if 0 // don't be overzealous.
600 if (!d_channel_rings[channel]) {
601 std::cerr << "usrp2: channel " << channel
602 << " not streaming" << std::endl;
610 memset(&cmd, 0, sizeof(cmd));
611 init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1);
612 cmd.op.opcode = OP_STOP_RX;
613 cmd.op.len = sizeof(cmd.op);
614 cmd.op.rid = d_next_rid++;
615 cmd.eop.opcode = OP_EOP;
616 cmd.eop.len = sizeof(cmd.eop);
618 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
619 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
622 bool success = (ntohx(reply.ok) == 1);
624 d_channel_rings[channel].reset();
631 usrp2::impl::rx_samples(unsigned int channel, rx_sample_handler *handler)
633 if (channel > MAX_CHAN) {
634 std::cerr << "usrp2: invalid channel (" << channel
635 << " )" << std::endl;
640 std::cerr << "usrp2: channel " << channel
641 << " not implemented" << std::endl;
645 ring_sptr rp = d_channel_rings[channel];
647 std::cerr << "usrp2: channel " << channel
648 << " not receiving" << std::endl;
652 // Wait for frames available in channel ring
654 rp->wait_for_not_empty();
657 // Iterate through frames and present to user
659 size_t frame_len_in_bytes;
660 while (rp->dequeue(&p, &frame_len_in_bytes)) {
661 uint32_t *items; // points to beginning of data items
662 size_t nitems_in_uint32s;
664 if (!parse_rx_metadata(p, frame_len_in_bytes, &items, &nitems_in_uint32s, &md))
667 bool want_more = (*handler)(items, nitems_in_uint32s, &md);
668 d_eth_buf->release_frame(p);
678 // ----------------------------------------------------------------
680 // ----------------------------------------------------------------
683 usrp2::impl::set_tx_gain(double gain)
685 op_config_tx_v2_cmd cmd;
686 op_config_tx_reply_v2_t reply;
688 init_config_tx_v2_cmd(&cmd);
689 cmd.op.valid = htons(CFGV_GAIN);
690 cmd.op.gain = htons(u2_double_to_fxpt_gain(gain));
692 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
693 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
696 bool success = (ntohx(reply.ok) == 1);
701 usrp2::impl::set_tx_center_freq(double frequency, tune_result *result)
703 op_config_tx_v2_cmd cmd;
704 op_config_tx_reply_v2_t reply;
706 init_config_tx_v2_cmd(&cmd);
707 cmd.op.valid = htons(CFGV_FREQ);
708 u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency);
709 cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt));
710 cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt));
712 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
713 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
716 bool success = (ntohx(reply.ok) == 1);
717 if (result && success) {
718 result->baseband_freq =
719 u2_fxpt_freq_to_double(
720 u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi),
721 ntohl(reply.baseband_freq_lo)));
724 u2_fxpt_freq_to_double(
725 u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi),
726 ntohl(reply.duc_freq_lo)));
728 result->residual_freq =
729 u2_fxpt_freq_to_double(
730 u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi),
731 ntohl(reply.residual_freq_lo)));
733 result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1);
740 usrp2::impl::set_tx_interp(int interpolation_factor)
742 op_config_tx_v2_cmd cmd;
743 op_config_tx_reply_v2_t reply;
745 init_config_tx_v2_cmd(&cmd);
746 cmd.op.valid = htons(CFGV_INTERP_DECIM);
747 cmd.op.interp = htonl(interpolation_factor);
749 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
750 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
753 bool success = (ntohx(reply.ok) == 1);
758 usrp2::impl::set_tx_scale_iq(int scale_i, int scale_q)
760 op_config_tx_v2_cmd cmd;
761 op_config_tx_reply_v2_t reply;
763 init_config_tx_v2_cmd(&cmd);
764 cmd.op.valid = htons(CFGV_SCALE_IQ);
765 cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff));
767 pending_reply p(cmd.op.rid, &reply, sizeof(reply));
768 if (!transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT))
771 bool success = (ntohx(reply.ok) == 1);
776 usrp2::impl::tx_complex_float(unsigned int channel,
777 const std::complex<float> *samples,
779 const tx_metadata *metadata)
781 uint32_t items[nsamples];
782 copy_host_complex_float_to_u2_complex_16(nsamples, samples, items);
783 return tx_raw(channel, items, nsamples, metadata);
787 usrp2::impl::tx_complex_int16(unsigned int channel,
788 const std::complex<int16_t> *samples,
790 const tx_metadata *metadata)
792 #ifdef WORDS_BIGENDIAN
794 // Already binary equivalent to 16-bit I/Q on the wire.
795 // No conversion required.
797 assert(sizeof(samples[0]) == sizeof(uint32_t));
798 return tx_raw(channel, (const uint32_t *) samples, nsamples, metadata);
802 uint32_t items[nsamples];
803 copy_host_complex_16_to_u2_complex_16(nsamples, samples, items);
804 return tx_raw(channel, items, nsamples, metadata);
810 usrp2::impl::tx_raw(unsigned int channel,
811 const uint32_t *items,
813 const tx_metadata *metadata)
818 // FIXME there's the possibility that we send fewer than 9 items in a frame.
819 // That would end up glitching the transmitter, since the ethernet will pad to
820 // 64-bytes total (9 items). We really need some part of the stack to
821 // carry the real length (thdr?).
823 // fragment as necessary then fire away
825 size_t nframes = (nitems + U2_MAX_SAMPLES - 1) / U2_MAX_SAMPLES;
826 size_t last_frame = nframes - 1;
827 u2_eth_packet_t hdrs;
830 for (size_t fn = 0; fn < nframes; fn++){
831 uint32_t timestamp = 0;
835 timestamp = metadata->timestamp;
836 if (metadata->send_now)
837 flags |= U2P_TX_IMMEDIATE;
838 if (metadata->start_of_burst)
839 flags |= U2P_TX_START_OF_BURST;
842 flags |= U2P_TX_IMMEDIATE;
844 if (fn == last_frame){
845 if (metadata->end_of_burst)
846 flags |= U2P_TX_END_OF_BURST;
849 init_etf_hdrs(&hdrs, d_addr, flags, channel, timestamp);
851 size_t i = std::min((size_t) U2_MAX_SAMPLES, nitems - n);
854 iov[0].iov_base = &hdrs;
855 iov[0].iov_len = sizeof(hdrs);
856 iov[1].iov_base = const_cast<uint32_t *>(&items[n]);
857 iov[1].iov_len = i * sizeof(uint32_t);
859 size_t total = iov[0].iov_len + iov[1].iov_len;
861 fprintf(stderr, "usrp2::tx_raw: FIXME: short packet: %zd items (%zd bytes)\n", i, total);
863 if (d_eth_buf->tx_framev(iov, 2) != eth_buffer::EB_OK){