From: Bartosz Golaszewski Date: Wed, 24 Jan 2018 11:36:14 +0000 (+0100) Subject: API: use gpiod_ctxless_ as prefix for the high-level API X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=7bddc61ae570c04a1e7b6da2a83d9ff8934d53ef;p=qemu-gpiodev%2Flibgpiod.git API: use gpiod_ctxless_ as prefix for the high-level API As suggested by Linus Walleij: the word 'simple' is generally subjective and the high-level routines provided by libgpiod are not necessarily simple, but rather contextless, as they don't require any resource managemend. Use 'gpiod_ctxless_' as prefix for all high-level symbols. Signed-off-by: Bartosz Golaszewski --- diff --git a/include/gpiod.h b/include/gpiod.h index 62963db..8844e70 100644 --- a/include/gpiod.h +++ b/include/gpiod.h @@ -90,8 +90,8 @@ struct gpiod_line_iter; * @param consumer Name of the consumer. * @return 0 or 1 (GPIO value) if the operation succeeds, -1 on error. */ -int gpiod_simple_get_value(const char *device, unsigned int offset, - bool active_low, const char *consumer) GPIOD_API; +int gpiod_ctxless_get_value(const char *device, unsigned int offset, + bool active_low, const char *consumer) GPIOD_API; /** * @brief Read current values from a set of GPIO lines. @@ -103,15 +103,15 @@ int gpiod_simple_get_value(const char *device, unsigned int offset, * @param consumer Name of the consumer. * @return 0 if the operation succeeds, -1 on error. */ -int gpiod_simple_get_value_multiple(const char *device, - const unsigned int *offsets, int *values, - unsigned int num_lines, bool active_low, - const char *consumer) GPIOD_API; +int gpiod_ctxless_get_value_multiple(const char *device, + const unsigned int *offsets, int *values, + unsigned int num_lines, bool active_low, + const char *consumer) GPIOD_API; /** * @brief Simple set value callback signature. */ -typedef void (*gpiod_simple_set_value_cb)(void *); +typedef void (*gpiod_ctxless_set_value_cb)(void *); /** * @brief Set value of a single GPIO line. @@ -126,9 +126,10 @@ typedef void (*gpiod_simple_set_value_cb)(void *); * @param data User data that will be passed to the callback function. * @return 0 if the operation succeeds, -1 on error. */ -int gpiod_simple_set_value(const char *device, unsigned int offset, int value, - bool active_low, const char *consumer, - gpiod_simple_set_value_cb cb, void *data) GPIOD_API; +int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value, + bool active_low, const char *consumer, + gpiod_ctxless_set_value_cb cb, + void *data) GPIOD_API; /** * @brief Set values of multiple GPIO lines. @@ -139,38 +140,38 @@ int gpiod_simple_set_value(const char *device, unsigned int offset, int value, * @param active_low The active state of the lines - true if low. * @param consumer Name of the consumer. * @param cb Callback function that will be called right after the values are - * set. Works the same as in ::gpiod_simple_set_value. + * set. Works the same as in ::gpiod_ctxless_set_value. * @param data User data that will be passed to the callback function. * @return 0 if the operation succeeds, -1 on error. */ -int gpiod_simple_set_value_multiple(const char *device, - const unsigned int *offsets, - const int *values, unsigned int num_lines, - bool active_low, const char *consumer, - gpiod_simple_set_value_cb cb, - void *data) GPIOD_API; +int gpiod_ctxless_set_value_multiple(const char *device, + const unsigned int *offsets, + const int *values, unsigned int num_lines, + bool active_low, const char *consumer, + gpiod_ctxless_set_value_cb cb, + void *data) GPIOD_API; /** - * @brief Event types that can be passed to the simple event callback. + * @brief Event types that can be passed to the ctxless event callback. */ enum { - GPIOD_SIMPLE_EVENT_CB_TIMEOUT, + GPIOD_CTXLESS_EVENT_CB_TIMEOUT, /**< Waiting for events timed out. */ - GPIOD_SIMPLE_EVENT_CB_RISING_EDGE, + GPIOD_CTXLESS_EVENT_CB_RISING_EDGE, /**< Rising edge event occured. */ - GPIOD_SIMPLE_EVENT_CB_FALLING_EDGE, + GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE, /**< Falling edge event occured. */ }; /** - * @brief Return status values that the simple event callback can return. + * @brief Return status values that the ctxless event callback can return. */ enum { - GPIOD_SIMPLE_EVENT_CB_RET_ERR = -1, + GPIOD_CTXLESS_EVENT_CB_RET_ERR = -1, /**< Stop processing events and indicate an error. */ - GPIOD_SIMPLE_EVENT_CB_RET_OK = 0, + GPIOD_CTXLESS_EVENT_CB_RET_OK = 0, /**< Continue processing events. */ - GPIOD_SIMPLE_EVENT_CB_RET_STOP = 1, + GPIOD_CTXLESS_EVENT_CB_RET_STOP = 1, /**< Stop processing events. */ }; @@ -181,32 +182,32 @@ enum { * GPIO line offset (unsigned int), event timestamp (const struct timespec *) * and a pointer to user data (void *). * - * This callback is called by the simple event loop functions for each GPIO - * event. If the callback returns ::GPIOD_SIMPLE_EVENT_CB_RET_ERR, it should + * This callback is called by the ctxless event loop functions for each GPIO + * event. If the callback returns ::GPIOD_CTXLESS_EVENT_CB_RET_ERR, it should * also set errno. */ -typedef int (*gpiod_simple_event_handle_cb)(int, unsigned int, - const struct timespec *, void *); +typedef int (*gpiod_ctxless_event_handle_cb)(int, unsigned int, + const struct timespec *, void *); /** - * @brief Return status values that the simple event poll callback can return. + * @brief Return status values that the ctxless event poll callback can return. * * Positive value returned from the polling callback indicates the number of * events that occurred on the set of monitored lines. */ enum { - GPIOD_SIMPLE_EVENT_POLL_RET_STOP = -2, + GPIOD_CTXLESS_EVENT_POLL_RET_STOP = -2, /**< The event loop should stop processing events. */ - GPIOD_SIMPLE_EVENT_POLL_RET_ERR = -1, + GPIOD_CTXLESS_EVENT_POLL_RET_ERR = -1, /**< Polling error occurred (the polling function should set errno). */ - GPIOD_SIMPLE_EVENT_POLL_RET_TIMEOUT = 0, + GPIOD_CTXLESS_EVENT_POLL_RET_TIMEOUT = 0, /**< Poll timed out. */ }; /** - * @brief Helper structure for the simple event loop poll callback. + * @brief Helper structure for the ctxless event loop poll callback. */ -struct gpiod_simple_event_poll_fd { +struct gpiod_ctxless_event_poll_fd { int fd; /**< File descriptor number. */ bool event; @@ -218,16 +219,16 @@ struct gpiod_simple_event_poll_fd { * * The poll callback function takes the following arguments: number of lines * (unsigned int), an array of file descriptors on which input events should - * be monitored (struct gpiod_simple_event_poll_fd *), poll timeout + * be monitored (struct gpiod_ctxless_event_poll_fd *), poll timeout * (const struct timespec *) and a pointer to user data (void *). * * The callback should poll for input events on the set of descriptors and * return an appropriate value that can be interpreted by the event loop * routine. */ -typedef int (*gpiod_simple_event_poll_cb)(unsigned int, - struct gpiod_simple_event_poll_fd *, - const struct timespec *, void *); +typedef int (*gpiod_ctxless_event_poll_cb)(unsigned int, + struct gpiod_ctxless_event_poll_fd *, + const struct timespec *, void *); /** * @brief Wait for events on a single GPIO line. @@ -240,16 +241,16 @@ typedef int (*gpiod_simple_event_poll_cb)(unsigned int, * @param event_cb Callback function to call for each line event. * @param data User data passed to the callback. * @return 0 if no errors were encountered, -1 if an error occurred. - * @note The way the simple event loop works is described in detail in - * ::gpiod_simple_event_loop_multiple - this is just a wrapper aound + * @note The way the ctxless event loop works is described in detail in + * ::gpiod_ctxless_event_loop_multiple - this is just a wrapper aound * this routine which calls it for a single GPIO line. */ -int gpiod_simple_event_loop(const char *device, unsigned int offset, - bool active_low, const char *consumer, - const struct timespec *timeout, - gpiod_simple_event_poll_cb poll_cb, - gpiod_simple_event_handle_cb event_cb, - void *data) GPIOD_API; +int gpiod_ctxless_event_loop(const char *device, unsigned int offset, + bool active_low, const char *consumer, + const struct timespec *timeout, + gpiod_ctxless_event_poll_cb poll_cb, + gpiod_ctxless_event_handle_cb event_cb, + void *data) GPIOD_API; /** * @brief Wait for events on multiple GPIO lines. @@ -271,21 +272,21 @@ int gpiod_simple_event_loop(const char *device, unsigned int offset, * polling callback is to detect input events on a set of file descriptors and * notify the caller about the fds ready for reading. * - * The simple event loop then reads each queued event from marked descriptors + * The ctxless event loop then reads each queued event from marked descriptors * and calls the event callback. Both callbacks can stop the loop at any * point. * * The poll_cb argument can be NULL in which case the function falls back to * a default, ppoll() based callback. */ -int gpiod_simple_event_loop_multiple(const char *device, - const unsigned int *offsets, - unsigned int num_lines, bool active_low, - const char *consumer, - const struct timespec *timeout, - gpiod_simple_event_poll_cb poll_cb, - gpiod_simple_event_handle_cb event_cb, - void *data) GPIOD_API; +int gpiod_ctxless_event_loop_multiple(const char *device, + const unsigned int *offsets, + unsigned int num_lines, bool active_low, + const char *consumer, + const struct timespec *timeout, + gpiod_ctxless_event_poll_cb poll_cb, + gpiod_ctxless_event_handle_cb event_cb, + void *data) GPIOD_API; /** * @brief Determine the chip name and line offset of a line with given name. @@ -298,9 +299,9 @@ int gpiod_simple_event_loop_multiple(const char *device, * and offset remain unchanged. * @note The chip name is truncated if the buffer can't hold its entire size. */ -int gpiod_simple_find_line(const char *name, char *chipname, - size_t chipname_size, - unsigned int *offset) GPIOD_API; +int gpiod_ctxless_find_line(const char *name, char *chipname, + size_t chipname_size, + unsigned int *offset) GPIOD_API; /** * @} diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 057c1a1..56c6c97 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -8,7 +8,7 @@ # lib_LTLIBRARIES = libgpiod.la -libgpiod_la_SOURCES = core.c helpers.c iter.c misc.c simple.c +libgpiod_la_SOURCES = core.c ctxless.c helpers.c iter.c misc.c libgpiod_la_CFLAGS = -Wall -Wextra -g libgpiod_la_CFLAGS += -fvisibility=hidden -I$(top_srcdir)/include/ libgpiod_la_CFLAGS += -include $(top_builddir)/config.h diff --git a/src/lib/ctxless.c b/src/lib/ctxless.c new file mode 100644 index 0000000..65c9235 --- /dev/null +++ b/src/lib/ctxless.c @@ -0,0 +1,329 @@ +/* + * This file is part of libgpiod. + * + * Copyright (C) 2017-2018 Bartosz Golaszewski + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + */ + +/* Implementation of the high-level API. */ + +#include + +#include +#include +#include +#include + +int gpiod_ctxless_get_value(const char *device, unsigned int offset, + bool active_low, const char *consumer) +{ + int value, status; + + status = gpiod_ctxless_get_value_multiple(device, &offset, &value, + 1, active_low, consumer); + if (status < 0) + return status; + + return value; +} + +int gpiod_ctxless_get_value_multiple(const char *device, + const unsigned int *offsets, int *values, + unsigned int num_lines, bool active_low, + const char *consumer) +{ + struct gpiod_line_bulk bulk; + struct gpiod_chip *chip; + struct gpiod_line *line; + int status, flags; + unsigned int i; + + if (num_lines > GPIOD_LINE_BULK_MAX_LINES) { + errno = EINVAL; + return -1; + } + + chip = gpiod_chip_open_lookup(device); + if (!chip) + return -1; + + gpiod_line_bulk_init(&bulk); + + for (i = 0; i < num_lines; i++) { + line = gpiod_chip_get_line(chip, offsets[i]); + if (!line) { + gpiod_chip_close(chip); + return -1; + } + + gpiod_line_bulk_add(&bulk, line); + } + + flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0; + + status = gpiod_line_request_bulk_input_flags(&bulk, consumer, flags); + if (status < 0) { + gpiod_chip_close(chip); + return -1; + } + + memset(values, 0, sizeof(*values) * num_lines); + status = gpiod_line_get_value_bulk(&bulk, values); + + gpiod_chip_close(chip); + + return status; +} + +int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value, + bool active_low, const char *consumer, + gpiod_ctxless_set_value_cb cb, void *data) +{ + return gpiod_ctxless_set_value_multiple(device, &offset, &value, 1, + active_low, consumer, cb, data); +} + +int gpiod_ctxless_set_value_multiple(const char *device, + const unsigned int *offsets, + const int *values, unsigned int num_lines, + bool active_low, const char *consumer, + gpiod_ctxless_set_value_cb cb, void *data) +{ + struct gpiod_line_bulk bulk; + struct gpiod_chip *chip; + struct gpiod_line *line; + int status, flags; + unsigned int i; + + if (num_lines > GPIOD_LINE_BULK_MAX_LINES) { + errno = EINVAL; + return -1; + } + + chip = gpiod_chip_open_lookup(device); + if (!chip) + return -1; + + gpiod_line_bulk_init(&bulk); + + for (i = 0; i < num_lines; i++) { + line = gpiod_chip_get_line(chip, offsets[i]); + if (!line) { + gpiod_chip_close(chip); + return -1; + } + + gpiod_line_bulk_add(&bulk, line); + } + + flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0; + + status = gpiod_line_request_bulk_output_flags(&bulk, consumer, + flags, values); + if (status < 0) { + gpiod_chip_close(chip); + return -1; + } + + if (cb) + cb(data); + + gpiod_chip_close(chip); + + return 0; +} + +static int basic_event_poll(unsigned int num_lines, + struct gpiod_ctxless_event_poll_fd *fds, + const struct timespec *timeout, + void *data GPIOD_UNUSED) +{ + struct pollfd poll_fds[GPIOD_LINE_BULK_MAX_LINES]; + unsigned int i; + int rv, ret; + + if (num_lines > GPIOD_LINE_BULK_MAX_LINES) + return GPIOD_CTXLESS_EVENT_POLL_RET_ERR; + + memset(poll_fds, 0, sizeof(poll_fds)); + + for (i = 0; i < num_lines; i++) { + poll_fds[i].fd = fds[i].fd; + poll_fds[i].events = POLLIN | POLLPRI; + } + + rv = ppoll(poll_fds, num_lines, timeout, NULL); + if (rv < 0) { + if (errno == EINTR) + return GPIOD_CTXLESS_EVENT_POLL_RET_TIMEOUT; + else + return GPIOD_CTXLESS_EVENT_POLL_RET_ERR; + } else if (rv == 0) { + return GPIOD_CTXLESS_EVENT_POLL_RET_TIMEOUT; + } + + ret = rv; + for (i = 0; i < num_lines; i++) { + if (poll_fds[i].revents) { + fds[i].event = true; + if (!--rv) + break; + } + } + + return ret; +} + +int gpiod_ctxless_event_loop(const char *device, unsigned int offset, + bool active_low, const char *consumer, + const struct timespec *timeout, + gpiod_ctxless_event_poll_cb poll_cb, + gpiod_ctxless_event_handle_cb event_cb, + void *data) +{ + return gpiod_ctxless_event_loop_multiple(device, &offset, 1, + active_low, consumer, timeout, + poll_cb, event_cb, data); +} + +int gpiod_ctxless_event_loop_multiple(const char *device, + const unsigned int *offsets, + unsigned int num_lines, bool active_low, + const char *consumer, + const struct timespec *timeout, + gpiod_ctxless_event_poll_cb poll_cb, + gpiod_ctxless_event_handle_cb event_cb, + void *data) +{ + struct gpiod_ctxless_event_poll_fd fds[GPIOD_LINE_BULK_MAX_LINES]; + int rv, ret, flags, evtype, cnt; + struct gpiod_line_event event; + struct gpiod_line_bulk bulk; + struct gpiod_chip *chip; + struct gpiod_line *line; + unsigned int i; + + if (num_lines > GPIOD_LINE_BULK_MAX_LINES) { + errno = EINVAL; + return -1; + } + + if (!poll_cb) + poll_cb = basic_event_poll; + + chip = gpiod_chip_open_lookup(device); + if (!chip) + return -1; + + gpiod_line_bulk_init(&bulk); + + for (i = 0; i < num_lines; i++) { + line = gpiod_chip_get_line(chip, offsets[i]); + if (!line) { + gpiod_chip_close(chip); + return -1; + } + + gpiod_line_bulk_add(&bulk, line); + } + + flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0; + + rv = gpiod_line_request_bulk_both_edges_events_flags(&bulk, + consumer, flags); + if (rv) { + ret = -1; + goto out; + } + + memset(fds, 0, sizeof(fds)); + for (i = 0; i < num_lines; i++) { + line = gpiod_line_bulk_get_line(&bulk, i); + fds[i].fd = gpiod_line_event_get_fd(line); + } + + for (;;) { + for (i = 0; i < num_lines; i++) + fds[i].event = false; + + cnt = poll_cb(num_lines, fds, timeout, data); + if (cnt == GPIOD_CTXLESS_EVENT_POLL_RET_ERR) { + ret = -1; + goto out; + } else if (cnt == GPIOD_CTXLESS_EVENT_POLL_RET_TIMEOUT) { + rv = event_cb(GPIOD_CTXLESS_EVENT_CB_TIMEOUT, + 0, &event.ts, data); + if (rv == GPIOD_CTXLESS_EVENT_CB_RET_ERR) { + ret = -1; + goto out; + } else if (rv == GPIOD_CTXLESS_EVENT_CB_RET_STOP) { + ret = 0; + goto out; + } + } else if (cnt == GPIOD_CTXLESS_EVENT_POLL_RET_STOP) { + ret = 0; + goto out; + } + + for (i = 0; i < num_lines; i++) { + if (!fds[i].event) + continue; + + line = gpiod_line_bulk_get_line(&bulk, i); + rv = gpiod_line_event_read(line, &event); + if (rv < 0) { + ret = rv; + goto out; + } + + if (event.event_type == GPIOD_LINE_EVENT_RISING_EDGE) + evtype = GPIOD_CTXLESS_EVENT_CB_RISING_EDGE; + else + evtype = GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE; + + rv = event_cb(evtype, gpiod_line_offset(line), + &event.ts, data); + if (rv == GPIOD_CTXLESS_EVENT_CB_RET_ERR) { + ret = -1; + goto out; + } else if (rv == GPIOD_CTXLESS_EVENT_CB_RET_STOP) { + ret = 0; + goto out; + } + + if (!--cnt) + break; + } + } + +out: + gpiod_chip_close(chip); + + return ret; +} + +int gpiod_ctxless_find_line(const char *name, char *chipname, + size_t chipname_size, unsigned int *offset) +{ + struct gpiod_chip *chip; + struct gpiod_line *line; + + line = gpiod_line_find(name); + if (!line) { + if (errno == ENOENT) + return 0; + else + return -1; + } + + chip = gpiod_line_get_chip(line); + snprintf(chipname, chipname_size, "%s", gpiod_chip_name(chip)); + *offset = gpiod_line_offset(line); + gpiod_chip_close(chip); + + return 1; +} diff --git a/src/lib/simple.c b/src/lib/simple.c deleted file mode 100644 index 064eb29..0000000 --- a/src/lib/simple.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * This file is part of libgpiod. - * - * Copyright (C) 2017-2018 Bartosz Golaszewski - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -/* Implementation of the high-level API. */ - -#include - -#include -#include -#include -#include - -int gpiod_simple_get_value(const char *device, unsigned int offset, - bool active_low, const char *consumer) -{ - int value, status; - - status = gpiod_simple_get_value_multiple(device, &offset, &value, - 1, active_low, consumer); - if (status < 0) - return status; - - return value; -} - -int gpiod_simple_get_value_multiple(const char *device, - const unsigned int *offsets, int *values, - unsigned int num_lines, bool active_low, - const char *consumer) -{ - struct gpiod_line_bulk bulk; - struct gpiod_chip *chip; - struct gpiod_line *line; - int status, flags; - unsigned int i; - - if (num_lines > GPIOD_LINE_BULK_MAX_LINES) { - errno = EINVAL; - return -1; - } - - chip = gpiod_chip_open_lookup(device); - if (!chip) - return -1; - - gpiod_line_bulk_init(&bulk); - - for (i = 0; i < num_lines; i++) { - line = gpiod_chip_get_line(chip, offsets[i]); - if (!line) { - gpiod_chip_close(chip); - return -1; - } - - gpiod_line_bulk_add(&bulk, line); - } - - flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0; - - status = gpiod_line_request_bulk_input_flags(&bulk, consumer, flags); - if (status < 0) { - gpiod_chip_close(chip); - return -1; - } - - memset(values, 0, sizeof(*values) * num_lines); - status = gpiod_line_get_value_bulk(&bulk, values); - - gpiod_chip_close(chip); - - return status; -} - -int gpiod_simple_set_value(const char *device, unsigned int offset, int value, - bool active_low, const char *consumer, - gpiod_simple_set_value_cb cb, void *data) -{ - return gpiod_simple_set_value_multiple(device, &offset, &value, 1, - active_low, consumer, cb, data); -} - -int gpiod_simple_set_value_multiple(const char *device, - const unsigned int *offsets, - const int *values, unsigned int num_lines, - bool active_low, const char *consumer, - gpiod_simple_set_value_cb cb, void *data) -{ - struct gpiod_line_bulk bulk; - struct gpiod_chip *chip; - struct gpiod_line *line; - int status, flags; - unsigned int i; - - if (num_lines > GPIOD_LINE_BULK_MAX_LINES) { - errno = EINVAL; - return -1; - } - - chip = gpiod_chip_open_lookup(device); - if (!chip) - return -1; - - gpiod_line_bulk_init(&bulk); - - for (i = 0; i < num_lines; i++) { - line = gpiod_chip_get_line(chip, offsets[i]); - if (!line) { - gpiod_chip_close(chip); - return -1; - } - - gpiod_line_bulk_add(&bulk, line); - } - - flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0; - - status = gpiod_line_request_bulk_output_flags(&bulk, consumer, - flags, values); - if (status < 0) { - gpiod_chip_close(chip); - return -1; - } - - if (cb) - cb(data); - - gpiod_chip_close(chip); - - return 0; -} - -static int basic_event_poll(unsigned int num_lines, - struct gpiod_simple_event_poll_fd *fds, - const struct timespec *timeout, - void *data GPIOD_UNUSED) -{ - struct pollfd poll_fds[GPIOD_LINE_BULK_MAX_LINES]; - unsigned int i; - int rv, ret; - - if (num_lines > GPIOD_LINE_BULK_MAX_LINES) - return GPIOD_SIMPLE_EVENT_POLL_RET_ERR; - - memset(poll_fds, 0, sizeof(poll_fds)); - - for (i = 0; i < num_lines; i++) { - poll_fds[i].fd = fds[i].fd; - poll_fds[i].events = POLLIN | POLLPRI; - } - - rv = ppoll(poll_fds, num_lines, timeout, NULL); - if (rv < 0) { - if (errno == EINTR) - return GPIOD_SIMPLE_EVENT_POLL_RET_TIMEOUT; - else - return GPIOD_SIMPLE_EVENT_POLL_RET_ERR; - } else if (rv == 0) { - return GPIOD_SIMPLE_EVENT_POLL_RET_TIMEOUT; - } - - ret = rv; - for (i = 0; i < num_lines; i++) { - if (poll_fds[i].revents) { - fds[i].event = true; - if (!--rv) - break; - } - } - - return ret; -} - -int gpiod_simple_event_loop(const char *device, unsigned int offset, - bool active_low, const char *consumer, - const struct timespec *timeout, - gpiod_simple_event_poll_cb poll_cb, - gpiod_simple_event_handle_cb event_cb, void *data) -{ - return gpiod_simple_event_loop_multiple(device, &offset, 1, active_low, - consumer, timeout, poll_cb, - event_cb, data); -} - -int gpiod_simple_event_loop_multiple(const char *device, - const unsigned int *offsets, - unsigned int num_lines, bool active_low, - const char *consumer, - const struct timespec *timeout, - gpiod_simple_event_poll_cb poll_cb, - gpiod_simple_event_handle_cb event_cb, - void *data) -{ - struct gpiod_simple_event_poll_fd fds[GPIOD_LINE_BULK_MAX_LINES]; - int rv, ret, flags, evtype, cnt; - struct gpiod_line_event event; - struct gpiod_line_bulk bulk; - struct gpiod_chip *chip; - struct gpiod_line *line; - unsigned int i; - - if (num_lines > GPIOD_LINE_BULK_MAX_LINES) { - errno = EINVAL; - return -1; - } - - if (!poll_cb) - poll_cb = basic_event_poll; - - chip = gpiod_chip_open_lookup(device); - if (!chip) - return -1; - - gpiod_line_bulk_init(&bulk); - - for (i = 0; i < num_lines; i++) { - line = gpiod_chip_get_line(chip, offsets[i]); - if (!line) { - gpiod_chip_close(chip); - return -1; - } - - gpiod_line_bulk_add(&bulk, line); - } - - flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0; - - rv = gpiod_line_request_bulk_both_edges_events_flags(&bulk, - consumer, flags); - if (rv) { - ret = -1; - goto out; - } - - memset(fds, 0, sizeof(fds)); - for (i = 0; i < num_lines; i++) { - line = gpiod_line_bulk_get_line(&bulk, i); - fds[i].fd = gpiod_line_event_get_fd(line); - } - - for (;;) { - for (i = 0; i < num_lines; i++) - fds[i].event = false; - - cnt = poll_cb(num_lines, fds, timeout, data); - if (cnt == GPIOD_SIMPLE_EVENT_POLL_RET_ERR) { - ret = -1; - goto out; - } else if (cnt == GPIOD_SIMPLE_EVENT_POLL_RET_TIMEOUT) { - rv = event_cb(GPIOD_SIMPLE_EVENT_CB_TIMEOUT, - 0, &event.ts, data); - if (rv == GPIOD_SIMPLE_EVENT_CB_RET_ERR) { - ret = -1; - goto out; - } else if (rv == GPIOD_SIMPLE_EVENT_CB_RET_STOP) { - ret = 0; - goto out; - } - } else if (cnt == GPIOD_SIMPLE_EVENT_POLL_RET_STOP) { - ret = 0; - goto out; - } - - for (i = 0; i < num_lines; i++) { - if (!fds[i].event) - continue; - - line = gpiod_line_bulk_get_line(&bulk, i); - rv = gpiod_line_event_read(line, &event); - if (rv < 0) { - ret = rv; - goto out; - } - - if (event.event_type == GPIOD_LINE_EVENT_RISING_EDGE) - evtype = GPIOD_SIMPLE_EVENT_CB_RISING_EDGE; - else - evtype = GPIOD_SIMPLE_EVENT_CB_FALLING_EDGE; - - rv = event_cb(evtype, gpiod_line_offset(line), - &event.ts, data); - if (rv == GPIOD_SIMPLE_EVENT_CB_RET_ERR) { - ret = -1; - goto out; - } else if (rv == GPIOD_SIMPLE_EVENT_CB_RET_STOP) { - ret = 0; - goto out; - } - - if (!--cnt) - break; - } - } - -out: - gpiod_chip_close(chip); - - return ret; -} - -int gpiod_simple_find_line(const char *name, char *chipname, - size_t chipname_size, unsigned int *offset) -{ - struct gpiod_chip *chip; - struct gpiod_line *line; - - line = gpiod_line_find(name); - if (!line) { - if (errno == ENOENT) - return 0; - else - return -1; - } - - chip = gpiod_line_get_chip(line); - snprintf(chipname, chipname_size, "%s", gpiod_chip_name(chip)); - *offset = gpiod_line_offset(line); - gpiod_chip_close(chip); - - return 1; -} diff --git a/src/tools/gpiofind.c b/src/tools/gpiofind.c index e239416..0231ccd 100644 --- a/src/tools/gpiofind.c +++ b/src/tools/gpiofind.c @@ -64,7 +64,7 @@ int main(int argc, char **argv) if (argc != 1) die("exactly one GPIO line name must be specified"); - rv = gpiod_simple_find_line(argv[0], chip, sizeof(chip), &offset); + rv = gpiod_ctxless_find_line(argv[0], chip, sizeof(chip), &offset); if (rv < 0) die_perror("error performing the line lookup"); else if (rv == 0) diff --git a/src/tools/gpioget.c b/src/tools/gpioget.c index fd6fa67..e1c6a5c 100644 --- a/src/tools/gpioget.c +++ b/src/tools/gpioget.c @@ -89,9 +89,9 @@ int main(int argc, char **argv) die("invalid GPIO offset: %s", argv[i + 1]); } - status = gpiod_simple_get_value_multiple(device, offsets, values, - num_lines, active_low, - "gpioget"); + status = gpiod_ctxless_get_value_multiple(device, offsets, values, + num_lines, active_low, + "gpioget"); if (status < 0) die_perror("error reading GPIO values"); diff --git a/src/tools/gpiomon.c b/src/tools/gpiomon.c index 5e68a4f..596a572 100644 --- a/src/tools/gpiomon.c +++ b/src/tools/gpiomon.c @@ -96,7 +96,7 @@ static void event_print_custom(unsigned int offset, printf("%u", offset); break; case 'e': - if (event_type == GPIOD_SIMPLE_EVENT_CB_RISING_EDGE) + if (event_type == GPIOD_CTXLESS_EVENT_CB_RISING_EDGE) fputc('1', stdout); else fputc('0', stdout); @@ -132,7 +132,7 @@ static void event_print_human_readable(unsigned int offset, { char *evname; - if (event_type == GPIOD_SIMPLE_EVENT_CB_RISING_EDGE) + if (event_type == GPIOD_CTXLESS_EVENT_CB_RISING_EDGE) evname = " RISING EDGE"; else evname = "FALLING EDGE"; @@ -142,7 +142,7 @@ static void event_print_human_readable(unsigned int offset, } static int poll_callback(unsigned int num_lines, - struct gpiod_simple_event_poll_fd *fds, + struct gpiod_ctxless_event_poll_fd *fds, const struct timespec *timeout, void *data) { struct pollfd pfds[GPIOD_LINE_BULK_MAX_LINES + 1]; @@ -162,9 +162,9 @@ static int poll_callback(unsigned int num_lines, cnt = poll(pfds, num_lines + 1, ts); if (cnt < 0) - return GPIOD_SIMPLE_EVENT_POLL_RET_ERR; + return GPIOD_CTXLESS_EVENT_POLL_RET_ERR; else if (cnt == 0) - return GPIOD_SIMPLE_EVENT_POLL_RET_TIMEOUT; + return GPIOD_CTXLESS_EVENT_POLL_RET_TIMEOUT; ret = cnt; for (i = 0; i < num_lines; i++) { @@ -181,7 +181,7 @@ static int poll_callback(unsigned int num_lines, */ close(ctx->sigfd); - return GPIOD_SIMPLE_EVENT_POLL_RET_STOP; + return GPIOD_CTXLESS_EVENT_POLL_RET_STOP; } static void handle_event(struct mon_ctx *ctx, int event_type, @@ -206,22 +206,22 @@ static int event_callback(int event_type, unsigned int line_offset, struct mon_ctx *ctx = data; switch (event_type) { - case GPIOD_SIMPLE_EVENT_CB_RISING_EDGE: + case GPIOD_CTXLESS_EVENT_CB_RISING_EDGE: if (ctx->watch_rising) handle_event(ctx, event_type, line_offset, timestamp); break; - case GPIOD_SIMPLE_EVENT_CB_FALLING_EDGE: + case GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE: if (ctx->watch_falling) handle_event(ctx, event_type, line_offset, timestamp); break; default: - return GPIOD_SIMPLE_EVENT_CB_RET_OK; + return GPIOD_CTXLESS_EVENT_CB_RET_OK; } if (ctx->events_wanted && ctx->events_done >= ctx->events_wanted) - return GPIOD_SIMPLE_EVENT_CB_RET_STOP; + return GPIOD_CTXLESS_EVENT_CB_RET_STOP; - return GPIOD_SIMPLE_EVENT_CB_RET_OK; + return GPIOD_CTXLESS_EVENT_CB_RET_OK; } static int make_signalfd(void) @@ -318,10 +318,10 @@ int main(int argc, char **argv) ctx.sigfd = make_signalfd(); - ret = gpiod_simple_event_loop_multiple(argv[0], offsets, num_lines, - active_low, "gpiomon", &timeout, - poll_callback, - event_callback, &ctx); + ret = gpiod_ctxless_event_loop_multiple(argv[0], offsets, num_lines, + active_low, "gpiomon", + &timeout, poll_callback, + event_callback, &ctx); if (ret) die_perror("error waiting for events"); diff --git a/src/tools/gpioset.c b/src/tools/gpioset.c index f1ce074..e77ee60 100644 --- a/src/tools/gpioset.c +++ b/src/tools/gpioset.c @@ -138,7 +138,7 @@ enum { struct mode_mapping { int id; const char *name; - gpiod_simple_set_value_cb callback; + gpiod_ctxless_set_value_cb callback; }; static const struct mode_mapping modes[] = { @@ -265,10 +265,10 @@ int main(int argc, char **argv) die("invalid offset: %s", argv[i + 1]); } - status = gpiod_simple_set_value_multiple(device, offsets, values, - num_lines, active_low, - "gpioset", mode->callback, - &cbdata); + status = gpiod_ctxless_set_value_multiple(device, offsets, values, + num_lines, active_low, + "gpioset", mode->callback, + &cbdata); if (status < 0) die_perror("error setting the GPIO line values"); diff --git a/tests/Makefile.am b/tests/Makefile.am index 65e9d58..0b755ab 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -17,11 +17,11 @@ check_PROGRAMS = gpiod-test gpiod_test_SOURCES = gpiod-test.c \ gpiod-test.h \ tests-chip.c \ + tests-ctxless.c \ tests-event.c \ tests-iter.c \ tests-line.c \ - tests-misc.c \ - tests-simple-api.c + tests-misc.c if WITH_TOOLS diff --git a/tests/tests-ctxless.c b/tests/tests-ctxless.c new file mode 100644 index 0000000..c116f9e --- /dev/null +++ b/tests/tests-ctxless.c @@ -0,0 +1,288 @@ +/* + * This file is part of libgpiod. + * + * Copyright (C) 2017-2018 Bartosz Golaszewski + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + */ + +/* Test cases for the high-level API. */ + +#include "gpiod-test.h" + +#include + +static void ctxless_set_get_value(void) +{ + int ret; + + ret = gpiod_ctxless_get_value(test_chip_name(0), 3, + false, TEST_CONSUMER); + TEST_ASSERT_EQ(ret, 0); + + ret = gpiod_ctxless_set_value(test_chip_name(0), 3, 1, + false, TEST_CONSUMER, NULL, NULL); + TEST_ASSERT_RET_OK(ret); + + ret = gpiod_ctxless_get_value(test_chip_name(0), 3, + false, TEST_CONSUMER); + TEST_ASSERT_EQ(ret, 1); +} +TEST_DEFINE(ctxless_set_get_value, + "ctxless set/get value - single line", + 0, { 8 }); + +static void ctxless_set_get_value_multiple(void) +{ + unsigned int offsets[] = { 0, 1, 2, 3, 4, 5, 6, 12, 13, 15 }; + int values[10], rv; + + rv = gpiod_ctxless_get_value_multiple(test_chip_name(0), offsets, + values, 10, false, TEST_CONSUMER); + TEST_ASSERT_RET_OK(rv); + + TEST_ASSERT_EQ(values[0], 0); + TEST_ASSERT_EQ(values[1], 0); + TEST_ASSERT_EQ(values[2], 0); + TEST_ASSERT_EQ(values[3], 0); + TEST_ASSERT_EQ(values[4], 0); + TEST_ASSERT_EQ(values[5], 0); + TEST_ASSERT_EQ(values[6], 0); + TEST_ASSERT_EQ(values[7], 0); + TEST_ASSERT_EQ(values[8], 0); + TEST_ASSERT_EQ(values[9], 0); + + values[0] = 1; + values[1] = 1; + values[2] = 1; + values[3] = 0; + values[4] = 0; + values[5] = 1; + values[6] = 0; + values[7] = 1; + values[8] = 0; + values[9] = 0; + + rv = gpiod_ctxless_set_value_multiple(test_chip_name(0), offsets, + values, 10, false, TEST_CONSUMER, + NULL, NULL); + TEST_ASSERT_RET_OK(rv); + + rv = gpiod_ctxless_get_value_multiple(test_chip_name(0), offsets, + values, 10, false, TEST_CONSUMER); + TEST_ASSERT_RET_OK(rv); + + TEST_ASSERT_EQ(values[0], 1); + TEST_ASSERT_EQ(values[1], 1); + TEST_ASSERT_EQ(values[2], 1); + TEST_ASSERT_EQ(values[3], 0); + TEST_ASSERT_EQ(values[4], 0); + TEST_ASSERT_EQ(values[5], 1); + TEST_ASSERT_EQ(values[6], 0); + TEST_ASSERT_EQ(values[7], 1); + TEST_ASSERT_EQ(values[8], 0); + TEST_ASSERT_EQ(values[9], 0); +} +TEST_DEFINE(ctxless_set_get_value_multiple, + "ctxless set/get value - multiple lines", + 0, { 16 }); + +static void ctxless_get_value_multiple_max_lines(void) +{ + unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES + 1]; + int values[GPIOD_LINE_BULK_MAX_LINES + 1], ret; + + ret = gpiod_ctxless_get_value_multiple(test_chip_name(0), offsets, + values, + GPIOD_LINE_BULK_MAX_LINES + 1, + false, TEST_CONSUMER); + TEST_ASSERT_NOTEQ(ret, 0); + TEST_ASSERT_ERRNO_IS(EINVAL); +} +TEST_DEFINE(ctxless_get_value_multiple_max_lines, + "gpiod_ctxless_get_value_multiple() exceed max lines", + 0, { 128 }); + +static void ctxless_set_value_multiple_max_lines(void) +{ + unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES + 1]; + int values[GPIOD_LINE_BULK_MAX_LINES + 1], ret; + + ret = gpiod_ctxless_set_value_multiple(test_chip_name(0), offsets, + values, + GPIOD_LINE_BULK_MAX_LINES + 1, + false, TEST_CONSUMER, + NULL, NULL); + TEST_ASSERT_NOTEQ(ret, 0); + TEST_ASSERT_ERRNO_IS(EINVAL); +} +TEST_DEFINE(ctxless_set_value_multiple_max_lines, + "gpiod_ctxless_set_value_multiple() exceed max lines", + 0, { 128 }); + +struct ctxless_event_data { + bool got_rising_edge; + bool got_falling_edge; + unsigned int offset; + unsigned int count; +}; + +static int ctxless_event_cb(int evtype, unsigned int offset, + const struct timespec *ts TEST_UNUSED, void *data) +{ + struct ctxless_event_data *evdata = data; + + if (evtype == GPIOD_CTXLESS_EVENT_CB_RISING_EDGE) + evdata->got_rising_edge = true; + else if (evtype == GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE) + evdata->got_falling_edge = true; + + evdata->offset = offset; + + return ++evdata->count == 2 ? GPIOD_CTXLESS_EVENT_CB_RET_STOP + : GPIOD_CTXLESS_EVENT_CB_RET_OK; +} + +static void ctxless_event_loop(void) +{ + struct ctxless_event_data evdata = { false, false, 0, 0 }; + struct timespec ts = { 1, 0 }; + int status; + + test_set_event(0, 3, TEST_EVENT_ALTERNATING, 100); + + status = gpiod_ctxless_event_loop(test_chip_name(0), 3, false, + TEST_CONSUMER, &ts, NULL, + ctxless_event_cb, &evdata); + + TEST_ASSERT_RET_OK(status); + TEST_ASSERT(evdata.got_rising_edge); + TEST_ASSERT(evdata.got_falling_edge); + TEST_ASSERT_EQ(evdata.count, 2); + TEST_ASSERT_EQ(evdata.offset, 3); +} +TEST_DEFINE(ctxless_event_loop, + "gpiod_ctxless_event_loop() - single event", + 0, { 8 }); + +static void ctxless_event_loop_multiple(void) +{ + struct ctxless_event_data evdata = { false, false, 0, 0 }; + struct timespec ts = { 1, 0 }; + unsigned int offsets[4]; + int status; + + offsets[0] = 2; + offsets[1] = 3; + offsets[2] = 5; + offsets[3] = 6; + + test_set_event(0, 3, TEST_EVENT_ALTERNATING, 100); + + status = gpiod_ctxless_event_loop_multiple(test_chip_name(0), offsets, + 4, false, TEST_CONSUMER, + &ts, NULL, ctxless_event_cb, + &evdata); + + TEST_ASSERT_RET_OK(status); + TEST_ASSERT(evdata.got_rising_edge); + TEST_ASSERT(evdata.got_falling_edge); + TEST_ASSERT_EQ(evdata.count, 2); + TEST_ASSERT_EQ(evdata.offset, 3); +} +TEST_DEFINE(ctxless_event_loop_multiple, + "gpiod_ctxless_event_loop_multiple() - single event", + 0, { 8 }); + +static int error_event_cb(int evtype TEST_UNUSED, + unsigned int offset TEST_UNUSED, + const struct timespec *ts TEST_UNUSED, + void *data TEST_UNUSED) +{ + errno = ENOTBLK; + + return GPIOD_CTXLESS_EVENT_CB_RET_ERR; +} + +static void ctxless_event_loop_indicate_error(void) +{ + struct timespec ts = { 1, 0 }; + int rv; + + test_set_event(0, 3, TEST_EVENT_ALTERNATING, 100); + + rv = gpiod_ctxless_event_loop(test_chip_name(0), 3, false, + TEST_CONSUMER, &ts, NULL, + error_event_cb, NULL); + + TEST_ASSERT_EQ(rv, -1); + TEST_ASSERT_ERRNO_IS(ENOTBLK); +} +TEST_DEFINE(ctxless_event_loop_indicate_error, + "gpiod_ctxless_event_loop() - error in callback", + 0, { 8 }); + +static void ctxless_event_loop_indicate_error_timeout(void) +{ + struct timespec ts = { 0, 100000 }; + int rv; + + rv = gpiod_ctxless_event_loop(test_chip_name(0), 3, false, + TEST_CONSUMER, &ts, NULL, + error_event_cb, NULL); + + TEST_ASSERT_EQ(rv, -1); + TEST_ASSERT_ERRNO_IS(ENOTBLK); +} +TEST_DEFINE(ctxless_event_loop_indicate_error_timeout, + "gpiod_ctxless_event_loop() - error in callback after timeout", + 0, { 8 }); + +static void ctxless_find_line_good(void) +{ + unsigned int offset; + char chip[32]; + int rv; + + rv = gpiod_ctxless_find_line("gpio-mockup-C-14", chip, + sizeof(chip), &offset); + TEST_ASSERT_EQ(rv, 1); + TEST_ASSERT_EQ(offset, 14); + TEST_ASSERT_STR_EQ(chip, test_chip_name(2)); +} +TEST_DEFINE(ctxless_find_line_good, + "gpiod_ctxless_find_line() - good", + TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 }); + +static void ctxless_find_line_truncated(void) +{ + unsigned int offset; + char chip[6]; + int rv; + + rv = gpiod_ctxless_find_line("gpio-mockup-C-14", chip, + sizeof(chip), &offset); + TEST_ASSERT_EQ(rv, 1); + TEST_ASSERT_EQ(offset, 14); + TEST_ASSERT_STR_EQ(chip, "gpioc"); +} +TEST_DEFINE(ctxless_find_line_truncated, + "gpiod_ctxless_find_line() - chip name truncated", + TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 }); + +static void ctxless_find_line_not_found(void) +{ + unsigned int offset; + char chip[32]; + int rv; + + rv = gpiod_ctxless_find_line("nonexistent", chip, + sizeof(chip), &offset); + TEST_ASSERT_EQ(rv, 0); +} +TEST_DEFINE(ctxless_find_line_not_found, + "gpiod_ctxless_find_line() - not found", + TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 }); diff --git a/tests/tests-gpioget.c b/tests/tests-gpioget.c index 73a36ce..82c489a 100644 --- a/tests/tests-gpioget.c +++ b/tests/tests-gpioget.c @@ -35,9 +35,9 @@ static void gpioget_read_all_lines(void) values[0] = values[1] = values[2] = values[3] = 1; - rv = gpiod_simple_set_value_multiple(test_chip_name(1), offsets, - values, 4, false, TEST_CONSUMER, - NULL, NULL); + rv = gpiod_ctxless_set_value_multiple(test_chip_name(1), offsets, + values, 4, false, TEST_CONSUMER, + NULL, NULL); TEST_ASSERT_RET_OK(rv); test_tool_run("gpioget", test_chip_name(1), @@ -76,9 +76,9 @@ static void gpioget_read_all_lines_active_low(void) values[0] = values[1] = values[2] = values[3] = 1; - rv = gpiod_simple_set_value_multiple(test_chip_name(1), offsets, - values, 4, false, TEST_CONSUMER, - NULL, NULL); + rv = gpiod_ctxless_set_value_multiple(test_chip_name(1), offsets, + values, 4, false, TEST_CONSUMER, + NULL, NULL); TEST_ASSERT_RET_OK(rv); test_tool_run("gpioget", "--active-low", test_chip_name(1), @@ -116,9 +116,9 @@ static void gpioget_read_some_lines(void) values[0] = values[1] = values[2] = 1; - rv = gpiod_simple_set_value_multiple(test_chip_name(1), offsets, - values, 3, false, TEST_CONSUMER, - NULL, NULL); + rv = gpiod_ctxless_set_value_multiple(test_chip_name(1), offsets, + values, 3, false, TEST_CONSUMER, + NULL, NULL); TEST_ASSERT_RET_OK(rv); test_tool_run("gpioget", test_chip_name(1), diff --git a/tests/tests-gpioset.c b/tests/tests-gpioset.c index 014697c..ed18cec 100644 --- a/tests/tests-gpioset.c +++ b/tests/tests-gpioset.c @@ -40,8 +40,8 @@ static void gpioset_set_lines_and_exit(void) offsets[6] = 6; offsets[7] = 7; - rv = gpiod_simple_get_value_multiple(test_chip_name(2), offsets, - values, 8, false, TEST_CONSUMER); + rv = gpiod_ctxless_get_value_multiple(test_chip_name(2), offsets, + values, 8, false, TEST_CONSUMER); TEST_ASSERT_RET_OK(rv); TEST_ASSERT_EQ(values[0], 0); @@ -81,8 +81,8 @@ static void gpioset_set_lines_and_exit_active_low(void) offsets[6] = 6; offsets[7] = 7; - rv = gpiod_simple_get_value_multiple(test_chip_name(2), offsets, - values, 8, false, TEST_CONSUMER); + rv = gpiod_ctxless_get_value_multiple(test_chip_name(2), offsets, + values, 8, false, TEST_CONSUMER); TEST_ASSERT_RET_OK(rv); TEST_ASSERT_EQ(values[0], 1); @@ -122,8 +122,8 @@ static void gpioset_set_lines_and_exit_explicit_mode(void) offsets[6] = 6; offsets[7] = 7; - rv = gpiod_simple_get_value_multiple(test_chip_name(2), offsets, - values, 8, false, TEST_CONSUMER); + rv = gpiod_ctxless_get_value_multiple(test_chip_name(2), offsets, + values, 8, false, TEST_CONSUMER); TEST_ASSERT_RET_OK(rv); TEST_ASSERT_EQ(values[0], 0); @@ -160,8 +160,8 @@ static void gpioset_set_some_lines_and_wait_for_enter(void) offsets[3] = 6; offsets[4] = 7; - rv = gpiod_simple_get_value_multiple(test_chip_name(2), offsets, - values, 5, false, TEST_CONSUMER); + rv = gpiod_ctxless_get_value_multiple(test_chip_name(2), offsets, + values, 5, false, TEST_CONSUMER); TEST_ASSERT_RET_OK(rv); TEST_ASSERT_EQ(values[0], 0); @@ -199,9 +199,9 @@ static void gpioset_set_some_lines_and_wait_for_signal(void) offsets[3] = 6; offsets[4] = 7; - rv = gpiod_simple_get_value_multiple(test_chip_name(2), - offsets, values, - 5, false, TEST_CONSUMER); + rv = gpiod_ctxless_get_value_multiple(test_chip_name(2), + offsets, values, + 5, false, TEST_CONSUMER); TEST_ASSERT_RET_OK(rv); TEST_ASSERT_EQ(values[0], 0); @@ -235,8 +235,8 @@ static void gpioset_set_some_lines_and_wait_time(void) offsets[1] = 2; offsets[2] = 5; - rv = gpiod_simple_get_value_multiple(test_chip_name(0), offsets, - values, 3, false, TEST_CONSUMER); + rv = gpiod_ctxless_get_value_multiple(test_chip_name(0), offsets, + values, 3, false, TEST_CONSUMER); TEST_ASSERT_RET_OK(rv); TEST_ASSERT_EQ(values[0], 1); diff --git a/tests/tests-simple-api.c b/tests/tests-simple-api.c deleted file mode 100644 index c940cec..0000000 --- a/tests/tests-simple-api.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * This file is part of libgpiod. - * - * Copyright (C) 2017-2018 Bartosz Golaszewski - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -/* Test cases for the simple API. */ - -#include "gpiod-test.h" - -#include - -static void simple_set_get_value(void) -{ - int ret; - - ret = gpiod_simple_get_value(test_chip_name(0), 3, - false, TEST_CONSUMER); - TEST_ASSERT_EQ(ret, 0); - - ret = gpiod_simple_set_value(test_chip_name(0), 3, 1, - false, TEST_CONSUMER, NULL, NULL); - TEST_ASSERT_RET_OK(ret); - - ret = gpiod_simple_get_value(test_chip_name(0), 3, - false, TEST_CONSUMER); - TEST_ASSERT_EQ(ret, 1); -} -TEST_DEFINE(simple_set_get_value, - "simple set/get value - single line", - 0, { 8 }); - -static void simple_set_get_value_multiple(void) -{ - unsigned int offsets[] = { 0, 1, 2, 3, 4, 5, 6, 12, 13, 15 }; - int values[10], rv; - - rv = gpiod_simple_get_value_multiple(test_chip_name(0), offsets, - values, 10, false, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); - - TEST_ASSERT_EQ(values[0], 0); - TEST_ASSERT_EQ(values[1], 0); - TEST_ASSERT_EQ(values[2], 0); - TEST_ASSERT_EQ(values[3], 0); - TEST_ASSERT_EQ(values[4], 0); - TEST_ASSERT_EQ(values[5], 0); - TEST_ASSERT_EQ(values[6], 0); - TEST_ASSERT_EQ(values[7], 0); - TEST_ASSERT_EQ(values[8], 0); - TEST_ASSERT_EQ(values[9], 0); - - values[0] = 1; - values[1] = 1; - values[2] = 1; - values[3] = 0; - values[4] = 0; - values[5] = 1; - values[6] = 0; - values[7] = 1; - values[8] = 0; - values[9] = 0; - - rv = gpiod_simple_set_value_multiple(test_chip_name(0), offsets, - values, 10, false, TEST_CONSUMER, - NULL, NULL); - TEST_ASSERT_RET_OK(rv); - - rv = gpiod_simple_get_value_multiple(test_chip_name(0), offsets, - values, 10, false, TEST_CONSUMER); - TEST_ASSERT_RET_OK(rv); - - TEST_ASSERT_EQ(values[0], 1); - TEST_ASSERT_EQ(values[1], 1); - TEST_ASSERT_EQ(values[2], 1); - TEST_ASSERT_EQ(values[3], 0); - TEST_ASSERT_EQ(values[4], 0); - TEST_ASSERT_EQ(values[5], 1); - TEST_ASSERT_EQ(values[6], 0); - TEST_ASSERT_EQ(values[7], 1); - TEST_ASSERT_EQ(values[8], 0); - TEST_ASSERT_EQ(values[9], 0); -} -TEST_DEFINE(simple_set_get_value_multiple, - "simple set/get value - multiple lines", - 0, { 16 }); - -static void simple_get_value_multiple_max_lines(void) -{ - unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES + 1]; - int values[GPIOD_LINE_BULK_MAX_LINES + 1], ret; - - ret = gpiod_simple_get_value_multiple(test_chip_name(0), offsets, - values, - GPIOD_LINE_BULK_MAX_LINES + 1, - false, TEST_CONSUMER); - TEST_ASSERT_NOTEQ(ret, 0); - TEST_ASSERT_ERRNO_IS(EINVAL); -} -TEST_DEFINE(simple_get_value_multiple_max_lines, - "gpiod_simple_get_value_multiple() exceed max lines", - 0, { 128 }); - -static void simple_set_value_multiple_max_lines(void) -{ - unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES + 1]; - int values[GPIOD_LINE_BULK_MAX_LINES + 1], ret; - - ret = gpiod_simple_set_value_multiple(test_chip_name(0), offsets, - values, - GPIOD_LINE_BULK_MAX_LINES + 1, - false, TEST_CONSUMER, NULL, NULL); - TEST_ASSERT_NOTEQ(ret, 0); - TEST_ASSERT_ERRNO_IS(EINVAL); -} -TEST_DEFINE(simple_set_value_multiple_max_lines, - "gpiod_simple_set_value_multiple() exceed max lines", - 0, { 128 }); - -struct simple_event_data { - bool got_rising_edge; - bool got_falling_edge; - unsigned int offset; - unsigned int count; -}; - -static int simple_event_cb(int evtype, unsigned int offset, - const struct timespec *ts TEST_UNUSED, void *data) -{ - struct simple_event_data *evdata = data; - - if (evtype == GPIOD_SIMPLE_EVENT_CB_RISING_EDGE) - evdata->got_rising_edge = true; - else if (evtype == GPIOD_SIMPLE_EVENT_CB_FALLING_EDGE) - evdata->got_falling_edge = true; - - evdata->offset = offset; - - return ++evdata->count == 2 ? GPIOD_SIMPLE_EVENT_CB_RET_STOP - : GPIOD_SIMPLE_EVENT_CB_RET_OK; -} - -static void simple_event_loop(void) -{ - struct simple_event_data evdata = { false, false, 0, 0 }; - struct timespec ts = { 1, 0 }; - int status; - - test_set_event(0, 3, TEST_EVENT_ALTERNATING, 100); - - status = gpiod_simple_event_loop(test_chip_name(0), 3, false, - TEST_CONSUMER, &ts, NULL, - simple_event_cb, &evdata); - - TEST_ASSERT_RET_OK(status); - TEST_ASSERT(evdata.got_rising_edge); - TEST_ASSERT(evdata.got_falling_edge); - TEST_ASSERT_EQ(evdata.count, 2); - TEST_ASSERT_EQ(evdata.offset, 3); -} -TEST_DEFINE(simple_event_loop, - "gpiod_simple_event_loop() - single event", - 0, { 8 }); - -static void simple_event_loop_multiple(void) -{ - struct simple_event_data evdata = { false, false, 0, 0 }; - struct timespec ts = { 1, 0 }; - unsigned int offsets[4]; - int status; - - offsets[0] = 2; - offsets[1] = 3; - offsets[2] = 5; - offsets[3] = 6; - - test_set_event(0, 3, TEST_EVENT_ALTERNATING, 100); - - status = gpiod_simple_event_loop_multiple(test_chip_name(0), offsets, - 4, false, TEST_CONSUMER, &ts, - NULL, simple_event_cb, - &evdata); - - TEST_ASSERT_RET_OK(status); - TEST_ASSERT(evdata.got_rising_edge); - TEST_ASSERT(evdata.got_falling_edge); - TEST_ASSERT_EQ(evdata.count, 2); - TEST_ASSERT_EQ(evdata.offset, 3); -} -TEST_DEFINE(simple_event_loop_multiple, - "gpiod_simple_event_loop_multiple() - single event", - 0, { 8 }); - -static int error_event_cb(int evtype TEST_UNUSED, - unsigned int offset TEST_UNUSED, - const struct timespec *ts TEST_UNUSED, - void *data TEST_UNUSED) -{ - errno = ENOTBLK; - - return GPIOD_SIMPLE_EVENT_CB_RET_ERR; -} - -static void simple_event_loop_indicate_error(void) -{ - struct timespec ts = { 1, 0 }; - int rv; - - test_set_event(0, 3, TEST_EVENT_ALTERNATING, 100); - - rv = gpiod_simple_event_loop(test_chip_name(0), 3, false, - TEST_CONSUMER, &ts, NULL, - error_event_cb, NULL); - - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(ENOTBLK); -} -TEST_DEFINE(simple_event_loop_indicate_error, - "gpiod_simple_event_loop() - error in callback", - 0, { 8 }); - -static void simple_event_loop_indicate_error_timeout(void) -{ - struct timespec ts = { 0, 100000 }; - int rv; - - rv = gpiod_simple_event_loop(test_chip_name(0), 3, false, - TEST_CONSUMER, &ts, NULL, - error_event_cb, NULL); - - TEST_ASSERT_EQ(rv, -1); - TEST_ASSERT_ERRNO_IS(ENOTBLK); -} -TEST_DEFINE(simple_event_loop_indicate_error_timeout, - "gpiod_simple_event_loop() - error in callback after timeout", - 0, { 8 }); - -static void simple_find_line_good(void) -{ - unsigned int offset; - char chip[32]; - int rv; - - rv = gpiod_simple_find_line("gpio-mockup-C-14", chip, - sizeof(chip), &offset); - TEST_ASSERT_EQ(rv, 1); - TEST_ASSERT_EQ(offset, 14); - TEST_ASSERT_STR_EQ(chip, test_chip_name(2)); -} -TEST_DEFINE(simple_find_line_good, - "gpiod_simple_find_line() - good", - TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 }); - -static void simple_find_line_truncated(void) -{ - unsigned int offset; - char chip[6]; - int rv; - - rv = gpiod_simple_find_line("gpio-mockup-C-14", chip, - sizeof(chip), &offset); - TEST_ASSERT_EQ(rv, 1); - TEST_ASSERT_EQ(offset, 14); - TEST_ASSERT_STR_EQ(chip, "gpioc"); -} -TEST_DEFINE(simple_find_line_truncated, - "gpiod_simple_find_line() - chip name truncated", - TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 }); - -static void simple_find_line_not_found(void) -{ - unsigned int offset; - char chip[32]; - int rv; - - rv = gpiod_simple_find_line("nonexistent", chip, - sizeof(chip), &offset); - TEST_ASSERT_EQ(rv, 0); -} -TEST_DEFINE(simple_find_line_not_found, - "gpiod_simple_find_line() - not found", - TEST_FLAG_NAMED_LINES, { 8, 16, 16, 8 });