aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartosz Golaszewski <bartekgola@gmail.com>2018-10-07 15:49:50 +0200
committerBartosz Golaszewski <bartekgola@gmail.com>2018-10-07 15:49:50 +0200
commit4bf402d3a49336eacd33654441d575bd267780b8 (patch)
treec9fe11aa42acf3b46544584ff265ca94958d8394
parent63c72c92d60702a6d9445c7b65482ad4eb7a0c06 (diff)
parent5095bdd01a62eeb6c5ca9a38b6c84272f653134c (diff)
Merge branch 'next'
This introduces the new context-less event monitor with specifiable event types and a small tweak in configure.ac.
-rw-r--r--configure.ac2
-rw-r--r--include/gpiod.h84
-rw-r--r--src/lib/ctxless.c58
-rw-r--r--src/tools/gpiomon.c41
-rw-r--r--tests/tests-ctxless.c77
5 files changed, 207 insertions, 55 deletions
diff --git a/configure.ac b/configure.ac
index 445bd0c..782b395 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,7 +20,7 @@ AC_SUBST(VERSION_STR, [$PACKAGE_VERSION$EXTRA_VERSION])
#
# (...)
# 3. If the library source code has changed at all since the last update, then
-# increment revision (‘c:r:a’ becomes ‘c:r+1:a’).
+# increment revision ('c:r:a' becomes 'c:r+1:a').
# 4. If any interfaces have been added, removed, or changed since the last
# update, increment current, and set revision to 0.
# 5. If any interfaces have been added since the last public release, then
diff --git a/include/gpiod.h b/include/gpiod.h
index 5ae45aa..ccff977 100644
--- a/include/gpiod.h
+++ b/include/gpiod.h
@@ -70,6 +70,11 @@ struct gpiod_line_bulk;
#define GPIOD_BIT(nr) (1UL << (nr))
/**
+ * @brief Marks a public function as deprecated.
+ */
+#define GPIOD_DEPRECATED __attribute__((deprecated))
+
+/**
* @}
*
* @defgroup __high_level__ High-level API
@@ -149,6 +154,18 @@ int gpiod_ctxless_set_value_multiple(const char *device,
void *data) GPIOD_API;
/**
+ * @brief Event types that the ctxless event monitor can wait for.
+ */
+enum {
+ /**< Wait for rising edge events only. */
+ GPIOD_CTXLESS_EVENT_RISING_EDGE = 1,
+ /**< Wait for falling edge events only. */
+ GPIOD_CTXLESS_EVENT_FALLING_EDGE,
+ /**< Wait for both types of events. */
+ GPIOD_CTXLESS_EVENT_BOTH_EDGES,
+};
+
+/**
* @brief Event types that can be passed to the ctxless event callback.
*/
enum {
@@ -247,7 +264,7 @@ int gpiod_ctxless_event_loop(const char *device, unsigned int offset,
const struct timespec *timeout,
gpiod_ctxless_event_poll_cb poll_cb,
gpiod_ctxless_event_handle_cb event_cb,
- void *data) GPIOD_API;
+ void *data) GPIOD_API GPIOD_DEPRECATED;
/**
* @brief Wait for events on multiple GPIO lines.
@@ -284,7 +301,70 @@ int gpiod_ctxless_event_loop_multiple(const char *device,
const struct timespec *timeout,
gpiod_ctxless_event_poll_cb poll_cb,
gpiod_ctxless_event_handle_cb event_cb,
- void *data) GPIOD_API;
+ void *data) GPIOD_API GPIOD_DEPRECATED;
+
+/**
+ * @brief Wait for events on a single GPIO line.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param event_type Type of events to listen for.
+ * @param offset GPIO line offset to monitor.
+ * @param active_low The active state of this line - true if low.
+ * @param consumer Name of the consumer.
+ * @param timeout Maximum wait time for each iteration.
+ * @param poll_cb Callback function to call when waiting for events.
+ * @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 ctxless event loop works is described in detail in
+ * ::gpiod_ctxless_event_monitor_multiple - this is just a wrapper aound
+ * this routine which calls it for a single GPIO line.
+ */
+int gpiod_ctxless_event_monitor(const char *device, int event_type,
+ 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.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param event_type Type of events to listen for.
+ * @param offsets Array of GPIO line offsets to monitor.
+ * @param num_lines Number of lines to monitor.
+ * @param active_low The active state of this line - true if low.
+ * @param consumer Name of the consumer.
+ * @param timeout Maximum wait time for each iteration.
+ * @param poll_cb Callback function to call when waiting for events. Can
+ * be NULL.
+ * @param event_cb Callback function to call on event occurrence.
+ * @param data User data passed to the callback.
+ * @return 0 no errors were encountered, -1 if an error occurred.
+ * @note The poll callback can be NULL in which case the routine will fall
+ * back to a basic, ppoll() based callback.
+ *
+ * Internally this routine opens the GPIO chip, requests the set of lines for
+ * the type of events specified in the event_type paramter and calls the
+ * polling callback in a loop. The role of the polling callback is to detect
+ * input events on a set of file descriptors and notify the caller about the
+ * fds ready for reading.
+ *
+ * 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_ctxless_event_monitor_multiple(
+ const char *device, int event_type,
+ 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.
diff --git a/src/lib/ctxless.c b/src/lib/ctxless.c
index f3545cf..0009504 100644
--- a/src/lib/ctxless.c
+++ b/src/lib/ctxless.c
@@ -181,9 +181,10 @@ int gpiod_ctxless_event_loop(const char *device, unsigned int offset,
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);
+ return gpiod_ctxless_event_monitor(device,
+ GPIOD_CTXLESS_EVENT_BOTH_EDGES,
+ offset, active_low, consumer,
+ timeout, poll_cb, event_cb, data);
}
int gpiod_ctxless_event_loop_multiple(const char *device,
@@ -195,10 +196,41 @@ int gpiod_ctxless_event_loop_multiple(const char *device,
gpiod_ctxless_event_handle_cb event_cb,
void *data)
{
+ return gpiod_ctxless_event_monitor_multiple(
+ device, GPIOD_CTXLESS_EVENT_BOTH_EDGES,
+ offsets, num_lines, active_low, consumer,
+ timeout, poll_cb, event_cb, data);
+}
+
+int gpiod_ctxless_event_monitor(const char *device, int event_type,
+ 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_monitor_multiple(device, event_type,
+ &offset, 1, active_low,
+ consumer, timeout,
+ poll_cb, event_cb, data);
+}
+
+int gpiod_ctxless_event_monitor_multiple(
+ const char *device, int event_type,
+ 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_request_config conf;
struct gpiod_line_event event;
struct gpiod_line_bulk bulk;
+ int rv, ret, evtype, cnt;
struct gpiod_chip *chip;
struct gpiod_line *line;
unsigned int i;
@@ -227,10 +259,22 @@ int gpiod_ctxless_event_loop_multiple(const char *device,
gpiod_line_bulk_add(&bulk, line);
}
- flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0;
+ conf.flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0;
+ conf.consumer = consumer;
+
+ if (event_type == GPIOD_CTXLESS_EVENT_RISING_EDGE) {
+ conf.request_type = GPIOD_LINE_REQUEST_EVENT_RISING_EDGE;
+ } else if (event_type == GPIOD_CTXLESS_EVENT_FALLING_EDGE) {
+ conf.request_type = GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE;
+ } else if (event_type == GPIOD_CTXLESS_EVENT_BOTH_EDGES) {
+ conf.request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES;
+ } else {
+ errno = -EINVAL;
+ ret = -1;
+ goto out;
+ }
- rv = gpiod_line_request_bulk_both_edges_events_flags(&bulk,
- consumer, flags);
+ rv = gpiod_line_request_bulk(&bulk, &conf, NULL);
if (rv) {
ret = -1;
goto out;
diff --git a/src/tools/gpiomon.c b/src/tools/gpiomon.c
index 298062a..3c42018 100644
--- a/src/tools/gpiomon.c
+++ b/src/tools/gpiomon.c
@@ -55,9 +55,6 @@ static void print_help(void)
}
struct mon_ctx {
- bool watch_rising;
- bool watch_falling;
-
unsigned int offset;
unsigned int events_wanted;
unsigned int events_done;
@@ -203,14 +200,14 @@ static int event_callback(int event_type, unsigned int line_offset,
switch (event_type) {
case GPIOD_CTXLESS_EVENT_CB_RISING_EDGE:
- if (ctx->watch_rising)
- handle_event(ctx, event_type, line_offset, timestamp);
- break;
case GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE:
- if (ctx->watch_falling)
- handle_event(ctx, event_type, line_offset, timestamp);
+ handle_event(ctx, event_type, line_offset, timestamp);
break;
default:
+ /*
+ * REVISIT: This happening would indicate a problem in the
+ * library.
+ */
return GPIOD_CTXLESS_EVENT_CB_RET_OK;
}
@@ -242,11 +239,10 @@ static int make_signalfd(void)
int main(int argc, char **argv)
{
- unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES];
+ unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES], num_lines = 0, offset;
+ bool active_low = false, watch_rising = false, watch_falling = false;
struct timespec timeout = { 10, 0 };
- unsigned int num_lines = 0, offset;
- bool active_low = false;
- int optc, opti, ret, i;
+ int optc, opti, ret, i, event_type;
struct mon_ctx ctx;
char *end;
@@ -276,10 +272,10 @@ int main(int argc, char **argv)
ctx.silent = true;
break;
case 'r':
- ctx.watch_rising = true;
+ watch_rising = true;
break;
case 'f':
- ctx.watch_falling = true;
+ watch_falling = true;
break;
case 'F':
ctx.fmt = optarg;
@@ -294,8 +290,12 @@ int main(int argc, char **argv)
argc -= optind;
argv += optind;
- if (!ctx.watch_rising && !ctx.watch_falling)
- ctx.watch_rising = ctx.watch_falling = true;
+ if (watch_rising && !watch_falling)
+ event_type = GPIOD_CTXLESS_EVENT_RISING_EDGE;
+ else if (watch_falling && !watch_rising)
+ event_type = GPIOD_CTXLESS_EVENT_FALLING_EDGE;
+ else
+ event_type = GPIOD_CTXLESS_EVENT_BOTH_EDGES;
if (argc < 1)
die("gpiochip must be specified");
@@ -314,10 +314,11 @@ int main(int argc, char **argv)
ctx.sigfd = make_signalfd();
- ret = gpiod_ctxless_event_loop_multiple(argv[0], offsets, num_lines,
- active_low, "gpiomon",
- &timeout, poll_callback,
- event_callback, &ctx);
+ ret = gpiod_ctxless_event_monitor_multiple(argv[0], event_type,
+ offsets, num_lines,
+ active_low, "gpiomon",
+ &timeout, poll_callback,
+ event_callback, &ctx);
if (ret)
die_perror("error waiting for events");
diff --git a/tests/tests-ctxless.c b/tests/tests-ctxless.c
index db8585d..ea9403d 100644
--- a/tests/tests-ctxless.c
+++ b/tests/tests-ctxless.c
@@ -142,7 +142,7 @@ static int ctxless_event_cb(int evtype, unsigned int offset,
: GPIOD_CTXLESS_EVENT_CB_RET_OK;
}
-static void ctxless_event_loop(void)
+static void ctxless_event_monitor(void)
{
struct ctxless_event_data evdata = { false, false, 0, 0 };
struct timespec ts = { 1, 0 };
@@ -150,9 +150,10 @@ static void ctxless_event_loop(void)
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);
+ status = gpiod_ctxless_event_monitor(test_chip_name(0),
+ GPIOD_CTXLESS_EVENT_BOTH_EDGES,
+ 3, false, TEST_CONSUMER, &ts,
+ NULL, ctxless_event_cb, &evdata);
TEST_ASSERT_RET_OK(status);
TEST_ASSERT(evdata.got_rising_edge);
@@ -160,11 +161,34 @@ static void ctxless_event_loop(void)
TEST_ASSERT_EQ(evdata.count, 2);
TEST_ASSERT_EQ(evdata.offset, 3);
}
-TEST_DEFINE(ctxless_event_loop,
- "gpiod_ctxless_event_loop() - single event",
+TEST_DEFINE(ctxless_event_monitor,
+ "gpiod_ctxless_event_monitor() - single event",
0, { 8 });
-static void ctxless_event_loop_multiple(void)
+static void ctxless_event_monitor_single_event_type(void)
+{
+ struct ctxless_event_data evdata = { false, false, 0, 0 };
+ struct timespec ts = { 1, 0 };
+ int rv;
+
+ test_set_event(0, 3, TEST_EVENT_ALTERNATING, 100);
+
+ rv = gpiod_ctxless_event_monitor(test_chip_name(0),
+ GPIOD_CTXLESS_EVENT_FALLING_EDGE,
+ 3, false, TEST_CONSUMER, &ts,
+ NULL, ctxless_event_cb, &evdata);
+
+ TEST_ASSERT_RET_OK(rv);
+ TEST_ASSERT(evdata.got_falling_edge);
+ TEST_ASSERT_FALSE(evdata.got_rising_edge);
+ TEST_ASSERT_EQ(evdata.count, 2);
+ TEST_ASSERT_EQ(evdata.offset, 3);
+}
+TEST_DEFINE(ctxless_event_monitor_single_event_type,
+ "gpiod_ctxless_event_monitor() - specify event type",
+ 0, { 8 });
+
+static void ctxless_event_monitor_multiple(void)
{
struct ctxless_event_data evdata = { false, false, 0, 0 };
struct timespec ts = { 1, 0 };
@@ -178,10 +202,11 @@ static void ctxless_event_loop_multiple(void)
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);
+ status = gpiod_ctxless_event_monitor_multiple(
+ test_chip_name(0),
+ GPIOD_CTXLESS_EVENT_BOTH_EDGES,
+ offsets, 4, false, TEST_CONSUMER,
+ &ts, NULL, ctxless_event_cb, &evdata);
TEST_ASSERT_RET_OK(status);
TEST_ASSERT(evdata.got_rising_edge);
@@ -189,8 +214,8 @@ static void ctxless_event_loop_multiple(void)
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",
+TEST_DEFINE(ctxless_event_monitor_multiple,
+ "gpiod_ctxless_event_monitor_multiple() - single event",
0, { 8 });
static int error_event_cb(int evtype TEST_UNUSED,
@@ -203,38 +228,40 @@ static int error_event_cb(int evtype TEST_UNUSED,
return GPIOD_CTXLESS_EVENT_CB_RET_ERR;
}
-static void ctxless_event_loop_indicate_error(void)
+static void ctxless_event_monitor_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);
+ rv = gpiod_ctxless_event_monitor(test_chip_name(0),
+ GPIOD_CTXLESS_EVENT_BOTH_EDGES,
+ 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",
+TEST_DEFINE(ctxless_event_monitor_indicate_error,
+ "gpiod_ctxless_event_monitor() - error in callback",
0, { 8 });
-static void ctxless_event_loop_indicate_error_timeout(void)
+static void ctxless_event_monitor_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);
+ rv = gpiod_ctxless_event_monitor(test_chip_name(0),
+ GPIOD_CTXLESS_EVENT_BOTH_EDGES,
+ 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",
+TEST_DEFINE(ctxless_event_monitor_indicate_error_timeout,
+ "gpiod_ctxless_event_monitor() - error in callback after timeout",
0, { 8 });
static void ctxless_find_line_good(void)