<commit_before>/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * This file is part of libgpiod.
 *
 * Copyright (C) 2019 <NAME> <<EMAIL>>
 */

#include <catch2/catch.hpp>
#include <gpiod.hpp>
#include <map>
#include <poll.h>

#include "gpio-mockup.hpp"

using ::gpiod::test::mockup;

namespace {

const ::std::string consumer = "event-test";

} /* namespace */

TEST_CASE("Line events can be detected", "[event][line]")
{
	mockup::probe_guard mockup_chips({ 8 });
	mockup::event_thread events(0, 4, 200);
	::gpiod::chip chip(mockup::instance().chip_name(0));
	auto line = chip.get_line(4);
	::gpiod::line_request config;

	config.consumer = consumer.c_str();

	SECTION("rising edge")
	{
		config.request_type = ::gpiod::line_request::EVENT_RISING_EDGE;
		line.request(config);

		auto got_event = line.event_wait(::std::chrono::seconds(1));
		REQUIRE(got_event);

		auto event = line.event_read();
		REQUIRE(event.source == line);
		REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE);
	}

	SECTION("falling edge")
	{
		config.request_type = ::gpiod::line_request::EVENT_FALLING_EDGE;

		line.request(config);

		auto got_event = line.event_wait(::std::chrono::seconds(1));
		REQUIRE(got_event);

		auto event = line.event_read();
		REQUIRE(event.source == line);
		REQUIRE(event.event_type == ::gpiod::line_event::FALLING_EDGE);
	}

	SECTION("both edges")
	{
		config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES;

		line.request(config);

		auto got_event = line.event_wait(::std::chrono::seconds(1));
		REQUIRE(got_event);

		auto event = line.event_read();
		REQUIRE(event.source == line);
		REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE);

		got_event = line.event_wait(::std::chrono::seconds(1));
		REQUIRE(got_event);

		event = line.event_read();
		REQUIRE(event.source == line);
		REQUIRE(event.event_type == ::gpiod::line_event::FALLING_EDGE);
	}

	SECTION("active-low")
	{
		config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES;
		config.flags = ::gpiod::line_request::FLAG_ACTIVE_LOW;

		line.request(config);

		auto got_event = line.event_wait(::std::chrono::seconds(1));
		REQUIRE(got_event);

		auto event = line.event_read();
		REQUIRE(event.source == line);
		REQUIRE(event.event_type == ::gpiod::line_event::FALLING_EDGE);

		got_event = line.event_wait(::std::chrono::seconds(1));
		REQUIRE(got_event);

		event = line.event_read();
		REQUIRE(event.source == line);
		REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE);
	}
}

TEST_CASE("Watching line_bulk objects for events works", "[event][bulk]")
{
	mockup::probe_guard mockup_chips({ 8 });
	mockup::event_thread events(0, 2, 200);
	::gpiod::chip chip(mockup::instance().chip_name(0));
	auto lines = chip.get_lines({ 0, 1, 2, 3 });
	::gpiod::line_request config;

	config.consumer = consumer.c_str();
	config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES;
	lines.request(config);

	auto event_lines = lines.event_wait(::std::chrono::seconds(1));
	REQUIRE(event_lines);
	REQUIRE(event_lines.size() == 1);

	auto event = event_lines.get(0).event_read();
	REQUIRE(event.source == event_lines.get(0));
	REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE);

	event_lines = lines.event_wait(::std::chrono::seconds(1));
	REQUIRE(event_lines);
	REQUIRE(event_lines.size() == 1);

	event = event_lines.get(0).event_read();
	REQUIRE(event.source == event_lines.get(0));
	REQUIRE(event.event_type == ::gpiod::line_event::FALLING_EDGE);
}

TEST_CASE("It's possible to retrieve the event file descriptor", "[event][line]")
{
	mockup::probe_guard mockup_chips({ 8 });
	::gpiod::chip chip(mockup::instance().chip_name(0));
	auto line = chip.get_line(4);
	::gpiod::line_request config;

	config.consumer = consumer.c_str();

	SECTION("get the fd")
	{
		config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES;

		line.request(config);
		REQUIRE(line.event_get_fd() >= 0);
	}

	SECTION("error if not requested")
	{
		REQUIRE_THROWS_AS(line.event_get_fd(), ::std::system_error);
	}

	SECTION("error if requested for values")
	{
		config.request_type = ::gpiod::line_request::DIRECTION_INPUT;

		line.request(config);
		REQUIRE_THROWS_AS(line.event_get_fd(), ::std::system_error);
	}
}

