diff options
-rw-r--r-- | firmware/zpu/apps/txrx_uhd.c | 33 | ||||
-rw-r--r-- | firmware/zpu/lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | firmware/zpu/lib/net_common.c | 4 | ||||
-rw-r--r-- | firmware/zpu/lib/udp_uart.c | 115 | ||||
-rw-r--r-- | firmware/zpu/lib/udp_uart.h | 36 | ||||
-rw-r--r-- | firmware/zpu/usrp2/CMakeLists.txt | 1 | ||||
-rw-r--r-- | firmware/zpu/usrp2p/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/include/uhd/transport/udp_simple.hpp | 8 | ||||
-rw-r--r-- | host/include/uhd/types/serial.hpp | 8 | ||||
-rw-r--r-- | host/include/uhd/usrp/gps_ctrl.hpp | 15 | ||||
-rw-r--r-- | host/lib/transport/udp_simple.cpp | 46 | ||||
-rw-r--r-- | host/lib/usrp/e100/codec_ctrl.cpp | 16 | ||||
-rw-r--r-- | host/lib/usrp/e100/e100_ctrl.cpp | 69 | ||||
-rw-r--r-- | host/lib/usrp/e100/e100_ctrl.hpp | 3 | ||||
-rw-r--r-- | host/lib/usrp/e100/e100_impl.cpp | 25 | ||||
-rw-r--r-- | host/lib/usrp/e100/e100_impl.hpp | 3 | ||||
-rw-r--r-- | host/lib/usrp/gps_ctrl.cpp | 44 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/fw_common.h | 14 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_iface.cpp | 60 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_iface.hpp | 9 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 9 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 2 |
22 files changed, 379 insertions, 143 deletions
diff --git a/firmware/zpu/apps/txrx_uhd.c b/firmware/zpu/apps/txrx_uhd.c index dfb484bc5..f9eedfc7d 100644 --- a/firmware/zpu/apps/txrx_uhd.c +++ b/firmware/zpu/apps/txrx_uhd.c @@ -32,6 +32,7 @@ #include "usrp2/fw_common.h" #include "udp_fw_update.h" #include "pkt_ctrl.h" +#include "udp_uart.h" //standard headers #include <stddef.h> @@ -109,7 +110,7 @@ static void handle_udp_ctrl_packet( //ensure that the protocol versions match if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_FW_COMPAT_NUM){ - printf("!Error in control packet handler: Expected compatibility number %d, but got %d\n", + if (ctrl_data_in->proto_ver) printf("!Error in control packet handler: Expected compatibility number %d, but got %d\n", USRP2_FW_COMPAT_NUM, ctrl_data_in->proto_ver ); ctrl_data_in_id = USRP2_CTRL_ID_WAZZUP_BRO; @@ -221,31 +222,6 @@ static void handle_udp_ctrl_packet( break; /******************************************************************* - * UART Control - ******************************************************************/ - case USRP2_CTRL_ID_SO_LIKE_CAN_YOU_READ_THIS_UART_BRO:{ - //executes a readline()-style read, up to num_bytes long, up to and including newline - int num_bytes = ctrl_data_in->data.uart_args.bytes; - if(num_bytes > 20) num_bytes = 20; - num_bytes = fngets_noblock(ctrl_data_in->data.uart_args.dev, (char *) ctrl_data_out.data.uart_args.data, num_bytes); - ctrl_data_out.id = USRP2_CTRL_ID_I_HELLA_READ_THAT_UART_DUDE; - ctrl_data_out.data.uart_args.bytes = num_bytes; - break; - } - - case USRP2_CTRL_ID_HEY_WRITE_THIS_UART_FOR_ME_BRO:{ - int num_bytes = ctrl_data_in->data.uart_args.bytes; - if(num_bytes > 20) num_bytes = 20; - //before we write to the UART, we flush the receive buffer - //this assumes that we're interested in the reply - hal_uart_rx_flush(ctrl_data_in->data.uart_args.dev); - fnputstr(ctrl_data_in->data.uart_args.dev, (char *) ctrl_data_in->data.uart_args.data, num_bytes); - ctrl_data_out.id = USRP2_CTRL_ID_MAN_I_TOTALLY_WROTE_THAT_UART_DUDE; - ctrl_data_out.data.uart_args.bytes = num_bytes; - break; - } - - /******************************************************************* * Echo test ******************************************************************/ case USRP2_CTRL_ID_HOLLER_AT_ME_BRO: @@ -336,10 +312,13 @@ main(void) register_udp_listener(USRP2_UDP_RX_DSP0_PORT, handle_udp_data_packet); register_udp_listener(USRP2_UDP_RX_DSP1_PORT, handle_udp_data_packet); register_udp_listener(USRP2_UDP_TX_DSP0_PORT, handle_udp_data_packet); + #ifdef USRP2P register_udp_listener(USRP2_UDP_UPDATE_PORT, handle_udp_fw_update_packet); #endif + udp_uart_init(USRP2_UDP_UART_BASE_PORT); //setup uart messaging + //3) set the routing mode to slave to set defaults pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_SLAVE); @@ -356,6 +335,8 @@ main(void) pkt_ctrl_release_incoming_buffer(); } + udp_uart_poll(); //uart message handling + pic_interrupt_handler(); /* int pending = pic_regs->pending; // poll for under or overrun diff --git a/firmware/zpu/lib/CMakeLists.txt b/firmware/zpu/lib/CMakeLists.txt index 193d63cfa..ce6b7fa44 100644 --- a/firmware/zpu/lib/CMakeLists.txt +++ b/firmware/zpu/lib/CMakeLists.txt @@ -44,4 +44,5 @@ SET(COMMON_SRCS ${CMAKE_SOURCE_DIR}/lib/net_common.c ${CMAKE_SOURCE_DIR}/lib/arp_cache.c ${CMAKE_SOURCE_DIR}/lib/banal.c + ${CMAKE_SOURCE_DIR}/lib/udp_uart.c ) diff --git a/firmware/zpu/lib/net_common.c b/firmware/zpu/lib/net_common.c index 9a3f8c5a5..42e365393 100644 --- a/firmware/zpu/lib/net_common.c +++ b/firmware/zpu/lib/net_common.c @@ -42,7 +42,7 @@ static const bool debug = false; static const size_t out_buff_size = 2048; static const eth_mac_addr_t BCAST_MAC_ADDR = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; -#define MAX_UDP_LISTENERS 6 +#define MAX_UDP_LISTENERS 10 /*********************************************************************** * 16-bit one's complement sum @@ -201,7 +201,7 @@ send_pkt( //create a list of all buffers to copy const void *buffs[] = {&ctrl_word, &ehdr, buf0, buf1, buf2}; - size_t lens[] = {sizeof(ctrl_word), sizeof(ehdr), len0, len1, len2}; + size_t lens[] = {sizeof(ctrl_word), sizeof(ehdr), len0, len1, (len2 + 3) & ~3}; //copy each buffer into the out buffer for (size_t i = 0; i < sizeof(buffs)/sizeof(buffs[0]); i++){ diff --git a/firmware/zpu/lib/udp_uart.c b/firmware/zpu/lib/udp_uart.c new file mode 100644 index 000000000..6f6b9ee91 --- /dev/null +++ b/firmware/zpu/lib/udp_uart.c @@ -0,0 +1,115 @@ +/* + * Copyright 2011 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 <http://www.gnu.org/licenses/>. + */ + +#include "udp_uart.h" +#include "hal_uart.h" +#include "net_common.h" +#include "compiler.h" +#include <stdbool.h> + +/*********************************************************************** + * Constants + **********************************************************************/ +#define MAX_NUM_UARTS 4 +#ifndef UDP_UART_MASK + #error missing definition for UDP_UART_MASK enable mask +#endif +static const size_t num_idle_cyc_b4_flush = 11; //small but lucky number + +/*********************************************************************** + * Globals + **********************************************************************/ +static uint16_t _base_port; + +typedef struct{ + struct socket_address dst; + _AL4 uint8_t buf[256]; + size_t len; //length of buffer + size_t cyc; //idle cycle count +} udp_uart_state_t; + +static udp_uart_state_t _states[MAX_NUM_UARTS]; + +/*********************************************************************** + * UDP handler for UARTs + **********************************************************************/ +static void handle_uart_data_packet( + struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len +){ + //handle ICMP destination unreachable + if (payload == NULL){ + const size_t which = src.port-_base_port; + if (which >= MAX_NUM_UARTS) return; + _states[which].dst.port = 0; + } + + //handle a regular blocking UART write + else{ + const size_t which = dst.port-_base_port; + if (which >= MAX_NUM_UARTS) return; + _states[which].dst = src; + for (size_t i = 0; i < payload_len; i++){ + hal_uart_putc((hal_uart_name_t)which, (int)payload[i]); + } + } +} + +/*********************************************************************** + * Public init function + **********************************************************************/ +void udp_uart_init(const uint16_t base_port){ + _base_port = base_port; + for(size_t i = 0; i < MAX_NUM_UARTS; i++){ + _states[i].dst.port = 0; //reset to null port + _states[i].len = 0; + _states[i].cyc = 0; + register_udp_listener(_base_port+i, handle_uart_data_packet); + } +} + +/*********************************************************************** + * Public poll function + **********************************************************************/ +void udp_uart_poll(void){ + for (size_t i = 0; i < MAX_NUM_UARTS; i++){ + if (((UDP_UART_MASK) & (1 << i)) == 0) continue; + + bool newline = false; + udp_uart_state_t *state = &_states[i]; + + //read all characters we can without blocking + for (size_t j = state->len; j < sizeof(_states[0].buf); j++){ + uint8_t ch = hal_uart_getc_noblock((hal_uart_name_t)i); + if (ch == 255) break; + if (ch == '\n' || ch == '\r') newline = true; + state->buf[j] = ch; + state->len++; + state->cyc = 0; //reset idle cycles + } + + //nothing in buffer, continue to next uart + if (state->len == 0) continue; + + //send out a message if newline or forced flush + if (newline || state->cyc++ > num_idle_cyc_b4_flush){ + if (state->dst.port != 0) send_udp_pkt(_base_port+i, state->dst, state->buf, state->len); + state->len = 0; + state->cyc = 0; + } + } +} diff --git a/firmware/zpu/lib/udp_uart.h b/firmware/zpu/lib/udp_uart.h new file mode 100644 index 000000000..d448e7611 --- /dev/null +++ b/firmware/zpu/lib/udp_uart.h @@ -0,0 +1,36 @@ +/* + * Copyright 2011 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_UDP_UART_H +#define INCLUDED_UDP_UART_H + +#include <stdint.h> + +/*! + * Initialize the UDP/UART module. + * Registers handler into the network. + * \param base_port the source port for UART0 + */ +void udp_uart_init(const uint16_t base_port); + +/*! + * Polls the UART state machine, + * and sends messages over UDP. + */ +void udp_uart_poll(void); + +#endif /* INCLUDED_UDP_UART_H */ diff --git a/firmware/zpu/usrp2/CMakeLists.txt b/firmware/zpu/usrp2/CMakeLists.txt index 190ea9af1..3662532f1 100644 --- a/firmware/zpu/usrp2/CMakeLists.txt +++ b/firmware/zpu/usrp2/CMakeLists.txt @@ -20,6 +20,7 @@ INCLUDE(${CMAKE_SOURCE_DIR}/lib/CMakeLists.txt) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) ADD_DEFINITIONS(-DUSRP2) +ADD_DEFINITIONS(-DUDP_UART_MASK=0) ADD_LIBRARY(libusrp2fw STATIC ${COMMON_SRCS} diff --git a/firmware/zpu/usrp2p/CMakeLists.txt b/firmware/zpu/usrp2p/CMakeLists.txt index 976dccb9a..4cb663742 100644 --- a/firmware/zpu/usrp2p/CMakeLists.txt +++ b/firmware/zpu/usrp2p/CMakeLists.txt @@ -20,6 +20,7 @@ INCLUDE(${CMAKE_SOURCE_DIR}/lib/CMakeLists.txt) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) ADD_DEFINITIONS(-DUSRP2P) +ADD_DEFINITIONS(-DUDP_UART_MASK=4) #GPS=UART2 streaming enabled ADD_LIBRARY(libusrp2pfw STATIC ${COMMON_SRCS} diff --git a/host/include/uhd/transport/udp_simple.hpp b/host/include/uhd/transport/udp_simple.hpp index 83f895ba9..83d1072ee 100644 --- a/host/include/uhd/transport/udp_simple.hpp +++ b/host/include/uhd/transport/udp_simple.hpp @@ -19,6 +19,7 @@ #define INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP #include <uhd/config.hpp> +#include <uhd/types/serial.hpp> #include <boost/asio/buffer.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> @@ -62,6 +63,13 @@ public: static sptr make_broadcast(const std::string &addr, const std::string &port); /*! + * Make a UART interface from a UDP transport. + * \param udp the UDP transport object + * \return a new UART interface + */ + static uart_iface::sptr make_uart(sptr udp); + + /*! * Send a single buffer. * Blocks until the data is sent. * \param buff single asio buffer diff --git a/host/include/uhd/types/serial.hpp b/host/include/uhd/types/serial.hpp index 8a5ed1c32..f66822775 100644 --- a/host/include/uhd/types/serial.hpp +++ b/host/include/uhd/types/serial.hpp @@ -184,17 +184,17 @@ namespace uhd{ /*! * Write to a serial port. - * \param dev which UART to write to * \param buf the data to write */ - virtual void write_uart(boost::uint8_t dev, const std::string &buf) = 0; + virtual void write_uart(const std::string &buf) = 0; /*! * Read from a serial port. - * \param dev which UART to read from + * Reads until complete line or timeout. + * \param timeout the timeout in seconds * \return the data read from the serial port */ - virtual std::string read_uart(boost::uint8_t dev) = 0; + virtual std::string read_uart(double timeout) = 0; }; } //namespace uhd diff --git a/host/include/uhd/usrp/gps_ctrl.hpp b/host/include/uhd/usrp/gps_ctrl.hpp index 6ff00e03c..0c1389d48 100644 --- a/host/include/uhd/usrp/gps_ctrl.hpp +++ b/host/include/uhd/usrp/gps_ctrl.hpp @@ -18,26 +18,23 @@ #ifndef INCLUDED_GPS_CTRL_HPP #define INCLUDED_GPS_CTRL_HPP +#include <uhd/types/serial.hpp> +#include <uhd/types/sensors.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> #include <boost/function.hpp> -#include <boost/date_time/posix_time/posix_time_types.hpp> #include <vector> -#include <uhd/types/sensors.hpp> -using namespace boost::posix_time; +namespace uhd{ -typedef boost::function<void(std::string)> gps_send_fn_t; -typedef boost::function<std::string(void)> gps_recv_fn_t; - -class gps_ctrl : boost::noncopyable{ +class UHD_API gps_ctrl : boost::noncopyable{ public: typedef boost::shared_ptr<gps_ctrl> sptr; /*! * Make a GPS config for Jackson Labs or generic NMEA GPS devices */ - static sptr make(gps_send_fn_t, gps_recv_fn_t); + static sptr make(uart_iface::sptr uart); /*! * Retrieve the list of sensors this GPS object provides @@ -59,4 +56,6 @@ public: }; +} //namespace uhd + #endif /* INCLUDED_GPS_CTRL_HPP */ diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp index ed778fbf4..bc1bdaf2f 100644 --- a/host/lib/transport/udp_simple.cpp +++ b/host/lib/transport/udp_simple.cpp @@ -81,3 +81,49 @@ udp_simple::sptr udp_simple::make_broadcast( ){ return sptr(new udp_simple_impl(addr, port, true, false /* bcast, no connect */)); } + +/*********************************************************************** + * Simple UART over UDP + **********************************************************************/ +#include <boost/thread/thread.hpp> +class udp_simple_uart_impl : public uhd::uart_iface{ +public: + udp_simple_uart_impl(udp_simple::sptr udp){ + _udp = udp; + _len = 0; + _off = 0; + this->write_uart(""); //send an empty packet to init + } + + void write_uart(const std::string &buf){ + _udp->send(asio::buffer(buf)); + } + + std::string read_uart(double timeout){ + std::string line; + const boost::system_time exit_time = boost::get_system_time() + boost::posix_time::milliseconds(long(timeout*1000)); + do{ + //drain anything in current buffer + while (_off < _len){ + const char ch = _buf[_off]; _off++; + line += std::string(1, ch); + if (ch == '\n' or ch == '\r') return line; + } + + //recv a new packet into the buffer + _len = _udp->recv(asio::buffer(_buf), std::max((exit_time - boost::get_system_time()).total_milliseconds()/1000., 0.0)); + _off = 0; + + } while (_len != 0); + return line; + } + +private: + udp_simple::sptr _udp; + size_t _len, _off; + boost::uint8_t _buf[udp_simple::mtu]; +}; + +uhd::uart_iface::sptr udp_simple::make_uart(sptr udp){ + return uart_iface::sptr(new udp_simple_uart_impl(udp)); +} diff --git a/host/lib/usrp/e100/codec_ctrl.cpp b/host/lib/usrp/e100/codec_ctrl.cpp index 6efeb10e8..f3d2a04b5 100644 --- a/host/lib/usrp/e100/codec_ctrl.cpp +++ b/host/lib/usrp/e100/codec_ctrl.cpp @@ -74,14 +74,15 @@ e100_codec_ctrl_impl::e100_codec_ctrl_impl(spi_iface::sptr iface){ _ad9862_regs.soft_reset = 0; //setup rx side of codec - _ad9862_regs.byp_buffer_a = 1; - _ad9862_regs.byp_buffer_b = 1; - _ad9862_regs.buffer_a_pd = 1; - _ad9862_regs.buffer_b_pd = 1; + _ad9862_regs.byp_buffer_a = 0; + _ad9862_regs.byp_buffer_b = 0; + _ad9862_regs.buffer_a_pd = 0; + _ad9862_regs.buffer_b_pd = 0; _ad9862_regs.rx_pga_a = 0;//0x1f; //TODO bring under api control _ad9862_regs.rx_pga_b = 0;//0x1f; //TODO bring under api control _ad9862_regs.rx_twos_comp = 1; _ad9862_regs.rx_hilbert = ad9862_regs_t::RX_HILBERT_DIS; + _ad9862_regs.shared_ref = 1; //setup tx side of codec _ad9862_regs.two_data_paths = ad9862_regs_t::TWO_DATA_PATHS_BOTH; @@ -101,6 +102,12 @@ e100_codec_ctrl_impl::e100_codec_ctrl_impl(spi_iface::sptr iface){ _ad9862_regs.input_clk_ctrl = ad9862_regs_t::INPUT_CLK_CTRL_EXTERNAL; _ad9862_regs.dll_mult = ad9862_regs_t::DLL_MULT_2; _ad9862_regs.dll_mode = ad9862_regs_t::DLL_MODE_FAST; + _ad9862_regs.hs_duty_cycle = 1; + _ad9862_regs.clk_duty = 1; + + //disable clkout1 and clkout2 + _ad9862_regs.dis1 = ad9862_regs_t::DIS1_DIS; + _ad9862_regs.dis2 = ad9862_regs_t::DIS2_DIS; //write the register settings to the codec for (uint8_t addr = 0; addr <= 25; addr++){ @@ -114,6 +121,7 @@ e100_codec_ctrl_impl::e100_codec_ctrl_impl(spi_iface::sptr iface){ //aux adc clock _ad9862_regs.clk_4 = ad9862_regs_t::CLK_4_1_4; this->send_reg(34); + this->send_reg(35); } e100_codec_ctrl_impl::~e100_codec_ctrl_impl(void){ diff --git a/host/lib/usrp/e100/e100_ctrl.cpp b/host/lib/usrp/e100/e100_ctrl.cpp index 87f7855d3..eb529c9c1 100644 --- a/host/lib/usrp/e100/e100_ctrl.cpp +++ b/host/lib/usrp/e100/e100_ctrl.cpp @@ -18,12 +18,14 @@ #include "e100_ctrl.hpp" #include "e100_regs.hpp" #include <uhd/exception.hpp> +#include <uhd/utils/log.hpp> #include <uhd/utils/msg.hpp> #include <sys/ioctl.h> //ioctl #include <fcntl.h> //open, close #include <linux/usrp_e.h> //ioctl structures and constants #include <boost/thread/thread.hpp> //sleep #include <boost/thread/mutex.hpp> +#include <boost/foreach.hpp> #include <boost/format.hpp> #include <fstream> @@ -175,6 +177,73 @@ uhd::i2c_iface::sptr e100_ctrl::make_dev_i2c_iface(const std::string &node){ } /*********************************************************************** + * UART control implementation + **********************************************************************/ +#include <termios.h> +#include <cstring> +class uart_dev_iface : public uart_iface{ +public: + uart_dev_iface(const std::string &node){ + if ((_node_fd = ::open(node.c_str(), O_RDWR | O_NONBLOCK)) < 0){ + throw uhd::io_error("Failed to open " + node); + } + + //init the tty settings w/ termios + termios tio; + std::memset(&tio,0,sizeof(tio)); + tio.c_iflag = IGNCR; //Ignore CR + tio.c_oflag = OPOST | ONLCR; //Map NL to CR-NL on output + tio.c_cflag = CS8 | CREAD | CLOCAL; // 8n1 + tio.c_lflag = 0; + + cfsetospeed(&tio, B115200); // 115200 baud + cfsetispeed(&tio, B115200); // 115200 baud + + tcsetattr(_node_fd, TCSANOW, &tio); + } + + void write_uart(const std::string &buf){ + const ssize_t ret = ::write(_node_fd, buf.c_str(), buf.size()); + if (size_t(ret) != buf.size()) UHD_LOG << ret; + } + + std::string read_uart(double timeout){ + const boost::system_time exit_time = boost::get_system_time() + boost::posix_time::milliseconds(long(timeout*1000)); + + std::string line; + while(true){ + char ch; + const ssize_t ret = ::read(_node_fd, &ch, 1); + + //got a character -> process it + if (ret == 1){ + const bool flush = ch == '\n' or ch == '\r'; + if (flush and line.empty()) continue; //avoid flushing on empty lines + line += std::string(1, ch); + if (flush) break; + } + + //didnt get a character, check the timeout + else if (boost::get_system_time() > exit_time){ + break; + } + + //otherwise sleep for a bit + else{ + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + } + } + return line; + } + +private: int _node_fd; +}; + +uhd::uart_iface::sptr e100_ctrl::make_gps_uart_iface(const std::string &node){ + return uhd::uart_iface::sptr(new uart_dev_iface(node)); +} + +/*********************************************************************** * USRP-E100 control implementation **********************************************************************/ class e100_ctrl_impl : public e100_ctrl{ diff --git a/host/lib/usrp/e100/e100_ctrl.hpp b/host/lib/usrp/e100/e100_ctrl.hpp index 8520ea595..fd66791d4 100644 --- a/host/lib/usrp/e100/e100_ctrl.hpp +++ b/host/lib/usrp/e100/e100_ctrl.hpp @@ -36,6 +36,9 @@ public: //! Make an i2c iface for the i2c device node static uhd::spi_iface::sptr make_aux_spi_iface(void); + //! Make a uart iface for the uart device node + static uhd::uart_iface::sptr make_gps_uart_iface(const std::string &node); + virtual void ioctl(int request, void *mem) = 0; virtual int get_file_descriptor(void) = 0; diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp index b988de9a1..564a05a7e 100644 --- a/host/lib/usrp/e100/e100_impl.cpp +++ b/host/lib/usrp/e100/e100_impl.cpp @@ -230,6 +230,22 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ .publish(boost::bind(&e100_impl::get_ref_locked, this)); //////////////////////////////////////////////////////////////////// + // Create the GPSDO control + //////////////////////////////////////////////////////////////////// + try{ + _gps = gps_ctrl::make(e100_ctrl::make_gps_uart_iface(E100_UART_DEV_NODE)); + } + catch(std::exception &e){ + UHD_MSG(error) << "An error occurred making GPSDO control: " << e.what() << std::endl; + } + if (_gps.get() != NULL and _gps->gps_detected()){ + BOOST_FOREACH(const std::string &name, _gps->get_sensors()){ + _tree->create<sensor_value_t>(mb_path / "sensors" / name) + .publish(boost::bind(&gps_ctrl::get_sensor, _gps, name)); + } + } + + //////////////////////////////////////////////////////////////////// // create frontend control objects //////////////////////////////////////////////////////////////////// _rx_fe = rx_frontend_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_FRONT)); @@ -376,6 +392,15 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ _tree->access<std::string>(mb_path / "clock_source/value").set("internal"); _tree->access<std::string>(mb_path / "time_source/value").set("none"); + //GPS installed: use external ref, time, and init time spec + if (_gps.get() != NULL and _gps->gps_detected()){ + UHD_MSG(status) << "Setting references to the internal GPSDO" << std::endl; + _tree->access<std::string>(mb_path / "time_source/value").set("external"); + _tree->access<std::string>(mb_path / "clock_source/value").set("external"); + UHD_MSG(status) << "Initializing time to the internal GPSDO" << std::endl; + _time64->set_time_next_pps(time_spec_t(time_t(_gps->get_sensor("gps_time").to_int()+1))); + } + } e100_impl::~e100_impl(void){ diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp index 99c8481e3..4b2ec5ee0 100644 --- a/host/lib/usrp/e100/e100_impl.hpp +++ b/host/lib/usrp/e100/e100_impl.hpp @@ -31,6 +31,7 @@ #include <uhd/usrp/subdev_spec.hpp> #include <uhd/usrp/dboard_eeprom.hpp> #include <uhd/usrp/mboard_eeprom.hpp> +#include <uhd/usrp/gps_ctrl.hpp> #include <uhd/types/sensors.hpp> #include <uhd/types/otw_type.hpp> #include <uhd/types/clock_config.hpp> @@ -47,6 +48,7 @@ uhd::transport::zero_copy_if::sptr e100_make_mmap_zero_copy(e100_ctrl::sptr ifac static const double E100_RX_LINK_RATE_BPS = 166e6/3/2*2; static const double E100_TX_LINK_RATE_BPS = 166e6/3/1*2; static const std::string E100_I2C_DEV_NODE = "/dev/i2c-3"; +static const std::string E100_UART_DEV_NODE = "/dev/ttyO0"; static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x06; static const boost::uint32_t E100_RX_SID_BASE = 2; static const boost::uint32_t E100_TX_ASYNC_SID = 1; @@ -98,6 +100,7 @@ private: e100_ctrl::sptr _fpga_ctrl; uhd::i2c_iface::sptr _dev_i2c_iface; uhd::spi_iface::sptr _aux_spi_iface; + uhd::gps_ctrl::sptr _gps; //transports uhd::transport::zero_copy_if::sptr _data_transport; diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp index 342b0e2fe..c645d2948 100644 --- a/host/lib/usrp/gps_ctrl.cpp +++ b/host/lib/usrp/gps_ctrl.cpp @@ -40,24 +40,23 @@ using namespace boost::this_thread; class gps_ctrl_impl : public gps_ctrl{ public: - gps_ctrl_impl(gps_send_fn_t send, gps_recv_fn_t recv){ - _send = send; - _recv = recv; + gps_ctrl_impl(uart_iface::sptr uart){ + _uart = uart; std::string reply; bool i_heard_some_nmea = false, i_heard_something_weird = false; gps_type = GPS_TYPE_NONE; //first we look for a Jackson Labs Firefly (since that's what we provide...) - _recv(); //get whatever junk is in the rx buffer right now, and throw it away + _flush(); //get whatever junk is in the rx buffer right now, and throw it away _send("HAAAY GUYYYYS\n"); //to elicit a response from the Firefly - //wait for _send(...) to return + //wait for _send(...) to return sleep(milliseconds(FIREFLY_STUPID_DELAY_MS)); //then we loop until we either timeout, or until we get a response that indicates we're a JL device - int timeout = GPS_TIMEOUT_TRIES; - while(timeout--) { + const boost::system_time comm_timeout = boost::get_system_time() + milliseconds(GPS_COMM_TIMEOUT_MS); + while(boost::get_system_time() < comm_timeout) { reply = _recv(); if(reply.find("Command Error") != std::string::npos) { gps_type = GPS_TYPE_JACKSON_LABS; @@ -65,7 +64,7 @@ public: } else if(reply.substr(0, 3) == "$GP") i_heard_some_nmea = true; //but keep looking for that "Command Error" response else if(reply.length() != 0) i_heard_something_weird = true; //probably wrong baud rate - sleep(milliseconds(200)); + sleep(milliseconds(GPS_TIMEOUT_DELAY_MS)); } if((i_heard_some_nmea) && (gps_type != GPS_TYPE_JACKSON_LABS)) gps_type = GPS_TYPE_GENERIC_NMEA; @@ -155,10 +154,10 @@ private: return std::string(); } - while(_recv().size() != 0) sleep(milliseconds(GPS_TIMEOUT_DELAY_MS)); + _flush(); //flush all input before waiting for a message - int timeout = GPS_TIMEOUT_TRIES; - while(timeout--) { + const boost::system_time comm_timeout = boost::get_system_time() + milliseconds(GPS_COMM_TIMEOUT_MS); + while(boost::get_system_time() < comm_timeout) { reply = _recv(); if(reply.substr(0, 6) == msgtype) return reply; @@ -242,8 +241,21 @@ private: return false; } - gps_send_fn_t _send; - gps_recv_fn_t _recv; + uart_iface::sptr _uart; + + void _flush(void){ + while (not _uart->read_uart(0.0).empty()){ + //NOP + } + } + + std::string _recv(void){ + return _uart->read_uart(GPS_TIMEOUT_DELAY_MS/1000.); + } + + void _send(const std::string &buf){ + return _uart->write_uart(buf); + } enum { GPS_TYPE_JACKSON_LABS, @@ -251,7 +263,7 @@ private: GPS_TYPE_NONE } gps_type; - static const int GPS_TIMEOUT_TRIES = 10; + static const int GPS_COMM_TIMEOUT_MS = 1500; static const int GPS_TIMEOUT_DELAY_MS = 200; static const int FIREFLY_STUPID_DELAY_MS = 200; }; @@ -259,6 +271,6 @@ private: /*********************************************************************** * Public make function for the GPS control **********************************************************************/ -gps_ctrl::sptr gps_ctrl::make(gps_send_fn_t send, gps_recv_fn_t recv){ - return sptr(new gps_ctrl_impl(send, recv)); +gps_ctrl::sptr gps_ctrl::make(uart_iface::sptr uart){ + return sptr(new gps_ctrl_impl(uart)); } diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 35d128054..7ad06f33f 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -31,8 +31,8 @@ extern "C" { //fpga and firmware compatibility numbers #define USRP2_FPGA_COMPAT_NUM 7 -#define USRP2_FW_COMPAT_NUM 10 -#define USRP2_FW_VER_MINOR 4 +#define USRP2_FW_COMPAT_NUM 11 +#define USRP2_FW_VER_MINOR 0 //used to differentiate control packets over data port #define USRP2_INVALID_VRT_HEADER 0 @@ -44,6 +44,8 @@ extern "C" { #define USRP2_UDP_RX_DSP0_PORT 49156 #define USRP2_UDP_TX_DSP0_PORT 49157 #define USRP2_UDP_RX_DSP1_PORT 49158 +#define USRP2_UDP_UART_BASE_PORT 49170 +#define USRP2_UDP_UART_GPS_PORT 49172 // Map for virtual firmware regs (not very big so we can keep it here for now) #define U2_FW_REG_LOCK_TIME 0 @@ -89,9 +91,6 @@ typedef enum{ USRP2_CTRL_ID_HEY_WRITE_THIS_UART_FOR_ME_BRO = 'u', USRP2_CTRL_ID_MAN_I_TOTALLY_WROTE_THAT_UART_DUDE = 'U', - USRP2_CTRL_ID_SO_LIKE_CAN_YOU_READ_THIS_UART_BRO = 'v', - USRP2_CTRL_ID_I_HELLA_READ_THAT_UART_DUDE = 'V', - USRP2_CTRL_ID_HOLLER_AT_ME_BRO = 'l', USRP2_CTRL_ID_HOLLER_BACK_DUDE = 'L', @@ -143,11 +142,6 @@ typedef struct{ uint8_t action; } reg_args; struct { - uint8_t dev; - uint8_t bytes; - uint8_t data[20]; - } uart_args; - struct { uint32_t len; } echo_args; } data; diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index d91dd0e40..c1e92e7d4 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -245,66 +245,6 @@ public: } /*********************************************************************** - * UART - **********************************************************************/ - void write_uart(boost::uint8_t dev, const std::string &buf){ - //first tokenize the string into 20-byte substrings - boost::offset_separator f(20, 20, true, true); - boost::tokenizer<boost::offset_separator> tok(buf, f); - std::vector<std::string> queue(tok.begin(), tok.end()); - - BOOST_FOREACH(std::string item, queue) { - //setup the out data - usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t(); - out_data.id = htonl(USRP2_CTRL_ID_HEY_WRITE_THIS_UART_FOR_ME_BRO); - out_data.data.uart_args.dev = dev; - out_data.data.uart_args.bytes = item.size(); - - //limitation of uart transaction size - UHD_ASSERT_THROW(item.size() <= sizeof(out_data.data.uart_args.data)); - - //copy in the data - std::copy(item.begin(), item.end(), out_data.data.uart_args.data); - - //send and recv - usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_UART); - UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_MAN_I_TOTALLY_WROTE_THAT_UART_DUDE); - } - } - - std::string read_uart(boost::uint8_t dev){ - int readlen = 20; - std::string result; - while(readlen == 20) { //while we keep receiving full packets - //setup the out data - usrp2_ctrl_data_t out_data = usrp2_ctrl_data_t(); - out_data.id = htonl(USRP2_CTRL_ID_SO_LIKE_CAN_YOU_READ_THIS_UART_BRO); - out_data.data.uart_args.dev = dev; - out_data.data.uart_args.bytes = 20; - - //limitation of uart transaction size - //UHD_ASSERT_THROW(num_bytes <= sizeof(out_data.data.uart_args.data)); - - //send and recv - usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_UART); - UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_I_HELLA_READ_THAT_UART_DUDE); - readlen = in_data.data.uart_args.bytes; - - //copy out the data - result += std::string((const char *)in_data.data.uart_args.data, (size_t)readlen); - } - return result; - } - - gps_send_fn_t get_gps_write_fn(void) { - return boost::bind(&usrp2_iface_impl::write_uart, this, 2, _1); //2 is the GPS UART port on USRP2 - } - - gps_recv_fn_t get_gps_read_fn(void) { - return boost::bind(&usrp2_iface_impl::read_uart, this, 2); //2 is the GPS UART port on USRP2 - } - -/*********************************************************************** * Send/Recv over control **********************************************************************/ usrp2_ctrl_data_t ctrl_send_and_recv( diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index b3c3ef4a2..9aa1a16aa 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -28,16 +28,12 @@ #include "wb_iface.hpp" #include <string> -//TODO: kill this crap when you have the top level GPS include file -typedef boost::function<void(std::string)> gps_send_fn_t; -typedef boost::function<std::string(void)> gps_recv_fn_t; - /*! * The usrp2 interface class: * Provides a set of functions to implementation layer. * Including spi, peek, poke, control... */ -class usrp2_iface : public wb_iface, public uhd::spi_iface, public uhd::i2c_iface, public uhd::uart_iface{ +class usrp2_iface : public wb_iface, public uhd::spi_iface, public uhd::i2c_iface{ public: typedef boost::shared_ptr<usrp2_iface> sptr; /*! @@ -47,9 +43,6 @@ public: */ static sptr make(uhd::transport::udp_simple::sptr ctrl_transport); - virtual gps_recv_fn_t get_gps_read_fn(void) = 0; - virtual gps_send_fn_t get_gps_write_fn(void) = 0; - //! The list of possible revision types enum rev_type { USRP2_REV3 = 3, diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 03a9d09fe..47aec08d5 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -438,10 +438,9 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ // create gpsdo control objects //////////////////////////////////////////////////////////////// if (_mbc[mb].iface->mb_eeprom["gpsdo"] == "internal"){ - _mbc[mb].gps = gps_ctrl::make( - _mbc[mb].iface->get_gps_write_fn(), - _mbc[mb].iface->get_gps_read_fn() - ); + _mbc[mb].gps = gps_ctrl::make(udp_simple::make_uart(udp_simple::make_connected( + addr, BOOST_STRINGIZE(USRP2_UDP_UART_GPS_PORT) + ))); if(_mbc[mb].gps->gps_detected()) { BOOST_FOREACH(const std::string &name, _mbc[mb].gps->get_sensors()){ _tree->create<sensor_value_t>(mb_path / "sensors" / name) @@ -624,8 +623,10 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ //GPS installed: use external ref, time, and init time spec if (_mbc[mb].gps.get() and _mbc[mb].gps->gps_detected()){ + UHD_MSG(status) << "Setting references to the internal GPSDO" << std::endl; _tree->access<std::string>(root / "time_source/value").set("external"); _tree->access<std::string>(root / "clock_source/value").set("external"); + UHD_MSG(status) << "Initializing time to the internal GPSDO" << std::endl; _mbc[mb].time64->set_time_next_pps(time_spec_t(time_t(_mbc[mb].gps->get_sensor("gps_time").to_int()+1))); } } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 28cbaf479..6f133f411 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -93,7 +93,7 @@ private: usrp2_iface::sptr iface; usrp2_clock_ctrl::sptr clock; usrp2_codec_ctrl::sptr codec; - gps_ctrl::sptr gps; + uhd::gps_ctrl::sptr gps; rx_frontend_core_200::sptr rx_fe; tx_frontend_core_200::sptr tx_fe; std::vector<rx_dsp_core_200::sptr> rx_dsps; |