// // Copyright 2010-2011,2014 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 "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_LOG << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; //resolve the address asio::ip::udp::resolver resolver(_io_service); asio::ip::udp::resolver::query query(asio::ip::udp::v4(), addr, port); _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(), timeout)) return 0; return _socket->receive_from(asio::buffer(buff), _recv_endpoint); } std::string get_recv_addr(void){ return _recv_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]; _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)); }