aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/usrp2/io_impl.cpp
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2010-03-15 17:00:04 +0000
committerJosh Blum <josh@joshknows.com>2010-03-15 17:00:04 +0000
commit1bfb556262d12740c71e68a2a071e6e67ed2b3e7 (patch)
treea081bfd3a61ccb42372a627be7b57ce19a3baa0d /host/lib/usrp/usrp2/io_impl.cpp
parent1b965831ae7588c7879d84de4e5fbd78ca614761 (diff)
parentfc40ff2f1327d01c72c4d7dbc07a14e473251981 (diff)
downloaduhd-1bfb556262d12740c71e68a2a071e6e67ed2b3e7.tar.gz
uhd-1bfb556262d12740c71e68a2a071e6e67ed2b3e7.tar.bz2
uhd-1bfb556262d12740c71e68a2a071e6e67ed2b3e7.zip
Merge branch 'master' of git@ettus.sourcerepo.com:ettus/uhd into u1e_uhd
Conflicts: host/apps/CMakeLists.txt host/lib/usrp/usrp2/usrp2_impl.cpp
Diffstat (limited to 'host/lib/usrp/usrp2/io_impl.cpp')
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp329
1 files changed, 172 insertions, 157 deletions
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 43334ddc6..cc7746720 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -16,12 +16,13 @@
//
#include <complex>
-#include <boost/shared_array.hpp>
#include <boost/format.hpp>
#include "usrp2_impl.hpp"
using namespace uhd;
using namespace uhd::usrp;
+using namespace uhd::transport;
+namespace asio = boost::asio;
/***********************************************************************
* Constants
@@ -29,214 +30,228 @@ using namespace uhd::usrp;
typedef std::complex<float> fc32_t;
typedef std::complex<int16_t> sc16_t;
-static const float float_scale_factor = pow(2.0, 15);
-
-//max length with header, stream id, seconds, fractional seconds
-static const size_t max_vrt_header_words = 5;
+static const float shorts_per_float = pow(2.0, 15);
+static const float floats_per_short = 1.0/shorts_per_float;
/***********************************************************************
* Helper Functions
**********************************************************************/
-static inline void host_floats_to_usrp2_shorts(
- int16_t *usrp2_shorts,
- const float *host_floats,
- size_t num_samps
-){
- for(size_t i = 0; i < num_samps; i++){
- usrp2_shorts[i] = htons(int16_t(host_floats[i]*float_scale_factor));
- }
+void usrp2_impl::io_init(void){
+ //initially empty copy buffer
+ _rx_copy_buff = asio::buffer("", 0);
+
+ //send a small data packet so the usrp2 knows the udp source port
+ uint32_t zero_data = 0;
+ _data_transport->send(asio::buffer(&zero_data, sizeof(zero_data)));
+}
+
+#define unrolled_loop(__i, __len, __inst) {\
+ size_t __i = 0; \
+ while(__i < (__len & ~0x7)){ \
+ __inst; __i++; __inst; __i++; \
+ __inst; __i++; __inst; __i++; \
+ __inst; __i++; __inst; __i++; \
+ __inst; __i++; __inst; __i++; \
+ } \
+ while(__i < __len){ \
+ __inst; __i++;\
+ } \
}
-static inline void usrp2_shorts_to_host_floats(
- float *host_floats,
- const int16_t *usrp2_shorts,
+// set a boolean flag that indicates the endianess
+#ifdef HAVE_BIG_ENDIAN
+static const bool is_big_endian = true;
+#else
+static const bool is_big_endian = false;
+#endif
+
+static inline void host_floats_to_usrp2_items(
+ uint32_t *usrp2_items,
+ const fc32_t *host_floats,
size_t num_samps
){
- for(size_t i = 0; i < num_samps; i++){
- host_floats[i] = float(ntohs(usrp2_shorts[i])/float_scale_factor);
- }
+ unrolled_loop(i, num_samps,{
+ uint16_t real = host_floats[i].real()*shorts_per_float;
+ uint16_t imag = host_floats[i].imag()*shorts_per_float;
+ usrp2_items[i] = htonl((real << 16) | (imag << 0));
+ });
}
-static inline void host_shorts_to_usrp2_shorts(
- int16_t *usrp2_shorts,
- const int16_t *host_shorts,
+static inline void usrp2_items_to_host_floats(
+ fc32_t *host_floats,
+ const uint32_t *usrp2_items,
size_t num_samps
){
- for(size_t i = 0; i < num_samps; i++){
- usrp2_shorts[i] = htons(host_shorts[i]);
- }
+ unrolled_loop(i, num_samps,{
+ uint32_t item = ntohl(usrp2_items[i]);
+ int16_t real = item >> 16;
+ int16_t imag = item >> 0;
+ host_floats[i] = fc32_t(real*floats_per_short, imag*floats_per_short);
+ });
}
-static inline void usrp2_shorts_to_host_shorts(
- int16_t *host_shorts,
- const int16_t *usrp2_shorts,
+static inline void host_items_to_usrp2_items(
+ uint32_t *usrp2_items,
+ const uint32_t *host_items,
size_t num_samps
){
- for(size_t i = 0; i < num_samps; i++){
- host_shorts[i] = ntohs(usrp2_shorts[i]);
+ if (is_big_endian){
+ std::memcpy(usrp2_items, host_items, num_samps*sizeof(uint32_t));
+ }
+ else{
+ unrolled_loop(i, num_samps, usrp2_items[i] = htonl(host_items[i]));
}
}
-/***********************************************************************
- * Send Raw Data
- **********************************************************************/
-size_t usrp2_impl::send_raw(
- const boost::asio::const_buffer &buff,
- const uhd::metadata_t &metadata
+static inline void usrp2_items_to_host_items(
+ uint32_t *host_items,
+ const uint32_t *usrp2_items,
+ size_t num_samps
){
- std::vector<boost::asio::const_buffer> buffs(2);
- uint32_t vrt_hdr[max_vrt_header_words];
- uint32_t vrt_hdr_flags = 0;
- size_t num_vrt_hdr_words = 1;
-
- //load the vrt header and flags
- if(metadata.has_stream_id){
- vrt_hdr_flags |= (0x1 << 28); //IF Data packet with Stream Identifier
- vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.stream_id);
+ if (is_big_endian){
+ std::memcpy(host_items, usrp2_items, num_samps*sizeof(uint32_t));
}
- if(metadata.has_time_spec){
- vrt_hdr_flags |= (0x3 << 22) | (0x1 << 20); //TSI: Other, TSF: Sample Count Timestamp
- vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.time_spec.secs);
- vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.time_spec.ticks);
- vrt_hdr[num_vrt_hdr_words++] = 0; //unused part of fractional seconds
+ else{
+ unrolled_loop(i, num_samps, host_items[i] = ntohl(usrp2_items[i]));
}
- vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0;
- vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0;
-
- //fill in complete header word
- vrt_hdr[0] = htonl(vrt_hdr_flags |
- ((_stream_id_to_packet_seq[metadata.stream_id]++ & 0xf) << 16) |
- ((boost::asio::buffer_size(buff)/sizeof(uint32_t)) & 0xffff)
- );
-
- //load the buffer vector
- size_t vrt_hdr_size = num_vrt_hdr_words*sizeof(uint32_t);
- buffs[0] = boost::asio::buffer(&vrt_hdr, vrt_hdr_size);
- buffs[1] = buff;
-
- //send and return number of samples
- return (_data_transport->send(buffs) - vrt_hdr_size)/sizeof(sc16_t);
}
/***********************************************************************
* Receive Raw Data
**********************************************************************/
-size_t usrp2_impl::recv_raw(
- const boost::asio::mutable_buffer &buff,
- uhd::metadata_t &metadata
-){
- //load the buffer vector
- std::vector<boost::asio::mutable_buffer> buffs(2);
- uint32_t vrt_hdr[max_vrt_header_words];
- buffs[0] = boost::asio::buffer(vrt_hdr, max_vrt_header_words);
- buffs[1] = buff;
+void usrp2_impl::recv_raw(rx_metadata_t &metadata){
+ //do a receive
+ _rx_smart_buff = _data_transport->recv();
- //receive into the buffers
- size_t bytes_recvd = _data_transport->recv(buffs);
+ //unpack the vrt header
+ size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(uint32_t);
+ if (num_packet_words32 == 0){
+ _rx_copy_buff = boost::asio::buffer("", 0);
+ return; //must exit here after setting the buffer
+ }
+ const uint32_t *vrt_hdr = asio::buffer_cast<const uint32_t *>(_rx_smart_buff->get());
+ size_t num_header_words32_out, num_payload_words32_out, packet_count_out;
+ try{
+ vrt::unpack(
+ metadata, //output
+ vrt_hdr, //input
+ num_header_words32_out, //output
+ num_payload_words32_out, //output
+ num_packet_words32, //input
+ packet_count_out //output
+ );
+ }catch(const std::exception &e){
+ std::cerr << "bad vrt header: " << e.what() << std::endl;
+ _rx_copy_buff = boost::asio::buffer("", 0);
+ return; //must exit here after setting the buffer
+ }
- //failure case
- if (bytes_recvd < max_vrt_header_words*sizeof(uint32_t)) return 0;
+ //handle the packet count / sequence number
+ size_t expected_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id];
+ if (packet_count_out != expected_packet_count){
+ std::cerr << "bad packet count: " << packet_count_out << std::endl;
+ }
+ _rx_stream_id_to_packet_seq[metadata.stream_id] = (packet_count_out+1)%16;
- //unpack the vrt header
- metadata = uhd::metadata_t();
- uint32_t vrt_header = ntohl(vrt_hdr[0]);
- metadata.has_stream_id = true;
- metadata.stream_id = ntohl(vrt_hdr[1]);
- metadata.has_time_spec = true;
- metadata.time_spec.secs = ntohl(vrt_hdr[2]);
- metadata.time_spec.ticks = ntohl(vrt_hdr[3]);
-
- //return the number of samples received
- size_t num_words = vrt_header & 0xffff;
- return (num_words*sizeof(uint32_t))/sizeof(sc16_t);
+ //setup the rx buffer to point to the data
+ _rx_copy_buff = asio::buffer(
+ vrt_hdr + num_header_words32_out,
+ num_payload_words32_out*sizeof(uint32_t)
+ );
}
/***********************************************************************
* Send Data
**********************************************************************/
size_t usrp2_impl::send(
- const boost::asio::const_buffer &buff,
- const uhd::metadata_t &metadata,
+ const asio::const_buffer &buff,
+ const tx_metadata_t &metadata,
const std::string &type
){
- if (type == "fc32"){
- size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t);
- boost::shared_array<sc16_t> raw_mem(new sc16_t[num_samps]);
- boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t));
-
- host_floats_to_usrp2_shorts(
- boost::asio::buffer_cast<int16_t*>(raw_buff),
- boost::asio::buffer_cast<const float*>(buff),
- num_samps*2 //double for complex
- );
-
- return send_raw(raw_buff, metadata);
+ uint32_t tx_mem[_mtu/sizeof(uint32_t)];
+ uint32_t *items = tx_mem + vrt::max_header_words32; //offset for data
+ size_t num_samps = _max_tx_samples_per_packet;
+
+ //calculate the number of samples to be copied
+ //and copy the samples into the send buffer
+ if (type == "32fc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps);
+ host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps);
+ }
+ else if (type == "16sc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps);
+ host_items_to_usrp2_items(items, asio::buffer_cast<const uint32_t*>(buff), num_samps);
+ }
+ else{
+ throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type));
}
- if (type == "sc16"){
- #ifdef HAVE_BIG_ENDIAN
- return send_raw(buff, metadata);
- #else
- size_t num_samps = boost::asio::buffer_size(buff)/sizeof(sc16_t);
- boost::shared_array<sc16_t> raw_mem(new sc16_t[num_samps]);
- boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t));
-
- host_shorts_to_usrp2_shorts(
- boost::asio::buffer_cast<int16_t*>(raw_buff),
- boost::asio::buffer_cast<const int16_t*>(buff),
- num_samps*2 //double for complex
- );
+ uint32_t vrt_hdr[vrt::max_header_words32];
+ size_t num_header_words32, num_packet_words32;
+ size_t packet_count = _tx_stream_id_to_packet_seq[metadata.stream_id]++;
+
+ //pack metadata into a vrt header
+ vrt::pack(
+ metadata, //input
+ vrt_hdr, //output
+ num_header_words32, //output
+ num_samps, //input
+ num_packet_words32, //output
+ packet_count //input
+ );
- return send_raw(raw_buff, metadata);
- #endif
- }
+ //copy in the vrt header (yes we left space)
+ items -= num_header_words32;
+ std::memcpy(items, vrt_hdr, num_header_words32*sizeof(uint32_t));
- throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type));
+ //send and return number of samples
+ _data_transport->send(asio::buffer(items, num_packet_words32*sizeof(uint32_t)));
+ return num_samps;
}
/***********************************************************************
* Receive Data
**********************************************************************/
size_t usrp2_impl::recv(
- const boost::asio::mutable_buffer &buff,
- uhd::metadata_t &metadata,
+ const asio::mutable_buffer &buff,
+ rx_metadata_t &metadata,
const std::string &type
){
- if (type == "fc32"){
- size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t);
- boost::shared_array<sc16_t> raw_mem(new sc16_t[num_samps]);
- boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t));
-
- num_samps = recv_raw(raw_buff, metadata);
-
- usrp2_shorts_to_host_floats(
- boost::asio::buffer_cast<float*>(buff),
- boost::asio::buffer_cast<const int16_t*>(raw_buff),
- num_samps*2 //double for complex
- );
-
- return num_samps;
+ //perform a receive if no rx data is waiting to be copied
+ if (asio::buffer_size(_rx_copy_buff) == 0){
+ recv_raw(metadata);
+ }
+ //otherwise flag the metadata to show that is is a fragment
+ else{
+ metadata = rx_metadata_t();
+ metadata.is_fragment = true;
}
- if (type == "sc16"){
- #ifdef HAVE_BIG_ENDIAN
- return recv_raw(buff, metadata);
- #else
- size_t num_samps = boost::asio::buffer_size(buff)/sizeof(sc16_t);
- boost::shared_array<sc16_t> raw_mem(new sc16_t[num_samps]);
- boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t));
-
- num_samps = recv_raw(raw_buff, metadata);
-
- usrp2_shorts_to_host_shorts(
- boost::asio::buffer_cast<int16_t*>(buff),
- boost::asio::buffer_cast<const int16_t*>(raw_buff),
- num_samps*2 //double for complex
- );
-
- return num_samps;
- #endif
+ //extract the number of samples available to copy
+ //and a pointer into the usrp2 received items memory
+ size_t bytes_to_copy = asio::buffer_size(_rx_copy_buff);
+ if (bytes_to_copy == 0) return 0; //nothing to receive
+ size_t num_samps = bytes_to_copy/sizeof(uint32_t);
+ const uint32_t *items = asio::buffer_cast<const uint32_t*>(_rx_copy_buff);
+
+ //calculate the number of samples to be copied
+ //and copy the samples from the recv buffer
+ if (type == "32fc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps);
+ usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps);
+ }
+ else if (type == "16sc"){
+ num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps);
+ usrp2_items_to_host_items(asio::buffer_cast<uint32_t*>(buff), items, num_samps);
}
+ else{
+ throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type));
+ }
+
+ //update the rx copy buffer to reflect the bytes copied
+ _rx_copy_buff = asio::buffer(
+ items + num_samps, bytes_to_copy - num_samps*sizeof(uint32_t)
+ );
- throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type));
+ return num_samps;
}