diff mbox series

[libgpiod,12/16] bindings: cxx: add line_config.set_output_values()

Message ID 20230113215210.616812-13-brgl@bgdev.pl
State New
Headers show
Series [libgpiod,01/16] README: update for libgpiod v2 | expand

Commit Message

Bartosz Golaszewski Jan. 13, 2023, 9:52 p.m. UTC
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Extend line_config to expose a new method - set_output_values() - which
wraps the new C function for setting multiple output values at once.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 bindings/cxx/gpiodcxx/line-config.hpp    |  7 ++++
 bindings/cxx/internal.hpp                |  1 +
 bindings/cxx/line-config.cpp             | 15 +++++++
 bindings/cxx/line-settings.cpp           |  5 +++
 bindings/cxx/tests/tests-line-config.cpp | 51 ++++++++++++++++++++++++
 5 files changed, 79 insertions(+)

Comments

Andy Shevchenko Jan. 14, 2023, 11:20 a.m. UTC | #1
On Fri, Jan 13, 2023 at 10:52:06PM +0100, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> 
> Extend line_config to expose a new method - set_output_values() - which
> wraps the new C function for setting multiple output values at once.

...

Side Q: Does documentation describe the order in which lines are being set?
Or is it solely specified by a kernel driver for a hardware?

(I can imagine that this may be not so trivial as long as the input parameters,
 i.e. line offsets, are not sorted and hardware supports full bank atomic
 write, this may have a lot of interesting side effects.)
diff mbox series

Patch

diff --git a/bindings/cxx/gpiodcxx/line-config.hpp b/bindings/cxx/gpiodcxx/line-config.hpp
index a917913..b76fdff 100644
--- a/bindings/cxx/gpiodcxx/line-config.hpp
+++ b/bindings/cxx/gpiodcxx/line-config.hpp
@@ -76,6 +76,13 @@  public:
 	 */
 	line_config& add_line_settings(const line::offsets& offsets, const line_settings& settings);
 
+	/**
+	 * @brief Set output values for a number of lines.
+	 * @param values Buffer containing the output values.
+	 * @return Reference to self.
+	 */
+	line_config& set_output_values(const line::values& values);
+
 	/**
 	 * @brief Get a mapping of offsets to line settings stored by this
 	 *        object.
diff --git a/bindings/cxx/internal.hpp b/bindings/cxx/internal.hpp
index 6aceac1..8322e12 100644
--- a/bindings/cxx/internal.hpp
+++ b/bindings/cxx/internal.hpp
@@ -31,6 +31,7 @@  map_enum_c_to_cxx(c_enum_type value, const ::std::map<c_enum_type, cxx_enum_type
 }
 
 void throw_from_errno(const ::std::string& what);
+::gpiod_line_value map_output_value(line::value value);
 
 template<class T, void F(T*)> struct deleter
 {
diff --git a/bindings/cxx/line-config.cpp b/bindings/cxx/line-config.cpp
index 3ec99f0..233ba33 100644
--- a/bindings/cxx/line-config.cpp
+++ b/bindings/cxx/line-config.cpp
@@ -100,6 +100,21 @@  GPIOD_CXX_API line_config& line_config::add_line_settings(const line::offsets& o
 	return *this;
 }
 
+GPIOD_CXX_API line_config& line_config::set_output_values(const line::values& values)
+{
+	::std::vector<::gpiod_line_value> mapped_values(values.size());
+
+	for (unsigned int i = 0; i < values.size(); i++)
+		mapped_values[i] = map_output_value(values[i]);
+
+	auto ret = ::gpiod_line_config_set_output_values(this->_m_priv->config.get(),
+							 mapped_values.data(), mapped_values.size());
+	if (ret)
+		throw_from_errno("unable to set output values");
+
+	return *this;
+}
+
 GPIOD_CXX_API ::std::map<line::offset, line_settings> line_config::get_line_settings() const
 {
 	::std::size_t num_offsets = ::gpiod_line_config_get_num_configured_offsets(
diff --git a/bindings/cxx/line-settings.cpp b/bindings/cxx/line-settings.cpp
index 32f21a3..2159062 100644
--- a/bindings/cxx/line-settings.cpp
+++ b/bindings/cxx/line-settings.cpp
@@ -139,6 +139,11 @@  cxx_enum_type get_mapped_value(::gpiod_line_settings* settings,
 
 } /* namespace */
 
+::gpiod_line_value map_output_value(line::value value)
+{
+	return do_map_value(value, value_mapping);
+}
+
 line_settings::impl::impl()
 	: settings(make_line_settings())
 {
diff --git a/bindings/cxx/tests/tests-line-config.cpp b/bindings/cxx/tests/tests-line-config.cpp
index 5fa0f94..5e439a1 100644
--- a/bindings/cxx/tests/tests-line-config.cpp
+++ b/bindings/cxx/tests/tests-line-config.cpp
@@ -4,12 +4,17 @@ 
 #include <catch2/catch.hpp>
 #include <gpiod.hpp>
 
+#include "gpiosim.hpp"
 #include "helpers.hpp"
 
+using ::gpiosim::make_sim;
 using namespace ::std::chrono_literals;
 using direction = ::gpiod::line::direction;
 using drive = ::gpiod::line::drive;
 using edge = ::gpiod::line::edge;
+using simval = ::gpiosim::chip::value;
+using value = ::gpiod::line::value;
+using values = ::gpiod::line::values;
 
 namespace {
 
@@ -72,6 +77,52 @@  TEST_CASE("line_config can be reset", "[line-config]")
 	REQUIRE(cfg.get_line_settings().size() == 0);
 }
 
+TEST_CASE("output values can be set globally", "[line-config]")
+{
+	const values vals = { value::ACTIVE, value::INACTIVE, value::ACTIVE, value::INACTIVE };
+
+	auto sim = make_sim()
+		.set_num_lines(4)
+		.build();
+
+	::gpiod::line_config cfg;
+
+	SECTION("request with globally set output values")
+	{
+		cfg
+			.add_line_settings(
+				{0, 1, 2, 3},
+				::gpiod::line_settings().set_direction(direction::OUTPUT)
+			)
+			.set_output_values(vals);
+
+		auto request = ::gpiod::chip(sim.dev_path())
+			.prepare_request()
+			.set_line_config(cfg)
+			.do_request();
+
+		REQUIRE(sim.get_value(0) == simval::ACTIVE);
+		REQUIRE(sim.get_value(1) == simval::INACTIVE);
+		REQUIRE(sim.get_value(2) == simval::ACTIVE);
+		REQUIRE(sim.get_value(3) == simval::INACTIVE);
+	}
+
+	SECTION("read back global output values")
+	{
+		cfg
+			.add_line_settings(
+				{0, 1, 2, 3},
+				::gpiod::line_settings()
+					.set_direction(direction::OUTPUT)
+					.set_output_value(value::ACTIVE)
+			)
+			.set_output_values(vals);
+
+		auto settings = cfg.get_line_settings()[1];
+		REQUIRE(settings.output_value() == value::INACTIVE);
+	}
+}
+
 TEST_CASE("line_config stream insertion operator works", "[line-config]")
 {
 	::gpiod::line_config cfg;