aboutsummaryrefslogtreecommitdiffstats
path: root/gr-soapy
diff options
context:
space:
mode:
authorNicholas Corgan <n.corgan@gmail.com>2021-05-11 08:25:08 -0500
committerJeff Long <willcode4@gmail.com>2021-05-12 06:14:50 -0400
commit406bd0ab8add97083ec03c724d857001130c88a0 (patch)
treea171223fd6fc202c9cbeb17e16edbba4664e17a4 /gr-soapy
parentsoapy: consistency in input validation in new functions (diff)
downloadgnuradio-406bd0ab8add97083ec03c724d857001130c88a0.tar.xz
gnuradio-406bd0ab8add97083ec03c724d857001130c88a0.zip
soapy: added remaining functions that need custom pybind functions
* Refactored out pybind functions into own utility functions Signed-off-by: Nicholas Corgan <n.corgan@gmail.com>
Diffstat (limited to 'gr-soapy')
-rw-r--r--gr-soapy/include/gnuradio/soapy/block.h97
-rw-r--r--gr-soapy/lib/block_impl.cc113
-rw-r--r--gr-soapy/lib/block_impl.h17
-rw-r--r--gr-soapy/python/soapy/bindings/CMakeLists.txt1
-rw-r--r--gr-soapy/python/soapy/bindings/block_python.cc131
-rw-r--r--gr-soapy/python/soapy/bindings/docstrings/block_pydoc_template.h36
-rw-r--r--gr-soapy/python/soapy/bindings/soapy_common.cc130
-rw-r--r--gr-soapy/python/soapy/bindings/soapy_common.h29
-rw-r--r--gr-soapy/python/soapy/bindings/soapy_types_python.cc114
9 files changed, 555 insertions, 113 deletions
diff --git a/gr-soapy/include/gnuradio/soapy/block.h b/gr-soapy/include/gnuradio/soapy/block.h
index 583d7af4b..f69a2379e 100644
--- a/gr-soapy/include/gnuradio/soapy/block.h
+++ b/gr-soapy/include/gnuradio/soapy/block.h
@@ -354,6 +354,103 @@ public:
* \return the name of the clock source
*/
virtual std::string get_clock_source() const = 0;
+
+ /*!
+ * List the available global readback sensors.
+ * A sensor can represent a reference lock, RSSI, temperature.
+ * \return a list of available sensor string names
+ */
+ virtual std::vector<std::string> list_sensors() const = 0;
+
+ /*!
+ * Get meta-information about a sensor.
+ * Example: displayable name, type, range.
+ * \param key the ID name of an available sensor
+ * \return meta-information about a sensor
+ */
+ virtual arginfo_t get_sensor_info(const std::string& key) const = 0;
+
+ /*!
+ * Readback a global sensor given the name.
+ * The value returned is a string which can represent
+ * a boolean ("true"/"false"), an integer, or float.
+ * \param key the ID name of an available sensor
+ * \return the current value of the sensor
+ */
+ virtual std::string read_sensor(const std::string& key) const = 0;
+
+ /*!
+ * List the available channel readback sensors.
+ * A sensor can represent a reference lock, RSSI, temperature.
+ * \param channel an available channel on the device
+ * \return a list of available sensor string names
+ */
+ virtual std::vector<std::string> list_sensors(size_t channel) const = 0;
+
+ /*!
+ * Get meta-information about a channel sensor.
+ * Example: displayable name, type, range.
+ * \param channel an available channel on the device
+ * \param key the ID name of an available sensor
+ * \return meta-information about a sensor
+ */
+ virtual arginfo_t get_sensor_info(size_t channel, const std::string& key) const = 0;
+
+ /*!
+ * Readback a channel sensor given the name.
+ * The value returned is a string which can represent
+ * a boolean ("true"/"false"), an integer, or float.
+ * \param channel an available channel on the device
+ * \param key the ID name of an available sensor
+ * \return the current value of the sensor
+ */
+ virtual std::string read_sensor(size_t channel, const std::string& key) const = 0;
+
+ /*!
+ * Describe the allowed keys and values used for settings.
+ * \return a list of argument info structures
+ */
+ virtual arginfo_list_t get_setting_info() const = 0;
+
+ /*!
+ * Write an arbitrary setting on the device.
+ * The interpretation is up the implementation.
+ * \param key the setting identifier
+ * \param value the setting value
+ */
+ virtual void write_setting(const std::string& key, const std::string& value) = 0;
+
+ /*!
+ * Read an arbitrary setting on the device.
+ * \param key the setting identifier
+ * \return the setting value
+ */
+ virtual std::string read_setting(const std::string& key) const = 0;
+
+ /*!
+ * Describe the allowed keys and values used for channel settings.
+ * \param channel an available channel on the device
+ * \return a list of argument info structures
+ */
+ virtual arginfo_list_t get_setting_info(size_t channel) const = 0;
+
+ /*!
+ * Write an arbitrary channel setting on the device.
+ * The interpretation is up the implementation.
+ * \param channel an available channel on the device
+ * \param key the setting identifier
+ * \param value the setting value
+ */
+ virtual void
+ write_setting(size_t channel, const std::string& key, const std::string& value) = 0;
+
+ /*!
+ * Read an arbitrary channel setting on the device.
+ * \param channel an available channel on the device
+ * \param key the setting identifier
+ * \return the setting value
+ */
+ virtual std::string read_setting(size_t channel, const std::string& key) const = 0;
};
} // namespace soapy
diff --git a/gr-soapy/lib/block_impl.cc b/gr-soapy/lib/block_impl.cc
index d9c895d80..0e41182b4 100644
--- a/gr-soapy/lib/block_impl.cc
+++ b/gr-soapy/lib/block_impl.cc
@@ -727,6 +727,119 @@ void block_impl::set_clock_source(const std::string& clock_source)
std::string block_impl::get_clock_source() const { return d_device->getClockSource(); }
+std::vector<std::string> block_impl::list_sensors() const
+{
+ return d_device->listSensors();
+}
+
+arginfo_t block_impl::get_sensor_info(const std::string& key) const
+{
+ const auto sensors = d_device->listSensors();
+
+ if (vector_contains(sensors, key)) {
+ return d_device->getSensorInfo(key);
+ } else {
+ throw std::invalid_argument("Invalid sensor: " + key);
+ }
+}
+
+std::string block_impl::read_sensor(const std::string& key) const
+{
+ const auto sensors = d_device->listSensors();
+
+ if (vector_contains(sensors, key)) {
+ return d_device->readSensor(key);
+ } else {
+ throw std::invalid_argument("Invalid sensor: " + key);
+ }
+}
+
+std::vector<std::string> block_impl::list_sensors(size_t channel) const
+{
+ validate_channel(channel);
+ return d_device->listSensors(d_direction, channel);
+}
+
+arginfo_t block_impl::get_sensor_info(size_t channel, const std::string& key) const
+{
+ validate_channel(channel);
+ const auto sensors = d_device->listSensors(d_direction, channel);
+
+ if (vector_contains(sensors, key)) {
+ return d_device->getSensorInfo(d_direction, channel, key);
+ } else {
+ throw std::invalid_argument("Invalid sensor: " + key);
+ }
+}
+
+std::string block_impl::read_sensor(size_t channel, const std::string& key) const
+{
+ validate_channel(channel);
+ const auto sensors = d_device->listSensors(d_direction, channel);
+
+ if (vector_contains(sensors, key)) {
+ return d_device->readSensor(d_direction, channel, key);
+ } else {
+ throw std::invalid_argument("Invalid sensor: " + key);
+ }
+}
+
+arginfo_list_t block_impl::get_setting_info() const { return d_device->getSettingInfo(); }
+
+void block_impl::write_setting(const std::string& key, const std::string& value)
+{
+ const auto setting_info = d_device->getSettingInfo();
+
+ if (arg_info_has_key(setting_info, key)) {
+ d_device->writeSetting(key, value);
+ } else {
+ throw std::invalid_argument("Invalid setting: " + key);
+ }
+}
+
+std::string block_impl::read_setting(const std::string& key) const
+{
+ const auto setting_info = d_device->getSettingInfo();
+
+ if (arg_info_has_key(setting_info, key)) {
+ return d_device->readSetting(key);
+ } else {
+ throw std::invalid_argument("Invalid setting: " + key);
+ }
+}
+
+arginfo_list_t block_impl::get_setting_info(size_t channel) const
+{
+ validate_channel(channel);
+ return d_device->getSettingInfo(d_direction, channel);
+}
+
+void block_impl::write_setting(size_t channel,
+ const std::string& key,
+ const std::string& value)
+{
+ validate_channel(channel);
+ const auto setting_info = d_device->getSettingInfo(d_direction, channel);
+
+ if (arg_info_has_key(setting_info, key)) {
+ d_device->writeSetting(d_direction, channel, key, value);
+ } else {
+ throw std::invalid_argument("Invalid setting: " + key);
+ }
+}
+
+std::string block_impl::read_setting(size_t channel, const std::string& key) const
+{
+ validate_channel(channel);
+ const auto setting_info = d_device->getSettingInfo(d_direction, channel);
+
+ if (arg_info_has_key(setting_info, key)) {
+ return d_device->readSetting(d_direction, channel, key);
+ } else {
+ throw std::invalid_argument("Invalid setting: " + key);
+ }
+}
+
/* End public API implementation */
void block_impl::cmd_handler_frequency(pmt::pmt_t val, size_t channel)
diff --git a/gr-soapy/lib/block_impl.h b/gr-soapy/lib/block_impl.h
index 3fa1bec68..819ee5a03 100644
--- a/gr-soapy/lib/block_impl.h
+++ b/gr-soapy/lib/block_impl.h
@@ -156,6 +156,23 @@ public:
void set_clock_source(const std::string& clock_source) override;
std::string get_clock_source() const override;
+ std::vector<std::string> list_sensors() const override;
+ arginfo_t get_sensor_info(const std::string& key) const override;
+ std::string read_sensor(const std::string& key) const override;
+ std::vector<std::string> list_sensors(size_t channel) const override;
+ arginfo_t get_sensor_info(size_t channel, const std::string& key) const override;
+ std::string read_sensor(size_t channel, const std::string& key) const override;
+
+ virtual arginfo_list_t get_setting_info() const override;
+ virtual void write_setting(const std::string& key, const std::string& value) override;
+ virtual std::string read_setting(const std::string& key) const override;
+ virtual arginfo_list_t get_setting_info(size_t channel) const override;
+ virtual void write_setting(size_t channel,
+ const std::string& key,
+ const std::string& value) override;
+ virtual std::string read_setting(size_t channel,
+ const std::string& key) const override;
+
/*** End public API implementation ***/
protected:
diff --git a/gr-soapy/python/soapy/bindings/CMakeLists.txt b/gr-soapy/python/soapy/bindings/CMakeLists.txt
index 902cf9c42..5c54909ea 100644
--- a/gr-soapy/python/soapy/bindings/CMakeLists.txt
+++ b/gr-soapy/python/soapy/bindings/CMakeLists.txt
@@ -13,6 +13,7 @@ include(GrPybind)
list(APPEND soapy_python_files
block_python.cc
+ soapy_common.cc
soapy_types_python.cc
source_python.cc
sink_python.cc
diff --git a/gr-soapy/python/soapy/bindings/block_python.cc b/gr-soapy/python/soapy/bindings/block_python.cc
index 29311ef02..53b0a1ec6 100644
--- a/gr-soapy/python/soapy/bindings/block_python.cc
+++ b/gr-soapy/python/soapy/bindings/block_python.cc
@@ -15,9 +15,11 @@
/* BINDTOOL_GEN_AUTOMATIC(0) */
/* BINDTOOL_USE_PYGCCXML(0) */
/* BINDTOOL_HEADER_FILE(block.h) */
-/* BINDTOOL_HEADER_FILE_HASH(7742c1003b34ca79350bfaa736f25ce2) */
+/* BINDTOOL_HEADER_FILE_HASH(6aea02a7cec962d25665546a614ee437) */
/***********************************************************************************/
+#include "soapy_common.h"
+
#include <pybind11/complex.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
@@ -28,6 +30,24 @@ namespace py = pybind11;
// pydoc.h is automatically generated in the build directory
#include <block_pydoc.h>
+#include <algorithm>
+#include <cassert>
+
+// Assumption: we've validated that this key exists,
+// probably through get_setting_info.
+static gr::soapy::arginfo_t
+get_specific_arginfo(const gr::soapy::arginfo_list_t& arginfo_list,
+ const std::string& key)
+{
+ auto iter = std::find_if(
+ arginfo_list.begin(),
+ arginfo_list.end(),
+ [&key](const gr::soapy::arginfo_t& arginfo) { return (arginfo.key == key); });
+ assert(iter != arginfo_list.end());
+
+ return (*iter);
+}
+
void bind_block(py::module& m)
{
@@ -103,13 +123,14 @@ void bind_block(py::module& m)
.def("get_frequency_range",
- (SoapySDR::RangeList(block::*)(size_t) const) & block::get_frequency_range,
+ (gr::soapy::range_list_t(block::*)(size_t) const) &
+ block::get_frequency_range,
py::arg("channel"),
D(block, get_frequency_range, 0))
.def("get_frequency_range",
- (SoapySDR::RangeList(block::*)(size_t, const std::string&) const) &
+ (gr::soapy::range_list_t(block::*)(size_t, const std::string&) const) &
block::get_frequency_range,
py::arg("channel"),
py::arg("name"),
@@ -203,13 +224,13 @@ void bind_block(py::module& m)
.def("get_gain_range",
- (SoapySDR::Range(block::*)(size_t) const) & block::get_gain_range,
+ (gr::soapy::range_t(block::*)(size_t) const) & block::get_gain_range,
py::arg("channel"),
D(block, get_gain_range, 0))
.def("get_gain_range",
- (SoapySDR::Range(block::*)(size_t, const std::string&) const) &
+ (gr::soapy::range_t(block::*)(size_t, const std::string&) const) &
block::get_gain_range,
py::arg("channel"),
py::arg("name"),
@@ -321,5 +342,103 @@ void bind_block(py::module& m)
.def("get_clock_source", &block::get_clock_source, D(block, get_clock_source))
- ;
+ .def("list_sensors",
+ (std::vector<std::string>(block::*)() const) & block::list_sensors,
+ D(block, list_sensors, 0))
+
+ .def("get_sensor_info",
+ (gr::soapy::arginfo_t(block::*)(const std::string&) const) &
+ block::get_sensor_info,
+ py::arg("key"),
+ D(block, get_sensor_info, 0))
+
+ .def(
+ "read_sensor",
+ [](const block& self, const std::string& key) -> py::object {
+ const auto arginfo = self.get_sensor_info(key);
+
+ return cast_string_to_arginfo_type(arginfo.type, arginfo.value);
+ },
+ py::arg("key"),
+ D(block, read_sensor, 0))
+
+ .def("list_sensors",
+ (std::vector<std::string>(block::*)(size_t) const) & block::list_sensors,
+ py::arg("channel"),
+ D(block, list_sensors, 1))
+
+ .def("get_sensor_info",
+ (gr::soapy::arginfo_t(block::*)(size_t, const std::string&) const) &
+ block::get_sensor_info,
+ py::arg("channel"),
+ py::arg("key"),
+ D(block, get_sensor_info, 1))
+
+ .def(
+ "read_sensor",
+ [](const block& self, size_t channel, const std::string& key) -> py::object {
+ const auto arginfo = self.get_sensor_info(channel, key);
+
+ return cast_string_to_arginfo_type(arginfo.type, arginfo.value);
+ },
+ py::arg("channel"),
+ py::arg("key"),
+ D(block, read_sensor, 1))
+
+ .def("get_setting_info",
+ (gr::soapy::arginfo_list_t(block::*)() const) & block::get_setting_info,
+ D(block, get_setting_info, 0))
+
+ .def(
+ "write_setting",
+ [](block& self, const std::string& key, py::object value) -> void {
+ auto setting_info = cast_pyobject_to_arginfo_string(value);
+
+ self.write_setting(key, setting_info.value);
+ },
+ py::arg("key"),
+ py::arg("value"),
+ D(block, write_setting, 0))
+
+ .def(
+ "read_setting",
+ [](const block& self, const std::string& key) -> py::object {
+ const auto setting_info =
+ get_specific_arginfo(self.get_setting_info(), key);
+
+ return cast_string_to_arginfo_type(setting_info.type, setting_info.value);
+ },
+ py::arg("key"),
+ D(block, read_setting, 0))
+
+ .def("get_setting_info",
+ (gr::soapy::arginfo_list_t(block::*)(size_t) const) &
+ block::get_setting_info,
+ py::arg("channel"),
+ D(block, get_setting_info, 0))
+
+ .def(
+ "write_setting",
+ [](block& self, size_t channel, const std::string& key, py::object value)
+ -> void {
+ auto setting_info = cast_pyobject_to_arginfo_string(value);
+
+ self.write_setting(channel, key, setting_info.value);
+ },
+ py::arg("channel"),
+ py::arg("key"),
+ py::arg("value"),
+ D(block, write_setting, 0))
+
+ .def(
+ "read_setting",
+ [](const block& self, size_t channel, const std::string& key) -> py::object {
+ const auto setting_info =
+ get_specific_arginfo(self.get_setting_info(channel), key);
+
+ return cast_string_to_arginfo_type(setting_info.type, setting_info.value);
+ },
+ py::arg("channel"),
+ py::arg("key"),
+ D(block, read_setting, 0));
}
diff --git a/gr-soapy/python/soapy/bindings/docstrings/block_pydoc_template.h b/gr-soapy/python/soapy/bindings/docstrings/block_pydoc_template.h
index b690474aa..5318204af 100644
--- a/gr-soapy/python/soapy/bindings/docstrings/block_pydoc_template.h
+++ b/gr-soapy/python/soapy/bindings/docstrings/block_pydoc_template.h
@@ -166,3 +166,39 @@ static const char* __doc_gr_soapy_block_set_clock_source = R"doc()doc";
static const char* __doc_gr_soapy_block_get_clock_source = R"doc()doc";
+
+
+static const char* __doc_gr_soapy_block_list_sensors_0 = R"doc()doc";
+
+
+static const char* __doc_gr_soapy_block_get_sensor_info_0 = R"doc()doc";
+
+
+static const char* __doc_gr_soapy_block_read_sensor_0 = R"doc()doc";
+
+
+static const char* __doc_gr_soapy_block_list_sensors_1 = R"doc()doc";
+
+
+static const char* __doc_gr_soapy_block_get_sensor_info_1 = R"doc()doc";
+
+
+static const char* __doc_gr_soapy_block_read_sensor_1 = R"doc()doc";
+
+
+static const char* __doc_gr_soapy_block_get_setting_info_0 = R"doc()doc";
+
+
+static const char* __doc_gr_soapy_block_write_setting_0 = R"doc()doc";
+
+
+static const char* __doc_gr_soapy_block_read_setting_0 = R"doc()doc";
+
+
+static const char* __doc_gr_soapy_block_get_setting_info_1 = R"doc()doc";
+
+
+static const char* __doc_gr_soapy_block_write_setting_1 = R"doc()doc";
+
+
+static const char* __doc_gr_soapy_block_read_setting_1 = R"doc()doc";
diff --git a/gr-soapy/python/soapy/bindings/soapy_common.cc b/gr-soapy/python/soapy/bindings/soapy_common.cc
new file mode 100644
index 000000000..98d59be03
--- /dev/null
+++ b/gr-soapy/python/soapy/bindings/soapy_common.cc
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2021 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#include "soapy_common.h"
+
+#include <SoapySDR/Types.hpp>
+#include <SoapySDR/Version.h>
+
+// SoapySDR doesn't have an API define for SettingToString, so we need
+// to check the version. 0.8 is the first tagged version to have this
+// functionality.
+#if SOAPY_SDR_API_VERSION >= 0x080000
+
+template <typename T>
+static inline T string_to_setting(const std::string& str)
+{
+ return SoapySDR::StringToSetting<T>(str);
+}
+
+template <typename T>
+static inline std::string setting_to_string(const T& setting)
+{
+ return SoapySDR::SettingToString<T>(setting);
+}
+
+#else
+
+// Copied from SoapySDR 0.8
+#define SOAPY_SDR_TRUE "true"
+#define SOAPY_SDR_FALSE "false"
+
+#include <sstream>
+
+template <typename T>
+static inline T string_to_setting(const std::string& str)
+{
+ std::stringstream sstream(str);
+ T setting;
+
+ sstream >> setting;
+
+ return setting;
+}
+
+// Copied from SoapySDR 0.8
+template <>
+inline bool string_to_setting<bool>(const std::string& str)
+{
+ if (str == SOAPY_SDR_TRUE)
+ return true;
+ if (str == SOAPY_SDR_FALSE)
+ return false;
+
+ // zeros and empty strings are false
+ if (str == "0")
+ return false;
+ if (str == "0.0")
+ return false;
+ if (str == "")
+ return false;
+
+ // other values are true
+ return true;
+}
+
+template <typename T>
+static inline std::string setting_to_string(const T& setting)
+{
+ return std::to_string(setting);
+}
+
+template <>
+inline std::string setting_to_string<bool>(const bool& setting)
+{
+ return setting ? SOAPY_SDR_TRUE : SOAPY_SDR_FALSE;
+}
+
+#endif
+
+py::object cast_string_to_arginfo_type(gr::soapy::argtype_t argtype,
+ const std::string& str)
+{
+ py::object ret;
+ switch (argtype) {
+ case SoapySDR::ArgInfo::BOOL:
+ ret = py::bool_(string_to_setting<bool>(str));
+ break;
+
+ case SoapySDR::ArgInfo::INT:
+ ret = py::int_(string_to_setting<int>(str));
+ break;
+
+ case SoapySDR::ArgInfo::FLOAT:
+ ret = py::float_(string_to_setting<double>(str));
+ break;
+
+ default:
+ ret = py::str(str);
+ break;
+ }
+
+ return ret;
+}
+
+setting_info cast_pyobject_to_arginfo_string(py::object obj)
+{
+ setting_info info;
+
+ if (py::isinstance<py::bool_>(obj)) {
+ info.value = setting_to_string(bool(py::cast<py::bool_>(obj)));
+ info.type = SoapySDR::ArgInfo::BOOL;
+ } else if (py::isinstance<py::int_>(obj)) {
+ info.value = setting_to_string(int(py::cast<py::int_>(obj)));
+ info.type = SoapySDR::ArgInfo::INT;
+ } else if (py::isinstance<py::float_>(obj)) {
+ info.value = setting_to_string(double(py::cast<py::float_>(obj)));
+ info.type = SoapySDR::ArgInfo::FLOAT;
+ } else {
+ info.value = py::str(obj);
+ info.type = SoapySDR::ArgInfo::STRING;
+ }
+
+ return info;
+}
diff --git a/gr-soapy/python/soapy/bindings/soapy_common.h b/gr-soapy/python/soapy/bindings/soapy_common.h
new file mode 100644
index 000000000..90d5b9035
--- /dev/null
+++ b/gr-soapy/python/soapy/bindings/soapy_common.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#pragma once
+
+#include <pybind11/complex.h>
+#include <pybind11/operators.h>
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+
+namespace py = pybind11;
+
+#include <gnuradio/soapy/soapy_types.h>
+
+py::object cast_string_to_arginfo_type(gr::soapy::argtype_t argtype,
+ const std::string& str);
+
+struct setting_info {
+ std::string value;
+ gr::soapy::argtype_t type;
+};
+
+setting_info cast_pyobject_to_arginfo_string(py::object obj);
diff --git a/gr-soapy/python/soapy/bindings/soapy_types_python.cc b/gr-soapy/python/soapy/bindings/soapy_types_python.cc
index abcfa182a..f91e03f61 100644
--- a/gr-soapy/python/soapy/bindings/soapy_types_python.cc
+++ b/gr-soapy/python/soapy/bindings/soapy_types_python.cc
@@ -7,6 +7,8 @@
*
*/
+#include "soapy_common.h"
+
#include <pybind11/complex.h>
#include <pybind11/operators.h>
#include <pybind11/pybind11.h>
@@ -16,80 +18,6 @@ namespace py = pybind11;
#include <gnuradio/soapy/soapy_types.h>
-#include <SoapySDR/Types.hpp>
-#include <SoapySDR/Version.h>
-
-// SoapySDR doesn't have an API define for SettingToString, so we need
-// to check the version. 0.8 is the first tagged version to have this
-// functionality.
-#if SOAPY_SDR_API_VERSION >= 0x080000
-
-template <typename T>
-static inline T string_to_setting(const std::string& str)
-{
- return SoapySDR::StringToSetting<T>(str);
-}
-
-template <typename T>
-static inline std::string setting_to_string(const T& setting)
-{
- return SoapySDR::SettingToString<T>(setting);
-}
-
-#else
-
-// Copied from SoapySDR 0.8
-#define SOAPY_SDR_TRUE "true"
-#define SOAPY_SDR_FALSE "false"
-
-#include <sstream>
-
-template <typename T>
-static inline T string_to_setting(const std::string& str)
-{
- std::stringstream sstream(str);
- T setting;
-
- sstream >> setting;
-
- return setting;
-}
-
-// Copied from SoapySDR 0.8
-template <>
-inline bool string_to_setting<bool>(const std::string& str)
-{
- if (str == SOAPY_SDR_TRUE)
- return true;
- if (str == SOAPY_SDR_FALSE)
- return false;
-
- // zeros and empty strings are false
- if (str == "0")
- return false;
- if (str == "0.0")
- return false;
- if (str == "")
- return false;
-
- // other values are true
- return true;
-}
-
-template <typename T>
-static inline std::string setting_to_string(const T& setting)
-{
- return std::to_string(setting);
-}
-
-template <>
-inline std::string setting_to_string<bool>(const bool& setting)
-{
- return setting ? SOAPY_SDR_TRUE : SOAPY_SDR_FALSE;
-}
-
-#endif
-
void bind_soapy_types(py::module& m)
{
py::class_<gr::soapy::range_t>(m, "range_t")
@@ -131,42 +59,14 @@ void bind_soapy_types(py::module& m)
.def_property(
"value",
[](const gr::soapy::arginfo_t& arginfo) -> py::object {
- py::object ret;
- switch (arginfo.type) {
- case gr::soapy::arginfo_t::BOOL:
- ret = py::bool_(string_to_setting<bool>(arginfo.value));
- break;
-
- case gr::soapy::arginfo_t::INT:
- ret = py::int_(string_to_setting<int>(arginfo.value));
- break;
-
- case gr::soapy::arginfo_t::FLOAT:
- ret = py::float_(string_to_setting<double>(arginfo.value));
- break;
-
- default:
- ret = py::str(arginfo.value);
- break;
- }
-
- return ret;
+ return cast_string_to_arginfo_type(arginfo.type, arginfo.value);
},
// So we can implicitly convert to Soapy's convention
[](gr::soapy::arginfo_t& arginfo, py::object obj) -> void {
- if (py::isinstance<py::bool_>(obj)) {
- arginfo.value = setting_to_string(bool(py::cast<py::bool_>(obj)));
- arginfo.type = gr::soapy::arginfo_t::BOOL;
- } else if (py::isinstance<py::int_>(obj)) {
- arginfo.value = setting_to_string(int(py::cast<py::int_>(obj)));
- arginfo.type = gr::soapy::arginfo_t::INT;
- } else if (py::isinstance<py::float_>(obj)) {
- arginfo.value = setting_to_string(double(py::cast<py::float_>(obj)));
- arginfo.type = gr::soapy::arginfo_t::FLOAT;
- } else {
- arginfo.value = py::str(obj);
- arginfo.type = gr::soapy::arginfo_t::STRING;
- }
+ const auto info = cast_pyobject_to_arginfo_string(obj);
+
+ arginfo.value = info.value;
+ arginfo.type = info.type;
})
.def_readwrite("name", &gr::soapy::arginfo_t::name)