diff options
author | Jacob Gilbert <jacob.gilbert@protonmail.com> | 2021-06-11 08:34:20 -0600 |
---|---|---|
committer | mormj <34754695+mormj@users.noreply.github.com> | 2021-07-19 06:44:24 -0400 |
commit | 98cadbf3d54176b474d8257ae0f2ae6f7c01fc3a (patch) | |
tree | 3dfcac84566b837c139f1dcad7e8093e69d51979 | |
parent | 15a8cce4dadaa895081d1d9816f37e65117cffb5 (diff) |
pdu: Adding new blocks
Added take_skip_to_pdu block and pdu lambda blocks, needs examples still
Signed-off-by: Jacob Gilbert <jacob.gilbert@protonmail.com>
21 files changed, 724 insertions, 1 deletions
diff --git a/gnuradio-runtime/include/gnuradio/pdu.h b/gnuradio-runtime/include/gnuradio/pdu.h index 187f01abd0..d7dc0a2550 100644 --- a/gnuradio-runtime/include/gnuradio/pdu.h +++ b/gnuradio-runtime/include/gnuradio/pdu.h @@ -16,6 +16,10 @@ #include <pmt/pmt.h> namespace gr { +namespace metadata_keys { +GR_RUNTIME_API const pmt::pmt_t pdu_num(); +} /* namespace metadata_keys */ + namespace msgport_names { // static const PMT interned string getters for standard port names GR_RUNTIME_API const pmt::pmt_t bpdu(); diff --git a/gnuradio-runtime/lib/pdu.cc b/gnuradio-runtime/lib/pdu.cc index 0c0468419a..f860bf395d 100644 --- a/gnuradio-runtime/lib/pdu.cc +++ b/gnuradio-runtime/lib/pdu.cc @@ -15,6 +15,15 @@ #include <pmt/pmt.h> namespace gr { +namespace metadata_keys { + +const pmt::pmt_t pdu_num() +{ + static const pmt::pmt_t val = pmt::mp("pdu_num"); + return val; +} + +} /* namespace metadata_keys */ namespace msgport_names { const pmt::pmt_t bpdu() 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 index 8ba6b5ddd0..95180a0309 100644 --- a/gnuradio-runtime/python/gnuradio/gr/bindings/docstrings/pdu_pydoc_template.h +++ b/gnuradio-runtime/python/gnuradio/gr/bindings/docstrings/pdu_pydoc_template.h @@ -15,6 +15,9 @@ */ +static const char* __doc_gr_metadata_keys_pdu_num = R"doc()doc"; + + static const char* __doc_gr_msgport_names_bpdu = 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 index 29af603677..e6dec295e7 100644 --- a/gnuradio-runtime/python/gnuradio/gr/bindings/pdu_python.cc +++ b/gnuradio-runtime/python/gnuradio/gr/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(d5f32198890a9b1099e6b7ed492650f9) */ +/* BINDTOOL_HEADER_FILE_HASH(e6887fee8ea637d80f0ed7b6f2ffc552) */ /***********************************************************************************/ #include <pybind11/complex.h> @@ -43,6 +43,12 @@ void bind_pdu(py::module& m) py::implicitly_convertible<int, ::gr::types::vector_type>(); + py::module m_metadata_keys = m.def_submodule("metadata_keys"); + + m_metadata_keys.def( + "pdu_num", &::gr::metadata_keys::pdu_num, D(metadata_keys, pdu_num)); + + py::module m_msgport_names = m.def_submodule("msgport_names"); m_msgport_names.def("bpdu", &::gr::msgport_names::bpdu, D(msgport_names, bpdu)); diff --git a/gr-pdu/grc/pdu.tree.yml b/gr-pdu/grc/pdu.tree.yml index 2c1d2a2c9c..c1e6a5aca5 100644 --- a/gr-pdu/grc/pdu.tree.yml +++ b/gr-pdu/grc/pdu.tree.yml @@ -2,10 +2,12 @@ - PDU Tools: - pdu_add_system_time - pdu_pdu_filter + - pdu_pdu_lambda - pdu_pdu_remove - pdu_pdu_set - pdu_pdu_split - pdu_pdu_to_tagged_stream - pdu_tagged_stream_to_pdu - pdu_random_pdu + - pdu_take_skip_to_pdu - pdu_time_delta diff --git a/gr-pdu/grc/pdu_pdu_lambda.block.yml b/gr-pdu/grc/pdu_pdu_lambda.block.yml new file mode 100644 index 0000000000..c483d840e4 --- /dev/null +++ b/gr-pdu/grc/pdu_pdu_lambda.block.yml @@ -0,0 +1,41 @@ +id: pdu_pdu_lambda +label: PDU Lambda +flags: [ python ] + +parameters: +- id: fn + label: Function + dtype: raw + default: 'lambda x: x*10' +- id: metadict + label: Mode + dtype: enum + options: [Metadata, Uniform Vector] + option_attributes: + mode: [True, False] + default: True + hide: part +- id: key + label: Key + dtype: raw + default: 'pmt.intern("key")' + hide: ${ 'none' if metadict.mode else 'all' } + +inputs: +- id: pdu + domain: message + optional: true + +outputs: +- id: pdu + domain: message + optional: true + +templates: + imports: import pylambda, pmt, numpy as np + make: pylambda.pdu_lambda(${fn}, ${metadict.mode}, ${key}) + callbacks: + - set_fn(${fn}) + - set_fn(${key}) + +file_format: 1 diff --git a/gr-pdu/grc/pdu_take_skip_to_pdu.block.yml b/gr-pdu/grc/pdu_take_skip_to_pdu.block.yml new file mode 100644 index 0000000000..293d22c82f --- /dev/null +++ b/gr-pdu/grc/pdu_take_skip_to_pdu.block.yml @@ -0,0 +1,43 @@ +id: pdu_take_skip_to_pdu +label: Take/Skip To PDU +flags: [ python ] + +parameters: +- id: type + label: PDU Type + dtype: enum + options: [complex, float, int, short, byte] + option_labels: [Complex, Float, Int, Short, Byte] + option_attributes: + t: [c, f, i, s, b] + hide: part +- id: take + label: Take + dtype: int + default: '1024' +- id: skip + label: Skip + dtype: int + default: '4096' + +inputs: +- domain: stream + dtype: ${ type } + +outputs: +- domain: message + id: pdus + optional: true + +asserts: +- ${ take >= 1 } +- ${ skip >= 0 } + +templates: + imports: from gnuradio import pdu + make: pdu.take_skip_to_pdu_${type.t}(${take}, ${skip}) + callbacks: + - set_take(${take}) + - set_skip(${skip}) + +file_format: 1 diff --git a/gr-pdu/include/gnuradio/pdu/CMakeLists.txt b/gr-pdu/include/gnuradio/pdu/CMakeLists.txt index c3d626a3be..89057c021d 100644 --- a/gr-pdu/include/gnuradio/pdu/CMakeLists.txt +++ b/gr-pdu/include/gnuradio/pdu/CMakeLists.txt @@ -18,6 +18,7 @@ install(FILES pdu_to_tagged_stream.h random_pdu.h tagged_stream_to_pdu.h + take_skip_to_pdu.h time_delta.h DESTINATION ${GR_INCLUDE_DIR}/gnuradio/pdu ) diff --git a/gr-pdu/include/gnuradio/pdu/take_skip_to_pdu.h b/gr-pdu/include/gnuradio/pdu/take_skip_to_pdu.h new file mode 100644 index 0000000000..3952a64918 --- /dev/null +++ b/gr-pdu/include/gnuradio/pdu/take_skip_to_pdu.h @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2021 NTESS LLC. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_TAKE_SKIP_TO_PDU_H +#define INCLUDED_PDU_TAKE_SKIP_TO_PDU_H + +#include <gnuradio/pdu/api.h> +#include <gnuradio/sync_block.h> + +namespace gr { +namespace pdu { + +#ifndef MAXIMUM_PDU_SIZE +#define MAXIMUM_PDU_SIZE +#endif + +/*! + * \brief Extract periodic PDUs from a data stream. + * \ingroup pdu_blk + * + * This block will generate PDUs of size TAKE skipping SKIP samples between + * + */ +template <class T> +class PDU_API take_skip_to_pdu : virtual public gr::sync_block +{ +public: + typedef std::shared_ptr<take_skip_to_pdu<T>> sptr; + + /*! + * \brief Return a shared_ptr to a new instance of pdu::take_skip_to_pdu. + * + * @param take - size of generated PDUs in samples + * @param skip - number of samples to skip between takes + */ + static sptr make(uint32_t take, uint32_t skip); + + virtual void set_take(uint32_t take) = 0; + virtual void set_skip(uint32_t skip) = 0; +}; + +typedef take_skip_to_pdu<unsigned char> take_skip_to_pdu_b; +typedef take_skip_to_pdu<short> take_skip_to_pdu_s; +typedef take_skip_to_pdu<int> take_skip_to_pdu_i; +typedef take_skip_to_pdu<float> take_skip_to_pdu_f; +typedef take_skip_to_pdu<gr_complex> take_skip_to_pdu_c; +} // namespace pdu +} // namespace gr + +#endif /* INCLUDED_PDU_TAKE_SKIP_TO_PDU_H */ diff --git a/gr-pdu/lib/CMakeLists.txt b/gr-pdu/lib/CMakeLists.txt index cd071cf73f..331fe0c6ef 100644 --- a/gr-pdu/lib/CMakeLists.txt +++ b/gr-pdu/lib/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(gnuradio-pdu pdu_to_tagged_stream_impl.cc random_pdu_impl.cc tagged_stream_to_pdu_impl.cc + take_skip_to_pdu_impl.cc time_delta_impl.cc ) diff --git a/gr-pdu/lib/take_skip_to_pdu_impl.cc b/gr-pdu/lib/take_skip_to_pdu_impl.cc new file mode 100644 index 0000000000..0e035fc94b --- /dev/null +++ b/gr-pdu/lib/take_skip_to_pdu_impl.cc @@ -0,0 +1,157 @@ +/* -*- c++ -*- */ +/* + * Copyright 2021 NTESS LLC. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "take_skip_to_pdu_impl.h" +#include <gnuradio/io_signature.h> +#include <gnuradio/pdu.h> + +namespace gr { +namespace pdu { + +template <class T> +typename take_skip_to_pdu<T>::sptr take_skip_to_pdu<T>::make(uint32_t take, uint32_t skip) +{ + return gnuradio::make_block_sptr<take_skip_to_pdu_impl<T>>(take, skip); +} + +/* + * The private constructor + */ +template <class T> +take_skip_to_pdu_impl<T>::take_skip_to_pdu_impl(uint32_t take, uint32_t skip) + : gr::sync_block("take_skip_to_pdu", + gr::io_signature::make(1, 1, sizeof(T)), + gr::io_signature::make(0, 0, 0)), + d_take(take), + d_skip(skip), + d_next(take), + d_triggered(true), + d_burst_counter(0), + d_prev_byte(0) +{ + if (d_take == 0) { + GR_LOG_FATAL(this->d_logger, "TAKE value too small, must be > 0"); + throw std::invalid_argument("TAKE value out of bounds"); + } + + d_vector.clear(); + d_meta_dict = pmt::make_dict(); + this->message_port_register_out(msgport_names::pdus()); + + GR_LOG_INFO(this->d_logger, "Starting Take Skip PDU Generator!"); +} + + +/* + * Our virtual destructor. + */ +template <class T> +take_skip_to_pdu_impl<T>::~take_skip_to_pdu_impl() +{ +} + +template <class T> +bool take_skip_to_pdu_impl<T>::stop() +{ + GR_LOG_NOTICE(this->d_logger, boost::format("Generated %d PDUs") % d_burst_counter); + return true; +} + +template <class T> +void take_skip_to_pdu_impl<T>::publish_message() +{ + d_meta_dict = pmt::dict_add( + d_meta_dict, metadata_keys::pdu_num(), pmt::from_uint64(d_burst_counter)); + + // publish mesage + this->message_port_pub(msgport_names::pdus(), + pmt::cons(d_meta_dict, this->init_data(d_vector))); + + // prepare for next burst + d_burst_counter++; + d_triggered = false; + d_vector.clear(); +} + + +template <class T> +int take_skip_to_pdu_impl<T>::work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + gr::thread::scoped_lock l(this->d_setlock); + + const T* in = (const T*)input_items[0]; + uint64_t consumed = noutput_items; + bool start_stop = false; + + // figure out where the next start/stop point is + if (d_next <= (this->nitems_read(0) + noutput_items)) { + // we are going to start/stop during this buffer + consumed = d_next - this->nitems_read(0); + start_stop = true; + if (d_triggered) { + d_next += d_skip; + } else { + d_next += d_take; + } + } + + if (d_triggered) { + // we are saving data + // std::cout << " adding " << consumed << " items to the queue" << std::endl; + d_vector.insert(d_vector.end(), &in[0], &in[consumed]); + if (start_stop) { + // std::cout << " publishing message with " << d_vector.size() << " items" + // << std::endl; + publish_message(); + if (d_skip == 0) { + d_triggered = true; + d_next += d_take; + } + } + } else { + // if we are not saving data but need to start next time: + if (start_stop) + d_triggered = true; + } + + // Tell runtime system how many output items we produced. + return consumed; +} + +template <class T> +void take_skip_to_pdu_impl<T>::set_take(uint32_t take) +{ + gr::thread::scoped_lock l(this->d_setlock); + + d_take = take; +} + + +template <class T> +void take_skip_to_pdu_impl<T>::set_skip(uint32_t skip) +{ + gr::thread::scoped_lock l(this->d_setlock); + + d_skip = skip; +} + +template class take_skip_to_pdu<unsigned char>; +template class take_skip_to_pdu<short>; +template class take_skip_to_pdu<int>; +template class take_skip_to_pdu<float>; +template class take_skip_to_pdu<gr_complex>; +} /* namespace pdu */ +} /* namespace gr */ diff --git a/gr-pdu/lib/take_skip_to_pdu_impl.h b/gr-pdu/lib/take_skip_to_pdu_impl.h new file mode 100644 index 0000000000..f4dc8828be --- /dev/null +++ b/gr-pdu/lib/take_skip_to_pdu_impl.h @@ -0,0 +1,79 @@ +/* -*- c++ -*- */ +/* + * Copyright 2021 NTESS LLC. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef INCLUDED_PDU_TAKE_SKIP_TO_PDU_IMPL_H +#define INCLUDED_PDU_TAKE_SKIP_TO_PDU_IMPL_H + +#include <gnuradio/pdu/take_skip_to_pdu.h> + +namespace gr { +namespace pdu { + +template <class T> +class PDU_API take_skip_to_pdu_impl : public take_skip_to_pdu<T> +{ +private: + // overloaded pmt uniform vector initializers + inline pmt::pmt_t init_data(const std::vector<unsigned char> data) + { + return pmt::init_u8vector(data.size(), (const unsigned char*)&data[0]); + } + inline pmt::pmt_t init_data(const std::vector<short> data) + { + return pmt::init_s16vector(data.size(), (const short*)&data[0]); + } + inline pmt::pmt_t init_data(const std::vector<int> data) + { + return pmt::init_s32vector(data.size(), (const int*)&data[0]); + } + inline pmt::pmt_t init_data(const std::vector<float> data) + { + return pmt::init_f32vector(data.size(), (const float*)&data[0]); + } + inline pmt::pmt_t init_data(const std::vector<gr_complex> data) + { + return pmt::init_c32vector(data.size(), (const gr_complex*)&data[0]); + } + +private: + uint32_t d_take; + uint32_t d_skip; + uint64_t d_next; + bool d_triggered; + uint64_t d_burst_counter; + uint8_t d_prev_byte; + + std::vector<T> d_vector; + pmt::pmt_t d_meta_dict; + + /*! + * \brief Publishes accumulated data as a PDU. + */ + void publish_message(); + +public: + take_skip_to_pdu_impl(uint32_t take, uint32_t skip); + + ~take_skip_to_pdu_impl() override; + bool stop() override; + + void set_take(const uint32_t take) override; + void set_skip(const uint32_t skip) override; + + // Where all the action really happens + int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) override; +}; + +} // namespace pdu +} // namespace gr + +#endif /* INCLUDED_PDU_TAKE_SKIP_TO_PDU_IMPL_H */ diff --git a/gr-pdu/python/pdu/CMakeLists.txt b/gr-pdu/python/pdu/CMakeLists.txt index 1a1bb25f8e..902dadc2f5 100644 --- a/gr-pdu/python/pdu/CMakeLists.txt +++ b/gr-pdu/python/pdu/CMakeLists.txt @@ -11,6 +11,7 @@ include(GrPython) GR_PYTHON_INSTALL( FILES __init__.py + pdu_lambda.py DESTINATION ${GR_PYTHON_DIR}/gnuradio/pdu ) diff --git a/gr-pdu/python/pdu/__init__.py b/gr-pdu/python/pdu/__init__.py index 01e94a056c..c1b7861d7d 100644 --- a/gr-pdu/python/pdu/__init__.py +++ b/gr-pdu/python/pdu/__init__.py @@ -21,3 +21,4 @@ except ImportError: from .pdu_python import * # import any pure python here +from .pdu_lambda import pdu_lambda diff --git a/gr-pdu/python/pdu/bindings/CMakeLists.txt b/gr-pdu/python/pdu/bindings/CMakeLists.txt index 79334e2440..c462de7a97 100644 --- a/gr-pdu/python/pdu/bindings/CMakeLists.txt +++ b/gr-pdu/python/pdu/bindings/CMakeLists.txt @@ -13,6 +13,7 @@ list(APPEND pdu_python_files pdu_to_tagged_stream_python.cc random_pdu_python.cc tagged_stream_to_pdu_python.cc + take_skip_to_pdu_python.cc time_delta_python.cc python_bindings.cc) diff --git a/gr-pdu/python/pdu/bindings/docstrings/take_skip_to_pdu_pydoc_template.h b/gr-pdu/python/pdu/bindings/docstrings/take_skip_to_pdu_pydoc_template.h new file mode 100644 index 0000000000..4437743663 --- /dev/null +++ b/gr-pdu/python/pdu/bindings/docstrings/take_skip_to_pdu_pydoc_template.h @@ -0,0 +1,27 @@ +/* + * 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_take_skip_to_pdu = R"doc()doc"; + + +static const char* __doc_gr_pdu_take_skip_to_pdu_make = R"doc()doc"; + + +static const char* __doc_gr_pdu_take_skip_to_pdu_set_take = R"doc()doc"; + + +static const char* __doc_gr_pdu_take_skip_to_pdu_set_skip = R"doc()doc"; diff --git a/gr-pdu/python/pdu/bindings/python_bindings.cc b/gr-pdu/python/pdu/bindings/python_bindings.cc index 0739908789..7929b89d88 100644 --- a/gr-pdu/python/pdu/bindings/python_bindings.cc +++ b/gr-pdu/python/pdu/bindings/python_bindings.cc @@ -23,6 +23,7 @@ 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&); +void bind_take_skip_to_pdu(py::module&); void bind_time_delta(py::module&); // We need this hack because import_array() returns NULL @@ -52,5 +53,6 @@ PYBIND11_MODULE(pdu_python, m) bind_pdu_to_tagged_stream(m); bind_random_pdu(m); bind_tagged_stream_to_pdu(m); + bind_take_skip_to_pdu(m); bind_time_delta(m); } diff --git a/gr-pdu/python/pdu/bindings/take_skip_to_pdu_python.cc b/gr-pdu/python/pdu/bindings/take_skip_to_pdu_python.cc new file mode 100644 index 0000000000..6cf9fa3fd0 --- /dev/null +++ b/gr-pdu/python/pdu/bindings/take_skip_to_pdu_python.cc @@ -0,0 +1,65 @@ +/* + * 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(take_skip_to_pdu.h) */ +/* BINDTOOL_HEADER_FILE_HASH(0fd64d6f3ff06d4bdfa2031a0afffd27) */ +/***********************************************************************************/ + +#include <pybind11/complex.h> +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + +namespace py = pybind11; + +#include <gnuradio/pdu/take_skip_to_pdu.h> +// pydoc.h is automatically generated in the build directory +#include <take_skip_to_pdu_pydoc.h> + +template <typename T> +void bind_take_skip_to_pdu_template(py::module& m, const char* classname) +{ + + using take_skip_to_pdu = ::gr::pdu::take_skip_to_pdu<T>; + + + py::class_<take_skip_to_pdu, + gr::sync_block, + gr::block, + gr::basic_block, + std::shared_ptr<take_skip_to_pdu>>(m, classname) + + .def(py::init(&gr::pdu::take_skip_to_pdu<T>::make), + py::arg("take"), + py::arg("skip"), + D(take_skip_to_pdu, make)) + + .def("set_take", + &take_skip_to_pdu::set_take, + py::arg("take"), + D(take_skip_to_pdu, set_take)) + + .def("set_skip", + &take_skip_to_pdu::set_skip, + py::arg("skip"), + D(take_skip_to_pdu, set_skip)); +} + +void bind_take_skip_to_pdu(py::module& m) +{ + bind_take_skip_to_pdu_template<unsigned char>(m, "take_skip_to_pdu_b"); + bind_take_skip_to_pdu_template<short>(m, "take_skip_to_pdu_s"); + bind_take_skip_to_pdu_template<float>(m, "take_skip_to_pdu_f"); + bind_take_skip_to_pdu_template<gr_complex>(m, "take_skip_to_pdu_c"); +} diff --git a/gr-pdu/python/pdu/pdu_lambda.py b/gr-pdu/python/pdu/pdu_lambda.py new file mode 100644 index 0000000000..6eeb2223a1 --- /dev/null +++ b/gr-pdu/python/pdu/pdu_lambda.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2015,2021 Tim O'Shea, Jacob Gilbert. +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# + + +from gnuradio import gr +import numpy as np +import math, pmt, time + + +class pdu_lambda(gr.basic_block): + """ + PDU Lambda Block + + This block allows stateless manipulation of PDU metadata fields and uniform vectors + through python lambda functions. In uniform vector mode the lamnda function will be + applied with the python-ified uniform vector as the argument. In metadata dictionary + mode the lambda function will be applied to the python-ified value associated with + the PMT key the block is configured with. + + The following python modules are imported for use: + `import numpy as np` + `import pmt, math, time` + These should also be imported in the flowgraph implementing this block if utilized. + + Errors are generally silently dropped as all function application is done within a + try/catch statement. In the event an exception is thrown the data will be emitted + as it was received. + + Examples of use: + - Phase demodulation of a complex PDU: Uniform Vector Mode with function: + `lambda x: np.unwrap(np.angle(x))` + - Scale metadata field `val1`: Metadata mode, separate QT range block with name `k`: + `lambda x: k*x` + + This block cannot add or remove metadata fields, which should be done with the + application specific blocks in-tree or the more generic `message_lambda` block. This + block also designed to accept and return explicitly PDU type objects, if the PMT + object type needs to change, use the `message_lambda` block. + """ + + def __init__(self, fn, metadict, key=pmt.PMT_NIL): + gr.basic_block.__init__(self, + name="pdu_lambda", + in_sig=[],out_sig=[]) + self.set_fn(fn) + self.set_key(key) + self.metadict_mode = metadict + self.message_port_register_in(pmt.intern("pdu")) + self.message_port_register_out(pmt.intern("pdu")) + self.set_msg_handler(pmt.intern("pdu"), self.handle_msg) + + def handle_msg(self, pdu): + if self.metadict_mode: + meta = pmt.car(pdu) + try: + val = pmt.to_python(pmt.dict_ref(meta, self.key, pmt.PMT_NIL)) + if val: + val = self.fn(val) + meta = pmt.dict_add(meta, self.key, pmt.to_pmt(val)) + except Exception as e: + print(e) + pass + self.message_port_pub(pmt.intern("pdu"), + pmt.cons(meta, pmt.cdr(pdu))); + + else: # PDU Vector mode + vec = pmt.cdr(pdu) + try: + vec = pmt.to_pmt(self.fn(pmt.to_python(vec))) + except Exception as e: + print(e) + pass + + self.message_port_pub(pmt.intern("pdu"), + pmt.cons(pmt.car(pdu), vec)); + + def set_fn(self,fn): + self.fn = fn + + def set_key(self,key): + self.key = key diff --git a/gr-pdu/python/pdu/qa_pdu_lambda.py b/gr-pdu/python/pdu/qa_pdu_lambda.py new file mode 100755 index 0000000000..f93475b8d9 --- /dev/null +++ b/gr-pdu/python/pdu/qa_pdu_lambda.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2021 Jacob Gilbert. +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# + + +from gnuradio import gr, gr_unittest +from gnuradio import pdu + +class qa_pdu_lambda(gr_unittest.TestCase): + + def setUp(self): + self.tb = gr.top_block() + + def tearDown(self): + self.tb = None + + def test_smoketest(self): + # FIXME: Test will fail until you pass sensible arguments to the constructor + instance = pdu.pdu_lambda(lambda uvec: uvec*10, False) + + def test_001_descriptive_test_name(self): + # set up fg + self.tb.run() + # check data + + +if __name__ == '__main__': + gr_unittest.run(qa_pdu_lambda) diff --git a/gr-pdu/python/pdu/qa_take_skip_to_pdu.py b/gr-pdu/python/pdu/qa_take_skip_to_pdu.py new file mode 100755 index 0000000000..76414c857a --- /dev/null +++ b/gr-pdu/python/pdu/qa_take_skip_to_pdu.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2018-2021 National Technology & Engineering Solutions of Sandia, LLC +# (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government +# retains certain rights in this software. +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +from builtins import range +from gnuradio import gr, gr_unittest, blocks, pdu +import pmt +import time +import numpy + +class qa_take_skip_to_pdu_X (gr_unittest.TestCase): + + # this method is necessary because by default pmt.equal does not evaluate + # the *contents* of a uniform vector + def assertEqualPDU(self, pdu1, pdu2): + # first check the equal() function: + if not pmt.equal(pdu1, pdu2): + self.assertTrue(False) + # then check the dictionaries: + if not pmt.equal(pmt.car(pdu1), pmt.car(pdu2)): + self.assertTrue(False) + # then check the elements of the respective vectors + vec1 = pmt.cdr(pdu1) + vec2 = pmt.cdr(pdu2) + if not pmt.equal(vec1, vec2): + self.assertTrue(False) + if not (pmt.to_python(vec1) == pmt.to_python(vec2)).all(): + print("vectors not equal? " + repr(vec1) + repr(vec2)) + self.assertTrue(False) + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_001_f_32 (self): + self.source = blocks.vector_source_f(range(0,32*3), False, 1, []) + self.ts_pdu = pdu.take_skip_to_pdu_f(32, 32) + self.debug = blocks.message_debug() + self.tb.connect((self.source, 0), (self.ts_pdu, 0)) + self.tb.msg_connect((self.ts_pdu, 'pdus'), (self.debug, 'store')) + + dic = pmt.dict_add(pmt.make_dict(), pmt.intern("pdu_num"), pmt.from_uint64(0)) + vec = pmt.init_f32vector(32, range(0,32)) + expected = pmt.cons(dic,vec) + self.tb.run () + actual = self.debug.get_message(0) + self.assertEqualPDU(actual, expected) + + def test_002_c_80 (self): + self.source = blocks.vector_source_c(range(0,32*3), False, 1, []) + self.ts_pdu = pdu.take_skip_to_pdu_c(80, 32) + self.debug = blocks.message_debug() + self.tb.connect((self.source, 0), (self.ts_pdu, 0)) + self.tb.msg_connect((self.ts_pdu, 'pdus'), (self.debug, 'store')) + + dic = pmt.dict_add(pmt.make_dict(), pmt.intern("pdu_num"), pmt.from_uint64(0)) + vec = pmt.init_c32vector(80, range(0,80)) + expected = pmt.cons(dic,vec) + self.tb.run () + actual = self.debug.get_message(0) + self.assertEqualPDU(actual, expected) + + + def test_003_s_2_11_7 (self): + self.source = blocks.vector_source_s(range(0,32*3), False, 1, []) + self.ts_pdu = pdu.take_skip_to_pdu_s(2, 11) + self.debug = blocks.message_debug() + self.tb.connect((self.source, 0), (self.ts_pdu, 0)) + self.tb.msg_connect((self.ts_pdu, 'pdus'), (self.debug, 'store')) + + dic = pmt.dict_add(pmt.make_dict(), pmt.intern("pdu_num"), pmt.from_uint64(7)) + vec = pmt.init_s16vector(2, list(range(91,93))) + expected = pmt.cons(dic,vec) + self.tb.run () + actual = self.debug.get_message(7) + self.assertEqualPDU(actual, expected) + + + def test_004_b_512 (self): + self.source = blocks.vector_source_b(list(range(0,256))*4, False, 1, []) + self.ts_pdu = pdu.take_skip_to_pdu_b(512,1) + self.debug = blocks.message_debug() + self.tb.connect((self.source, 0), (self.ts_pdu, 0)) + self.tb.msg_connect((self.ts_pdu, 'pdus'), (self.debug, 'store')) + + dic = pmt.dict_add(pmt.make_dict(), pmt.intern("pdu_num"), pmt.from_uint64(0)) + vec = pmt.init_u8vector(512, list(range(0,256))*2) + expected = pmt.cons(dic,vec) + self.tb.run () + actual = self.debug.get_message(0) + self.assertEqualPDU(actual, expected) + + +if __name__ == '__main__': + gr_unittest.run(qa_take_skip_to_pdu_X) |