TEST_CASE("Event file descriptors can be used for polling", "[event]")
{
	mockup::probe_guard mockup_chips({ 8 });
	mockup::event_thread events(0, 3, 200);
	::gpiod::chip chip(mockup::instance().chip_name(0));
	::std::map<int, ::gpiod::line> fd_line_map;
	auto lines = chip.get_lines({ 0, 1, 2, 3, 4, 5 });

	::gpiod::line_request config;
	config.consumer = consumer.c_str();
	config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES;

	lines.request(config);

	fd_line_map[lines[1].event_get_fd()] = lines[1];
	fd_line_map[lines[3].event_get_fd()] = lines[3];
	fd_line_map[lines[5].event_get_fd()] = lines[5];

	::pollfd fds[3];
	fds[0].fd = lines[1].event_get_fd();
	fds[1].fd = lines[3].event_get_fd();
	fds[2].fd = lines[5].event_get_fd();

	fds[0].events = fds[1].events = fds[2].events = POLLIN | POLLPRI;

	int ret = ::poll(fds, 3, 1000);
	REQUIRE(ret == 1);

	for (int i = 0; i < 3; i++) {
		if (fds[i].revents) {
			auto event = fd_line_map[fds[i].fd].event_read();
			REQUIRE(event.source == fd_line_map[fds[i].fd]);
			REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE);
		}
	}
}

TEST_CASE("It's possible to read values from lines requested for events", "[event][line]")
{
	mockup::probe_guard mockup_chips({ 8 });
	::gpiod::chip chip(mockup::instance().chip_name(0));
	auto line = chip.get_line(4);
	::gpiod::line_request config;

	config.consumer = consumer.c_str();
	config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES;

	mockup::instance().chip_set_pull(0, 4, 1);

	SECTION("active-high (default)")
	{
		line.request(config);
		REQUIRE(line.get_value() == 1);
	}

	SECTION("active-low")
	{
		config.flags = ::gpiod::line_request::FLAG_ACTIVE_LOW;
		line.request(config);
		REQUIRE(line.get_value() == 0);
	}<commit_msg>bindings: cxx: tests: simplify the event fd polling test case<commit_after>/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * This file is part of libgpiod.
 *
 * Copyright (C) 2019 <NAME> <<EMAIL>>
 */

#include <catch2/catch.hpp>
#include <gpiod.hpp>
#include <poll.h>

#include "gpio-mockup.hpp"

using ::gpiod::test::mockup;

namespace {

const ::std::string consumer = "event-test";

} /* namespace */

TEST_CASE("Line events can be detected", "[event][line]")
{
	mockup::probe_guard mockup_chips({ 8 });
	mockup::event_thread events(0, 4, 200);
	::gpiod::chip chip(mockup::instance().chip_name(0));
	auto line = chip.get_line(4);
	::gpiod::line_request config;

	config.consumer = consumer.c_str();

	SECTION("rising edge")
	{
		config.request_type = ::gpiod::line_request::EVENT_RISING_EDGE;
		line.request(config);

		auto got_event = line.event_wait(::std::chrono::seconds(1));
		REQUIRE(got_event);

		auto event = line.event_read();
		REQUIRE(event.source == line);
		REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE);
	}

	SECTION("falling edge")
	{
		config.request_type = ::gpiod::line_request::EVENT_FALLING_EDGE;

		line.request(config);

		auto got_event = line.event_wait(::std::chrono::seconds(1));
		REQUIRE(got_event);

		auto event = line.event_read();
		REQUIRE(event.source == line);
		REQUIRE(event.event_type == ::gpiod::line_event::FALLING_EDGE);
	}

	SECTION("both edges")
	{
		config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES;

		line.request(config);

		auto got_event = line.event_wait(::std::chrono::seconds(1));
		REQUIRE(got_event);

		auto event = line.event_read();
		REQUIRE(event.source == line);
		REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE);

		got_event = line.event_wait(::std::chrono::seconds(1));
		REQUIRE(got_event);

		event = line.event_read();
		REQUIRE(event.source == line);
		REQUIRE(event.event_type == ::gpiod::line_event::FALLING_EDGE);
	}

	SECTION("active-low")
	{
		config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES;
		config.flags = ::gpiod::line_request::FLAG_ACTIVE_LOW;

		line.request(config);

		auto got_event = line.event_wait(::std::chrono::seconds(1));
		REQUIRE(got_event);

		auto event = line.event_read();
		REQUIRE(event.source == line);
		REQUIRE(event.event_type == ::gpiod::line_event::FALLING_EDGE);

		got_event = line.event_wait(::std::chrono::seconds(1));
		REQUIRE(got_event);

		event = line.event_read();
		REQUIRE(event.source == line);
		REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE);
	}
}

