blob: 93e53a4da89e63b42cb935272d03d3dc00d51eb0 [file] [log] [blame]
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* This file is part of libgpiod.
*
* Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
*/
/* Test cases for GPIO line events. */
#include <errno.h>
#include <unistd.h>
#include "gpiod-test.h"
static void event_rising_edge_good(void)
{
TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL;
struct timespec ts = { 1, 0 };
struct gpiod_line_event ev;
struct gpiod_line *line;
int rv;
chip = gpiod_chip_open(test_chip_path(0));
TEST_ASSERT_NOT_NULL(chip);
line = gpiod_chip_get_line(chip, 7);
TEST_ASSERT_NOT_NULL(line);
rv = gpiod_line_request_rising_edge_events(line, TEST_CONSUMER);
TEST_ASSERT_RET_OK(rv);
test_set_event(0, 7, TEST_EVENT_RISING, 100);
rv = gpiod_line_event_wait(line, &ts);
TEST_ASSERT_EQ(rv, 1);
rv = gpiod_line_event_read(line, &ev);
TEST_ASSERT_RET_OK(rv);
TEST_ASSERT_EQ(ev.event_type, GPIOD_LINE_EVENT_RISING_EDGE);
}
TEST_DEFINE(event_rising_edge_good,
"events - receive single rising edge event",
0, { 8 });
static void event_falling_edge_good(void)
{
TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL;
struct timespec ts = { 1, 0 };
struct gpiod_line_event ev;
struct gpiod_line *line;
int rv;
chip = gpiod_chip_open(test_chip_path(0));
TEST_ASSERT_NOT_NULL(chip);
line = gpiod_chip_get_line(chip, 7);
TEST_ASSERT_NOT_NULL(line);
rv = gpiod_line_request_falling_edge_events(line, TEST_CONSUMER);
TEST_ASSERT_RET_OK(rv);
test_set_event(0, 7, TEST_EVENT_FALLING, 100);
rv = gpiod_line_event_wait(line, &ts);
TEST_ASSERT_EQ(rv, 1);
rv = gpiod_line_event_read(line, &ev);
TEST_ASSERT_RET_OK(rv);
TEST_ASSERT_EQ(ev.event_type, GPIOD_LINE_EVENT_FALLING_EDGE);
}
TEST_DEFINE(event_falling_edge_good,
"events - receive single falling edge event",
0, { 8 });
static void event_rising_edge_ignore_falling(void)
{
TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL;
struct timespec ts = { 0, 300 };
struct gpiod_line *line;
int rv;
chip = gpiod_chip_open(test_chip_path(0));
TEST_ASSERT_NOT_NULL(chip);
line = gpiod_chip_get_line(chip, 7);
TEST_ASSERT_NOT_NULL(line);
rv = gpiod_line_request_rising_edge_events(line, TEST_CONSUMER);
TEST_ASSERT_RET_OK(rv);
test_set_event(0, 7, TEST_EVENT_FALLING, 100);
rv = gpiod_line_event_wait(line, &ts);
TEST_ASSERT_EQ(rv, 0);
}
TEST_DEFINE(event_rising_edge_ignore_falling,
"events - request rising edge & ignore falling edge events",
0, { 8 });
static void event_rising_edge_active_low(void)
{
TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL;
struct timespec ts = { 1, 0 };
struct gpiod_line_event ev;
struct gpiod_line *line;
int rv;
chip = gpiod_chip_open(test_chip_path(0));
TEST_ASSERT_NOT_NULL(chip);
line = gpiod_chip_get_line(chip, 7);
TEST_ASSERT_NOT_NULL(line);
rv = gpiod_line_request_rising_edge_events_flags(line, TEST_CONSUMER,
GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW);
TEST_ASSERT_RET_OK(rv);
test_set_event(0, 7, TEST_EVENT_RISING, 100);
rv = gpiod_line_event_wait(line, &ts);
TEST_ASSERT_EQ(rv, 1);
rv = gpiod_line_event_read(line, &ev);
TEST_ASSERT_RET_OK(rv);
TEST_ASSERT_EQ(ev.event_type, GPIOD_LINE_EVENT_RISING_EDGE);
}
TEST_DEFINE(event_rising_edge_active_low,
"events - single rising edge event with low active state",
0, { 8 });
static void event_get_value(void)
{
TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL;
struct timespec ts = { 1, 0 };
struct gpiod_line_event ev;
struct gpiod_line *line;
int rv;
chip = gpiod_chip_open(test_chip_path(0));
TEST_ASSERT_NOT_NULL(chip);
line = gpiod_chip_get_line(chip, 7);
TEST_ASSERT_NOT_NULL(line);
rv = gpiod_line_request_rising_edge_events(line, TEST_CONSUMER);
TEST_ASSERT_RET_OK(rv);
rv = gpiod_line_get_value(line);
TEST_ASSERT_EQ(rv, 0);
test_set_event(0, 7, TEST_EVENT_RISING, 100);
rv = gpiod_line_event_wait(line, &ts);
TEST_ASSERT_EQ(rv, 1);
rv = gpiod_line_event_read(line, &ev);
TEST_ASSERT_RET_OK(rv);
TEST_ASSERT_EQ(ev.event_type, GPIOD_LINE_EVENT_RISING_EDGE);
rv = gpiod_line_get_value(line);
TEST_ASSERT_EQ(rv, 1);
}
TEST_DEFINE(event_get_value,
"events - mixing events and gpiod_line_get_value()",
0, { 8 });
static void event_get_value_active_low(void)
{
TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL;
struct timespec ts = { 1, 0 };
struct gpiod_line_event ev;
struct gpiod_line *line;
int rv;
chip = gpiod_chip_open(test_chip_path(0));
TEST_ASSERT_NOT_NULL(chip);
line = gpiod_chip_get_line(chip, 7);
TEST_ASSERT_NOT_NULL(line);
rv = gpiod_line_request_falling_edge_events_flags(line, TEST_CONSUMER,
GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW);
TEST_ASSERT_RET_OK(rv);
rv = gpiod_line_get_value(line);
TEST_ASSERT_EQ(rv, 1);
test_set_event(0, 7, TEST_EVENT_FALLING, 100);
rv = gpiod_line_event_wait(line, &ts);
TEST_ASSERT_EQ(rv, 1);
rv = gpiod_line_event_read(line, &ev);
TEST_ASSERT_RET_OK(rv);
TEST_ASSERT_EQ(ev.event_type, GPIOD_LINE_EVENT_FALLING_EDGE);
rv = gpiod_line_get_value(line);
TEST_ASSERT_EQ(rv, 0);
}
TEST_DEFINE(event_get_value_active_low,
"events - mixing events and gpiod_line_get_value() (active-low flag)",
0, { 8 });
static void event_wait_multiple(void)
{
TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL;
struct gpiod_line_bulk bulk, event_bulk;
struct timespec ts = { 1, 0 };
struct gpiod_line *line;
int rv, i;
chip = gpiod_chip_open(test_chip_path(0));
TEST_ASSERT_NOT_NULL(chip);
gpiod_line_bulk_init(&bulk);
for (i = 0; i < 8; i++) {
line = gpiod_chip_get_line(chip, i);
TEST_ASSERT_NOT_NULL(line);
gpiod_line_bulk_add(&bulk, line);
}
rv = gpiod_line_request_bulk_both_edges_events(&bulk, TEST_CONSUMER);
TEST_ASSERT_RET_OK(rv);
test_set_event(0, 4, TEST_EVENT_RISING, 100);
rv = gpiod_line_event_wait_bulk(&bulk, &ts, &event_bulk);
TEST_ASSERT_EQ(rv, 1);
TEST_ASSERT_EQ(gpiod_line_bulk_num_lines(&event_bulk), 1);
line = gpiod_line_bulk_get_line(&event_bulk, 0);
TEST_ASSERT_EQ(gpiod_line_offset(line), 4);
}
TEST_DEFINE(event_wait_multiple,
"events - wait for events on multiple lines",
0, { 8 });
static void event_get_fd_when_values_requested(void)
{
TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL;
struct gpiod_line *line;
int rv, fd;
chip = gpiod_chip_open(test_chip_path(0));
TEST_ASSERT_NOT_NULL(chip);
line = gpiod_chip_get_line(chip, 3);
TEST_ASSERT_NOT_NULL(line);
rv = gpiod_line_request_input(line, TEST_CONSUMER);
TEST_ASSERT_RET_OK(rv);
fd = gpiod_line_event_get_fd(line);
TEST_ASSERT_EQ(fd, -1);
TEST_ASSERT_ERRNO_IS(EPERM);
}
TEST_DEFINE(event_get_fd_when_values_requested,
"events - gpiod_line_event_get_fd(): line requested for values",
0, { 8 });
static void event_request_bulk_fail(void)
{
TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL;
struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER;
struct gpiod_line *line;
int rv, i;
chip = gpiod_chip_open(test_chip_path(0));
TEST_ASSERT_NOT_NULL(chip);
line = gpiod_chip_get_line(chip, 5);
TEST_ASSERT_NOT_NULL(line);
rv = gpiod_line_request_input(line, TEST_CONSUMER);
TEST_ASSERT_RET_OK(rv);
for (i = 0; i < 8; i++) {
line = gpiod_chip_get_line(chip, i);
TEST_ASSERT_NOT_NULL(line);
gpiod_line_bulk_add(&bulk, line);
}
rv = gpiod_line_request_bulk_both_edges_events(&bulk, TEST_CONSUMER);
TEST_ASSERT_EQ(rv, -1);
TEST_ASSERT_ERRNO_IS(EBUSY);
}
TEST_DEFINE(event_request_bulk_fail,
"events - failed bulk request (test reversed release)",
0, { 8 });
static void event_invalid_fd(void)
{
TEST_CLEANUP_CHIP struct gpiod_chip *chip = NULL;
struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER;
struct gpiod_line_bulk ev_bulk;
struct timespec ts = { 1, 0 };
struct gpiod_line *line;
int rv, fd;
chip = gpiod_chip_open(test_chip_path(0));
TEST_ASSERT_NOT_NULL(chip);
line = gpiod_chip_get_line(chip, 5);
TEST_ASSERT_NOT_NULL(line);
rv = gpiod_line_request_both_edges_events(line, TEST_CONSUMER);
TEST_ASSERT_RET_OK(rv);
fd = gpiod_line_event_get_fd(line);
close(fd);
rv = gpiod_line_event_wait(line, &ts);
TEST_ASSERT_EQ(rv, -1);
TEST_ASSERT_ERRNO_IS(EINVAL);
/*
* The single line variant calls gpiod_line_event_wait_bulk() with the
* event_bulk argument set to NULL, so test this use case explicitly
* as well.
*/
gpiod_line_bulk_add(&bulk, line);
rv = gpiod_line_event_wait_bulk(&bulk, &ts, &ev_bulk);
TEST_ASSERT_EQ(rv, -1);
TEST_ASSERT_ERRNO_IS(EINVAL);
}
TEST_DEFINE(event_invalid_fd,
"events - gpiod_line_event_wait() error on closed fd",
0, { 8 });