From a4452018d17329ca02fbda85cc6b6ac21084094a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 26 Feb 2010 12:01:03 -0800 Subject: removed empty uhd.hpp and cpp files --- host/apps/discover_usrps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'host/apps/discover_usrps.cpp') diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 7e8c21673..5172a4a26 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -15,7 +15,7 @@ // along with this program. If not, see . // -#include +#include #include #include #include -- cgit v1.2.3 From 6e8473e6eef84875e2c3babb35732f8c3b2a0247 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 1 Mar 2010 11:50:14 -0800 Subject: Recv noise with uhd. --- firmware/microblaze/apps/txrx.c | 3 ++ host/apps/discover_usrps.cpp | 3 -- host/include/uhd/device_addr.hpp | 6 +-- host/include/uhd/usrp/dboard_id.hpp | 6 +-- host/lib/usrp/usrp2/dsp_impl.cpp | 12 +++++- host/lib/usrp/usrp2/fw_common.h | 1 + host/lib/usrp/usrp2/io_impl.cpp | 86 +++++++++++++++++++++++++------------ host/lib/usrp/usrp2/usrp2_impl.hpp | 3 ++ 8 files changed, 82 insertions(+), 38 deletions(-) (limited to 'host/apps/discover_usrps.cpp') diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index 1724284b0..dccb2bdc9 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -430,6 +430,8 @@ void handle_udp_ctrl_packet( ******************************************************************/ case USRP2_CTRL_ID_SETUP_THIS_DDC_FOR_ME_BRO: dsp_rx_regs->freq = ctrl_data_in->data.ddc_args.freq_word; + dsp_rx_regs->scale_iq = ctrl_data_in->data.ddc_args.scale_iq; + dsp_rx_regs->rx_mux = 0x00 | (0x01 << 2); //TODO fill in from control //setup the interp and half band filters { @@ -471,6 +473,7 @@ void handle_udp_ctrl_packet( case USRP2_CTRL_ID_SETUP_THIS_DUC_FOR_ME_BRO: dsp_tx_regs->freq = ctrl_data_in->data.duc_args.freq_word; dsp_tx_regs->scale_iq = ctrl_data_in->data.duc_args.scale_iq; + dsp_tx_regs->tx_mux = 0x01; //TODO fill in from control //setup the interp and half band filters { diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 5172a4a26..20ac1f9ed 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -63,9 +63,6 @@ int main(int argc, char *argv[]){ std::cout << "-- USRP Device " << i << std::endl; std::cout << "--------------------------------------------------" << std::endl; std::cout << device_addrs[i] << std::endl << std::endl; - //make each device just to test (TODO: remove this) - uhd::device::sptr dev = uhd::device::make(device_addrs[i]); - std::cout << wax::cast((*dev)[uhd::DEVICE_PROP_MBOARD][uhd::MBOARD_PROP_NAME]) << std::endl; } return 0; diff --git a/host/include/uhd/device_addr.hpp b/host/include/uhd/device_addr.hpp index d02febd6c..ed538453a 100644 --- a/host/include/uhd/device_addr.hpp +++ b/host/include/uhd/device_addr.hpp @@ -56,9 +56,9 @@ namespace uhd{ * \param device_addr a device address instance * \return the string representation */ - struct device_addr{ - static std::string to_string(const device_addr_t &device_addr); - }; + namespace device_addr{ + std::string to_string(const device_addr_t &device_addr); + } } //namespace uhd diff --git a/host/include/uhd/usrp/dboard_id.hpp b/host/include/uhd/usrp/dboard_id.hpp index 8e904ff33..65e3d5707 100644 --- a/host/include/uhd/usrp/dboard_id.hpp +++ b/host/include/uhd/usrp/dboard_id.hpp @@ -28,9 +28,9 @@ enum dboard_id_t{ ID_BASIC_RX = 0x0001 }; -struct dboard_id{ - static std::string to_string(const dboard_id_t &id); -}; +namespace dboard_id{ + std::string to_string(const dboard_id_t &id); +} }} //namespace diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 22c00d99a..e5c4a4245 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -36,6 +36,10 @@ static uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t return freq_word; } +static uint32_t calculate_iq_scale_word(int16_t i, int16_t q){ + return ((i & 0xffff) << 16) | ((q & 0xffff) << 0); +} + void usrp2_impl::init_ddc_config(void){ //create the ddc in the rx dsp dict _rx_dsps["ddc0"] = wax_obj_proxy( @@ -61,6 +65,10 @@ void usrp2_impl::update_ddc_config(void){ calculate_freq_word_and_update_actual_freq(_ddc_freq, get_master_clock_freq()) ); out_data.data.ddc_args.decim = htonl(_ddc_decim); + static const uint32_t default_rx_scale_iq = 1024; + out_data.data.ddc_args.scale_iq = htonl( + calculate_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq) + ); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); @@ -209,7 +217,9 @@ void usrp2_impl::update_duc_config(void){ calculate_freq_word_and_update_actual_freq(_duc_freq, get_master_clock_freq()) ); out_data.data.duc_args.interp = htonl(_duc_interp); - out_data.data.duc_args.scale_iq = htonl(scale); + out_data.data.duc_args.scale_iq = htonl( + calculate_iq_scale_word(scale, scale) + ); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 3def8ddaa..aca0abb28 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -168,6 +168,7 @@ typedef struct{ struct { uint32_t freq_word; uint32_t decim; + uint32_t scale_iq; } ddc_args; struct { uint8_t enabled; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index c9a7b5fa4..9c7a41e49 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -22,6 +22,7 @@ using namespace uhd; using namespace uhd::usrp; +namespace asio = boost::asio; /*********************************************************************** * Constants @@ -38,28 +39,28 @@ static const size_t max_vrt_header_words = 5; * Helper Functions **********************************************************************/ static inline void host_floats_to_usrp2_shorts( - int16_t *usrp2_shorts, + short *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)); + usrp2_shorts[i] = htons(short(host_floats[i]*float_scale_factor)); } } static inline void usrp2_shorts_to_host_floats( float *host_floats, - const int16_t *usrp2_shorts, + const short *usrp2_shorts, size_t num_samps ){ for(size_t i = 0; i < num_samps; i++){ - host_floats[i] = float(ntohs(usrp2_shorts[i])/float_scale_factor); + host_floats[i] = float(short(ntohs(usrp2_shorts[i])))/float_scale_factor; } } static inline void host_shorts_to_usrp2_shorts( - int16_t *usrp2_shorts, - const int16_t *host_shorts, + short *usrp2_shorts, + const short *host_shorts, size_t num_samps ){ for(size_t i = 0; i < num_samps; i++){ @@ -68,8 +69,8 @@ static inline void host_shorts_to_usrp2_shorts( } static inline void usrp2_shorts_to_host_shorts( - int16_t *host_shorts, - const int16_t *usrp2_shorts, + short *host_shorts, + const short *usrp2_shorts, size_t num_samps ){ for(size_t i = 0; i < num_samps; i++){ @@ -102,16 +103,17 @@ size_t usrp2_impl::send_raw( } vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0; + num_vrt_hdr_words += asio::buffer_size(buff)/sizeof(uint32_t); //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) + (num_vrt_hdr_words & 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[0] = asio::buffer(&vrt_hdr, vrt_hdr_size); buffs[1] = buff; //send and return number of samples @@ -125,11 +127,33 @@ size_t usrp2_impl::recv_raw( const boost::asio::mutable_buffer &buff, uhd::metadata_t &metadata ){ + //handle the case where there is spillover + if (asio::buffer_size(_splillover_buff) != 0){ + size_t bytes_to_copy = std::min( + asio::buffer_size(_splillover_buff), + asio::buffer_size(buff) + ); + std::memcpy( + asio::buffer_cast(buff), + asio::buffer_cast(_splillover_buff), + bytes_to_copy + ); + _splillover_buff = asio::buffer( + asio::buffer_cast(_splillover_buff)+bytes_to_copy, + asio::buffer_size(_splillover_buff)-bytes_to_copy + ); + //std::cout << boost::format("Copied spillover %d samples") % (bytes_to_copy/sizeof(sc16_t)) << std::endl; + return bytes_to_copy/sizeof(sc16_t); + } + //load the buffer vector - std::vector buffs(2); + std::vector buffs(3); uint32_t vrt_hdr[max_vrt_header_words]; - buffs[0] = boost::asio::buffer(vrt_hdr, max_vrt_header_words); - buffs[1] = buff; + buffs[0] = asio::buffer(vrt_hdr, max_vrt_header_words*sizeof(uint32_t)); + buffs[1] = asio::buffer(//make sure its on a word boundary + buff, asio::buffer_size(buff) & ~(sizeof(uint32_t) - 1) + ); + buffs[2] = asio::buffer(_spillover_mem, _mtu); //receive into the buffers size_t bytes_recvd = _data_transport->recv(buffs); @@ -146,9 +170,15 @@ size_t usrp2_impl::recv_raw( 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); + //extract the number of bytes received + size_t num_words = (vrt_header & 0xffff) - max_vrt_header_words; + size_t num_bytes = num_words*sizeof(uint32_t); + + //handle the case where spillover memory was used + size_t spillover_size = num_bytes - std::min(num_bytes, asio::buffer_size(buff)); + _splillover_buff = asio::buffer(_spillover_mem, spillover_size); + + return (num_bytes - spillover_size)/sizeof(sc16_t); } /*********************************************************************** @@ -160,13 +190,13 @@ size_t usrp2_impl::send( const std::string &type ){ if (type == "32fc"){ - size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t); + size_t num_samps = asio::buffer_size(buff)/sizeof(fc32_t); boost::shared_array 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(raw_buff), - boost::asio::buffer_cast(buff), + asio::buffer_cast(raw_buff), + asio::buffer_cast(buff), num_samps*2 //double for complex ); @@ -177,13 +207,13 @@ size_t usrp2_impl::send( #ifdef HAVE_BIG_ENDIAN return send_raw(buff, metadata); #else - size_t num_samps = boost::asio::buffer_size(buff)/sizeof(sc16_t); + size_t num_samps = asio::buffer_size(buff)/sizeof(sc16_t); boost::shared_array 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(raw_buff), - boost::asio::buffer_cast(buff), + asio::buffer_cast(raw_buff), + asio::buffer_cast(buff), num_samps*2 //double for complex ); @@ -203,15 +233,15 @@ size_t usrp2_impl::recv( const std::string &type ){ if (type == "32fc"){ - size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t); + size_t num_samps = asio::buffer_size(buff)/sizeof(fc32_t); boost::shared_array 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(buff), - boost::asio::buffer_cast(raw_buff), + asio::buffer_cast(buff), + asio::buffer_cast(raw_buff), num_samps*2 //double for complex ); @@ -222,15 +252,15 @@ size_t usrp2_impl::recv( #ifdef HAVE_BIG_ENDIAN return recv_raw(buff, metadata); #else - size_t num_samps = boost::asio::buffer_size(buff)/sizeof(sc16_t); + size_t num_samps = asio::buffer_size(buff)/sizeof(sc16_t); boost::shared_array 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(buff), - boost::asio::buffer_cast(raw_buff), + asio::buffer_cast(buff), + asio::buffer_cast(raw_buff), num_samps*2 //double for complex ); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 9a4c42d42..47b01d1b1 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -106,6 +106,9 @@ private: size_t send_raw(const boost::asio::const_buffer &, const uhd::metadata_t &); size_t recv_raw(const boost::asio::mutable_buffer &, uhd::metadata_t &); uhd::dict _stream_id_to_packet_seq; + static const size_t _mtu = 1500; + uint8_t _spillover_mem[_mtu]; + boost::asio::mutable_buffer _splillover_buff; //udp transports for control and data uhd::transport::udp::sptr _ctrl_transport; -- cgit v1.2.3 From bb8417526c14bd49192c159cbdc52f5ea0063784 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 3 Mar 2010 01:19:00 -0800 Subject: Making use of vrt lib in the usrp2 io_impl. Added a packet size param to the vrt pack and unpack. --- host/apps/discover_usrps.cpp | 1 + host/include/uhd/transport/vrt.hpp | 4 ++ host/lib/transport/vrt.cpp | 10 +++- host/lib/usrp/usrp2/dsp_impl.cpp | 2 +- host/lib/usrp/usrp2/io_impl.cpp | 115 ++++++++++++++++--------------------- host/lib/usrp/usrp2/usrp2_impl.cpp | 4 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 17 +++--- host/test/vrt_test.cpp | 3 + 8 files changed, 76 insertions(+), 80 deletions(-) (limited to 'host/apps/discover_usrps.cpp') diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 20ac1f9ed..448095726 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -63,6 +63,7 @@ int main(int argc, char *argv[]){ std::cout << "-- USRP Device " << i << std::endl; std::cout << "--------------------------------------------------" << std::endl; std::cout << device_addrs[i] << std::endl << std::endl; + //uhd::device::make(device_addrs[i]); //test make } return 0; diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp index b56da4077..2fb90a497 100644 --- a/host/include/uhd/transport/vrt.hpp +++ b/host/include/uhd/transport/vrt.hpp @@ -33,6 +33,7 @@ namespace vrt{ * \param header_buff memory to write the packed vrt header * \param num_header_words32 number of words in the vrt header * \param num_payload_words32 the length of the payload + * \param num_packet_words32 the length of the packet * \param packet_count the packet count sequence number */ void pack( @@ -40,6 +41,7 @@ namespace vrt{ uint32_t *header_buff, //output size_t &num_header_words32, //output size_t num_payload_words32, //input + size_t &num_packet_words32, //output size_t packet_count //input ); @@ -49,6 +51,7 @@ namespace vrt{ * \param header_buff memory to read the packed vrt header * \param num_header_words32 number of words in the vrt header * \param num_payload_words32 the length of the payload + * \param num_packet_words32 the length of the packet * \param packet_count the packet count sequence number */ void unpack( @@ -56,6 +59,7 @@ namespace vrt{ const uint32_t *header_buff, //input size_t &num_header_words32, //output size_t &num_payload_words32, //output + size_t num_packet_words32, //input size_t &packet_count //output ); diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp index 40b26d31f..19bfc1d19 100644 --- a/host/lib/transport/vrt.cpp +++ b/host/lib/transport/vrt.cpp @@ -26,6 +26,7 @@ void vrt::pack( uint32_t *header_buff, //output size_t &num_header_words32, //output size_t num_payload_words32, //input + size_t &num_packet_words32, //output size_t packet_count //input ){ uint32_t vrt_hdr_flags = 0; @@ -47,10 +48,12 @@ void vrt::pack( vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0; + num_packet_words32 = num_header_words32 + num_payload_words32; + //fill in complete header word header_buff[0] = htonl(vrt_hdr_flags | ((packet_count & 0xf) << 16) | - ((num_header_words32 + num_payload_words32) & 0xffff) + (num_packet_words32 & 0xffff) ); } @@ -59,6 +62,7 @@ void vrt::unpack( const uint32_t *header_buff, //input size_t &num_header_words32, //output size_t &num_payload_words32, //output + size_t num_packet_words32, //input size_t &packet_count //output ){ //clear the metadata @@ -70,8 +74,8 @@ void vrt::unpack( packet_count = (vrt_hdr_word >> 16) & 0xf; //failure cases - if (packet_words32 == 0) //FIXME check the packet length before we continue - throw std::runtime_error("bad vrt header"); + if (packet_words32 == 0 or num_packet_words32 < packet_words32) + throw std::runtime_error("bad vrt header or packet fragment"); if (vrt_hdr_word & (0x7 << 29)) throw std::runtime_error("unsupported vrt packet type"); diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 8fdfd685f..a32f68872 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -82,7 +82,7 @@ void usrp2_impl::update_ddc_enabled(void){ out_data.data.streaming.enabled = (_ddc_enabled)? 1 : 0; out_data.data.streaming.secs = htonl(_ddc_stream_at.secs); out_data.data.streaming.ticks = htonl(_ddc_stream_at.ticks); - out_data.data.streaming.samples = htonl(_max_samples_per_packet); + out_data.data.streaming.samples = htonl(_max_rx_samples_per_packet); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 6969e0a89..9299bb04a 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -21,6 +21,7 @@ using namespace uhd; using namespace uhd::usrp; +using namespace uhd::transport; namespace asio = boost::asio; /*********************************************************************** @@ -115,45 +116,6 @@ static inline void usrp2_items_to_host_items( } } -/*********************************************************************** - * Send Raw Data - **********************************************************************/ -size_t usrp2_impl::send_raw(const uhd::metadata_t &metadata){ - size_t num_items = asio::buffer_size(_tx_copy_buff)/sizeof(uint32_t); - const uint32_t *items = asio::buffer_cast(_tx_copy_buff); - - uint32_t vrt_hdr[_tx_vrt_max_offset_words32]; - 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(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 - } - 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 | - ((_tx_stream_id_to_packet_seq[metadata.stream_id]++ & 0xf) << 16) | - ((num_vrt_hdr_words + num_items) & 0xffff) - ); - - //copy in the vrt header (yes we left space) - std::memcpy(((uint32_t *)items) - num_vrt_hdr_words, vrt_hdr, num_vrt_hdr_words); - asio::const_buffer buff(items - num_vrt_hdr_words, (num_vrt_hdr_words + num_items)*sizeof(uint32_t)); - - //send and return number of samples - return (_data_transport->send(buff) - num_vrt_hdr_words*sizeof(uint32_t))/sizeof(sc16_t); -} - /*********************************************************************** * Receive Raw Data **********************************************************************/ @@ -161,34 +123,37 @@ void usrp2_impl::recv_raw(uhd::metadata_t &metadata){ //do a receive _rx_smart_buff = _data_transport->recv(); - //////////////////////////////////////////////////////////////////// - // !!!! FIXME this is very flawed, use a proper vrt unpacker !!!!!!! - //////////////////////////////////////////////////////////////////// - //unpack the vrt header const uint32_t *vrt_hdr = asio::buffer_cast(_rx_smart_buff->get()); - 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]); - - size_t my_seq = (vrt_header >> 16) & 0xf; - //std::cout << "seq " << my_seq << std::endl; - if (my_seq != ((_rx_stream_id_to_packet_seq[metadata.stream_id]+1) & 0xf)) std::cout << "bad seq " << my_seq << std::endl; - _rx_stream_id_to_packet_seq[metadata.stream_id] = my_seq; + size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(uint32_t); + size_t num_header_words32_out; + size_t num_payload_words32_out; + size_t 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); + } - //extract the number of bytes received - size_t num_words = (vrt_header & 0xffff) - - USRP2_HOST_RX_VRT_HEADER_WORDS32 - - USRP2_HOST_RX_VRT_TRAILER_WORDS32; + //handle the packet count / sequence number + size_t last_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id]; + if (packet_count_out != (last_packet_count+1)%16){ + std::cerr << "bad packet count: " << packet_count_out << std::endl; + } + _rx_stream_id_to_packet_seq[metadata.stream_id] = packet_count_out; //setup the rx buffer to point to the data _rx_copy_buff = boost::asio::buffer( - vrt_hdr + USRP2_HOST_RX_VRT_HEADER_WORDS32, - num_words*sizeof(uint32_t) + vrt_hdr + num_header_words32_out, + num_payload_words32_out*sizeof(uint32_t) ); } @@ -200,8 +165,9 @@ size_t usrp2_impl::send( const uhd::metadata_t &metadata, const std::string &type ){ - uint32_t *items = _tx_mem + _tx_vrt_max_offset_words32; //offset for data - size_t num_samps = _max_samples_per_packet; + 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 @@ -217,9 +183,26 @@ size_t usrp2_impl::send( throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); } - //send the samples (this line seems silly, will be better with vrt lib) - _tx_copy_buff = asio::buffer(items, num_samps*sizeof(uint32_t)); - return send_raw(metadata); //return num_samps; + 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 + ); + + //copy in the vrt header (yes we left space) + std::memcpy(items - num_header_words32, vrt_hdr, num_header_words32); + asio::const_buffer send_buff(items - num_header_words32, num_packet_words32*sizeof(uint32_t)); + + //send and return number of samples + _data_transport->send(send_buff); return num_samps; } /*********************************************************************** diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 51082df15..752feb05b 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -209,11 +209,11 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ return; case DEVICE_PROP_MAX_RX_SAMPLES: - val = size_t(_max_samples_per_packet); + val = size_t(_max_rx_samples_per_packet); return; case DEVICE_PROP_MAX_TX_SAMPLES: - val = size_t(_max_samples_per_packet); + val = size_t(_max_tx_samples_per_packet); return; } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index a58bf8471..083ad7096 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -104,20 +105,20 @@ public: private: //the raw io interface (samples are in the usrp2 native format) - size_t send_raw(const uhd::metadata_t &); void recv_raw(uhd::metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; uhd::dict _rx_stream_id_to_packet_seq; static const size_t _mtu = 1500; //FIXME we have no idea - static const size_t _max_samples_per_packet = - _mtu/sizeof(uint32_t) - + static const size_t _hdrs = (2 + 14 + 20 + 8); //size of headers (pad, eth, ip, udp) + static const size_t _max_rx_samples_per_packet = + (_mtu - _hdrs)/sizeof(uint32_t) - USRP2_HOST_RX_VRT_HEADER_WORDS32 - - USRP2_HOST_RX_VRT_TRAILER_WORDS32 - - ((2 + 14 + 20 + 8)/sizeof(uint32_t)) //size of headers (pad, eth, ip, udp) + USRP2_HOST_RX_VRT_TRAILER_WORDS32 + ; + static const size_t _max_tx_samples_per_packet = + (_mtu - _hdrs)/sizeof(uint32_t) - + uhd::transport::vrt::max_header_words32 ; - static const size_t _tx_vrt_max_offset_words32 = 7; //TODO move to future vrt lib - uint32_t _tx_mem[_mtu/sizeof(uint32_t)]; - boost::asio::const_buffer _tx_copy_buff; uhd::transport::smart_buffer::sptr _rx_smart_buff; boost::asio::const_buffer _rx_copy_buff; void io_init(void); diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp index 9b2d43430..a4fad78fc 100644 --- a/host/test/vrt_test.cpp +++ b/host/test/vrt_test.cpp @@ -27,6 +27,7 @@ static void pack_and_unpack( ){ uint32_t header_buff[vrt::max_header_words32]; size_t num_header_words32; + size_t num_packet_words32; //pack metadata into a vrt header vrt::pack( @@ -34,6 +35,7 @@ static void pack_and_unpack( header_buff, //output num_header_words32, //output num_payload_words32, //input + num_packet_words32, //output packet_count //input ); @@ -48,6 +50,7 @@ static void pack_and_unpack( header_buff, //input num_header_words32_out, //output num_payload_words32_out, //output + num_packet_words32, //input packet_count_out //output ); -- cgit v1.2.3 From 8e9a8464386db03a596e0b88d0714d22723d37d0 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 10 Mar 2010 14:47:03 -0800 Subject: Added simple device to handle wrapping general properties up into simple api. Added setting time capability to the usrp2 impl. Messing with props and time specs... --- firmware/microblaze/apps/txrx.c | 10 ++ host/apps/discover_usrps.cpp | 2 +- host/include/uhd/CMakeLists.txt | 1 + host/include/uhd/props.hpp | 20 +-- host/include/uhd/simple_device.hpp | 111 +++++++++++++ host/include/uhd/time_spec.hpp | 19 ++- host/include/uhd/utils.hpp | 105 ++++++------- host/lib/CMakeLists.txt | 2 + host/lib/simple_device.cpp | 303 ++++++++++++++++++++++++++++++++++++ host/lib/time_spec.cpp | 40 +++++ host/lib/usrp/usrp2/dboard_impl.cpp | 9 +- host/lib/usrp/usrp2/dsp_impl.cpp | 21 +-- host/lib/usrp/usrp2/fw_common.h | 8 + host/lib/usrp/usrp2/mboard_impl.cpp | 35 ++++- host/lib/usrp/usrp2/usrp2_impl.hpp | 1 + 15 files changed, 591 insertions(+), 96 deletions(-) create mode 100644 host/include/uhd/simple_device.hpp create mode 100644 host/lib/simple_device.cpp create mode 100644 host/lib/time_spec.cpp (limited to 'host/apps/discover_usrps.cpp') diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index 1b3299150..18bbdd23d 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -489,6 +489,16 @@ void handle_udp_ctrl_packet( ctrl_data_out.id = USRP2_CTRL_ID_TOTALLY_SETUP_THE_DUC_DUDE; break; + /******************************************************************* + * Time Config + ******************************************************************/ + case USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO: + sr_time64->imm = (ctrl_data_in->data.time_args.now == 0)? 0 : 1; + sr_time64->ticks = ctrl_data_in->data.time_args.ticks; + sr_time64->secs = ctrl_data_in->data.time_args.secs; //set this last to latch the regs + ctrl_data_out.id = USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE; + break; + default: ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT; diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 448095726..d670d1651 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -63,7 +63,7 @@ int main(int argc, char *argv[]){ std::cout << "-- USRP Device " << i << std::endl; std::cout << "--------------------------------------------------" << std::endl; std::cout << device_addrs[i] << std::endl << std::endl; - //uhd::device::make(device_addrs[i]); //test make + uhd::device::make(device_addrs[i]); //test make } return 0; diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index f4fb96786..522f43afd 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -26,6 +26,7 @@ INSTALL(FILES gain_handler.hpp metadata.hpp props.hpp + simple_device.hpp time_spec.hpp utils.hpp wax.hpp diff --git a/host/include/uhd/props.hpp b/host/include/uhd/props.hpp index cf301d4bd..dea2baf52 100644 --- a/host/include/uhd/props.hpp +++ b/host/include/uhd/props.hpp @@ -116,16 +116,16 @@ namespace uhd{ enum dboard_prop_t{ DBOARD_PROP_NAME, //ro, std::string DBOARD_PROP_SUBDEV, //ro, wax::obj - DBOARD_PROP_SUBDEV_NAMES, //ro, prop_names_t - DBOARD_PROP_CODEC //ro, wax::obj - }; + DBOARD_PROP_SUBDEV_NAMES //ro, prop_names_t + //DBOARD_PROP_CODEC //ro, wax::obj //----> not sure, dont have to deal with yet + }; - /*! + /*! ------ not dealing with yet, commented out ------------ * Possible device codec properties: * A codec is expected to have a rate and gain elements. * Other properties can be discovered through the others prop. */ - enum codec_prop_t{ + /*enum codec_prop_t{ CODEC_PROP_NAME, //ro, std::string CODEC_PROP_OTHERS, //ro, prop_names_t CODEC_PROP_GAIN, //rw, gain_t @@ -133,8 +133,8 @@ namespace uhd{ CODEC_PROP_GAIN_MIN, //ro, gain_t CODEC_PROP_GAIN_STEP, //ro, gain_t CODEC_PROP_GAIN_NAMES, //ro, prop_names_t - CODEC_PROP_CLOCK_RATE //ro, freq_t - }; + //CODEC_PROP_CLOCK_RATE //ro, freq_t //----> not sure we care to know + };*/ /*! * Possible device subdev properties @@ -156,9 +156,9 @@ namespace uhd{ SUBDEV_PROP_QUADRATURE, //ro, bool SUBDEV_PROP_IQ_SWAPPED, //ro, bool SUBDEV_PROP_SPECTRUM_INVERTED, //ro, bool - SUBDEV_PROP_IS_TX, //ro, bool - SUBDEV_PROP_RSSI, //ro, gain_t - SUBDEV_PROP_BANDWIDTH //rw, freq_t + SUBDEV_PROP_LO_INTERFERES //ro, bool + //SUBDEV_PROP_RSSI, //ro, gain_t //----> not on all boards, use named prop + //SUBDEV_PROP_BANDWIDTH //rw, freq_t //----> not on all boards, use named prop }; } //namespace uhd diff --git a/host/include/uhd/simple_device.hpp b/host/include/uhd/simple_device.hpp new file mode 100644 index 000000000..64ec85a5c --- /dev/null +++ b/host/include/uhd/simple_device.hpp @@ -0,0 +1,111 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include +#include +#include +#include + +#ifndef INCLUDED_UHD_SIMPLE_DEVICE_HPP +#define INCLUDED_UHD_SIMPLE_DEVICE_HPP + +namespace uhd{ + +/*! + * The tune result struct holds result of a 2-phase tuning: + * The struct hold the result of tuning the dboard as + * the target and actual intermediate frequency. + * The struct hold the result of tuning the DDC/DUC as + * the target and actual digital converter frequency. + * It also tell us weather or not the spectrum is inverted. + */ +struct tune_result_t{ + double target_inter_freq; + double actual_inter_freq; + double target_dxc_freq; + double actual_dxc_freq; + bool spectrum_inverted; + tune_result_t(void); +}; + +/*! + * The simple UHD device class: + * A simple device facilitates ease-of-use for most use-case scenarios. + * The wrapper provides convenience functions to tune the devices + * as well as to set the dboard gains, antennas, and other properties. + */ +class simple_device : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + static sptr make(const std::string &args); + + virtual device::sptr get_device(void) = 0; + + virtual std::string get_name(void) = 0; + + /******************************************************************* + * Streaming + ******************************************************************/ + virtual void set_streaming(bool enb) = 0; + virtual bool get_streaming(void) = 0; + + /******************************************************************* + * RX methods + ******************************************************************/ + virtual void set_rx_rate(double rate) = 0; + virtual double get_rx_rate(void) = 0; + virtual std::vector get_rx_rates(void) = 0; + + virtual tune_result_t set_rx_freq(double target_freq, double lo_offset) = 0; + virtual double get_rx_freq_min(void) = 0; + virtual double get_rx_freq_max(void) = 0; + + virtual void set_rx_gain(float gain) = 0; + virtual float get_rx_gain(void) = 0; + virtual float get_rx_gain_min(void) = 0; + virtual float get_rx_gain_max(void) = 0; + virtual float get_rx_gain_step(void) = 0; + + virtual void set_rx_antenna(const std::string &ant) = 0; + virtual std::string get_rx_antenna(void) = 0; + virtual std::vector get_rx_antennas(void) = 0; + + /******************************************************************* + * TX methods + ******************************************************************/ + virtual void set_tx_rate(double rate) = 0; + virtual double get_tx_rate(void) = 0; + virtual std::vector get_tx_rates(void) = 0; + + virtual tune_result_t set_tx_freq(double target_freq, double lo_offset) = 0; + virtual double get_tx_freq_min(void) = 0; + virtual double get_tx_freq_max(void) = 0; + + virtual void set_tx_gain(float gain) = 0; + virtual float get_tx_gain(void) = 0; + virtual float get_tx_gain_min(void) = 0; + virtual float get_tx_gain_max(void) = 0; + virtual float get_tx_gain_step(void) = 0; + + virtual void set_tx_antenna(const std::string &ant) = 0; + virtual std::string get_tx_antenna(void) = 0; + virtual std::vector get_tx_antennas(void) = 0; +}; + +} //namespace uhd + +#endif /* INCLUDED_UHD_SIMPLE_DEVICE_HPP */ diff --git a/host/include/uhd/time_spec.hpp b/host/include/uhd/time_spec.hpp index e5657e555..7e182236b 100644 --- a/host/include/uhd/time_spec.hpp +++ b/host/include/uhd/time_spec.hpp @@ -15,6 +15,7 @@ // along with this program. If not, see . // +#include #include #ifndef INCLUDED_UHD_TIME_SPEC_HPP @@ -36,20 +37,22 @@ namespace uhd{ * Create a time_spec_t that holds a wildcard time. * This will have implementation-specific meaning. */ - time_spec_t(void){ - secs = ~0; - ticks = ~0; - } + time_spec_t(void); /*! * Create a time_spec_t from seconds and ticks. * \param new_secs the new seconds * \param new_ticks the new ticks (default = 0) */ - time_spec_t(uint32_t new_secs, uint32_t new_ticks = 0){ - secs = new_secs; - ticks = new_ticks; - } + time_spec_t(uint32_t new_secs, uint32_t new_ticks = 0); + + /*! + * Create a time_spec_t from boost posix time. + * \param time fine-grained boost posix time + * \param tick_rate the rate of ticks per second + */ + time_spec_t(boost::posix_time::ptime time, double tick_rate); + }; } //namespace uhd diff --git a/host/include/uhd/utils.hpp b/host/include/uhd/utils.hpp index 9bbdc83c9..25a7b5abd 100644 --- a/host/include/uhd/utils.hpp +++ b/host/include/uhd/utils.hpp @@ -15,18 +15,14 @@ // along with this program. If not, see . // -#include -#include -#include -#include -#include -#include -#include -#include - #ifndef INCLUDED_UHD_UTILS_HPP #define INCLUDED_UHD_UTILS_HPP +#include +#include +#include +#include + /*! * Useful templated functions and classes that I like to pretend are part of stl */ @@ -40,7 +36,9 @@ namespace std{ }; #define ASSERT_THROW(_x) if (not (_x)) { \ - throw std::assert_error("Assertion Failed: " + std::string(#_x)); \ + throw std::assert_error(str(boost::format( \ + "Assertion Failed:\n %s:%d\n %s\n __/ %s __/" \ + ) % __FILE__ % __LINE__ % BOOST_CURRENT_FUNCTION % std::string(#_x))); \ } template @@ -57,9 +55,9 @@ namespace std{ return last != std::find(first, last, elem); } - template - bool has(const V &vector, const T &elem){ - return has(vector.begin(), vector.end(), elem); + template + bool has(const Iterable &iterable, const T &elem){ + return has(iterable.begin(), iterable.end(), elem); } template @@ -75,52 +73,43 @@ namespace std{ }//namespace std -/*namespace uhd{ - -inline void tune( - freq_t target_freq, - freq_t lo_offset, - wax::obj subdev_freq_proxy, - bool subdev_quadrature, - bool subdev_spectrum_inverted, - bool subdev_is_tx, - wax::obj dsp_freq_proxy, - freq_t dsp_sample_rate -){ - // Ask the d'board to tune as closely as it can to target_freq+lo_offset - subdev_freq_proxy = target_freq + lo_offset; - freq_t inter_freq = wax::cast(subdev_freq_proxy); - - // Calculate the DDC setting that will downconvert the baseband from the - // daughterboard to our target frequency. - freq_t delta_freq = target_freq - inter_freq; - freq_t delta_sign = std::signum(delta_freq); - delta_freq *= delta_sign; - delta_freq = fmod(delta_freq, dsp_sample_rate); - bool inverted = delta_freq > dsp_sample_rate/2.0; - freq_t dxc_freq = inverted? (delta_freq - dsp_sample_rate) : (-delta_freq); - dxc_freq *= delta_sign; - - // If the spectrum is inverted, and the daughterboard doesn't do - // quadrature downconversion, we can fix the inversion by flipping the - // sign of the dxc_freq... (This only happens using the basic_rx board) - if (subdev_spectrum_inverted){ - inverted = not inverted; - } - if (inverted and not subdev_quadrature){ - dxc_freq = -dxc_freq; - inverted = not inverted; - } - if (subdev_is_tx){ - dxc_freq = -dxc_freq; // down conversion versus up conversion +#include +#include +#include + +namespace uhd{ + + /*! + * Check that an element is found in a container. + * If not, throw a meaningful assertion error. + * The "what" in the error will show what is + * being set and a list of known good values. + * + * \param iterable a list of possible settings + * \param elem an element that may be in the list + * \param what a description of what is being set + * \throw assertion_error when elem not in list + */ + template void assert_has( + const Iterable &iterable, + const T &elem, + const std::string &what = "unknown" + ){ + if (std::has(iterable, elem)) return; + std::string possible_values = ""; + BOOST_FOREACH(T e, iterable){ + if (e != iterable.begin()[0]) possible_values += ", "; + possible_values += boost::lexical_cast(e); + } + throw std::assert_error(str(boost::format( + "Error: %s is not a valid %s. " + "Possible values are: [%s]." + ) + % boost::lexical_cast(elem) + % what % possible_values + )); } - dsp_freq_proxy = dxc_freq; - //freq_t actual_dxc_freq = wax::cast(dsp_freq_proxy); - - //return some kind of tune result tuple/struct -} - -} //namespace uhd*/ +}//namespace uhd #endif /* INCLUDED_UHD_UTILS_HPP */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index b1daf22d1..b141d67bb 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -23,6 +23,8 @@ SET(libuhd_sources device_addr.cpp gain_handler.cpp metadata.cpp + simple_device.cpp + time_spec.cpp wax.cpp transport/udp_simple.cpp transport/vrt.cpp diff --git a/host/lib/simple_device.cpp b/host/lib/simple_device.cpp new file mode 100644 index 000000000..63a17c52d --- /dev/null +++ b/host/lib/simple_device.cpp @@ -0,0 +1,303 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; + +tune_result_t::tune_result_t(void){ + /* NOP */ +} + +/*********************************************************************** + * Tune Helper Function + **********************************************************************/ +static tune_result_t tune( + double target_freq, + double lo_offset, + wax::obj subdev, + wax::obj dxc, + bool is_tx +){ + wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; + bool subdev_quadrature = wax::cast(subdev[SUBDEV_PROP_QUADRATURE]); + bool subdev_spectrum_inverted = wax::cast(subdev[SUBDEV_PROP_SPECTRUM_INVERTED]); + wax::obj dxc_freq_proxy = dxc[std::string("freq")]; + double dxc_sample_rate = wax::cast(dxc[std::string("rate")]); + + // Ask the d'board to tune as closely as it can to target_freq+lo_offset + double target_inter_freq = target_freq + lo_offset; + subdev_freq_proxy = target_inter_freq; + double actual_inter_freq = wax::cast(subdev_freq_proxy); + + // Calculate the DDC setting that will downconvert the baseband from the + // daughterboard to our target frequency. + double delta_freq = target_freq - actual_inter_freq; + double delta_sign = std::signum(delta_freq); + delta_freq *= delta_sign; + delta_freq = fmod(delta_freq, dxc_sample_rate); + bool inverted = delta_freq > dxc_sample_rate/2.0; + double target_dxc_freq = inverted? (delta_freq - dxc_sample_rate) : (-delta_freq); + target_dxc_freq *= delta_sign; + + // If the spectrum is inverted, and the daughterboard doesn't do + // quadrature downconversion, we can fix the inversion by flipping the + // sign of the dxc_freq... (This only happens using the basic_rx board) + if (subdev_spectrum_inverted){ + inverted = not inverted; + } + if (inverted and not subdev_quadrature){ + target_dxc_freq *= -1.0; + inverted = not inverted; + } + // down conversion versus up conversion, fight! + // your mother is ugly and your going down... + target_dxc_freq *= (is_tx)? -1.0 : +1.0; + + dxc_freq_proxy = target_dxc_freq; + double actual_dxc_freq = wax::cast(dxc_freq_proxy); + + //return some kind of tune result tuple/struct + tune_result_t tune_result; + tune_result.target_inter_freq = target_inter_freq; + tune_result.actual_inter_freq = actual_inter_freq; + tune_result.target_dxc_freq = target_dxc_freq; + tune_result.actual_dxc_freq = actual_dxc_freq; + tune_result.spectrum_inverted = inverted; + return tune_result; +} + +/*********************************************************************** + * Helper Functions + **********************************************************************/ +static std::string trim(const std::string &in){ + return boost::algorithm::trim_copy(in); +} + +device_addr_t args_to_device_addr(const std::string &args){ + device_addr_t addr; + + //split the args at the semi-colons + std::vector pairs; + boost::split(pairs, args, boost::is_any_of(";")); + BOOST_FOREACH(std::string pair, pairs){ + if (trim(pair) == "") continue; + + //split the key value pairs at the equals + std::vector key_val; + boost::split(key_val, pair, boost::is_any_of("=")); + if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args); + addr[trim(key_val[0])] = trim(key_val[1]); + } + + return addr; +} + +static std::vector get_xx_rates(wax::obj decerps, wax::obj rate){ + std::vector rates; + BOOST_FOREACH(size_t decerp, wax::cast >(decerps)){ + rates.push_back(wax::cast(rate)/decerp); + } + return rates; +} + +/*********************************************************************** + * Simple Device Implementation + **********************************************************************/ +class simple_device_impl : public simple_device{ +public: + simple_device_impl(const device_addr_t &addr){ + _dev = device::make(addr); + _mboard = (*_dev)[DEVICE_PROP_MBOARD]; + _rx_ddc = _mboard[named_prop_t(MBOARD_PROP_RX_DSP, "ddc0")]; + _tx_duc = _mboard[named_prop_t(MBOARD_PROP_TX_DSP, "duc0")]; + _rx_subdev = _mboard[MBOARD_PROP_RX_DBOARD][DBOARD_PROP_SUBDEV]; + _tx_subdev = _mboard[MBOARD_PROP_TX_DBOARD][DBOARD_PROP_SUBDEV]; + } + + ~simple_device_impl(void){ + /* NOP */ + } + + device::sptr get_device(void){ + return _dev; + } + + std::string get_name(void){ + return wax::cast(_mboard[MBOARD_PROP_NAME]); + } + + /******************************************************************* + * Streaming + ******************************************************************/ + void set_streaming(bool enb){ + _rx_ddc[std::string("enabled")] = enb; + } + + bool get_streaming(void){ + return wax::cast(_rx_ddc[std::string("enabled")]); + } + + /******************************************************************* + * RX methods + ******************************************************************/ + void set_rx_rate(double rate){ + double samp_rate = wax::cast(_rx_ddc[std::string("rate")]); + assert_has(get_rx_rates(), rate, "simple device rx rate"); + _rx_ddc[std::string("decim")] = size_t(samp_rate/rate); + } + + double get_rx_rate(void){ + double samp_rate = wax::cast(_rx_ddc[std::string("rate")]); + size_t decim = wax::cast(_rx_ddc[std::string("decim")]); + return samp_rate/decim; + } + + std::vector get_rx_rates(void){ + return get_xx_rates(_rx_ddc[std::string("decims")], _rx_ddc[std::string("rate")]); + } + + tune_result_t set_rx_freq(double target_freq, double lo_offset){ + return tune(target_freq, lo_offset, _rx_subdev, _rx_ddc, false/* not tx */); + } + + double get_rx_freq_min(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_FREQ_MIN]); + } + + double get_rx_freq_max(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_FREQ_MAX]); + } + + void set_rx_gain(float gain){ + _rx_subdev[SUBDEV_PROP_GAIN] = gain; + } + + float get_rx_gain(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN]); + } + + float get_rx_gain_min(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN_MIN]); + } + + float get_rx_gain_max(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN_MAX]); + } + + float get_rx_gain_step(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN_STEP]); + } + + void set_rx_antenna(const std::string &ant){ + _rx_subdev[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_rx_antenna(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_ANTENNA]); + } + + std::vector get_rx_antennas(void){ + return wax::cast >(_rx_subdev[SUBDEV_PROP_ANTENNA_NAMES]); + } + + /******************************************************************* + * TX methods + ******************************************************************/ + void set_tx_rate(double rate){ + double samp_rate = wax::cast(_tx_duc[std::string("rate")]); + assert_has(get_tx_rates(), rate, "simple device tx rate"); + _tx_duc[std::string("interp")] = size_t(samp_rate/rate); + } + + double get_tx_rate(void){ + double samp_rate = wax::cast(_tx_duc[std::string("rate")]); + size_t interp = wax::cast(_tx_duc[std::string("interp")]); + return samp_rate/interp; + } + + std::vector get_tx_rates(void){ + return get_xx_rates(_tx_duc[std::string("interps")], _tx_duc[std::string("rate")]); + } + + tune_result_t set_tx_freq(double target_freq, double lo_offset){ + return tune(target_freq, lo_offset, _tx_subdev, _tx_duc, true/* is tx */); + } + + double get_tx_freq_min(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_FREQ_MIN]); + } + + double get_tx_freq_max(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_FREQ_MAX]); + } + + void set_tx_gain(float gain){ + _tx_subdev[SUBDEV_PROP_GAIN] = gain; + } + + float get_tx_gain(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN]); + } + + float get_tx_gain_min(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN_MIN]); + } + + float get_tx_gain_max(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN_MAX]); + } + + float get_tx_gain_step(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN_STEP]); + } + + void set_tx_antenna(const std::string &ant){ + _tx_subdev[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_tx_antenna(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_ANTENNA]); + } + + std::vector get_tx_antennas(void){ + return wax::cast >(_tx_subdev[SUBDEV_PROP_ANTENNA_NAMES]); + } + +private: + device::sptr _dev; + wax::obj _mboard; + wax::obj _rx_ddc; + wax::obj _tx_duc; + wax::obj _rx_subdev; + wax::obj _tx_subdev; +}; + +/*********************************************************************** + * The Make Function + **********************************************************************/ +simple_device::sptr simple_device::make(const std::string &args){ + return sptr(new simple_device_impl(args_to_device_addr(args))); +} diff --git a/host/lib/time_spec.cpp b/host/lib/time_spec.cpp new file mode 100644 index 000000000..193441342 --- /dev/null +++ b/host/lib/time_spec.cpp @@ -0,0 +1,40 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include + +using namespace uhd; + +time_spec_t::time_spec_t(void){ + secs = ~0; + ticks = ~0; +} + +time_spec_t::time_spec_t(uint32_t new_secs, uint32_t new_ticks){ + secs = new_secs; + ticks = new_ticks; +} + +static const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); +static double time_tick_rate(boost::posix_time::time_duration::ticks_per_second()); + +time_spec_t::time_spec_t(boost::posix_time::ptime time, double tick_rate){ + boost::posix_time::time_duration td = time - epoch; + secs = td.total_seconds(); + double time_ticks_per_device_ticks = time_tick_rate/tick_rate; + ticks = td.fractional_seconds()/time_ticks_per_device_ticks; +} diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 32c64f541..da05c3241 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -16,6 +16,7 @@ // #include +#include #include "usrp2_impl.hpp" #include "dboard_interface.hpp" @@ -83,8 +84,8 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ val = _dboard_manager->get_rx_subdev_names(); return; - case DBOARD_PROP_CODEC: - throw std::runtime_error("unhandled prop in usrp2 dboard"); + //case DBOARD_PROP_CODEC: + // throw std::runtime_error("unhandled prop in usrp2 dboard"); } } @@ -113,8 +114,8 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ val = _dboard_manager->get_tx_subdev_names(); return; - case DBOARD_PROP_CODEC: - throw std::runtime_error("unhandled prop in usrp2 dboard"); + //case DBOARD_PROP_CODEC: + // throw std::runtime_error("unhandled prop in usrp2 dboard"); } } diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 7831b7667..cb7f58ec8 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -16,6 +16,7 @@ // #include +#include #include #include "usrp2_impl.hpp" @@ -110,7 +111,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ prop_names_t others = boost::assign::list_of ("rate") ("decim") - ("decim_rates") + ("decims") ("freq") ("enabled") ("stream_at") @@ -131,7 +132,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ val = _ddc_decim; return; } - else if (key_name == "decim_rates"){ + else if (key_name == "decims"){ val = _allowed_decim_and_interp_rates; return; } @@ -154,10 +155,10 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ std::string key_name = wax::cast(key); if (key_name == "decim"){ size_t new_decim = wax::cast(val); - ASSERT_THROW(std::has( + assert_has( _allowed_decim_and_interp_rates, - new_decim - )); + new_decim, "usrp2 decimation" + ); _ddc_decim = new_decim; //shadow update_ddc_config(); return; @@ -244,7 +245,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ prop_names_t others = boost::assign::list_of ("rate") ("interp") - ("interp_rates") + ("interps") ("freq") ; val = others; @@ -263,7 +264,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ val = _duc_interp; return; } - else if (key_name == "interp_rates"){ + else if (key_name == "interps"){ val = _allowed_decim_and_interp_rates; return; } @@ -282,10 +283,10 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){ std::string key_name = wax::cast(key); if (key_name == "interp"){ size_t new_interp = wax::cast(val); - ASSERT_THROW(std::has( + assert_has( _allowed_decim_and_interp_rates, - new_interp - )); + new_interp, "usrp2 interpolation" + ); _duc_interp = new_interp; //shadow update_duc_config(); return; diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 8e4b2ba35..10c1ef8cf 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -91,6 +91,9 @@ typedef enum{ USRP2_CTRL_ID_SETUP_THIS_DUC_FOR_ME_BRO, USRP2_CTRL_ID_TOTALLY_SETUP_THE_DUC_DUDE, + USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO, + USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE, + USRP2_CTRL_ID_PEACE_OUT } usrp2_ctrl_id_t; @@ -186,6 +189,11 @@ typedef struct{ uint32_t interp; uint32_t scale_iq; } duc_args; + struct { + uint32_t secs; + uint32_t ticks; + uint8_t now; + } time_args; } data; } usrp2_ctrl_data_t; diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 8e682a675..47e22c473 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -28,6 +28,10 @@ void usrp2_impl::mboard_init(void){ boost::bind(&usrp2_impl::mboard_get, this, _1, _2), boost::bind(&usrp2_impl::mboard_set, this, _1, _2) ); + + //set the time on the usrp2 as close as possible to the system utc time + boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time()); + set_time_spec(time_spec_t(now, get_master_clock_freq()), true); } void usrp2_impl::init_clock_config(void){ @@ -64,6 +68,19 @@ void usrp2_impl::update_clock_config(void){ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THE_NEW_CLOCK_CONFIG_DUDE); } +void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ + //setup the out data + usrp2_ctrl_data_t out_data; + out_data.id = htonl(USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO); + out_data.data.time_args.secs = htonl(time_spec.secs); + out_data.data.time_args.ticks = htonl(time_spec.ticks); + out_data.data.time_args.now = (now)? 1 : 0; + + //send and recv + usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE); +} + /*********************************************************************** * MBoard Get Properties **********************************************************************/ @@ -157,7 +174,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_PPS_SOURCE:{ std::string name = wax::cast(val); - ASSERT_THROW(_pps_source_dict.has_key(name)); + assert_has(_pps_source_dict.get_keys(), name, "usrp2 pps source"); _pps_source = name; //shadow update_clock_config(); } @@ -165,7 +182,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_PPS_POLARITY:{ std::string name = wax::cast(val); - ASSERT_THROW(_pps_polarity_dict.has_key(name)); + assert_has(_pps_polarity_dict.get_keys(), name, "usrp2 pps polarity"); _pps_polarity = name; //shadow update_clock_config(); } @@ -173,12 +190,22 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_REF_SOURCE:{ std::string name = wax::cast(val); - ASSERT_THROW(_ref_source_dict.has_key(name)); + assert_has(_ref_source_dict.get_keys(), name, "usrp2 reference source"); _ref_source = name; //shadow update_clock_config(); } return; + case MBOARD_PROP_TIME_NOW:{ + set_time_spec(wax::cast(val), true); + return; + } + + case MBOARD_PROP_TIME_NEXT_PPS:{ + set_time_spec(wax::cast(val), false); + return; + } + case MBOARD_PROP_NAME: case MBOARD_PROP_OTHERS: case MBOARD_PROP_CLOCK_RATE: @@ -192,8 +219,6 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_TX_DBOARD_NAMES: case MBOARD_PROP_PPS_SOURCE_NAMES: case MBOARD_PROP_REF_SOURCE_NAMES: - case MBOARD_PROP_TIME_NOW: - case MBOARD_PROP_TIME_NEXT_PPS: throw std::runtime_error("Error: trying to set read-only property on usrp2 mboard"); } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index f4e6054bd..fc713c2bf 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -135,6 +135,7 @@ private: std::string _pps_source, _pps_polarity, _ref_source; void init_clock_config(void); void update_clock_config(void); + void set_time_spec(const uhd::time_spec_t &time_spec, bool now); //mappings from clock config strings to over the wire enums uhd::dict _pps_source_dict; -- cgit v1.2.3