// SPDX-License-Identifier: LGPL-2.1-or-later // SPDX-FileCopyrightText: 2021-2022 Bartosz Golaszewski #include #include #include #include "internal.hpp" namespace gpiod { void line_request::impl::throw_if_released() const { if (!this->request) throw request_released("GPIO lines have been released"); } void line_request::impl::set_request_ptr(line_request_ptr& ptr) { this->request = ::std::move(ptr); this->offset_buf.resize(::gpiod_line_request_get_num_requested_lines(this->request.get())); } void line_request::impl::fill_offset_buf(const line::offsets& offsets) { for (unsigned int i = 0; i < offsets.size(); i++) this->offset_buf[i] = offsets[i]; } line_request::line_request() : _m_priv(new impl) { } GPIOD_CXX_API line_request::line_request(line_request&& other) noexcept : _m_priv(::std::move(other._m_priv)) { } GPIOD_CXX_API line_request::~line_request() { } GPIOD_CXX_API line_request& line_request::operator=(line_request&& other) noexcept { this->_m_priv = ::std::move(other._m_priv); return *this; } GPIOD_CXX_API line_request::operator bool() const noexcept { return this->_m_priv->request.get() != nullptr; } GPIOD_CXX_API void line_request::release() { this->_m_priv->throw_if_released(); this->_m_priv->request.reset(); } GPIOD_CXX_API ::std::string line_request::chip_name() const { this->_m_priv->throw_if_released(); return ::gpiod_line_request_get_chip_name(this->_m_priv->request.get()); } GPIOD_CXX_API ::std::size_t line_request::num_lines() const { this->_m_priv->throw_if_released(); return ::gpiod_line_request_get_num_requested_lines(this->_m_priv->request.get()); } GPIOD_CXX_API line::offsets line_request::offsets() const { this->_m_priv->throw_if_released(); auto num_lines = this->num_lines(); ::std::vector buf(num_lines); line::offsets offsets(num_lines); ::gpiod_line_request_get_requested_offsets(this->_m_priv->request.get(), buf.data(), buf.size()); for (unsigned int i = 0; i < num_lines; i++) offsets[i] = buf[i]; return offsets; } GPIOD_CXX_API line::value line_request::get_value(line::offset offset) { return this->get_values({ offset }).front(); } GPIOD_CXX_API line::values line_request::get_values(const line::offsets& offsets) { line::values vals(offsets.size()); this->get_values(offsets, vals); return vals; } GPIOD_CXX_API line::values line_request::get_values() { return this->get_values(this->offsets()); } GPIOD_CXX_API void line_request::get_values(const line::offsets& offsets, line::values& values) { this->_m_priv->throw_if_released(); if (offsets.size() != values.size()) throw ::std::invalid_argument("values must have the same size as the offsets"); this->_m_priv->fill_offset_buf(offsets); int ret = ::gpiod_line_request_get_values_subset( this->_m_priv->request.get(), offsets.size(), this->_m_priv->offset_buf.data(), reinterpret_cast<::gpiod_line_value*>(values.data())); if (ret) throw_from_errno("unable to retrieve line values"); } GPIOD_CXX_API void line_request::get_values(line::values& values) { this->get_values(this->offsets(), values); } GPIOD_CXX_API line_request& line_request::set_value(line::offset offset, line::value value) { return this->set_values({ offset }, { value }); } GPIOD_CXX_API line_request& line_request::set_values(const line::value_mappings& values) { line::offsets offsets(values.size()); line::values vals(values.size()); for (unsigned int i = 0; i < values.size(); i++) { offsets[i] = values[i].first; vals[i] = values[i].second; } return this->set_values(offsets, vals); } GPIOD_CXX_API line_request& line_request::set_values(const line::offsets& offsets, const line::values& values) { this->_m_priv->throw_if_released(); if (offsets.size() != values.size()) throw ::std::invalid_argument("values must have the same size as the offsets"); this->_m_priv->fill_offset_buf(offsets); int ret = ::gpiod_line_request_set_values_subset( this->_m_priv->request.get(), offsets.size(), this->_m_priv->offset_buf.data(), reinterpret_cast(values.data())); if (ret) throw_from_errno("unable to set line values"); return *this; } GPIOD_CXX_API line_request& line_request::set_values(const line::values& values) { return this->set_values(this->offsets(), values); } GPIOD_CXX_API line_request& line_request::reconfigure_lines(const line_config& config) { this->_m_priv->throw_if_released(); int ret = ::gpiod_line_request_reconfigure_lines(this->_m_priv->request.get(), config._m_priv->config.get()); if (ret) throw_from_errno("unable to reconfigure GPIO lines"); return *this; } GPIOD_CXX_API int line_request::fd() const { this->_m_priv->throw_if_released(); return ::gpiod_line_request_get_fd(this->_m_priv->request.get()); } GPIOD_CXX_API bool line_request::wait_edge_events(const ::std::chrono::nanoseconds& timeout) const { this->_m_priv->throw_if_released(); int ret = ::gpiod_line_request_wait_edge_events(this->_m_priv->request.get(), timeout.count()); if (ret < 0) throw_from_errno("error waiting for edge events"); return ret; } GPIOD_CXX_API ::std::size_t line_request::read_edge_events(edge_event_buffer& buffer) { return this->read_edge_events(buffer, buffer.capacity()); } GPIOD_CXX_API ::std::size_t line_request::read_edge_events(edge_event_buffer& buffer, ::std::size_t max_events) { this->_m_priv->throw_if_released(); return buffer._m_priv->read_events(this->_m_priv->request, max_events); } GPIOD_CXX_API ::std::ostream& operator<<(::std::ostream& out, const line_request& request) { if (!request) out << "gpiod::line_request(released)"; else out << "gpiod::line_request(chip=\"" << request.chip_name() << "\", num_lines=" << request.num_lines() << ", line_offsets=" << request.offsets() << ", fd=" << request.fd() << ")"; return out; } } /* namespace gpiod */