diff options
82 files changed, 3582 insertions, 45 deletions
diff --git a/gnuradio-runtime/include/gnuradio/CMakeLists.txt b/gnuradio-runtime/include/gnuradio/CMakeLists.txt index 4789a71bbe..9f38af335a 100644 --- a/gnuradio-runtime/include/gnuradio/CMakeLists.txt +++ b/gnuradio-runtime/include/gnuradio/CMakeLists.txt @@ -40,6 +40,7 @@ install(FILES msg_handler.h msg_queue.h nco.h + pdu.h prefs.h pycallback_object.h random.h diff --git a/gnuradio-runtime/include/gnuradio/pdu.h b/gnuradio-runtime/include/gnuradio/pdu.h new file mode 100644 index 0000000000..f6957e5487 --- /dev/null +++ b/gnuradio-runtime/include/gnuradio/pdu.h @@ -0,0 +1,46 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013,2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + + +#ifndef INCLUDED_GR_PDU_H +#define INCLUDED_GR_PDU_H + +#include <gnuradio/api.h> +#include <pmt/pmt.h> + +namespace gr { +namespace msgport_names { +// static const PMT interned string getters for standard port names +GR_RUNTIME_API const pmt::pmt_t bpdu(); +GR_RUNTIME_API const pmt::pmt_t cpdu(); +GR_RUNTIME_API const pmt::pmt_t dict(); +GR_RUNTIME_API const pmt::pmt_t fpdu(); +GR_RUNTIME_API const pmt::pmt_t msg(); +GR_RUNTIME_API const pmt::pmt_t pdu(); +GR_RUNTIME_API const pmt::pmt_t pdus(); // compatibility, use of pdu() preferred +GR_RUNTIME_API const pmt::pmt_t vec(); +} /* namespace ports */ + +namespace types { +enum vector_type { byte_t, float_t, complex_t }; +} /* namespace types */ + +namespace pdu { +// pdu functions +GR_RUNTIME_API size_t itemsize(types::vector_type type); +GR_RUNTIME_API bool type_matches(types::vector_type type, pmt::pmt_t v); +GR_RUNTIME_API pmt::pmt_t +make_pdu_vector(types::vector_type type, const uint8_t* buf, size_t items); +GR_RUNTIME_API types::vector_type type_from_pmt(pmt::pmt_t vector); + +} // namespace pdu +} // namespace gr + +#endif /* INCLUDED_GR_PDU_H */ diff --git a/gnuradio-runtime/lib/CMakeLists.txt b/gnuradio-runtime/lib/CMakeLists.txt index 4cddb26fe0..9a6cd4488f 100644 --- a/gnuradio-runtime/lib/CMakeLists.txt +++ b/gnuradio-runtime/lib/CMakeLists.txt @@ -72,6 +72,7 @@ add_library(gnuradio-runtime msg_handler.cc msg_queue.cc pagesize.cc + pdu.cc prefs.cc realtime.cc realtime_impl.cc diff --git a/gnuradio-runtime/lib/pdu.cc b/gnuradio-runtime/lib/pdu.cc new file mode 100644 index 0000000000..e01092de20 --- /dev/null +++ b/gnuradio-runtime/lib/pdu.cc @@ -0,0 +1,119 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013,2021 Free Software Foundation, Inc. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/gr_complex.h> +#include <gnuradio/pdu.h> +#include <pmt/pmt.h> + +namespace gr { +namespace msgport_names { + +const pmt::pmt_t bpdu() +{ + static const pmt::pmt_t val = pmt::mp("bpdu"); + return val; +} +const pmt::pmt_t cpdu() +{ + static const pmt::pmt_t val = pmt::mp("cpdu"); + return val; +} +const pmt::pmt_t dict() +{ + static const pmt::pmt_t val = pmt::mp("dict"); + return val; +} +const pmt::pmt_t fpdu() +{ + static const pmt::pmt_t val = pmt::mp("fpdu"); + return val; +} +const pmt::pmt_t msg() +{ + static const pmt::pmt_t val = pmt::mp("msg"); + return val; +} +const pmt::pmt_t pdu() +{ + static const pmt::pmt_t val = pmt::mp("pdu"); + return val; +} +const pmt::pmt_t pdus() +{ + static const pmt::pmt_t val = pmt::mp("pdus"); + return val; +} +const pmt::pmt_t vec() +{ + static const pmt::pmt_t val = pmt::mp("vec"); + return val; +} + +} /* namespace ports */ + +namespace pdu { + +size_t itemsize(types::vector_type type) +{ + switch (type) { + case types::byte_t: + return sizeof(char); + case types::float_t: + return sizeof(float); + case types::complex_t: + return sizeof(gr_complex); + default: + throw std::runtime_error("bad PDU type"); + } +} + +bool type_matches(types::vector_type type, pmt::pmt_t v) +{ + switch (type) { + case types::byte_t: + return pmt::is_u8vector(v); + case types::float_t: + return pmt::is_f32vector(v); + case types::complex_t: + return pmt::is_c32vector(v); + default: + throw std::runtime_error("bad PDU type"); + } +} + +pmt::pmt_t make_pdu_vector(types::vector_type type, const uint8_t* buf, size_t items) +{ + switch (type) { + case types::byte_t: + return pmt::init_u8vector(items, buf); + case types::float_t: + return pmt::init_f32vector(items, (const float*)buf); + case types::complex_t: + return pmt::init_c32vector(items, (const gr_complex*)buf); + default: + throw std::runtime_error("bad PDU type"); + } +} + +types::vector_type type_from_pmt(pmt::pmt_t vector) +{ + if (pmt::is_u8vector(vector)) + return types::byte_t; + if (pmt::is_f32vector(vector)) + return types::float_t; + if (pmt::is_c32vector(vector)) + return types::complex_t; + throw std::runtime_error("bad PDU type"); +} + +} /* namespace pdu */ +} /* namespace gr */ diff --git a/gnuradio-runtime/python/gnuradio/__init__.py b/gnuradio-runtime/python/gnuradio/__init__.py index 2326c3ab89..45bc91bf4d 100644 --- a/gnuradio-runtime/python/gnuradio/__init__.py +++ b/gnuradio-runtime/python/gnuradio/__init__.py @@ -57,4 +57,5 @@ if path.endswith(path_ending): __path__.append(os.path.join(build_path, 'gr-utils')) __path__.append(os.path.join(build_path, 'gr-uhd', 'python')) __path__.append(os.path.join(build_path, 'gr-pdu', 'python')) + __path__.append(os.path.join(build_path, 'gr-network', 'python')) __path__.append(os.path.join(build_path, 'gr-zeromq', 'python')) diff --git a/gnuradio-runtime/python/gnuradio/gr/bindings/CMakeLists.txt b/gnuradio-runtime/python/gnuradio/gr/bindings/CMakeLists.txt index 17b1a30590..ef8f1f10dd 100644 --- a/gnuradio-runtime/python/gnuradio/gr/bindings/CMakeLists.txt +++ b/gnuradio-runtime/python/gnuradio/gr/bindings/CMakeLists.txt @@ -42,6 +42,7 @@ messages/msg_queue_python.cc msg_handler_python.cc msg_queue_python.cc nco_python.cc + pdu_python.cc prefs_python.cc # pycallback_object_python.cc random_python.cc @@ -81,7 +82,7 @@ messages/msg_queue_python.cc # xoroshiro128p_python.cc python_bindings.cc) -GR_PYBIND_MAKE_CHECK_HASH(gr +GR_PYBIND_MAKE_CHECK_HASH(gr ../../../.. gr::gr "${gr_python_files}") diff --git a/gnuradio-runtime/python/gnuradio/gr/bindings/docstrings/pdu_pydoc_template.h b/gnuradio-runtime/python/gnuradio/gr/bindings/docstrings/pdu_pydoc_template.h new file mode 100644 index 0000000000..8ba6b5ddd0 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gr/bindings/docstrings/pdu_pydoc_template.h @@ -0,0 +1,51 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#include "pydoc_macros.h" +#define D(...) DOC(gr, __VA_ARGS__) +/* + This file contains placeholders for docstrings for the Python bindings. + Do not edit! These were automatically extracted during the binding process + and will be overwritten during the build process + */ + + +static const char* __doc_gr_msgport_names_bpdu = R"doc()doc"; + + +static const char* __doc_gr_msgport_names_cpdu = R"doc()doc"; + + +static const char* __doc_gr_msgport_names_dict = R"doc()doc"; + + +static const char* __doc_gr_msgport_names_fpdu = R"doc()doc"; + + +static const char* __doc_gr_msgport_names_msg = R"doc()doc"; + + +static const char* __doc_gr_msgport_names_pdu = R"doc()doc"; + + +static const char* __doc_gr_msgport_names_pdus = R"doc()doc"; + + +static const char* __doc_gr_msgport_names_vec = R"doc()doc"; + + +static const char* __doc_gr_pdu_itemsize = R"doc()doc"; + + +static const char* __doc_gr_pdu_type_matches = R"doc()doc"; + + +static const char* __doc_gr_pdu_make_pdu_vector = R"doc()doc"; + + +static const char* __doc_gr_pdu_type_from_pmt = R"doc()doc"; diff --git a/gnuradio-runtime/python/gnuradio/gr/bindings/pdu_python.cc b/gnuradio-runtime/python/gnuradio/gr/bindings/pdu_python.cc new file mode 100644 index 0000000000..98df9acd8c --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gr/bindings/pdu_python.cc @@ -0,0 +1,94 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +/***********************************************************************************/ +/* This file is automatically generated using bindtool and can be manually edited */ +/* The following lines can be configured to regenerate this file during cmake */ +/* If manual edits are made, the following tags should be modified accordingly. */ +/* BINDTOOL_GEN_AUTOMATIC(0) */ +/* BINDTOOL_USE_PYGCCXML(0) */ +/* BINDTOOL_HEADER_FILE(pdu.h) */ +/* BINDTOOL_HEADER_FILE_HASH(2b56328d8782d0a1816df04928cd83c5) */ +/***********************************************************************************/ + +#include <pybind11/complex.h> +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +namespace py = pybind11; + +#include <gnuradio/pdu.h> +// pydoc.h is automatically generated in the build directory +#include <pdu_pydoc.h> + +void bind_pdu(py::module& m) +{ + + py::module m_types = m.def_submodule("types"); + + py::enum_<::gr::types::vector_type>(m_types, "vector_type") + .value("byte_t", ::gr::types::byte_t) // 0 + .value("float_t", ::gr::types::float_t) // 1 + .value("complex_t", ::gr::types::complex_t) // 2 + .export_values(); + + py::implicitly_convertible<int, ::gr::types::vector_type>(); + + + py::module m_msgport_names = m.def_submodule("msgport_names"); + + m_msgport_names.def("bpdu", &::gr::msgport_names::bpdu, D(msgport_names, bpdu)); + + + m_msgport_names.def("cpdu", &::gr::msgport_names::cpdu, D(msgport_names, cpdu)); + + + m_msgport_names.def("dict", &::gr::msgport_names::dict, D(msgport_names, dict)); + + + m_msgport_names.def("fpdu", &::gr::msgport_names::fpdu, D(msgport_names, fpdu)); + + + m_msgport_names.def("msg", &::gr::msgport_names::msg, D(msgport_names, msg)); + + + m_msgport_names.def("pdu", &::gr::msgport_names::pdu, D(msgport_names, pdu)); + + + m_msgport_names.def("pdus", &::gr::msgport_names::pdus, D(msgport_names, pdus)); + + + m_msgport_names.def("vec", &::gr::msgport_names::vec, D(msgport_names, vec)); + + + py::module m_pdu = m.def_submodule("pdu"); + + m_pdu.def("itemsize", &::gr::pdu::itemsize, py::arg("type"), D(pdu, itemsize)); + + + m_pdu.def("type_matches", + &::gr::pdu::type_matches, + py::arg("type"), + py::arg("v"), + D(pdu, type_matches)); + + + m_pdu.def("make_pdu_vector", + &::gr::pdu::make_pdu_vector, + py::arg("type"), + py::arg("buf"), + py::arg("items"), + D(pdu, make_pdu_vector)); + + + m_pdu.def("type_from_pmt", + &::gr::pdu::type_from_pmt, + py::arg("vector"), + D(pdu, type_from_pmt)); +} diff --git a/gnuradio-runtime/python/gnuradio/gr/bindings/python_bindings.cc b/gnuradio-runtime/python/gnuradio/gr/bindings/python_bindings.cc index 8307fa8790..c180116c80 100644 --- a/gnuradio-runtime/python/gnuradio/gr/bindings/python_bindings.cc +++ b/gnuradio-runtime/python/gnuradio/gr/bindings/python_bindings.cc @@ -52,6 +52,7 @@ void bind_msg_queue(py::module&); void bind_msg_handler(py::module&); void bind_msg_queue(py::module&); void bind_nco(py::module&); +void bind_pdu(py::module&); void bind_prefs(py::module&); // void bind_pycallback_object(py::module&); void bind_random(py::module&); @@ -152,6 +153,7 @@ PYBIND11_MODULE(gr_python, m) bind_nco(m); + bind_pdu(m); bind_prefs(m); // // bind_pycallback_object(m); bind_random(m); diff --git a/gr-network/grc/CMakeLists.txt b/gr-network/grc/CMakeLists.txt index 8ac8bb68c8..622624e4e1 100644 --- a/gr-network/grc/CMakeLists.txt +++ b/gr-network/grc/CMakeLists.txt @@ -7,8 +7,10 @@ # install(FILES + network_socket_pdu.block.yml network_tcp_sink.block.yml network_tcp_source.block.yml + network_tuntap_pdu.block.yml network_udp_sink.block.yml network_udp_source.block.yml DESTINATION share/gnuradio/grc/blocks diff --git a/gr-network/grc/network_socket_pdu.block.yml b/gr-network/grc/network_socket_pdu.block.yml new file mode 100644 index 0000000000..0033c769ef --- /dev/null +++ b/gr-network/grc/network_socket_pdu.block.yml @@ -0,0 +1,57 @@ +id: network_socket_pdu +label: Socket PDU +category: '[Core]/Networking Tools' +flags: [ python, cpp ] + +parameters: +- id: type + label: Type + dtype: enum + default: TCP_SERVER + options: ["TCP_SERVER", "TCP_CLIENT", "UDP_SERVER", "UDP_CLIENT"] + option_labels: [TCP Server, TCP Client, UDP Server, UDP Client] +- id: host + label: Host + dtype: string +- id: port + label: Port + dtype: string + default: '52001' +- id: mtu + label: MTU + dtype: int + default: '10000' +- id: tcp_no_delay + label: TCP No Delay + dtype: enum + default: 'False' + options: ['True', 'False'] + option_labels: [Enabled, Disabled] + hide: ${ (( 'part' if (str(tcp_no_delay) == 'False') else 'none') if ((type == 'TCP_CLIENT') or (type == 'TCP_SERVER')) else 'all') } + +inputs: +- domain: message + id: pdus + optional: true + +outputs: +- domain: message + id: pdus + optional: true + +templates: + imports: from gnuradio import network + make: network.socket_pdu(${repr(type)}, ${host}, ${port}, ${mtu}, ${tcp_no_delay}) + +cpp_templates: + includes: ['#include <gnuradio/network/socket_pdu.h>'] + declarations: 'network::socket_pdu::sptr ${id};' + make: 'this->${id} = network::socket_pdu::make("${type}", ${host}, ${port}, ${mtu}, ${tcp_no_delay});' + translations: + 'True': 'true' + 'False': 'false' + +documentation: |- + For server modes, leave Host blank to bind to all interfaces (equivalent to 0.0.0.0). + +file_format: 1 diff --git a/gr-network/grc/network_tuntap_pdu.block.yml b/gr-network/grc/network_tuntap_pdu.block.yml new file mode 100644 index 0000000000..1542b89a98 --- /dev/null +++ b/gr-network/grc/network_tuntap_pdu.block.yml @@ -0,0 +1,44 @@ +id: network_tuntap_pdu +label: TUNTAP PDU +category: '[Core]/Networking Tools' +flags: [ python, cpp ] + +parameters: +- id: ifn + label: Interface Name + dtype: string + default: tap0 +- id: mtu + label: MTU + dtype: int + default: '10000' +- id: istunflag + label: Flag + dtype: enum + default: 'False' + options: ['True', 'False'] + option_labels: [TUN(IP Packet), TAP(Ethernet Frame)] + +inputs: +- domain: message + id: pdus + optional: true + +outputs: +- domain: message + id: pdus + optional: true + +templates: + imports: from gnuradio import network + make: network.tuntap_pdu(${ifn}, ${mtu}, ${istunflag}) + +cpp_templates: + includes: ['#include <gnuradio/network/tuntap_pdu.h>'] + declarations: 'network::tuntap_pdu::sptr ${id};' + make: 'this->${id} = network::tuntap_pdu::make(${ifn}, ${mtu}, ${istunflag});' + translations: + 'True': 'true' + 'False': 'false' + +file_format: 1 diff --git a/gr-network/include/gnuradio/network/CMakeLists.txt b/gr-network/include/gnuradio/network/CMakeLists.txt index 8712ed00d2..36ff1b48a7 100644 --- a/gr-network/include/gnuradio/network/CMakeLists.txt +++ b/gr-network/include/gnuradio/network/CMakeLists.txt @@ -11,7 +11,9 @@ install(FILES api.h packet_headers.h + socket_pdu.h tcp_sink.h + tuntap_pdu.h udp_header_types.h udp_sink.h udp_source.h diff --git a/gr-network/include/gnuradio/network/socket_pdu.h b/gr-network/include/gnuradio/network/socket_pdu.h new file mode 100644 index 0000000000..dba2522fab --- /dev/null +++ b/gr-network/include/gnuradio/network/socket_pdu.h @@ -0,0 +1,48 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_NETWORK_SOCKET_PDU_H +#define INCLUDED_NETWORK_SOCKET_PDU_H + +#include <gnuradio/block.h> +#include <gnuradio/network/api.h> + +namespace gr { +namespace network { + +/*! + * \brief Creates socket interface and translates traffic to PDUs + * \ingroup networking_tools_blk + */ +class NETWORK_API socket_pdu : virtual public block +{ +public: + // gr::network::socket_pdu::sptr + typedef std::shared_ptr<socket_pdu> sptr; + + /*! + * \brief Construct a SOCKET PDU interface + * \param type "TCP_SERVER", "TCP_CLIENT", "UDP_SERVER", or "UDP_CLIENT" + * \param addr network address to use + * \param port network port to use + * \param MTU maximum transmission unit + * \param tcp_no_delay TCP No Delay option (set to True to disable Nagle algorithm) + */ + static sptr make(std::string type, + std::string addr, + std::string port, + int MTU = 10000, + bool tcp_no_delay = false); +}; + +} /* namespace network */ +} /* namespace gr */ + +#endif /* INCLUDED_NETWORK_SOCKET_PDU_H */ diff --git a/gr-network/include/gnuradio/network/tuntap_pdu.h b/gr-network/include/gnuradio/network/tuntap_pdu.h new file mode 100644 index 0000000000..6ef34aeee2 --- /dev/null +++ b/gr-network/include/gnuradio/network/tuntap_pdu.h @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_NETWORK_TUNTAP_PDU_H +#define INCLUDED_NETWORK_TUNTAP_PDU_H + +#include <gnuradio/block.h> +#include <gnuradio/network/api.h> + +namespace gr { +namespace network { + +/*! + * \brief Creates TUNTAP interface and translates traffic to PDUs + * \ingroup networking_tools_blk + */ +class NETWORK_API tuntap_pdu : virtual public block +{ +public: + // gr::network::tuntap_pdu::sptr + typedef std::shared_ptr<tuntap_pdu> sptr; + + /*! + * \brief Construct a TUNTAP PDU interface + * \param dev Device name to create + * \param MTU Maximum Transmission Unit size + * \param istunflag Flag to indicate TUN or Tap + */ + static sptr make(std::string dev, int MTU = 10000, bool istunflag = false); +}; + +} /* namespace network */ +} /* namespace gr */ + +#endif /* INCLUDED_NETWORK_TUNTAP_PDU_H */ diff --git a/gr-network/lib/CMakeLists.txt b/gr-network/lib/CMakeLists.txt index 52a267079a..0eecda139f 100644 --- a/gr-network/lib/CMakeLists.txt +++ b/gr-network/lib/CMakeLists.txt @@ -13,7 +13,11 @@ include(GrPlatform) #define LIB_SUFFIX list(APPEND network_sources + socket_pdu_impl.cc + stream_pdu_base.cc + tcp_connection.cc tcp_sink_impl.cc + tuntap_pdu_impl.cc udp_sink_impl.cc udp_source_impl.cc ) diff --git a/gr-network/lib/socket_pdu_impl.cc b/gr-network/lib/socket_pdu_impl.cc new file mode 100644 index 0000000000..a9e854447a --- /dev/null +++ b/gr-network/lib/socket_pdu_impl.cc @@ -0,0 +1,271 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013,2019 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "socket_pdu_impl.h" +#include "tcp_connection.h" +#include <gnuradio/io_signature.h> +#include <gnuradio/pdu.h> + +namespace gr { +namespace network { + +socket_pdu::sptr socket_pdu::make(std::string type, + std::string addr, + std::string port, + int MTU /*= 10000*/, + bool tcp_no_delay /*= false*/) +{ + return gnuradio::make_block_sptr<socket_pdu_impl>( + type, addr, port, MTU, tcp_no_delay); +} + +socket_pdu_impl::socket_pdu_impl(std::string type, + std::string addr, + std::string port, + int MTU /*= 10000*/, + bool tcp_no_delay /*= false*/) + : block("socket_pdu", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + d_tcp_no_delay(tcp_no_delay) +{ + d_rxbuf.resize(MTU); + + message_port_register_in(msgport_names::pdus()); + message_port_register_out(msgport_names::pdus()); + + if ((type == "TCP_SERVER") && + ((addr.empty()) || (addr == "0.0.0.0"))) { // Bind on all interfaces + int port_num = atoi(port.c_str()); + if (port_num == 0) + throw std::invalid_argument( + "gr::pdu:socket_pdu: invalid port for TCP_SERVER"); + d_tcp_endpoint = + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port_num); + } else if ((type == "TCP_SERVER") || (type == "TCP_CLIENT")) { + boost::asio::ip::tcp::resolver resolver(d_io_service); + boost::asio::ip::tcp::resolver::query query( + boost::asio::ip::tcp::v4(), + addr, + port, + boost::asio::ip::resolver_query_base::passive); + d_tcp_endpoint = *resolver.resolve(query); + } else if ((type == "UDP_SERVER") && + ((addr.empty()) || (addr == "0.0.0.0"))) { // Bind on all interfaces + int port_num = atoi(port.c_str()); + if (port_num == 0) + throw std::invalid_argument( + "gr::pdu:socket_pdu: invalid port for UDP_SERVER"); + d_udp_endpoint = + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port_num); + } else if ((type == "UDP_SERVER") || (type == "UDP_CLIENT")) { + boost::asio::ip::udp::resolver resolver(d_io_service); + boost::asio::ip::udp::resolver::query query( + boost::asio::ip::udp::v4(), + addr, + port, + boost::asio::ip::resolver_query_base::passive); + + if (type == "UDP_SERVER") + d_udp_endpoint = *resolver.resolve(query); + else + d_udp_endpoint_other = *resolver.resolve(query); + } + + if (type == "TCP_SERVER") { + d_acceptor_tcp = std::make_shared<boost::asio::ip::tcp::acceptor>(d_io_service, + d_tcp_endpoint); + d_acceptor_tcp->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + + start_tcp_accept(); + + set_msg_handler(msgport_names::pdus(), + [this](pmt::pmt_t msg) { this->tcp_server_send(msg); }); + } else if (type == "TCP_CLIENT") { + boost::system::error_code error = boost::asio::error::host_not_found; + d_tcp_socket = std::make_shared<boost::asio::ip::tcp::socket>(d_io_service); + d_tcp_socket->connect(d_tcp_endpoint, error); + if (error) + throw boost::system::system_error(error); + d_tcp_socket->set_option(boost::asio::ip::tcp::no_delay(d_tcp_no_delay)); + + set_msg_handler(msgport_names::pdus(), + [this](pmt::pmt_t msg) { this->tcp_client_send(msg); }); + + d_tcp_socket->async_read_some( + boost::asio::buffer(d_rxbuf), + boost::bind(&socket_pdu_impl::handle_tcp_read, + this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } else if (type == "UDP_SERVER") { + d_udp_socket = + std::make_shared<boost::asio::ip::udp::socket>(d_io_service, d_udp_endpoint); + d_udp_socket->async_receive_from( + boost::asio::buffer(d_rxbuf), + d_udp_endpoint_other, + boost::bind(&socket_pdu_impl::handle_udp_read, + this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + + set_msg_handler(msgport_names::pdus(), + [this](pmt::pmt_t msg) { this->udp_send(msg); }); + } else if (type == "UDP_CLIENT") { + d_udp_socket = + std::make_shared<boost::asio::ip::udp::socket>(d_io_service, d_udp_endpoint); + d_udp_socket->async_receive_from( + boost::asio::buffer(d_rxbuf), + d_udp_endpoint_other, + boost::bind(&socket_pdu_impl::handle_udp_read, + this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + + set_msg_handler(msgport_names::pdus(), + [this](pmt::pmt_t msg) { this->udp_send(msg); }); + } else + throw std::runtime_error("gr::pdu:socket_pdu: unknown socket type"); + + d_thread = gr::thread::thread(boost::bind(&socket_pdu_impl::run_io_service, this)); + d_started = true; +} + +socket_pdu_impl::~socket_pdu_impl() { stop(); } + +bool socket_pdu_impl::stop() +{ + if (d_started) { + d_io_service.stop(); + d_thread.interrupt(); + d_thread.join(); + } + d_started = false; + return true; +} + +void socket_pdu_impl::handle_tcp_read(const boost::system::error_code& error, + size_t bytes_transferred) +{ + if (!error) { + pmt::pmt_t vector = + pmt::init_u8vector(bytes_transferred, (const uint8_t*)&d_rxbuf[0]); + pmt::pmt_t pdu = pmt::cons(pmt::PMT_NIL, vector); + message_port_pub(msgport_names::pdus(), pdu); + + d_tcp_socket->async_read_some( + boost::asio::buffer(d_rxbuf), + boost::bind(&socket_pdu_impl::handle_tcp_read, + this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } else + throw boost::system::system_error(error); +} + +void socket_pdu_impl::start_tcp_accept() +{ +#if (BOOST_VERSION >= 107000) + tcp_connection::sptr new_connection = + tcp_connection::make(d_io_service, d_rxbuf.size(), d_tcp_no_delay); +#else + tcp_connection::sptr new_connection = tcp_connection::make( + d_acceptor_tcp->get_io_service(), d_rxbuf.size(), d_tcp_no_delay); +#endif + + d_acceptor_tcp->async_accept(new_connection->socket(), + boost::bind(&socket_pdu_impl::handle_tcp_accept, + this, + new_connection, + boost::asio::placeholders::error)); +} + +void socket_pdu_impl::tcp_server_send(pmt::pmt_t msg) +{ + pmt::pmt_t vector = pmt::cdr(msg); + for (size_t i = 0; i < d_tcp_connections.size(); i++) + d_tcp_connections[i]->send(vector); +} + +void socket_pdu_impl::handle_tcp_accept(tcp_connection::sptr new_connection, + const boost::system::error_code& error) +{ + if (!error) { + // Garbage collect closed sockets + std::vector<tcp_connection::sptr>::iterator it = d_tcp_connections.begin(); + while (it != d_tcp_connections.end()) { + if (!(**it).socket().is_open()) + it = d_tcp_connections.erase(it); + else + ++it; + } + + new_connection->start(this); + d_tcp_connections.push_back(new_connection); + start_tcp_accept(); + } else + std::cout << error << std::endl; +} + +void socket_pdu_impl::tcp_client_send(pmt::pmt_t msg) +{ + pmt::pmt_t vector = pmt::cdr(msg); + size_t len = pmt::blob_length(vector); + size_t offset = 0; + std::vector<char> txbuf(std::min(len, d_rxbuf.size())); + while (offset < len) { + size_t send_len = std::min((len - offset), txbuf.size()); + memcpy(&txbuf[0], pmt::uniform_vector_elements(vector, offset), send_len); + offset += send_len; + d_tcp_socket->send(boost::asio::buffer(txbuf, send_len)); + } +} + +void socket_pdu_impl::udp_send(pmt::pmt_t msg) +{ + if (d_udp_endpoint_other.address().to_string() == "0.0.0.0") + return; + + pmt::pmt_t vector = pmt::cdr(msg); + size_t len = pmt::blob_length(vector); + size_t offset = 0; + std::vector<char> txbuf(std::min(len, d_rxbuf.size())); + while (offset < len) { + size_t send_len = std::min((len - offset), txbuf.size()); + memcpy(&txbuf[0], pmt::uniform_vector_elements(vector, offset), send_len); + offset += send_len; + d_udp_socket->send_to(boost::asio::buffer(txbuf, send_len), d_udp_endpoint_other); + } +} + +void socket_pdu_impl::handle_udp_read(const boost::system::error_code& error, + size_t bytes_transferred) +{ + if (!error) { + pmt::pmt_t vector = + pmt::init_u8vector(bytes_transferred, (const uint8_t*)&d_rxbuf[0]); + pmt::pmt_t pdu = pmt::cons(pmt::PMT_NIL, vector); + + message_port_pub(msgport_names::pdus(), pdu); + + d_udp_socket->async_receive_from( + boost::asio::buffer(d_rxbuf), + d_udp_endpoint_other, + boost::bind(&socket_pdu_impl::handle_udp_read, + this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } +} + +} /* namespace network */ +} /* namespace gr */ diff --git a/gr-network/lib/socket_pdu_impl.h b/gr-network/lib/socket_pdu_impl.h new file mode 100644 index 0000000000..9175290a4e --- /dev/null +++ b/gr-network/lib/socket_pdu_impl.h @@ -0,0 +1,68 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_NETWORK_SOCKET_PDU_IMPL_H +#define INCLUDED_NETWORK_SOCKET_PDU_IMPL_H + +#include "tcp_connection.h" +#include <gnuradio/network/socket_pdu.h> + +namespace gr { +namespace network { + +class socket_pdu_impl : public socket_pdu +{ +private: + boost::asio::io_service d_io_service; + std::vector<char> d_rxbuf; + void run_io_service() { d_io_service.run(); } + gr::thread::thread d_thread; + bool d_started; + + // TCP specific + boost::asio::ip::tcp::endpoint d_tcp_endpoint; + std::vector<tcp_connection::sptr> d_tcp_connections; + void handle_tcp_read(const boost::system::error_code& error, + size_t bytes_transferred); + const bool d_tcp_no_delay; + + // TCP server specific + std::shared_ptr<boost::asio::ip::tcp::acceptor> d_acceptor_tcp; + void start_tcp_accept(); + void tcp_server_send(pmt::pmt_t msg); + void handle_tcp_accept(tcp_connection::sptr new_connection, + const boost::system::error_code& error); + + // TCP client specific + std::shared_ptr<boost::asio::ip::tcp::socket> d_tcp_socket; + void tcp_client_send(pmt::pmt_t msg); + + // UDP specific + boost::asio::ip::udp::endpoint d_udp_endpoint; + boost::asio::ip::udp::endpoint d_udp_endpoint_other; + std::shared_ptr<boost::asio::ip::udp::socket> d_udp_socket; + void handle_udp_read(const boost::system::error_code& error, + size_t bytes_transferred); + void udp_send(pmt::pmt_t msg); + +public: + socket_pdu_impl(std::string type, + std::string addr, + std::string port, + int MTU = 10000, + bool tcp_no_delay = false); + ~socket_pdu_impl() override; + bool stop() override; +}; + +} /* namespace network */ +} /* namespace gr */ + +#endif /* INCLUDED_NETWORK_SOCKET_PDU_IMPL_H */ diff --git a/gr-network/lib/stream_pdu_base.cc b/gr-network/lib/stream_pdu_base.cc new file mode 100644 index 0000000000..a6519cedab --- /dev/null +++ b/gr-network/lib/stream_pdu_base.cc @@ -0,0 +1,110 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_IO_H +#include <io.h> +#endif + +#ifdef HAVE_WINDOWS_H +#include <winsock2.h> +#endif + +#include "stream_pdu_base.h" +#include <gnuradio/basic_block.h> +#include <gnuradio/logger.h> +#include <gnuradio/pdu.h> +#include <boost/format.hpp> + +static const long timeout_us = 100 * 1000; // 100ms + +namespace gr { +namespace network { + +stream_pdu_base::stream_pdu_base(int MTU) : d_fd(-1), d_started(false), d_finished(false) +{ + gr::configure_default_loggers(d_pdu_logger, d_pdu_debug_logger, "stream_pdu_base"); + // reserve space for rx buffer + d_rxbuf.resize(MTU, 0); +} + +stream_pdu_base::~stream_pdu_base() { stop_rxthread(); } + +void stream_pdu_base::start_rxthread(basic_block* blk, pmt::pmt_t port) +{ + d_blk = blk; + d_port = port; + d_thread = gr::thread::thread(std::bind(&stream_pdu_base::run, this)); + d_started = true; +} + +void stream_pdu_base::stop_rxthread() +{ + d_finished = true; + + if (d_started) { + d_thread.interrupt(); + d_thread.join(); + } +} + +void stream_pdu_base::run() +{ + while (!d_finished) { + if (!wait_ready()) + continue; + + const int result = read(d_fd, &d_rxbuf[0], d_rxbuf.size()); + if (result <= 0) + throw std::runtime_error("stream_pdu_base, bad socket read!"); + + pmt::pmt_t vector = pmt::init_u8vector(result, &d_rxbuf[0]); + pmt::pmt_t pdu = pmt::cons(pmt::PMT_NIL, vector); + + d_blk->message_port_pub(d_port, pdu); + } +} + +bool stream_pdu_base::wait_ready() +{ + // setup timeval for timeout + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = timeout_us; + + // setup rset for timeout + fd_set rset; + FD_ZERO(&rset); + FD_SET(d_fd, &rset); + + // call select with timeout on receive socket + return ::select(d_fd + 1, &rset, NULL, NULL, &tv) > 0; +} + +void stream_pdu_base::send(pmt::pmt_t msg) +{ + pmt::pmt_t vector = pmt::cdr(msg); + size_t offset(0); + size_t itemsize(pdu::itemsize(pdu::type_from_pmt(vector))); + int len(pmt::length(vector) * itemsize); + + const int rv = write(d_fd, pmt::uniform_vector_elements(vector, offset), len); + if (rv != len) { + static auto msg = boost::format( + "stream_pdu_base::send(pdu) write failed! (d_fd=%d, len=%d, rv=%d)"); + GR_LOG_WARN(d_pdu_logger, msg % d_fd % len % rv); + } +} + +} /* namespace network */ +} /* namespace gr */ diff --git a/gr-network/lib/stream_pdu_base.h b/gr-network/lib/stream_pdu_base.h new file mode 100644 index 0000000000..40940de7de --- /dev/null +++ b/gr-network/lib/stream_pdu_base.h @@ -0,0 +1,52 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_STREAM_PDU_BASE_H +#define INCLUDED_STREAM_PDU_BASE_H + +#include <gnuradio/basic_block.h> +#include <gnuradio/logger.h> +#include <gnuradio/thread/thread.h> +#include <pmt/pmt.h> + +class basic_block; + +namespace gr { +namespace network { + +class stream_pdu_base +{ +public: + stream_pdu_base(int MTU = 10000); + ~stream_pdu_base(); + +protected: + int d_fd; + bool d_started; + bool d_finished; + std::vector<uint8_t> d_rxbuf; + gr::thread::thread d_thread; + + pmt::pmt_t d_port; + basic_block* d_blk; + + void run(); + void send(pmt::pmt_t msg); + bool wait_ready(); + void start_rxthread(basic_block* blk, pmt::pmt_t rxport); + void stop_rxthread(); + + gr::logger_ptr d_pdu_logger, d_pdu_debug_logger; +}; + +} /* namespace network */ +} /* namespace gr */ + +#endif /* INCLUDED_STREAM_PDU_BASE_H */ diff --git a/gr-network/lib/tcp_connection.cc b/gr-network/lib/tcp_connection.cc new file mode 100644 index 0000000000..dfb511e053 --- /dev/null +++ b/gr-network/lib/tcp_connection.cc @@ -0,0 +1,101 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tcp_connection.h" +#include <gnuradio/basic_block.h> +#include <gnuradio/pdu.h> + +namespace gr { +namespace network { + +tcp_connection::sptr tcp_connection::make(boost::asio::io_service& io_service, + int MTU /*= 10000*/, + bool no_delay /*=false*/) +{ + return sptr(new tcp_connection(io_service, MTU, no_delay)); +} + +tcp_connection::tcp_connection(boost::asio::io_service& io_service, + int MTU /*= 10000*/, + bool no_delay /*=false*/) + : d_socket(io_service), d_buf(MTU), d_block(NULL), d_no_delay(no_delay) +{ + try { + d_socket.set_option(boost::asio::ip::tcp::no_delay(no_delay)); + } catch (...) { + // Silently ignore failure (socket might be current in accept stage) and try again + // in 'start' + } +} + +void tcp_connection::send(pmt::pmt_t vector) +{ + size_t len = pmt::blob_length(vector); + + // Asio async_write() requires the buffer to remain valid until the handler is called. + auto txbuf = std::make_shared<std::vector<char>>(len); + + size_t temp = 0; + memcpy(txbuf->data(), pmt::uniform_vector_elements(vector, temp), len); + + size_t offset = 0; + while (offset < len) { + // Limit the size of each write() to the MTU. + // FIXME: Note that this has the effect of breaking a large PDU into several + // smaller PDUs, each containing <= MTU bytes. Is this the desired behavior? + size_t send_len = std::min((len - offset), d_buf.size()); + boost::asio::async_write( + d_socket, + boost::asio::buffer(txbuf->data() + offset, send_len), + [txbuf](const boost::system::error_code& error, size_t bytes_transferred) {}); + offset += send_len; + } +} + +void tcp_connection::start(gr::basic_block* block) +{ + d_block = block; + d_socket.set_option(boost::asio::ip::tcp::no_delay(d_no_delay)); + d_socket.async_read_some(boost::asio::buffer(d_buf), + boost::bind(&tcp_connection::handle_read, + this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); +} + +void tcp_connection::handle_read(const boost::system::error_code& error, + size_t bytes_transferred) +{ + if (!error) { + if (d_block) { + pmt::pmt_t vector = + pmt::init_u8vector(bytes_transferred, (const uint8_t*)&d_buf[0]); + pmt::pmt_t pdu = pmt::cons(pmt::PMT_NIL, vector); + + d_block->message_port_pub(msgport_names::pdus(), pdu); + } + + d_socket.async_read_some( + boost::asio::buffer(d_buf), + boost::bind(&tcp_connection::handle_read, + this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } else { + d_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both); + d_socket.close(); + } +} +} /* namespace network */ +} /* namespace gr */ diff --git a/gr-network/lib/tcp_connection.h b/gr-network/lib/tcp_connection.h new file mode 100644 index 0000000000..29a2bd79fb --- /dev/null +++ b/gr-network/lib/tcp_connection.h @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_TCP_CONNECTION_H +#define INCLUDED_TCP_CONNECTION_H + +#include <pmt/pmt.h> +#include <boost/array.hpp> +#include <boost/asio.hpp> +#include <memory> + +namespace gr { + +class basic_block; + +namespace network { + +class tcp_connection +{ +private: + boost::asio::ip::tcp::socket d_socket; + std::vector<char> d_buf; + basic_block* d_block; + bool d_no_delay; + + tcp_connection(boost::asio::io_service& io_service, + int MTU = 10000, + bool no_delay = false); + + void handle_read(const boost::system::error_code& error, size_t bytes_transferred); + +public: + typedef std::shared_ptr<tcp_connection> sptr; + + static sptr + make(boost::asio::io_service& io_service, int MTU = 10000, bool no_delay = false); + + boost::asio::ip::tcp::socket& socket() { return d_socket; }; + + void start(gr::basic_block* block); + void send(pmt::pmt_t vector); +}; + +} /* namespace network */ +} /* namespace gr */ + +#endif /* INCLUDED_TCP_CONNECTION_H */ diff --git a/gr-network/lib/tuntap_pdu_impl.cc b/gr-network/lib/tuntap_pdu_impl.cc new file mode 100644 index 0000000000..87c3750fd9 --- /dev/null +++ b/gr-network/lib/tuntap_pdu_impl.cc @@ -0,0 +1,172 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tuntap_pdu_impl.h" +#include <gnuradio/io_signature.h> +#include <gnuradio/pdu.h> +#include <boost/format.hpp> + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#if (defined(linux) || defined(__linux) || defined(__linux__)) +#include <arpa/inet.h> +#include <linux/if.h> +#include <sys/ioctl.h> +#endif + +namespace gr { +namespace network { + +tuntap_pdu::sptr tuntap_pdu::make(std::string dev, int MTU, bool istunflag) +{ +#if (defined(linux) || defined(__linux) || defined(__linux__)) + return gnuradio::make_block_sptr<tuntap_pdu_impl>(dev, MTU, istunflag); +#else + throw std::runtime_error("tuntap_pdu not implemented on this platform"); +#endif +} + +#if (defined(linux) || defined(__linux) || defined(__linux__)) +tuntap_pdu_impl::tuntap_pdu_impl(std::string dev, int MTU, bool istunflag) + : block("tuntap_pdu", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + stream_pdu_base(istunflag ? MTU : MTU + 14), + d_dev(dev), + d_istunflag(istunflag) +{ + // make the tuntap + char dev_cstr[IFNAMSIZ]; + memset(dev_cstr, 0x00, IFNAMSIZ); + strncpy(dev_cstr, dev.c_str(), IFNAMSIZ); + dev_cstr[IFNAMSIZ - 1] = '\0'; + + + bool istun = d_istunflag; + if (istun) { + d_fd = tun_alloc(dev_cstr, (IFF_TUN | IFF_NO_PI)); + } else { + d_fd = tun_alloc(dev_cstr, (IFF_TAP | IFF_NO_PI)); + } + + if (d_fd <= 0) + throw std::runtime_error( + "gr::tuntap_pdu::make: tun_alloc failed (are you running as root?)"); + + int err = set_mtu(dev_cstr, MTU); + if (err < 0) { + std::ostringstream msg; + msg << boost::format("failed to set MTU to %d. You should use ifconfig to set " + "the MTU. E.g., `$ sudo ifconfig %s mtu %d`") % + MTU % dev % MTU; + GR_LOG_ERROR(d_logger, msg.str()); + } + + + std::cout << boost::format("Allocated virtual ethernet interface: %s\n" + "You must now use ifconfig to set its IP address. E.g.,\n" + " $ sudo ifconfig %s 192.168.200.1\n" + "Be sure to use a different address in the same subnet " + "for each machine.\n") % + dev % dev + << std::endl; + + // set up output message port + message_port_register_out(msgport_names::pdus()); + start_rxthread(this, msgport_names::pdus()); + + // set up input message port + message_port_register_in(msgport_names::pdus()); + set_msg_handler(msgport_names::pdus(), [this](pmt::pmt_t msg) { this->send(msg); }); +} + +int tuntap_pdu_impl::tun_alloc(char* dev, int flags) +{ + struct ifreq ifr; + int fd, err; + const char* clonedev = "/dev/net/tun"; + + /* Arguments taken by the function: + * + * char *dev: the name of an interface (or '\0'). MUST have enough + * space to hold the interface name if '\0' is passed + * int flags: interface flags (eg, IFF_TUN etc.) + */ + + /* open the clone device */ + if ((fd = open(clonedev, O_RDWR)) < 0) + return fd; + + /* preparation of the struct ifr, of type "struct ifreq" */ + memset(&ifr, 0, sizeof(ifr)); + + ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */ + + /* if a device name was specified, put it in the structure; otherwise, + * the kernel will try to allocate the "next" device of the + * specified type + */ + if (*dev) + strncpy(ifr.ifr_name, dev, IFNAMSIZ - 1); + + /* try to create the device */ + if ((err = ioctl(fd, TUNSETIFF, (void*)&ifr)) < 0) { + close(fd); + return err; + } + + /* if the operation was successful, write back the name of the + * interface to the variable "dev", so the caller can know + * it. Note that the caller MUST reserve space in *dev (see calling + * code below) + */ + strcpy(dev, ifr.ifr_name); + + /* this is the special file descriptor that the caller will use to talk + * with the virtual interface + */ + return fd; +} + +int tuntap_pdu_impl::set_mtu(const char* dev, int MTU) +{ + struct ifreq ifr; + int sfd, err; + + /* MTU must be set by passing a socket fd to ioctl; + * create an arbitrary socket for this purpose + */ + if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return sfd; + + /* preparation of the struct ifr, of type "struct ifreq" */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ - 1] = '\0'; + ifr.ifr_addr.sa_family = AF_INET; /* address family */ + ifr.ifr_mtu = MTU; + + /* try to set MTU */ + if ((err = ioctl(sfd, SIOCSIFMTU, (void*)&ifr)) < 0) { + close(sfd); + return err; + } + + close(sfd); + return MTU; +} +#endif + +} /* namespace network */ +} /* namespace gr */ diff --git a/gr-network/lib/tuntap_pdu_impl.h b/gr-network/lib/tuntap_pdu_impl.h new file mode 100644 index 0000000000..6811712fe8 --- /dev/null +++ b/gr-network/lib/tuntap_pdu_impl.h @@ -0,0 +1,41 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_NETWORK_TUNTAP_PDU_IMPL_H +#define INCLUDED_NETWORK_TUNTAP_PDU_IMPL_H + +#include "stream_pdu_base.h" +#include <gnuradio/network/tuntap_pdu.h> + +#if (defined(linux) || defined(__linux) || defined(__linux__)) +#include <linux/if_tun.h> +#endif + +namespace gr { +namespace network { + +class tuntap_pdu_impl : public tuntap_pdu, public stream_pdu_base +{ +#if (defined(linux) || defined(__linux) || defined(__linux__)) +private: + const std::string d_dev; + const bool d_istunflag; + int tun_alloc(char* dev, int flags); + int set_mtu(const char* dev, int MTU); + +public: + tuntap_pdu_impl(std::string dev, int MTU, bool istunflag); +#endif +}; + +} /* namespace network */ +} /* namespace gr */ + +#endif /* INCLUDED_NETWORK_TUNTAP_PDU_IMPL_H */ diff --git a/gr-network/python/network/CMakeLists.txt b/gr-network/python/network/CMakeLists.txt index a524e6390f..c6feaffc22 100644 --- a/gr-network/python/network/CMakeLists.txt +++ b/gr-network/python/network/CMakeLists.txt @@ -27,8 +27,18 @@ GR_PYTHON_INSTALL( ######################################################################## # Handle the unit tests ######################################################################## -include(GrTest) - -set(GR_TEST_TARGET_DEPS gnuradio-network) +if(ENABLE_TESTING) + set(GR_TEST_TARGET_DEPS "") + set(GR_TEST_LIBRARY_DIRS "") + set(GR_TEST_PYTHON_DIRS + ${CMAKE_BINARY_DIR}/gnuradio-runtime/python + ) + include(GrTest) + file(GLOB py_qa_test_files "qa_*.py") + foreach(py_qa_test_file ${py_qa_test_files}) + get_filename_component(py_qa_test_name ${py_qa_test_file} NAME_WE) + GR_ADD_TEST(${py_qa_test_name} ${QA_PYTHON_EXECUTABLE} -B ${py_qa_test_file}) + endforeach(py_qa_test_file) +endif(ENABLE_TESTING) add_subdirectory(bindings) diff --git a/gr-network/python/network/bindings/CMakeLists.txt b/gr-network/python/network/bindings/CMakeLists.txt index 80f02c00b2..d87f644fd8 100644 --- a/gr-network/python/network/bindings/CMakeLists.txt +++ b/gr-network/python/network/bindings/CMakeLists.txt @@ -6,14 +6,16 @@ include(GrPybind) list(APPEND network_python_files # packet_headers_python.cc + socket_pdu_python.cc tcp_sink_python.cc + tuntap_pdu_python.cc # udp_header_types_python.cc udp_sink_python.cc udp_source_python.cc python_bindings.cc) -GR_PYBIND_MAKE_CHECK_HASH(network - ../../.. +GR_PYBIND_MAKE_CHECK_HASH(network + ../../.. gr::network "${network_python_files}") diff --git a/gr-network/python/network/bindings/docstrings/socket_pdu_pydoc_template.h b/gr-network/python/network/bindings/docstrings/socket_pdu_pydoc_template.h new file mode 100644 index 0000000000..f7b9cb72bf --- /dev/null +++ b/gr-network/python/network/bindings/docstrings/socket_pdu_pydoc_template.h @@ -0,0 +1,24 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#include "pydoc_macros.h" +#define D(...) DOC(gr, network, __VA_ARGS__) +/* + This file contains placeholders for docstrings for the Python bindings. + Do not edit! These were automatically extracted during the binding process + and will be overwritten during the build process + */ + + +static const char* __doc_gr_network_socket_pdu = R"doc()doc"; + + +static const char* __doc_gr_network_socket_pdu_socket_pdu = R"doc()doc"; + + +static const char* __doc_gr_network_socket_pdu_make = R"doc()doc"; diff --git a/gr-network/python/network/bindings/docstrings/tuntap_pdu_pydoc_template.h b/gr-network/python/network/bindings/docstrings/tuntap_pdu_pydoc_template.h new file mode 100644 index 0000000000..ec5bf4be2e --- /dev/null +++ b/gr-network/python/network/bindings/docstrings/tuntap_pdu_pydoc_template.h @@ -0,0 +1,24 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#include "pydoc_macros.h" +#define D(...) DOC(gr, network, __VA_ARGS__) +/* + This file contains placeholders for docstrings for the Python bindings. + Do not edit! These were automatically extracted during the binding process + and will be overwritten during the build process + */ + + +static const char* __doc_gr_network_tuntap_pdu = R"doc()doc"; + + +static const char* __doc_gr_network_tuntap_pdu_tuntap_pdu = R"doc()doc"; + + +static const char* __doc_gr_network_tuntap_pdu_make = R"doc()doc"; diff --git a/gr-network/python/network/bindings/python_bindings.cc b/gr-network/python/network/bindings/python_bindings.cc index 3de111aa79..cacd4a1bf7 100644 --- a/gr-network/python/network/bindings/python_bindings.cc +++ b/gr-network/python/network/bindings/python_bindings.cc @@ -16,7 +16,9 @@ namespace py = pybind11; // void bind_packet_headers(py::module&); +void bind_socket_pdu(py::module&); void bind_tcp_sink(py::module&); +void bind_tuntap_pdu(py::module&); // void bind_udp_header_types(py::module&); void bind_udp_sink(py::module&); void bind_udp_source(py::module&); @@ -41,7 +43,9 @@ PYBIND11_MODULE(network_python, m) py::module::import("gnuradio.gr"); // bind_packet_headers(m); + bind_socket_pdu(m); bind_tcp_sink(m); + bind_tuntap_pdu(m); // bind_udp_header_types(m); bind_udp_sink(m); bind_udp_source(m); diff --git a/gr-network/python/network/bindings/socket_pdu_python.cc b/gr-network/python/network/bindings/socket_pdu_python.cc new file mode 100644 index 0000000000..a3fb134ec1 --- /dev/null +++ b/gr-network/python/network/bindings/socket_pdu_python.cc @@ -0,0 +1,49 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +/***********************************************************************************/ +/* This file is automatically generated using bindtool and can be manually edited */ +/* The following lines can be configured to regenerate this file during cmake */ +/* If manual edits are made, the following tags should be modified accordingly. */ +/* BINDTOOL_GEN_AUTOMATIC(0) */ +/* BINDTOOL_USE_PYGCCXML(0) */ +/* BINDTOOL_HEADER_FILE(socket_pdu.h) */ +/* BINDTOOL_HEADER_FILE_HASH(4c11b80b4561122125568a9ab76cea3a) */ +/***********************************************************************************/ + +#include <pybind11/complex.h> +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +namespace py = pybind11; + +#include <gnuradio/network/socket_pdu.h> +// pydoc.h is automatically generated in the build directory +#include <socket_pdu_pydoc.h> + +void bind_socket_pdu(py::module& m) +{ + + using socket_pdu = gr::network::socket_pdu; + + + py::class_<socket_pdu, gr::block, gr::basic_block, std::shared_ptr<socket_pdu>>( + m, "socket_pdu", D(socket_pdu)) + + .def(py::init(&socket_pdu::make), + py::arg("type"), + py::arg("addr"), + py::arg("port"), + py::arg("MTU") = 10000, + py::arg("tcp_no_delay") = false, + D(socket_pdu, make)) + + + ; +} diff --git a/gr-network/python/network/bindings/tuntap_pdu_python.cc b/gr-network/python/network/bindings/tuntap_pdu_python.cc new file mode 100644 index 0000000000..a5a09f2516 --- /dev/null +++ b/gr-network/python/network/bindings/tuntap_pdu_python.cc @@ -0,0 +1,47 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +/***********************************************************************************/ +/* This file is automatically generated using bindtool and can be manually edited */ +/* The following lines can be configured to regenerate this file during cmake */ +/* If manual edits are made, the following tags should be modified accordingly. */ +/* BINDTOOL_GEN_AUTOMATIC(0) */ +/* BINDTOOL_USE_PYGCCXML(0) */ +/* BINDTOOL_HEADER_FILE(tuntap_pdu.h) */ +/* BINDTOOL_HEADER_FILE_HASH(26b7f31af528ff1bf62a965e6b0dd636) */ +/***********************************************************************************/ + +#include <pybind11/complex.h> +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +namespace py = pybind11; + +#include <gnuradio/network/tuntap_pdu.h> +// pydoc.h is automatically generated in the build directory +#include <tuntap_pdu_pydoc.h> + +void bind_tuntap_pdu(py::module& m) +{ + + using tuntap_pdu = gr::network::tuntap_pdu; + + + py::class_<tuntap_pdu, gr::block, gr::basic_block, std::shared_ptr<tuntap_pdu>>( + m, "tuntap_pdu", D(tuntap_pdu)) + + .def(py::init(&tuntap_pdu::make), + py::arg("dev"), + py::arg("MTU") = 10000, + py::arg("istunflag") = false, + D(tuntap_pdu, make)) + + + ; +} diff --git a/gr-network/python/network/qa_socket_pdu.py b/gr-network/python/network/qa_socket_pdu.py new file mode 100644 index 0000000000..136f7e4cc6 --- /dev/null +++ b/gr-network/python/network/qa_socket_pdu.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python +# +# Copyright 2013 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# + + +from gnuradio import gr, gr_unittest, blocks, pdu +from gnuradio import network +import random +import pmt +import time + + +class qa_socket_pdu (gr_unittest.TestCase): + + def setUp(self): + random.seed(0) + self.tb = gr.top_block() + + def tearDown(self): + self.tb = None + + def test_001(self): + # Test that blocks can be created and destroyed without hanging + port = str(random.Random().randint(0, 30000) + 10000) + self.pdu_send = network.socket_pdu("UDP_CLIENT", "localhost", port) + self.pdu_recv = network.socket_pdu("UDP_SERVER", "localhost", port) + self.pdu_send = None + self.pdu_recv = None + + def test_002(self): + # Send a PDU through a pair of UDP sockets + port = str(random.Random().randint(0, 30000) + 10000) + srcdata = (0x64, 0x6f, 0x67, 0x65) + data = pmt.init_u8vector(srcdata.__len__(), srcdata) + pdu_msg = pmt.cons(pmt.PMT_NIL, data) + + self.pdu_source = blocks.message_strobe(pdu_msg, 500) + self.pdu_recv = network.socket_pdu("UDP_SERVER", "localhost", port) + self.pdu_send = network.socket_pdu("UDP_CLIENT", "localhost", port) + + self.dbg = blocks.message_debug() + + self.tb.msg_connect(self.pdu_source, "strobe", self.pdu_send, "pdus") + self.tb.msg_connect(self.pdu_recv, "pdus", self.dbg, "store") + + self.tb.start() + time.sleep(1) + self.tb.stop() + self.tb.wait() + self.pdu_send = None + self.pdu_recv = None + + received = self.dbg.get_message(0) + received_data = pmt.cdr(received) + msg_data = [] + for i in range(4): + msg_data.append(pmt.u8vector_ref(received_data, i)) + self.assertEqual(srcdata, tuple(msg_data)) + + def test_003(self): + # Test that block stops when interacting with streaming interface + port = str(random.Random().randint(0, 30000) + 10000) + srcdata = ( + 0x73, + 0x75, + 0x63, + 0x68, + 0x74, + 0x65, + 0x73, + 0x74, + 0x76, + 0x65, + 0x72, + 0x79, + 0x70, + 0x61, + 0x73, + 0x73) + tag_dict = {"offset": 0} + tag_dict["key"] = pmt.intern("len") + tag_dict["value"] = pmt.from_long(8) + tag1 = gr.python_to_tag(tag_dict) + tag_dict["offset"] = 8 + tag2 = gr.python_to_tag(tag_dict) + tags = [tag1, tag2] + + src = blocks.vector_source_b(srcdata, False, 1, tags) + ts_to_pdu = pdu.tagged_stream_to_pdu(gr.types.byte_t, "len") + pdu_send = network.socket_pdu("UDP_CLIENT", "localhost", "4141") + #pdu_recv = network.socket_pdu("UDP_SERVER", "localhost", port) + pdu_to_ts = pdu.pdu_to_tagged_stream(gr.types.byte_t, "len") + head = blocks.head(gr.sizeof_char, 10) + sink = blocks.vector_sink_b(1) + + self.tb.connect(src, ts_to_pdu) + self.tb.msg_connect(ts_to_pdu, "pdus", pdu_send, "pdus") + # a UDP socket connects pdu_send to pdu_recv + # TODO: test that the recv socket can be destroyed from downstream + # that signals DONE. Also that we get the PDUs we sent + #self.tb.msg_connect(pdu_recv, "pdus", pdu_to_ts, "pdus") + #self.tb.connect(pdu_to_ts, head, sink) + self.tb.run() + + def test_004(self): + # Test that the TCP server can stream PDUs <= the MTU size. + port = str(random.Random().randint(0, 30000) + 10000) + mtu = 10000 + srcdata = tuple(x % 256 for x in range(mtu)) + data = pmt.init_u8vector(srcdata.__len__(), srcdata) + pdu_msg = pmt.cons(pmt.PMT_NIL, data) + + self.pdu_source = blocks.message_strobe(pdu_msg, 500) + self.pdu_send = network.socket_pdu("TCP_SERVER", "localhost", port, mtu) + self.pdu_recv = network.socket_pdu("TCP_CLIENT", "localhost", port, mtu) + self.pdu_sink = blocks.message_debug() + + self.tb.msg_connect(self.pdu_source, "strobe", self.pdu_send, "pdus") + self.tb.msg_connect(self.pdu_recv, "pdus", self.pdu_sink, "store") + + self.tb.start() + time.sleep(1) + self.tb.stop() + self.tb.wait() + + received = self.pdu_sink.get_message(0) + received_data = pmt.cdr(received) + msg_data = [] + for i in range(mtu): + msg_data.append(pmt.u8vector_ref(received_data, i)) + self.assertEqual(srcdata, tuple(msg_data)) + + +if __name__ == '__main__': + gr_unittest.run(qa_socket_pdu) diff --git a/gr-pdu/grc/CMakeLists.txt b/gr-pdu/grc/CMakeLists.txt index d6ac0115b0..fd0870c6cb 100644 --- a/gr-pdu/grc/CMakeLists.txt +++ b/gr-pdu/grc/CMakeLists.txt @@ -5,7 +5,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later # -install(FILES - pdu_pdu_split.block.yml - DESTINATION ${GRC_BLOCKS_DIR} -) +######################################################################## +file(GLOB yml_files "*.yml") + +install(FILES ${yml_files} DESTINATION ${GRC_BLOCKS_DIR}) diff --git a/gr-pdu/grc/pdu.tree.yml b/gr-pdu/grc/pdu.tree.yml new file mode 100644 index 0000000000..da988d007d --- /dev/null +++ b/gr-pdu/grc/pdu.tree.yml @@ -0,0 +1,9 @@ +'[Core]': +- Message Tools: + - pdu_pdu_filter + - pdu_pdu_remove + - pdu_pdu_set + - pdu_pdu_split + - pdu_pdu_to_tagged_stream + - pdu_tagged_stream_to_pdu + - pdu_random_pdu diff --git a/gr-pdu/grc/pdu_pdu_filter.block.yml b/gr-pdu/grc/pdu_pdu_filter.block.yml new file mode 100644 index 0000000000..292b7ab975 --- /dev/null +++ b/gr-pdu/grc/pdu_pdu_filter.block.yml @@ -0,0 +1,41 @@ +id: pdu_pdu_filter +label: PDU Filter +flags: [ python ] + +parameters: +- id: k + label: Key + dtype: raw + default: pmt.intern("key") +- id: v + label: Value + dtype: raw + default: pmt.intern("value") +- id: invert + label: Invert Filter + dtype: bool + default: 'False' + options: ['False', 'True'] + option_labels: ['No', 'Yes'] + +inputs: +- domain: message + id: pdus + optional: true + +outputs: +- domain: message + id: pdus + optional: true + +templates: + imports: |- + from gnuradio import pdu + import pmt + make: pdu.pdu_filter(${k}, ${v}, ${invert}) + callbacks: + - set_key(${k}) + - set_val(${v}) + - set_inversion(${invert}) + +file_format: 1 diff --git a/gr-pdu/grc/pdu_pdu_remove.block.yml b/gr-pdu/grc/pdu_pdu_remove.block.yml new file mode 100644 index 0000000000..bcb582f0b4 --- /dev/null +++ b/gr-pdu/grc/pdu_pdu_remove.block.yml @@ -0,0 +1,29 @@ +id: pdu_pdu_remove +label: PDU Remove +flags: [ python ] + +parameters: +- id: k + label: Key + dtype: raw + default: pmt.intern("key") + +inputs: +- domain: message + id: pdus + optional: true + +outputs: +- domain: message + id: pdus + optional: true + +templates: + imports: |- + from gnuradio import pdu + import pmt + make: pdu.pdu_remove(${k}) + callbacks: + - set_key(${k}) + +file_format: 1 diff --git a/gr-pdu/grc/pdu_pdu_set.block.yml b/gr-pdu/grc/pdu_pdu_set.block.yml new file mode 100644 index 0000000000..f3d3633d4d --- /dev/null +++ b/gr-pdu/grc/pdu_pdu_set.block.yml @@ -0,0 +1,34 @@ +id: pdu_pdu_set +label: PDU Set +flags: [ python ] + +parameters: +- id: k + label: Key + dtype: raw + default: pmt.intern("key") +- id: v + label: Value + dtype: raw + default: pmt.intern("value") + +inputs: +- domain: message + id: pdus + optional: true + +outputs: +- domain: message + id: pdus + optional: true + +templates: + imports: |- + from gnuradio import pdu + import pmt + make: pdu.pdu_set(${k}, ${v}) + callbacks: + - set_key(${k}) + - set_val(${v}) + +file_format: 1 diff --git a/gr-pdu/grc/pdu_pdu_to_tagged_stream.block.yml b/gr-pdu/grc/pdu_pdu_to_tagged_stream.block.yml new file mode 100644 index 0000000000..b1bb660151 --- /dev/null +++ b/gr-pdu/grc/pdu_pdu_to_tagged_stream.block.yml @@ -0,0 +1,37 @@ +id: pdu_pdu_to_tagged_stream +label: PDU to Tagged Stream +flags: [ python, cpp ] + +parameters: +- id: type + label: Item Type + dtype: enum + options: [byte, complex, float] + option_attributes: + tv: [pdu.byte_t, pdu.complex_t, pdu.float_t] + hide: part +- id: tag + label: Length tag name + dtype: string + default: packet_len + +inputs: +- domain: message + id: pdus + +outputs: +- domain: stream + dtype: ${ type } + +templates: + imports: from gnuradio import pdu + make: pdu.pdu_to_tagged_stream(${type.tv}, ${tag}) + +cpp_templates: + includes: ['#include <gnuradio/pdu/pdu_to_tagged_stream.h>'] + declarations: 'pdu::pdu_to_tagged_stream::sptr ${id};' + make: 'this->${id} = pdu::pdu_to_tagged_stream::make(${type.tv}, ${tag});' + translations: + pdu.: 'pdu::' + +file_format: 1 diff --git a/gr-pdu/grc/pdu_random_pdu.block.yml b/gr-pdu/grc/pdu_random_pdu.block.yml new file mode 100644 index 0000000000..ec2bf72460 --- /dev/null +++ b/gr-pdu/grc/pdu_random_pdu.block.yml @@ -0,0 +1,39 @@ +id: pdu_random_pdu +label: Random PDU Generator +flags: [ python ] + +parameters: +- id: minsize + label: Min Bytes + dtype: int + default: '50' +- id: maxsize + label: Max Bytes + dtype: int + default: '2000' +- id: mask + label: Byte Mask + dtype: int + default: '0xFF' +- id: length_modulo + label: Length Modulo + dtype: int + default: '2' + +inputs: +- domain: message + id: generate + optional: true + +outputs: +- domain: message + id: pdus + optional: true + +templates: + imports: |- + from gnuradio import pdu + import pmt + make: pdu.random_pdu(${minsize}, ${maxsize}, ${mask}, ${length_modulo}) + +file_format: 1 diff --git a/gr-pdu/grc/pdu_tagged_stream_to_pdu.block.yml b/gr-pdu/grc/pdu_tagged_stream_to_pdu.block.yml new file mode 100644 index 0000000000..2fc3071d91 --- /dev/null +++ b/gr-pdu/grc/pdu_tagged_stream_to_pdu.block.yml @@ -0,0 +1,36 @@ +id: pdu_tagged_stream_to_pdu +label: Tagged Stream to PDU +flags: [ python ] + +parameters: +- id: type + label: Item Type + dtype: enum + options: [byte, complex, float] + option_attributes: + tv: [pdu.byte_t, pdu.complex_t, pdu.float_t] + hide: part +- id: tag + label: Length tag name + dtype: string + default: packet_len + +inputs: +- domain: stream + dtype: ${ type } + +outputs: +- domain: message + id: pdus + optional: true + +templates: + imports: from gnuradio import pdu + make: pdu.tagged_stream_to_pdu(${type.tv}, ${tag}) + +cpp_templates: + includes: ['#include <gnuradio/pdu/tagged_stream_to_pdu.h>'] + declarations: 'pdu::tagged_stream_to_pdu::sptr ${id};' + make: 'this->${id} = pdu::tagged_stream_to_pdu::make(${type.tv}, ${tag});' + +file_format: 1 diff --git a/gr-pdu/include/gnuradio/pdu/CMakeLists.txt b/gr-pdu/include/gnuradio/pdu/CMakeLists.txt index b007685797..2daa248c19 100644 --- a/gr-pdu/include/gnuradio/pdu/CMakeLists.txt +++ b/gr-pdu/include/gnuradio/pdu/CMakeLists.txt @@ -10,8 +10,14 @@ ######################################################################## install(FILES api.h - pdu_split.h pdu.h + pdu_filter.h + pdu_remove.h + pdu_set.h + pdu_split.h + pdu_to_tagged_stream.h + random_pdu.h + tagged_stream_to_pdu.h DESTINATION ${GR_INCLUDE_DIR}/gnuradio/pdu ) diff --git a/gr-pdu/include/gnuradio/pdu/pdu.h b/gr-pdu/include/gnuradio/pdu/pdu.h index c6c0b4db3c..bb0ed72473 100644 --- a/gr-pdu/include/gnuradio/pdu/pdu.h +++ b/gr-pdu/include/gnuradio/pdu/pdu.h @@ -1,19 +1,24 @@ /* -*- c++ -*- */ /* - * Copyright 2021 NTESS LLC. + * Copyright 2013,2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio * * SPDX-License-Identifier: GPL-3.0-or-later + * */ -#ifndef INCLUDED_PDU_PORT_NAMES_H -#define INCLUDED_PDU_PORT_NAMES_H +#ifndef INCLUDED_PDU_PDU_H +#define INCLUDED_PDU_PDU_H +#include <gnuradio/gr_complex.h> #include <gnuradio/pdu/api.h> #include <pmt/pmt.h> namespace gr { namespace pdu { +enum vector_type { byte_t, float_t, complex_t }; // static const PMT interned string getters @@ -23,8 +28,14 @@ PDU_API const pmt::pmt_t PMTCONSTSTR__emit(); PDU_API const pmt::pmt_t PMTCONSTSTR__msg(); PDU_API const pmt::pmt_t PMTCONSTSTR__pdus(); +// pdu functions +PDU_API size_t itemsize(vector_type type); +PDU_API bool type_matches(vector_type type, pmt::pmt_t v); +PDU_API pmt::pmt_t make_pdu_vector(vector_type type, const uint8_t* buf, size_t items); +PDU_API vector_type type_from_pmt(pmt::pmt_t vector); + } // namespace pdu } // namespace gr -#endif /* INCLUDED_PDU_PORT_NAMES_H */ +#endif /* INCLUDED_PDU_PDU_H */ diff --git a/gr-pdu/include/gnuradio/pdu/pdu_filter.h b/gr-pdu/include/gnuradio/pdu/pdu_filter.h new file mode 100644 index 0000000000..6437c04052 --- /dev/null +++ b/gr-pdu/include/gnuradio/pdu/pdu_filter.h @@ -0,0 +1,43 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_PDU_FILTER_H +#define INCLUDED_PDU_PDU_FILTER_H + +#include <gnuradio/block.h> +#include <gnuradio/pdu/api.h> + +namespace gr { +namespace pdu { + +/*! + * \brief Propagates only pdus containing k=>v in meta + * \ingroup message_tools_blk + * \ingroup debug_tools_blk + */ +class PDU_API pdu_filter : virtual public block +{ +public: + // gr::pdu::pdu_filter::sptr + typedef std::shared_ptr<pdu_filter> sptr; + + /*! + * \brief Construct a PDU filter + */ + static sptr make(pmt::pmt_t k, pmt::pmt_t v, bool invert = false); + virtual void set_key(pmt::pmt_t key) = 0; + virtual void set_val(pmt::pmt_t val) = 0; + virtual void set_inversion(bool invert) = 0; +}; + +} /* namespace pdu */ +} /* namespace gr */ + +#endif /* INCLUDED_PDU_PDU_FILTER_H */ diff --git a/gr-pdu/include/gnuradio/pdu/pdu_remove.h b/gr-pdu/include/gnuradio/pdu/pdu_remove.h new file mode 100644 index 0000000000..22122b8a59 --- /dev/null +++ b/gr-pdu/include/gnuradio/pdu/pdu_remove.h @@ -0,0 +1,41 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_PDU_REMOVE_H +#define INCLUDED_PDU_PDU_REMOVE_H + +#include <gnuradio/block.h> +#include <gnuradio/pdu/api.h> + +namespace gr { +namespace pdu { + +/*! + * \brief remove key k in pdu's meta field and pass on + * \ingroup message_tools_blk + * \ingroup debug_tools_blk + */ +class PDU_API pdu_remove : virtual public block +{ +public: + // gr::pdu::pdu_remove::sptr + typedef std::shared_ptr<pdu_remove> sptr; + + /*! + * \brief Construct a PDU meta remove block + */ + static sptr make(pmt::pmt_t k); + virtual void set_key(pmt::pmt_t key) = 0; +}; + +} /* namespace pdu */ +} /* namespace gr */ + +#endif /* INCLUDED_PDU_PDU_REMOVE_H */ diff --git a/gr-pdu/include/gnuradio/pdu/pdu_set.h b/gr-pdu/include/gnuradio/pdu/pdu_set.h new file mode 100644 index 0000000000..1874cbe87e --- /dev/null +++ b/gr-pdu/include/gnuradio/pdu/pdu_set.h @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_PDU_SET_H +#define INCLUDED_PDU_PDU_SET_H + +#include <gnuradio/block.h> +#include <gnuradio/pdu/api.h> + +namespace gr { +namespace pdu { + +/*! + * \brief Set k=>v in pdu's meta field and pass on + * \ingroup message_tools_blk + * \ingroup debug_tools_blk + */ +class PDU_API pdu_set : virtual public block +{ +public: + // gr::pdu::pdu_set::sptr + typedef std::shared_ptr<pdu_set> sptr; + + /*! + * \brief Construct a PDU meta set block + */ + static sptr make(pmt::pmt_t k, pmt::pmt_t v); + virtual void set_key(pmt::pmt_t key) = 0; + virtual void set_val(pmt::pmt_t val) = 0; +}; + +} /* namespace pdu */ +} /* namespace gr */ + +#endif /* INCLUDED_PDU_PDU_SET_H */ diff --git a/gr-pdu/include/gnuradio/pdu/pdu_to_tagged_stream.h b/gr-pdu/include/gnuradio/pdu/pdu_to_tagged_stream.h new file mode 100644 index 0000000000..ed0c7b8064 --- /dev/null +++ b/gr-pdu/include/gnuradio/pdu/pdu_to_tagged_stream.h @@ -0,0 +1,44 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_PDU_TO_TAGGED_STREAM_H +#define INCLUDED_PDU_PDU_TO_TAGGED_STREAM_H + +#include <gnuradio/pdu.h> +#include <gnuradio/pdu/api.h> +#include <gnuradio/tagged_stream_block.h> + +namespace gr { +namespace pdu { + +/*! + * \brief Turns received PDUs into a tagged stream of items + * \ingroup message_tools_blk + */ +class PDU_API pdu_to_tagged_stream : virtual public tagged_stream_block +{ +public: + // gr::pdu::pdu_to_tagged_stream::sptr + typedef std::shared_ptr<pdu_to_tagged_stream> sptr; + + /*! + * \brief Construct a pdu_to_tagged_stream block + * \param type PDU type of gr::types::vector_type + * \param lengthtagname The name of the tag that specifies how long the packet is. + * Defaults to 'packet_len'. + */ + static sptr make(gr::types::vector_type type, + const std::string& lengthtagname = "packet_len"); +}; + +} /* namespace pdu */ +} /* namespace gr */ + +#endif /* INCLUDED_PDU_PDU_TO_TAGGED_STREAM_H */ diff --git a/gr-pdu/include/gnuradio/pdu/random_pdu.h b/gr-pdu/include/gnuradio/pdu/random_pdu.h new file mode 100644 index 0000000000..a9b8b6ed78 --- /dev/null +++ b/gr-pdu/include/gnuradio/pdu/random_pdu.h @@ -0,0 +1,41 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_RANDOM_PDU_H +#define INCLUDED_PDU_RANDOM_PDU_H + +#include <gnuradio/block.h> +#include <gnuradio/pdu/api.h> + +namespace gr { +namespace pdu { + +/*! + * \brief Sends a random PDU at intervals + * \ingroup message_tools_blk + * \ingroup debug_tools_blk + */ +class PDU_API random_pdu : virtual public block +{ +public: + // gr::pdu::random_pdu::sptr + typedef std::shared_ptr<random_pdu> sptr; + + /*! + * \brief Construct a random PDU generator + */ + static sptr + make(int mintime, int maxtime, unsigned char byte_mask = 0xFF, int length_modulo = 1); +}; + +} /* namespace pdu */ +} /* namespace gr */ + +#endif /* INCLUDED_PDU_RANDOM_PDU_H */ diff --git a/gr-pdu/include/gnuradio/pdu/tagged_stream_to_pdu.h b/gr-pdu/include/gnuradio/pdu/tagged_stream_to_pdu.h new file mode 100644 index 0000000000..c46ac72982 --- /dev/null +++ b/gr-pdu/include/gnuradio/pdu/tagged_stream_to_pdu.h @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013,2014 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_TAGGED_STREAM_TO_PDU_H +#define INCLUDED_PDU_TAGGED_STREAM_TO_PDU_H + +#include <gnuradio/pdu.h> +#include <gnuradio/pdu/api.h> +#include <gnuradio/tagged_stream_block.h> + +namespace gr { +namespace pdu { + +/*! + * \brief Turns received stream data and tags into PDUs and sends + * them through a message port. + * \ingroup message_tools_blk + * + * The sent message is a PMT-pair (created by pmt::cons()). The + * first element is a dictionary containing all the tags. The + * second is a vector containing the actual data. + */ +class PDU_API tagged_stream_to_pdu : virtual public tagged_stream_block +{ +public: + // gr::pdu::tagged_stream_to_pdu::sptr + typedef std::shared_ptr<tagged_stream_to_pdu> sptr; + + /*! + * \brief Construct a tagged_stream_to_pdu block + * \param type PDU type of gr::types::vector_type + * \param lengthtagname The name of the tag that specifies + * how long the packet is. + */ + static sptr make(gr::types::vector_type type, + const std::string& lengthtagname = "packet_len"); +}; + +} /* namespace pdu */ +} /* namespace gr */ + +#endif /* INCLUDED_PDU_TAGGED_STREAM_TO_PDU_H */ diff --git a/gr-pdu/lib/CMakeLists.txt b/gr-pdu/lib/CMakeLists.txt index 72fb6a80f3..e0d609424a 100644 --- a/gr-pdu/lib/CMakeLists.txt +++ b/gr-pdu/lib/CMakeLists.txt @@ -9,8 +9,14 @@ # Setup library ######################################################################## add_library(gnuradio-pdu - pdu_split_impl.cc pdu.cc + pdu_filter_impl.cc + pdu_remove_impl.cc + pdu_set_impl.cc + pdu_split_impl.cc + pdu_to_tagged_stream_impl.cc + random_pdu_impl.cc + tagged_stream_to_pdu_impl.cc ) #Add Windows DLL resource file if using MSVC diff --git a/gr-pdu/lib/pdu.cc b/gr-pdu/lib/pdu.cc index 68d7dec3a4..3f0a32e6e4 100644 --- a/gr-pdu/lib/pdu.cc +++ b/gr-pdu/lib/pdu.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2021 NTESS LLC. + * Copyright 2013,2021 Free Software Foundation, Inc. * * SPDX-License-Identifier: GPL-3.0-or-later */ @@ -44,5 +44,58 @@ const pmt::pmt_t PMTCONSTSTR__pdus() } +size_t itemsize(vector_type type) +{ + switch (type) { + case byte_t: + return sizeof(char); + case float_t: + return sizeof(float); + case complex_t: + return sizeof(gr_complex); + default: + throw std::runtime_error("bad PDU type"); + } +} + +bool type_matches(vector_type type, pmt::pmt_t v) +{ + switch (type) { + case byte_t: + return pmt::is_u8vector(v); + case float_t: + return pmt::is_f32vector(v); + case complex_t: + return pmt::is_c32vector(v); + default: + throw std::runtime_error("bad PDU type"); + } +} + +pmt::pmt_t make_pdu_vector(vector_type type, const uint8_t* buf, size_t items) +{ + switch (type) { + case byte_t: + return pmt::init_u8vector(items, buf); + case float_t: + return pmt::init_f32vector(items, (const float*)buf); + case complex_t: + return pmt::init_c32vector(items, (const gr_complex*)buf); + default: + throw std::runtime_error("bad PDU type"); + } +} + +vector_type type_from_pmt(pmt::pmt_t vector) +{ + if (pmt::is_u8vector(vector)) + return byte_t; + if (pmt::is_f32vector(vector)) + return float_t; + if (pmt::is_c32vector(vector)) + return complex_t; + throw std::runtime_error("bad PDU type"); +} + } /* namespace pdu */ } /* namespace gr */ diff --git a/gr-pdu/lib/pdu_filter_impl.cc b/gr-pdu/lib/pdu_filter_impl.cc new file mode 100644 index 0000000000..34c519a1f6 --- /dev/null +++ b/gr-pdu/lib/pdu_filter_impl.cc @@ -0,0 +1,59 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pdu_filter_impl.h" +#include <gnuradio/io_signature.h> +#include <gnuradio/pdu.h> + +namespace gr { +namespace pdu { + +pdu_filter::sptr pdu_filter::make(pmt::pmt_t k, pmt::pmt_t v, bool invert) +{ + return gnuradio::make_block_sptr<pdu_filter_impl>(k, v, invert); +} + +pdu_filter_impl::pdu_filter_impl(pmt::pmt_t k, pmt::pmt_t v, bool invert) + : block("pdu_filter", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + d_k(k), + d_v(v), + d_invert(invert) +{ + message_port_register_out(msgport_names::pdus()); + message_port_register_in(msgport_names::pdus()); + set_msg_handler(msgport_names::pdus(), + [this](pmt::pmt_t msg) { this->handle_msg(msg); }); +} + +void pdu_filter_impl::handle_msg(pmt::pmt_t pdu) +{ + pmt::pmt_t meta = pmt::car(pdu); + bool output = d_invert; + + // check base type + // key exists + // value matches + if (pmt::is_dict(meta) && dict_has_key(meta, d_k) && + pmt::eqv(pmt::dict_ref(meta, d_k, pmt::PMT_NIL), d_v)) { + output = !d_invert; + } + + // if all tests pass, propagate the pdu + if (output) { + message_port_pub(msgport_names::pdus(), pdu); + } +} + +} /* namespace pdu */ +} /* namespace gr */ diff --git a/gr-pdu/lib/pdu_filter_impl.h b/gr-pdu/lib/pdu_filter_impl.h new file mode 100644 index 0000000000..e8f532f132 --- /dev/null +++ b/gr-pdu/lib/pdu_filter_impl.h @@ -0,0 +1,37 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_PDU_FILTER_IMPL_H +#define INCLUDED_PDU_PDU_FILTER_IMPL_H + +#include <gnuradio/pdu/pdu_filter.h> + +namespace gr { +namespace pdu { + +class pdu_filter_impl : public pdu_filter +{ +private: + pmt::pmt_t d_k; + pmt::pmt_t d_v; + bool d_invert; + +public: + pdu_filter_impl(pmt::pmt_t k, pmt::pmt_t v, bool invert); + void handle_msg(pmt::pmt_t msg); + void set_key(pmt::pmt_t key) override { d_k = key; }; + void set_val(pmt::pmt_t val) override { d_v = val; }; + void set_inversion(bool invert) override { d_invert = invert; }; +}; + +} /* namespace pdu */ +} /* namespace gr */ + +#endif /* INCLUDED_PDU_PDU_FILTER_IMPL_H */ diff --git a/gr-pdu/lib/pdu_remove_impl.cc b/gr-pdu/lib/pdu_remove_impl.cc new file mode 100644 index 0000000000..a23869a9ff --- /dev/null +++ b/gr-pdu/lib/pdu_remove_impl.cc @@ -0,0 +1,51 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pdu_remove_impl.h" +#include <gnuradio/io_signature.h> +#include <gnuradio/pdu.h> + +namespace gr { +namespace pdu { + +pdu_remove::sptr pdu_remove::make(pmt::pmt_t k) +{ + return gnuradio::make_block_sptr<pdu_remove_impl>(k); +} + +pdu_remove_impl::pdu_remove_impl(pmt::pmt_t k) + : block("pdu_remove", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + d_k(k) +{ + message_port_register_out(msgport_names::pdus()); + message_port_register_in(msgport_names::pdus()); + set_msg_handler(msgport_names::pdus(), + [this](pmt::pmt_t msg) { this->handle_msg(msg); }); +} + +void pdu_remove_impl::handle_msg(pmt::pmt_t pdu) +{ + // add the field and publish + pmt::pmt_t meta = pmt::car(pdu); + if (pmt::is_null(meta)) { + meta = pmt::make_dict(); + } else if (!pmt::is_dict(meta)) { + throw std::runtime_error("pdu_remove received non PDU input"); + } + meta = pmt::dict_delete(meta, d_k); + message_port_pub(msgport_names::pdus(), pmt::cons(meta, pmt::cdr(pdu))); +} + +} /* namespace pdu */ +} /* namespace gr */ diff --git a/gr-pdu/lib/pdu_remove_impl.h b/gr-pdu/lib/pdu_remove_impl.h new file mode 100644 index 0000000000..43da752ddf --- /dev/null +++ b/gr-pdu/lib/pdu_remove_impl.h @@ -0,0 +1,33 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_PDU_REMOVE_IMPL_H +#define INCLUDED_PDU_PDU_REMOVE_IMPL_H + +#include <gnuradio/pdu/pdu_remove.h> + +namespace gr { +namespace pdu { + +class pdu_remove_impl : public pdu_remove +{ +private: + pmt::pmt_t d_k; + +public: + pdu_remove_impl(pmt::pmt_t k); + void handle_msg(pmt::pmt_t msg); + void set_key(pmt::pmt_t key) override { d_k = key; }; +}; + +} /* namespace pdu */ +} /* namespace gr */ + +#endif /* INCLUDED_PDU_PDU_REMOVE_IMPL_H */ diff --git a/gr-pdu/lib/pdu_set_impl.cc b/gr-pdu/lib/pdu_set_impl.cc new file mode 100644 index 0000000000..08dd68d2b0 --- /dev/null +++ b/gr-pdu/lib/pdu_set_impl.cc @@ -0,0 +1,52 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pdu_set_impl.h" +#include <gnuradio/io_signature.h> +#include <gnuradio/pdu.h> + +namespace gr { +namespace pdu { + +pdu_set::sptr pdu_set::make(pmt::pmt_t k, pmt::pmt_t v) +{ + return gnuradio::make_block_sptr<pdu_set_impl>(k, v); +} + +pdu_set_impl::pdu_set_impl(pmt::pmt_t k, pmt::pmt_t v) + : block("pdu_set", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + d_k(k), + d_v(v) +{ + message_port_register_out(msgport_names::pdus()); + message_port_register_in(msgport_names::pdus()); + set_msg_handler(msgport_names::pdus(), + [this](pmt::pmt_t msg) { this->handle_msg(msg); }); +} + +void pdu_set_impl::handle_msg(pmt::pmt_t pdu) +{ + // add the field and publish + pmt::pmt_t meta = pmt::car(pdu); + if (pmt::is_null(meta)) { + meta = pmt::make_dict(); + } else if (!pmt::is_dict(meta)) { + throw std::runtime_error("pdu_set received non PDU input"); + } + meta = pmt::dict_add(meta, d_k, d_v); + message_port_pub(msgport_names::pdus(), pmt::cons(meta, pmt::cdr(pdu))); +} + +} /* namespace pdu */ +} /* namespace gr */ diff --git a/gr-pdu/lib/pdu_set_impl.h b/gr-pdu/lib/pdu_set_impl.h new file mode 100644 index 0000000000..4ecfb8db44 --- /dev/null +++ b/gr-pdu/lib/pdu_set_impl.h @@ -0,0 +1,35 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_PDU_SET_IMPL_H +#define INCLUDED_PDU_PDU_SET_IMPL_H + +#include <gnuradio/pdu/pdu_set.h> + +namespace gr { +namespace pdu { + +class pdu_set_impl : public pdu_set +{ +private: + pmt::pmt_t d_k; + pmt::pmt_t d_v; + +public: + pdu_set_impl(pmt::pmt_t k, pmt::pmt_t v); + void handle_msg(pmt::pmt_t msg); + void set_key(pmt::pmt_t key) override { d_k = key; }; + void set_val(pmt::pmt_t val) override { d_v = val; }; +}; + +} /* namespace pdu */ +} /* namespace gr */ + +#endif /* INCLUDED_PDU_PDU_SET_IMPL_H */ diff --git a/gr-pdu/lib/pdu_split_impl.cc b/gr-pdu/lib/pdu_split_impl.cc index 491f00683c..678e650ee2 100644 --- a/gr-pdu/lib/pdu_split_impl.cc +++ b/gr-pdu/lib/pdu_split_impl.cc @@ -14,7 +14,7 @@ #include "pdu_split_impl.h" #include <gnuradio/io_signature.h> -#include <gnuradio/pdu/pdu.h> +#include <gnuradio/pdu.h> namespace gr { namespace pdu { @@ -28,11 +28,11 @@ pdu_split_impl::pdu_split_impl(const bool pass_empty_data) : gr::block("pdu_split", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), d_pass_empty_data(pass_empty_data) { - message_port_register_in(PMTCONSTSTR__pdus()); - set_msg_handler(PMTCONSTSTR__pdus(), + message_port_register_in(msgport_names::pdus()); + set_msg_handler(msgport_names::pdus(), [this](pmt::pmt_t msg) { this->handle_pdu(msg); }); - message_port_register_out(PMTCONSTSTR__dict()); - message_port_register_out(PMTCONSTSTR__data()); + message_port_register_out(msgport_names::dict()); + message_port_register_out(msgport_names::vec()); } pdu_split_impl::~pdu_split_impl() {} @@ -49,11 +49,11 @@ void pdu_split_impl::handle_pdu(pmt::pmt_t pdu) pmt::pmt_t data = pmt::cdr(pdu); if ((!pmt::equal(meta, pmt::PMT_NIL)) | d_pass_empty_data) { - message_port_pub(PMTCONSTSTR__dict(), meta); + message_port_pub(msgport_names::dict(), meta); } if (pmt::length(data) | d_pass_empty_data) { - message_port_pub(PMTCONSTSTR__data(), data); + message_port_pub(msgport_names::vec(), data); } } diff --git a/gr-pdu/lib/pdu_split_impl.h b/gr-pdu/lib/pdu_split_impl.h index e927463dba..cf26b5055e 100644 --- a/gr-pdu/lib/pdu_split_impl.h +++ b/gr-pdu/lib/pdu_split_impl.h @@ -21,11 +21,17 @@ class pdu_split_impl : public pdu_split private: const bool d_pass_empty_data; + /*! + * \brief PDU formatted messages received in this port are split into theier + * dictionary and vector which are each emitted on separate output ports. + * + * \param pdu A PDU message passed from the scheduler's message handling. + */ + void handle_pdu(pmt::pmt_t pdu); + public: pdu_split_impl(const bool pass_empty_data); - ~pdu_split_impl(); - - void handle_pdu(pmt::pmt_t pdu); + ~pdu_split_impl() override; }; } // namespace pdu diff --git a/gr-pdu/lib/pdu_to_tagged_stream_impl.cc b/gr-pdu/lib/pdu_to_tagged_stream_impl.cc new file mode 100644 index 0000000000..035e8f85af --- /dev/null +++ b/gr-pdu/lib/pdu_to_tagged_stream_impl.cc @@ -0,0 +1,98 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pdu_to_tagged_stream_impl.h" +#include <gnuradio/io_signature.h> +#include <gnuradio/pdu.h> + +namespace gr { +namespace pdu { + +pdu_to_tagged_stream::sptr pdu_to_tagged_stream::make(gr::types::vector_type type, + const std::string& tsb_tag_key) +{ + return gnuradio::make_block_sptr<pdu_to_tagged_stream_impl>(type, tsb_tag_key); +} + +pdu_to_tagged_stream_impl::pdu_to_tagged_stream_impl(gr::types::vector_type type, + const std::string& tsb_tag_key) + : tagged_stream_block("pdu_to_tagged_stream", + io_signature::make(0, 0, 0), + io_signature::make(1, 1, pdu::itemsize(type)), + tsb_tag_key), + d_itemsize(pdu::itemsize(type)), + d_curr_len(0) +{ + message_port_register_in(msgport_names::pdus()); +} + +int pdu_to_tagged_stream_impl::calculate_output_stream_length(const gr_vector_int&) +{ + if (d_curr_len == 0) { + pmt::pmt_t msg(delete_head_nowait(msgport_names::pdus())); + if (msg.get() == NULL) { + return 0; + } + + if (!pmt::is_pair(msg)) + throw std::runtime_error("received a malformed pdu message"); + + d_curr_meta = pmt::car(msg); + d_curr_vect = pmt::cdr(msg); + // do not assume the length of PMT is in items (e.g.: from socket_pdu) + d_curr_len = pmt::blob_length(d_curr_vect) / d_itemsize; + } + + return d_curr_len; +} + +int pdu_to_tagged_stream_impl::work(int noutput_items, + gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + uint8_t* out = (uint8_t*)output_items[0]; + + if (d_curr_len == 0) { + return 0; + } + + // work() should only be called if the current PDU fits entirely + // into the output buffer. + assert(noutput_items >= 0 && (unsigned int)noutput_items >= d_curr_len); + + // Copy vector output + size_t nout = d_curr_len; + size_t io(0); + const uint8_t* ptr = (const uint8_t*)uniform_vector_elements(d_curr_vect, io); + memcpy(out, ptr, d_curr_len * d_itemsize); + + // Copy tags + if (!pmt::eq(d_curr_meta, pmt::PMT_NIL)) { + pmt::pmt_t klist(pmt::dict_keys(d_curr_meta)); + for (size_t i = 0; i < pmt::length(klist); i++) { + pmt::pmt_t k(pmt::nth(i, klist)); + pmt::pmt_t v(pmt::dict_ref(d_curr_meta, k, pmt::PMT_NIL)); + add_item_tag(0, nitems_written(0), k, v, alias_pmt()); + } + } + + // Reset state + d_curr_len = 0; + + return nout; +} /* work() */ + +} /* namespace pdu */ +} /* namespace gr */ diff --git a/gr-pdu/lib/pdu_to_tagged_stream_impl.h b/gr-pdu/lib/pdu_to_tagged_stream_impl.h new file mode 100644 index 0000000000..3fdb71491c --- /dev/null +++ b/gr-pdu/lib/pdu_to_tagged_stream_impl.h @@ -0,0 +1,41 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_TO_TAGGED_STREAM_IMPL_H +#define INCLUDED_PDU_TO_TAGGED_STREAM_IMPL_H + +#include <gnuradio/pdu/pdu_to_tagged_stream.h> + +namespace gr { +namespace pdu { + +class PDU_API pdu_to_tagged_stream_impl : public pdu_to_tagged_stream +{ + const size_t d_itemsize; + pmt::pmt_t d_curr_meta; + pmt::pmt_t d_curr_vect; + size_t d_curr_len; + +public: + pdu_to_tagged_stream_impl(gr::types::vector_type type, + const std::string& lengthtagname = "packet_len"); + + int calculate_output_stream_length(const gr_vector_int& ninput_items) override; + + int work(int noutput_items, + gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) override; +}; + +} /* namespace pdu */ +} /* namespace gr */ + +#endif /* INCLUDED_PDU_TO_TAGGED_STREAM_IMPL_H */ diff --git a/gr-pdu/lib/random_pdu_impl.cc b/gr-pdu/lib/random_pdu_impl.cc new file mode 100644 index 0000000000..a31f82381e --- /dev/null +++ b/gr-pdu/lib/random_pdu_impl.cc @@ -0,0 +1,74 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "random_pdu_impl.h" +#include <gnuradio/io_signature.h> +#include <gnuradio/pdu.h> + +namespace gr { +namespace pdu { + +random_pdu::sptr +random_pdu::make(int min_items, int max_items, unsigned char byte_mask, int length_modulo) +{ + return gnuradio::make_block_sptr<random_pdu_impl>( + min_items, max_items, byte_mask, length_modulo); +} + +random_pdu_impl::random_pdu_impl(int min_items, + int max_items, + unsigned char byte_mask, + int length_modulo) + : block("random_pdu", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + d_urange(min_items, max_items), + d_brange(0, 255), + d_mask(byte_mask), + d_length_modulo(length_modulo) +{ + message_port_register_out(msgport_names::pdus()); + message_port_register_in(pmt::mp("generate")); + set_msg_handler(pmt::mp("generate"), + [this](pmt::pmt_t msg) { this->generate_pdu(msg); }); + if (length_modulo < 1) + throw std::runtime_error("length_module must be >= 1"); + if (max_items < length_modulo) + throw std::runtime_error("max_items must be >= to length_modulo"); +} + +bool random_pdu_impl::start() +{ + output_random(); + return true; +} + +void random_pdu_impl::output_random() +{ + // pick a random vector length + int len = d_urange(d_rng); + len = std::max(d_length_modulo, len - len % d_length_modulo); + + // fill it with random bytes + std::vector<unsigned char> vec(len); + for (int i = 0; i < len; i++) + vec[i] = ((unsigned char)d_brange(d_rng)) & d_mask; + + // send the vector + pmt::pmt_t vecpmt(pmt::make_blob(&vec[0], len)); + pmt::pmt_t pdu(pmt::cons(pmt::PMT_NIL, vecpmt)); + + message_port_pub(msgport_names::pdus(), pdu); +} + +} /* namespace pdu */ +} /* namespace gr */ diff --git a/gr-pdu/lib/random_pdu_impl.h b/gr-pdu/lib/random_pdu_impl.h new file mode 100644 index 0000000000..2f2535fe47 --- /dev/null +++ b/gr-pdu/lib/random_pdu_impl.h @@ -0,0 +1,46 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_RANDOM_PDU_IMPL_H +#define INCLUDED_PDU_RANDOM_PDU_IMPL_H + +#include <gnuradio/pdu/random_pdu.h> +#include <boost/generator_iterator.hpp> + +#include <random> + +namespace gr { +namespace pdu { + +class random_pdu_impl : public random_pdu +{ +private: + std::mt19937 d_rng; + std::uniform_int_distribution<> d_urange; + std::uniform_int_distribution<> d_brange; + const unsigned char d_mask; + const int d_length_modulo; + +public: + random_pdu_impl(int min_items, + int max_items, + unsigned char byte_mask, + int length_modulo); + + bool start() override; + void output_random(); + void generate_pdu(pmt::pmt_t msg) { output_random(); } + void generate_pdu() { output_random(); } +}; + +} /* namespace pdu */ +} /* namespace gr */ + +#endif /* INCLUDED_PDU_RANDOM_PDU_IMPL_H */ diff --git a/gr-pdu/lib/tagged_stream_to_pdu_impl.cc b/gr-pdu/lib/tagged_stream_to_pdu_impl.cc new file mode 100644 index 0000000000..66d3cb20e1 --- /dev/null +++ b/gr-pdu/lib/tagged_stream_to_pdu_impl.cc @@ -0,0 +1,66 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tagged_stream_to_pdu_impl.h" +#include <gnuradio/io_signature.h> +#include <gnuradio/pdu.h> + +namespace gr { +namespace pdu { + +tagged_stream_to_pdu::sptr tagged_stream_to_pdu::make(gr::types::vector_type type, + const std::string& lengthtagname) +{ + return gnuradio::make_block_sptr<tagged_stream_to_pdu_impl>(type, lengthtagname); +} + +tagged_stream_to_pdu_impl::tagged_stream_to_pdu_impl(gr::types::vector_type type, + const std::string& lengthtagname) + : tagged_stream_block("tagged_stream_to_pdu", + io_signature::make(1, 1, pdu::itemsize(type)), + io_signature::make(0, 0, 0), + lengthtagname), + d_type(type), + d_pdu_meta(pmt::PMT_NIL), + d_pdu_vector(pmt::PMT_NIL) +{ + message_port_register_out(msgport_names::pdus()); +} + +int tagged_stream_to_pdu_impl::work(int noutput_items, + gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + const uint8_t* in = (const uint8_t*)input_items[0]; + + // Grab tags, throw them into dict + get_tags_in_range(d_tags, 0, nitems_read(0), nitems_read(0) + ninput_items[0]); + d_pdu_meta = pmt::make_dict(); + for (const auto& tag : d_tags) { + d_pdu_meta = dict_add(d_pdu_meta, tag.key, tag.value); + } + + // Grab data, throw into vector + d_pdu_vector = pdu::make_pdu_vector(d_type, in, ninput_items[0]); + + // Send msg + pmt::pmt_t msg = pmt::cons(d_pdu_meta, d_pdu_vector); + message_port_pub(msgport_names::pdus(), msg); + + return ninput_items[0]; +} + +} /* namespace pdu */ +} /* namespace gr */ diff --git a/gr-pdu/lib/tagged_stream_to_pdu_impl.h b/gr-pdu/lib/tagged_stream_to_pdu_impl.h new file mode 100644 index 0000000000..5e685b89b1 --- /dev/null +++ b/gr-pdu/lib/tagged_stream_to_pdu_impl.h @@ -0,0 +1,39 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_TAGGED_STREAM_TO_PDU_IMPL_H +#define INCLUDED_TAGGED_STREAM_TO_PDU_IMPL_H + +#include <gnuradio/pdu/tagged_stream_to_pdu.h> + +namespace gr { +namespace pdu { + +class PDU_API tagged_stream_to_pdu_impl : public tagged_stream_to_pdu +{ + const gr::types::vector_type d_type; + pmt::pmt_t d_pdu_meta; + pmt::pmt_t d_pdu_vector; + std::vector<tag_t> d_tags; + +public: + tagged_stream_to_pdu_impl(gr::types::vector_type type, + const std::string& lengthtagname); + + int work(int noutput_items, + gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) override; +}; + +} /* namespace pdu */ +} /* namespace gr */ + +#endif diff --git a/gr-pdu/python/pdu/bindings/CMakeLists.txt b/gr-pdu/python/pdu/bindings/CMakeLists.txt index a6b3252af5..1bc138bdb8 100644 --- a/gr-pdu/python/pdu/bindings/CMakeLists.txt +++ b/gr-pdu/python/pdu/bindings/CMakeLists.txt @@ -5,8 +5,14 @@ include(GrPybind) ######################################################################## list(APPEND pdu_python_files - pdu_split_python.cc + pdu_filter_python.cc pdu_python.cc + pdu_remove_python.cc + pdu_set_python.cc + pdu_split_python.cc + pdu_to_tagged_stream_python.cc + random_pdu_python.cc + tagged_stream_to_pdu_python.cc python_bindings.cc) GR_PYBIND_MAKE_CHECK_HASH(pdu diff --git a/gr-pdu/python/pdu/bindings/docstrings/pdu_filter_pydoc_template.h b/gr-pdu/python/pdu/bindings/docstrings/pdu_filter_pydoc_template.h new file mode 100644 index 0000000000..349fa30c4f --- /dev/null +++ b/gr-pdu/python/pdu/bindings/docstrings/pdu_filter_pydoc_template.h @@ -0,0 +1,36 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#include "pydoc_macros.h" +#define D(...) DOC(gr, pdu, __VA_ARGS__) +/* + This file contains placeholders for docstrings for the Python bindings. + Do not edit! These were automatically extracted during the binding process + and will be overwritten during the build process + */ + + +static const char* __doc_gr_pdu_pdu_filter = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_filter_pdu_filter_0 = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_filter_pdu_filter_1 = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_filter_make = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_filter_set_key = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_filter_set_val = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_filter_set_inversion = R"doc()doc"; diff --git a/gr-pdu/python/pdu/bindings/docstrings/pdu_pydoc_template.h b/gr-pdu/python/pdu/bindings/docstrings/pdu_pydoc_template.h index b1840f5574..9fbbbf380a 100644 --- a/gr-pdu/python/pdu/bindings/docstrings/pdu_pydoc_template.h +++ b/gr-pdu/python/pdu/bindings/docstrings/pdu_pydoc_template.h @@ -28,3 +28,15 @@ static const char* __doc_gr_pdu_PMTCONSTSTR__msg = R"doc()doc"; static const char* __doc_gr_pdu_PMTCONSTSTR__pdus = R"doc()doc"; + + +static const char* __doc_gr_pdu_itemsize = R"doc()doc"; + + +static const char* __doc_gr_pdu_type_matches = R"doc()doc"; + + +static const char* __doc_gr_pdu_make_pdu_vector = R"doc()doc"; + + +static const char* __doc_gr_pdu_type_from_pmt = R"doc()doc"; diff --git a/gr-pdu/python/pdu/bindings/docstrings/pdu_remove_pydoc_template.h b/gr-pdu/python/pdu/bindings/docstrings/pdu_remove_pydoc_template.h new file mode 100644 index 0000000000..3360f01bd5 --- /dev/null +++ b/gr-pdu/python/pdu/bindings/docstrings/pdu_remove_pydoc_template.h @@ -0,0 +1,30 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#include "pydoc_macros.h" +#define D(...) DOC(gr, pdu, __VA_ARGS__) +/* + This file contains placeholders for docstrings for the Python bindings. + Do not edit! These were automatically extracted during the binding process + and will be overwritten during the build process + */ + + +static const char* __doc_gr_pdu_pdu_remove = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_remove_pdu_remove_0 = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_remove_pdu_remove_1 = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_remove_make = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_remove_set_key = R"doc()doc"; diff --git a/gr-pdu/python/pdu/bindings/docstrings/pdu_set_pydoc_template.h b/gr-pdu/python/pdu/bindings/docstrings/pdu_set_pydoc_template.h new file mode 100644 index 0000000000..69c0cf27e8 --- /dev/null +++ b/gr-pdu/python/pdu/bindings/docstrings/pdu_set_pydoc_template.h @@ -0,0 +1,33 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#include "pydoc_macros.h" +#define D(...) DOC(gr, pdu, __VA_ARGS__) +/* + This file contains placeholders for docstrings for the Python bindings. + Do not edit! These were automatically extracted during the binding process + and will be overwritten during the build process + */ + + +static const char* __doc_gr_pdu_pdu_set = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_set_pdu_set_0 = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_set_pdu_set_1 = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_set_make = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_set_set_key = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_set_set_val = R"doc()doc"; diff --git a/gr-pdu/python/pdu/bindings/docstrings/pdu_to_tagged_stream_pydoc_template.h b/gr-pdu/python/pdu/bindings/docstrings/pdu_to_tagged_stream_pydoc_template.h new file mode 100644 index 0000000000..77d9709900 --- /dev/null +++ b/gr-pdu/python/pdu/bindings/docstrings/pdu_to_tagged_stream_pydoc_template.h @@ -0,0 +1,24 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#include "pydoc_macros.h" +#define D(...) DOC(gr, pdu, __VA_ARGS__) +/* + This file contains placeholders for docstrings for the Python bindings. + Do not edit! These were automatically extracted during the binding process + and will be overwritten during the build process + */ + + +static const char* __doc_gr_pdu_pdu_to_tagged_stream = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_to_tagged_stream_pdu_to_tagged_stream = R"doc()doc"; + + +static const char* __doc_gr_pdu_pdu_to_tagged_stream_make = R"doc()doc"; diff --git a/gr-pdu/python/pdu/bindings/docstrings/random_pdu_pydoc_template.h b/gr-pdu/python/pdu/bindings/docstrings/random_pdu_pydoc_template.h new file mode 100644 index 0000000000..848eac8df3 --- /dev/null +++ b/gr-pdu/python/pdu/bindings/docstrings/random_pdu_pydoc_template.h @@ -0,0 +1,24 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#include "pydoc_macros.h" +#define D(...) DOC(gr, pdu, __VA_ARGS__) +/* + This file contains placeholders for docstrings for the Python bindings. + Do not edit! These were automatically extracted during the binding process + and will be overwritten during the build process + */ + + +static const char* __doc_gr_pdu_random_pdu = R"doc()doc"; + + +static const char* __doc_gr_pdu_random_pdu_random_pdu = R"doc()doc"; + + +static const char* __doc_gr_pdu_random_pdu_make = R"doc()doc"; diff --git a/gr-pdu/python/pdu/bindings/docstrings/tagged_stream_to_pdu_pydoc_template.h b/gr-pdu/python/pdu/bindings/docstrings/tagged_stream_to_pdu_pydoc_template.h new file mode 100644 index 0000000000..012f727ef9 --- /dev/null +++ b/gr-pdu/python/pdu/bindings/docstrings/tagged_stream_to_pdu_pydoc_template.h @@ -0,0 +1,24 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#include "pydoc_macros.h" +#define D(...) DOC(gr, pdu, __VA_ARGS__) +/* + This file contains placeholders for docstrings for the Python bindings. + Do not edit! These were automatically extracted during the binding process + and will be overwritten during the build process + */ + + +static const char* __doc_gr_pdu_tagged_stream_to_pdu = R"doc()doc"; + + +static const char* __doc_gr_pdu_tagged_stream_to_pdu_tagged_stream_to_pdu = R"doc()doc"; + + +static const char* __doc_gr_pdu_tagged_stream_to_pdu_make = R"doc()doc"; diff --git a/gr-pdu/python/pdu/bindings/pdu_filter_python.cc b/gr-pdu/python/pdu/bindings/pdu_filter_python.cc new file mode 100644 index 0000000000..51304a5bf5 --- /dev/null +++ b/gr-pdu/python/pdu/bindings/pdu_filter_python.cc @@ -0,0 +1,58 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +/***********************************************************************************/ +/* This file is automatically generated using bindtool and can be manually edited */ +/* The following lines can be configured to regenerate this file during cmake */ +/* If manual edits are made, the following tags should be modified accordingly. */ +/* BINDTOOL_GEN_AUTOMATIC(0) */ +/* BINDTOOL_USE_PYGCCXML(0) */ +/* BINDTOOL_HEADER_FILE(pdu_filter.h) */ +/* BINDTOOL_HEADER_FILE_HASH(8ca41a1466a0f9939a533af682d055cb) */ +/***********************************************************************************/ + +#include <pybind11/complex.h> +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +namespace py = pybind11; + +#include <gnuradio/pdu/pdu_filter.h> +// pydoc.h is automatically generated in the build directory +#include <pdu_filter_pydoc.h> + +void bind_pdu_filter(py::module& m) +{ + + using pdu_filter = ::gr::pdu::pdu_filter; + + + py::class_<pdu_filter, gr::block, gr::basic_block, std::shared_ptr<pdu_filter>>( + m, "pdu_filter", D(pdu_filter)) + + .def(py::init(&pdu_filter::make), + py::arg("k"), + py::arg("v"), + py::arg("invert") = false, + D(pdu_filter, make)) + + + .def("set_key", &pdu_filter::set_key, py::arg("key"), D(pdu_filter, set_key)) + + + .def("set_val", &pdu_filter::set_val, py::arg("val"), D(pdu_filter, set_val)) + + + .def("set_inversion", + &pdu_filter::set_inversion, + py::arg("invert"), + D(pdu_filter, set_inversion)) + + ; +} diff --git a/gr-pdu/python/pdu/bindings/pdu_python.cc b/gr-pdu/python/pdu/bindings/pdu_python.cc index bb34811618..2e25fdb179 100644 --- a/gr-pdu/python/pdu/bindings/pdu_python.cc +++ b/gr-pdu/python/pdu/bindings/pdu_python.cc @@ -14,7 +14,7 @@ /* BINDTOOL_GEN_AUTOMATIC(0) */ /* BINDTOOL_USE_PYGCCXML(0) */ /* BINDTOOL_HEADER_FILE(pdu.h) */ -/* BINDTOOL_HEADER_FILE_HASH(34ae96025ac87967432c6b7092d1fd60) */ +/* BINDTOOL_HEADER_FILE_HASH(15f56dfddfda75e396a0b32cca7b7b3d) */ /***********************************************************************************/ #include <pybind11/complex.h> @@ -31,6 +31,15 @@ void bind_pdu(py::module& m) { + py::enum_<::gr::pdu::vector_type>(m, "vector_type") + .value("byte_t", ::gr::pdu::byte_t) // 0 + .value("float_t", ::gr::pdu::float_t) // 1 + .value("complex_t", ::gr::pdu::complex_t) // 2 + .export_values(); + + py::implicitly_convertible<int, ::gr::pdu::vector_type>(); + + m.def("PMTCONSTSTR__data", &::gr::pdu::PMTCONSTSTR__data, D(PMTCONSTSTR__data)); @@ -43,5 +52,27 @@ void bind_pdu(py::module& m) m.def("PMTCONSTSTR__msg", &::gr::pdu::PMTCONSTSTR__msg, D(PMTCONSTSTR__msg)); - m.def("PMTCONSTSTR__pdu", &::gr::pdu::PMTCONSTSTR__pdus, D(PMTCONSTSTR__pdus)); + m.def("PMTCONSTSTR__pdus", &::gr::pdu::PMTCONSTSTR__pdus, D(PMTCONSTSTR__pdus)); + + + m.def("itemsize", &::gr::pdu::itemsize, py::arg("type"), D(itemsize)); + + + m.def("type_matches", + &::gr::pdu::type_matches, + py::arg("type"), + py::arg("v"), + D(type_matches)); + + + m.def("make_pdu_vector", + &::gr::pdu::make_pdu_vector, + py::arg("type"), + py::arg("buf"), + py::arg("items"), + D(make_pdu_vector)); + + + m.def( + "type_from_pmt", &::gr::pdu::type_from_pmt, py::arg("vector"), D(type_from_pmt)); } diff --git a/gr-pdu/python/pdu/bindings/pdu_remove_python.cc b/gr-pdu/python/pdu/bindings/pdu_remove_python.cc new file mode 100644 index 0000000000..47755e5cdf --- /dev/null +++ b/gr-pdu/python/pdu/bindings/pdu_remove_python.cc @@ -0,0 +1,45 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +/***********************************************************************************/ +/* This file is automatically generated using bindtool and can be manually edited */ +/* The following lines can be configured to regenerate this file during cmake */ +/* If manual edits are made, the following tags should be modified accordingly. */ +/* BINDTOOL_GEN_AUTOMATIC(0) */ +/* BINDTOOL_USE_PYGCCXML(0) */ +/* BINDTOOL_HEADER_FILE(pdu_remove.h) */ +/* BINDTOOL_HEADER_FILE_HASH(2b26df98561ff8f787fc8b3f0ea3a82a) */ +/***********************************************************************************/ + +#include <pybind11/complex.h> +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +namespace py = pybind11; + +#include <gnuradio/pdu/pdu_remove.h> +// pydoc.h is automatically generated in the build directory +#include <pdu_remove_pydoc.h> + +void bind_pdu_remove(py::module& m) +{ + + using pdu_remove = ::gr::pdu::pdu_remove; + + + py::class_<pdu_remove, gr::block, gr::basic_block, std::shared_ptr<pdu_remove>>( + m, "pdu_remove", D(pdu_remove)) + + .def(py::init(&pdu_remove::make), py::arg("k"), D(pdu_remove, make)) + + + .def("set_key", &pdu_remove::set_key, py::arg("key"), D(pdu_remove, set_key)) + + ; +} diff --git a/gr-pdu/python/pdu/bindings/pdu_set_python.cc b/gr-pdu/python/pdu/bindings/pdu_set_python.cc new file mode 100644 index 0000000000..834ae6a163 --- /dev/null +++ b/gr-pdu/python/pdu/bindings/pdu_set_python.cc @@ -0,0 +1,48 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +/***********************************************************************************/ +/* This file is automatically generated using bindtool and can be manually edited */ +/* The following lines can be configured to regenerate this file during cmake */ +/* If manual edits are made, the following tags should be modified accordingly. */ +/* BINDTOOL_GEN_AUTOMATIC(0) */ +/* BINDTOOL_USE_PYGCCXML(0) */ +/* BINDTOOL_HEADER_FILE(pdu_set.h) */ +/* BINDTOOL_HEADER_FILE_HASH(c7fba803e84070656e7898eb601df1f3) */ +/***********************************************************************************/ + +#include <pybind11/complex.h> +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +namespace py = pybind11; + +#include <gnuradio/pdu/pdu_set.h> +// pydoc.h is automatically generated in the build directory +#include <pdu_set_pydoc.h> + +void bind_pdu_set(py::module& m) +{ + + using pdu_set = ::gr::pdu::pdu_set; + + + py::class_<pdu_set, gr::block, gr::basic_block, std::shared_ptr<pdu_set>>( + m, "pdu_set", D(pdu_set)) + + .def(py::init(&pdu_set::make), py::arg("k"), py::arg("v"), D(pdu_set, make)) + + + .def("set_key", &pdu_set::set_key, py::arg("key"), D(pdu_set, set_key)) + + + .def("set_val", &pdu_set::set_val, py::arg("val"), D(pdu_set, set_val)) + + ; +} diff --git a/gr-pdu/python/pdu/bindings/pdu_to_tagged_stream_python.cc b/gr-pdu/python/pdu/bindings/pdu_to_tagged_stream_python.cc new file mode 100644 index 0000000000..5b857cad32 --- /dev/null +++ b/gr-pdu/python/pdu/bindings/pdu_to_tagged_stream_python.cc @@ -0,0 +1,50 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +/***********************************************************************************/ +/* This file is automatically generated using bindtool and can be manually edited */ +/* The following lines can be configured to regenerate this file during cmake */ +/* If manual edits are made, the following tags should be modified accordingly. */ +/* BINDTOOL_GEN_AUTOMATIC(0) */ +/* BINDTOOL_USE_PYGCCXML(0) */ +/* BINDTOOL_HEADER_FILE(pdu_to_tagged_stream.h) */ +/* BINDTOOL_HEADER_FILE_HASH(5a0731bc34a2a12add1e9909e2b27b9f) */ +/***********************************************************************************/ + +#include <pybind11/complex.h> +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +namespace py = pybind11; + +#include <gnuradio/pdu/pdu_to_tagged_stream.h> +// pydoc.h is automatically generated in the build directory +#include <pdu_to_tagged_stream_pydoc.h> + +void bind_pdu_to_tagged_stream(py::module& m) +{ + + using pdu_to_tagged_stream = ::gr::pdu::pdu_to_tagged_stream; + + + py::class_<pdu_to_tagged_stream, + gr::tagged_stream_block, + gr::block, + gr::basic_block, + std::shared_ptr<pdu_to_tagged_stream>>( + m, "pdu_to_tagged_stream", D(pdu_to_tagged_stream)) + + .def(py::init(&pdu_to_tagged_stream::make), + py::arg("type"), + py::arg("lengthtagname") = "packet_len", + D(pdu_to_tagged_stream, make)) + + + ; +} diff --git a/gr-pdu/python/pdu/bindings/python_bindings.cc b/gr-pdu/python/pdu/bindings/python_bindings.cc index 712021b8d1..7530b7a467 100644 --- a/gr-pdu/python/pdu/bindings/python_bindings.cc +++ b/gr-pdu/python/pdu/bindings/python_bindings.cc @@ -15,8 +15,14 @@ namespace py = pybind11; -void bind_pdu_split(py::module&); void bind_pdu(py::module&); +void bind_pdu_filter(py::module&); +void bind_pdu_remove(py::module&); +void bind_pdu_set(py::module&); +void bind_pdu_split(py::module&); +void bind_pdu_to_tagged_stream(py::module&); +void bind_random_pdu(py::module&); +void bind_tagged_stream_to_pdu(py::module&); // We need this hack because import_array() returns NULL // for newer Python versions. @@ -37,6 +43,12 @@ PYBIND11_MODULE(pdu_python, m) // Allow access to base block methods py::module::import("gnuradio.gr"); - bind_pdu_split(m); bind_pdu(m); + bind_pdu_filter(m); + bind_pdu_remove(m); + bind_pdu_set(m); + bind_pdu_split(m); + bind_pdu_to_tagged_stream(m); + bind_random_pdu(m); + bind_tagged_stream_to_pdu(m); } diff --git a/gr-pdu/python/pdu/bindings/random_pdu_python.cc b/gr-pdu/python/pdu/bindings/random_pdu_python.cc new file mode 100644 index 0000000000..20e238a7c4 --- /dev/null +++ b/gr-pdu/python/pdu/bindings/random_pdu_python.cc @@ -0,0 +1,48 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +/***********************************************************************************/ +/* This file is automatically generated using bindtool and can be manually edited */ +/* The following lines can be configured to regenerate this file during cmake */ +/* If manual edits are made, the following tags should be modified accordingly. */ +/* BINDTOOL_GEN_AUTOMATIC(0) */ +/* BINDTOOL_USE_PYGCCXML(0) */ +/* BINDTOOL_HEADER_FILE(random_pdu.h) */ +/* BINDTOOL_HEADER_FILE_HASH(0ec9de7a89f30dd5a050547975e7c3d4) */ +/***********************************************************************************/ + +#include <pybind11/complex.h> +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +namespace py = pybind11; + +#include <gnuradio/pdu/random_pdu.h> +// pydoc.h is automatically generated in the build directory +#include <random_pdu_pydoc.h> + +void bind_random_pdu(py::module& m) +{ + + using random_pdu = ::gr::pdu::random_pdu; + + + py::class_<random_pdu, gr::block, gr::basic_block, std::shared_ptr<random_pdu>>( + m, "random_pdu", D(random_pdu)) + + .def(py::init(&random_pdu::make), + py::arg("mintime"), + py::arg("maxtime"), + py::arg("byte_mask") = 255, + py::arg("length_modulo") = 1, + D(random_pdu, make)) + + + ; +} diff --git a/gr-pdu/python/pdu/bindings/tagged_stream_to_pdu_python.cc b/gr-pdu/python/pdu/bindings/tagged_stream_to_pdu_python.cc new file mode 100644 index 0000000000..047f25197a --- /dev/null +++ b/gr-pdu/python/pdu/bindings/tagged_stream_to_pdu_python.cc @@ -0,0 +1,50 @@ +/* + * Copyright 2021 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +/***********************************************************************************/ +/* This file is automatically generated using bindtool and can be manually edited */ +/* The following lines can be configured to regenerate this file during cmake */ +/* If manual edits are made, the following tags should be modified accordingly. */ +/* BINDTOOL_GEN_AUTOMATIC(0) */ +/* BINDTOOL_USE_PYGCCXML(0) */ +/* BINDTOOL_HEADER_FILE(tagged_stream_to_pdu.h) */ +/* BINDTOOL_HEADER_FILE_HASH(c3df8858e8b5d77e0d10d762db5238ff) */ +/***********************************************************************************/ + +#include <pybind11/complex.h> +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +namespace py = pybind11; + +#include <gnuradio/pdu/tagged_stream_to_pdu.h> +// pydoc.h is automatically generated in the build directory +#include <tagged_stream_to_pdu_pydoc.h> + +void bind_tagged_stream_to_pdu(py::module& m) +{ + + using tagged_stream_to_pdu = ::gr::pdu::tagged_stream_to_pdu; + + + py::class_<tagged_stream_to_pdu, + gr::tagged_stream_block, + gr::block, + gr::basic_block, + std::shared_ptr<tagged_stream_to_pdu>>( + m, "tagged_stream_to_pdu", D(tagged_stream_to_pdu)) + + .def(py::init(&tagged_stream_to_pdu::make), + py::arg("type"), + py::arg("lengthtagname") = "packet_len", + D(tagged_stream_to_pdu, make)) + + + ; +} diff --git a/gr-pdu/python/pdu/qa_pdu.py b/gr-pdu/python/pdu/qa_pdu.py new file mode 100644 index 0000000000..504f151089 --- /dev/null +++ b/gr-pdu/python/pdu/qa_pdu.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python +# +# Copyright 2013 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# + + +from gnuradio import gr, gr_unittest, blocks, pdu +import pmt +import time + + +class test_pdu(gr_unittest.TestCase): + + def setUp(self): + self.tb = gr.top_block() + + def tearDown(self): + self.tb = None + + def test_000(self): + # Just run some data through and make sure it doesn't puke. + src_data = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + + src = pdu.pdu_to_tagged_stream(pdu.byte_t) + snk3 = pdu.tagged_stream_to_pdu(pdu.byte_t) + snk2 = blocks.vector_sink_b() + snk = blocks.tag_debug(1, "test") + snk.set_display(False) + + dbg = blocks.message_debug() + + # Test that the right number of ports exist. + pi = snk3.message_ports_in() + po = snk3.message_ports_out() + # system port is defined automatically + self.assertEqual(pmt.length(pi), 1) + self.assertEqual(pmt.length(po), 1) + + self.tb.connect(src, snk) + self.tb.connect(src, snk2) + self.tb.connect(src, snk3) + self.tb.msg_connect(snk3, "pdus", dbg, "store") + + # make our reference and message pmts + port = pmt.intern("pdus") + msg = pmt.cons(pmt.PMT_NIL, pmt.make_u8vector(16, 0xFF)) + + # post the message + src.to_basic_block()._post(port, msg) + src.to_basic_block()._post( + pmt.intern("system"), pmt.cons( + pmt.intern("done"), pmt.from_long(1))) + + self.tb.start() + self.tb.wait() + + # Get the vector of data from the vector sink + result_data = snk2.data() + + # Get the vector of data from the message sink + # Convert the message PMT as a pair into its vector + result_msg = dbg.get_message(0) + msg_vec = pmt.cdr(result_msg) + # pmt.print(msg_vec) + + # Convert the PMT vector into a Python list + msg_data = [] + for i in range(16): + msg_data.append(pmt.u8vector_ref(msg_vec, i)) + + actual_data = 16 * [0xFF, ] + self.assertEqual(actual_data, list(result_data)) + self.assertEqual(actual_data, msg_data) + + def test_001(self): + # Test the overflow buffer in pdu_to_tagged_stream + src_data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0] + src = pdu.pdu_to_tagged_stream(pdu.float_t) + snk = blocks.vector_sink_f() + + self.tb.connect(src, snk) + port = pmt.intern("pdus") + + msg = pmt.cons(pmt.PMT_NIL, pmt.init_f32vector(10, src_data)) + src.to_basic_block()._post(port, msg) + src.to_basic_block()._post( + pmt.intern("system"), pmt.cons( + pmt.intern("done"), pmt.from_long(1))) + + self.tb.start() + self.tb.wait() + + self.assertEqual(src_data, list(snk.data())) + + def test_002_tags_plus_data(self): + packet_len = 16 + src_data = list(range(packet_len)) + tag1 = gr.tag_t() + tag1.offset = 0 + tag1.key = pmt.string_to_symbol('spam') + tag1.value = pmt.from_long(23) + tag2 = gr.tag_t() + tag2.offset = 10 # Must be < packet_len + tag2.key = pmt.string_to_symbol('eggs') + tag2.value = pmt.from_long(42) + src = blocks.vector_source_f(src_data, tags=(tag1, tag2)) + s2ts = blocks.stream_to_tagged_stream( + gr.sizeof_float, + vlen=1, + packet_len=packet_len, + len_tag_key="packet_len") + ts2pdu = pdu.tagged_stream_to_pdu(pdu.float_t, "packet_len") + dbg = blocks.message_debug() + self.tb.connect(src, s2ts, ts2pdu) + self.tb.msg_connect(ts2pdu, "pdus", dbg, "store") + self.tb.start() + self.tb.wait() + result_msg = dbg.get_message(0) + metadata = pmt.to_python(pmt.car(result_msg)) + vector = pmt.f32vector_elements(pmt.cdr(result_msg)) + self.assertEqual(metadata, {'eggs': 42, 'spam': 23}) + self.assertFloatTuplesAlmostEqual(tuple(vector), src_data) + + +if __name__ == '__main__': + gr_unittest.run(test_pdu) diff --git a/gr-pdu/python/pdu/qa_pdu_split.py b/gr-pdu/python/pdu/qa_pdu_split.py index 77f34936d9..76b60499a7 100644 --- a/gr-pdu/python/pdu/qa_pdu_split.py +++ b/gr-pdu/python/pdu/qa_pdu_split.py @@ -9,18 +9,10 @@ # -from gnuradio import gr, gr_unittest -from gnuradio import blocks +from gnuradio import gr, gr_unittest, blocks, pdu import pmt import time -try: - from gnuradio import pdu -except ImportError: - import os - import sys - dirname, filename = os.path.split(os.path.abspath(__file__)) - sys.path.append(os.path.join(dirname, "bindings")) - from gnuradio import pdu + class qa_pdu_split (gr_unittest.TestCase): @@ -36,7 +28,7 @@ class qa_pdu_split (gr_unittest.TestCase): d2 = blocks.message_debug() self.tb.msg_connect((split, 'dict'), (d1, 'store')) - self.tb.msg_connect((split, 'data'), (d2, 'store')) + self.tb.msg_connect((split, 'vec'), (d2, 'store')) in_meta1 = pmt.dict_add(pmt.make_dict(), pmt.intern('num'), pmt.from_long(4)) in_meta2 = pmt.dict_add(pmt.make_dict(), pmt.intern('n'), pmt.from_long(99)) @@ -63,9 +55,9 @@ class qa_pdu_split (gr_unittest.TestCase): split = pdu.pdu_split(True) d1 = blocks.message_debug() d2 = blocks.message_debug() - + self.tb.msg_connect((split, 'dict'), (d1, 'store')) - self.tb.msg_connect((split, 'data'), (d2, 'store')) + self.tb.msg_connect((split, 'vec'), (d2, 'store')) in_meta1 = pmt.dict_add(pmt.make_dict(), pmt.intern('num'), pmt.from_long(4)) in_meta2 = pmt.dict_add(pmt.make_dict(), pmt.intern('n'), pmt.from_long(99)) |