// // Copyright 2010-2011,2014 Ettus Research LLC // Copyright 2018 Ettus Research, a National Instruments Company // // SPDX-License-Identifier: GPL-3.0-or-later // #include "udp_common.hpp" #include #include #include using namespace uhd::transport; namespace asio = boost::asio; /*********************************************************************** * UDP simple implementation: connected and broadcast **********************************************************************/ class udp_simple_impl : public udp_simple { public: udp_simple_impl( const std::string& addr, const std::string& port, bool bcast, bool connect) : _connected(connect) { UHD_LOGGER_TRACE("UDP") << boost::format("Creating udp transport for %s %s") % addr % port; // resolve the address asio::ip::udp::resolver resolver(_io_service); asio::ip::udp::resolver::query query( asio::ip::udp::v4(), addr, port, asio::ip::resolver_query_base::all_matching); _send_endpoint = *resolver.resolve(query); // create and open the socket _socket = socket_sptr(new asio::ip::udp::socket(_io_service)); _socket->open(asio::ip::udp::v4()); // allow broadcasting _socket->set_option(asio::socket_base::broadcast(bcast)); // connect the socket if (connect) _socket->connect(_send_endpoint); } size_t send(const asio::const_buffer& buff) { if (_connected) return _socket->send(asio::buffer(buff)); return _socket->send_to(asio::buffer(buff), _send_endpoint); } size_t recv(const asio::mutable_buffer& buff, double timeout) { if (not wait_for_recv_ready(_socket->native_handle(), timeout)) return 0; return _socket->receive_from(asio::buffer(buff), _recv_endpoint); } std::string get_recv_addr(void) { return _recv_endpoint.address().to_string(); } std::string get_send_addr(void) { return _send_endpoint.address().to_string(); } private: bool _connected; asio::io_service _io_service; socket_sptr _socket; asio::ip::udp::endpoint _send_endpoint; asio::ip::udp::endpoint _recv_endpoint; }; udp_simple::~udp_simple(void) { /* NOP */ } /*********************************************************************** * UDP public make functions **********************************************************************/ udp_simple::sptr udp_simple::make_connected( const std::string& addr, const std::string& port) { return sptr(new udp_simple_impl(addr, port, false, true /* no bcast, connect */)); } udp_simple::sptr udp_simple::make_broadcast( const std::string& addr, const std::string& port) { return sptr(new udp_simple_impl(addr, port, true, false /* bcast, no connect */)); } /*********************************************************************** * Simple UART over UDP **********************************************************************/ #include 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++]; _line += ch; if (ch == '\n') { line.swap(_line); 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; uint8_t _buf[udp_simple::mtu]; std::string _line; }; uhd::uart_iface::sptr udp_simple::make_uart(sptr udp) { return uart_iface::sptr(new udp_simple_uart_impl(udp)); }