| // SPDX-License-Identifier: LGPL-2.1-or-later |
| // SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com> |
| |
| #include <system_error> |
| |
| #include "gpio-mockup.hpp" |
| |
| namespace gpiod { |
| namespace test { |
| |
| const ::std::bitset<32> mockup::FLAG_NAMED_LINES("1"); |
| |
| mockup& mockup::instance(void) |
| { |
| static mockup mockup; |
| |
| return mockup; |
| } |
| |
| mockup::mockup(void) : _m_mockup(::gpio_mockup_new()) |
| { |
| if (!this->_m_mockup) |
| throw ::std::system_error(errno, ::std::system_category(), |
| "unable to create the gpio-mockup context"); |
| } |
| |
| mockup::~mockup(void) |
| { |
| ::gpio_mockup_unref(this->_m_mockup); |
| } |
| |
| void mockup::probe(const ::std::vector<unsigned int>& chip_sizes, |
| const ::std::bitset<32>& flags) |
| { |
| int ret, probe_flags = 0; |
| |
| if (flags.to_ulong() & FLAG_NAMED_LINES.to_ulong()) |
| probe_flags |= GPIO_MOCKUP_FLAG_NAMED_LINES; |
| |
| ret = ::gpio_mockup_probe(this->_m_mockup, chip_sizes.size(), |
| chip_sizes.data(), probe_flags); |
| if (ret) |
| throw ::std::system_error(errno, ::std::system_category(), |
| "unable to probe gpio-mockup module"); |
| } |
| |
| void mockup::remove(void) |
| { |
| int ret = ::gpio_mockup_remove(this->_m_mockup); |
| if (ret) |
| throw ::std::system_error(errno, ::std::system_category(), |
| "unable to remove gpio-mockup module"); |
| } |
| |
| ::std::string mockup::chip_name(unsigned int idx) const |
| { |
| const char *name = ::gpio_mockup_chip_name(this->_m_mockup, idx); |
| if (!name) |
| throw ::std::system_error(errno, ::std::system_category(), |
| "unable to retrieve the chip name"); |
| |
| return ::std::string(name); |
| } |
| |
| ::std::string mockup::chip_path(unsigned int idx) const |
| { |
| const char *path = ::gpio_mockup_chip_path(this->_m_mockup, idx); |
| if (!path) |
| throw ::std::system_error(errno, ::std::system_category(), |
| "unable to retrieve the chip path"); |
| |
| return ::std::string(path); |
| } |
| |
| unsigned int mockup::chip_num(unsigned int idx) const |
| { |
| int num = ::gpio_mockup_chip_num(this->_m_mockup, idx); |
| if (num < 0) |
| throw ::std::system_error(errno, ::std::system_category(), |
| "unable to retrieve the chip number"); |
| |
| return num; |
| } |
| |
| int mockup::chip_get_value(unsigned int chip_idx, unsigned int line_offset) |
| { |
| int val = ::gpio_mockup_get_value(this->_m_mockup, chip_idx, line_offset); |
| if (val < 0) |
| throw ::std::system_error(errno, ::std::system_category(), |
| "error reading the line value"); |
| |
| return val; |
| } |
| |
| void mockup::chip_set_pull(unsigned int chip_idx, unsigned int line_offset, int pull) |
| { |
| int ret = ::gpio_mockup_set_pull(this->_m_mockup, chip_idx, line_offset, pull); |
| if (ret) |
| throw ::std::system_error(errno, ::std::system_category(), |
| "error setting line pull"); |
| } |
| |
| mockup::probe_guard::probe_guard(const ::std::vector<unsigned int>& chip_sizes, |
| const ::std::bitset<32>& flags) |
| { |
| mockup::instance().probe(chip_sizes, flags); |
| } |
| |
| mockup::probe_guard::~probe_guard(void) |
| { |
| mockup::instance().remove(); |
| } |
| |
| mockup::event_thread::event_thread(unsigned int chip_index, |
| unsigned int line_offset, unsigned int period_ms) |
| : _m_chip_index(chip_index), |
| _m_line_offset(line_offset), |
| _m_period_ms(period_ms), |
| _m_stop(false), |
| _m_mutex(), |
| _m_cond(), |
| _m_thread(&event_thread::event_worker, this) |
| { |
| |
| } |
| |
| mockup::event_thread::~event_thread(void) |
| { |
| ::std::unique_lock<::std::mutex> lock(this->_m_mutex); |
| this->_m_stop = true; |
| this->_m_cond.notify_all(); |
| lock.unlock(); |
| this->_m_thread.join(); |
| } |
| |
| void mockup::event_thread::event_worker(void) |
| { |
| for (unsigned int i = 0;; i++) { |
| ::std::unique_lock<::std::mutex> lock(this->_m_mutex); |
| |
| if (this->_m_stop) |
| break; |
| |
| ::std::cv_status status = this->_m_cond.wait_for(lock, |
| std::chrono::milliseconds(this->_m_period_ms)); |
| if (status == ::std::cv_status::timeout) |
| mockup::instance().chip_set_pull(this->_m_chip_index, |
| this->_m_line_offset, i % 2); |
| } |
| } |
| |
| } /* namespace test */ |
| } /* namespace gpiod */ |