TEST_CASE("Watching line_bulk objects for events works", "[event][bulk]")
{
	mockup::probe_guard mockup_chips({ 8 });
	mockup::event_thread events(0, 2, 200);
	::gpiod::chip chip(mockup::instance().chip_name(0));
	auto lines = chip.get_lines({ 0, 1, 2, 3 });
	::gpiod::line_request config;

	config.consumer = consumer.c_str();
	config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES;
	lines.request(config);

	auto event_lines = lines.event_wait(::std::chrono::seconds(1));
	REQUIRE(event_lines);
	REQUIRE(event_lines.size() == 1);

	auto event = event_lines.get(0).event_read();
	REQUIRE(event.source == event_lines.get(0));
	REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE);

	event_lines = lines.event_wait(::std::chrono::seconds(1));
	REQUIRE(event_lines);
	REQUIRE(event_lines.size() == 1);

	event = event_lines.get(0).event_read();
	REQUIRE(event.source == event_lines.get(0));
	REQUIRE(event.event_type == ::gpiod::line_event::FALLING_EDGE);
}

TEST_CASE("It's possible to retrieve the event file descriptor", "[event][line]")
{
	mockup::probe_guard mockup_chips({ 8 });
	::gpiod::chip chip(mockup::instance().chip_name(0));
	auto line = chip.get_line(4);
	::gpiod::line_request config;

	config.consumer = consumer.c_str();

	SECTION("get the fd")
	{
		config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES;

		line.request(config);
		REQUIRE(line.event_get_fd() >= 0);
	}

	SECTION("error if not requested")
	{
		REQUIRE_THROWS_AS(line.event_get_fd(), ::std::system_error);
	}

	SECTION("error if requested for values")
	{
		config.request_type = ::gpiod::line_request::DIRECTION_INPUT;

		line.request(config);
		REQUIRE_THROWS_AS(line.event_get_fd(), ::std::system_error);
	}
}

TEST_CASE("Event file descriptors can be used for polling", "[event]")
{
	mockup::probe_guard mockup_chips({ 8 });
	mockup::event_thread events(0, 3, 200);
	::gpiod::chip chip(mockup::instance().chip_name(0));
	auto lines = chip.get_lines({ 0, 1, 2, 3, 4, 5 });

	::gpiod::line_request config;
	config.consumer = consumer.c_str();
	config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES;

	lines.request(config);

	::std::vector<::pollfd> fds(3);
	fds[0].fd = lines[1].event_get_fd();
	fds[1].fd = lines[3].event_get_fd();
	fds[2].fd = lines[5].event_get_fd();

	fds[0].events = fds[1].events = fds[2].events = POLLIN | POLLPRI;

	int ret = ::poll(fds.data(), 3, 1000);
	REQUIRE(ret == 1);

	for (int i = 0; i < 3; i++) {
		if (fds[i].revents) {
			auto event = lines[3].event_read();
			REQUIRE(event.source == lines[3]);
			REQUIRE(event.event_type == ::gpiod::line_event::RISING_EDGE);
		}
	}
}

TEST_CASE("It's possible to read values from lines requested for events", "[event][line]")
{
	mockup::probe_guard mockup_chips({ 8 });
	::gpiod::chip chip(mockup::instance().chip_name(0));
	auto line = chip.get_line(4);
	::gpiod::line_request config;

	config.consumer = consumer.c_str();
	config.request_type = ::gpiod::line_request::EVENT_BOTH_EDGES;

	mockup::instance().chip_set_pull(0, 4, 1);

	SECTION("active-high (default)")
	{
		line.request(config);
		REQUIRE(line.get_value() == 1);
	}

	SECTION("active-low")
	{
		config.flags = ::gpiod::line_request::FLAG_ACTIVE_LOW;
		line.request(config);
		REQUIRE(line.get_value() == 0);
	}
{'fraction_non_alphanumeric': 0.18382041507835664, 'fraction_numerical': 0.014739517153748412, 'mean_word_length': 5.908133411351668, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5266772', 'n_tokens_mistral': 4873, 'n_tokens_neox': 4550, 'n_words': 706}