From 4ddbac3be37a84cc75c2775ba80d4e1e1245cae4 Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Thu, 3 Jun 2021 17:53:44 +0200 Subject: [PATCH 1/3] sys/event: add periodic event --- sys/Makefile.dep | 5 ++ sys/event/periodic.c | 42 ++++++++++++++ sys/include/event/periodic.h | 105 +++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 sys/event/periodic.c create mode 100644 sys/include/event/periodic.h diff --git a/sys/Makefile.dep b/sys/Makefile.dep index f6de237113..e08fbb6499 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -478,6 +478,11 @@ ifneq (,$(filter event_timeout_ztimer,$(USEMODULE))) USEMODULE += event_timeout endif +ifneq (,$(filter event_periodic_timeout,$(USEMODULE))) + USEMODULE += event_timeout + USEMODULE += ztimer_periodic +endif + ifneq (,$(filter event_timeout,$(USEMODULE))) ifneq (,$(filter event_timeout_ztimer,$(USEMODULE))) USEMODULE += ztimer_usec diff --git a/sys/event/periodic.c b/sys/event/periodic.c new file mode 100644 index 0000000000..e493b0ee33 --- /dev/null +++ b/sys/event/periodic.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 Inria + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_event + * @{ + * + * @file + * @brief Periodic Event Implementation + * + * @author Francisco Molina + * + * @} + */ +#include "kernel_defines.h" +#include "ztimer.h" +#include "ztimer/periodic.h" +#include "event/periodic.h" + +static int _event_periodic_callback(void *arg) +{ + event_periodic_t *event_periodic = (event_periodic_t *)arg; + + event_post(event_periodic->queue, event_periodic->event); + + return 0; +} + +void event_periodic_init(event_periodic_t *event_periodic, + ztimer_clock_t *clock, + event_queue_t *queue, event_t *event) +{ + ztimer_periodic_init(clock, &event_periodic->timer, _event_periodic_callback, + event_periodic, 0); + event_periodic->queue = queue; + event_periodic->event = event; +} diff --git a/sys/include/event/periodic.h b/sys/include/event/periodic.h new file mode 100644 index 0000000000..408e8f0eef --- /dev/null +++ b/sys/include/event/periodic.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021 Inria + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_event + * @brief Provides functionality to trigger periodic events + * + * event_periodic intentionally doesn't extend event structures in order to + * support events that are integrated in larger structs intrusively. + * + * Example: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * event_periodic_t event_periodic; + * + * printf("posting timed callback every 1sec\n"); + * event_periodic_init(&event_periodic, ZTIMER_USEC, &queue, (event_t*)&event); + * event_periodic_start(&event_periodic, 1000000); + * [...] + * ~~~~~~~~~~~~~~~~~~~~~~~~ + * + * @{ + * + * @file + * @brief Event Periodic API + * + * @author Francisco Molina + * + */ + +#ifndef EVENT_PERIODIC_H +#define EVENT_PERIODIC_H + +#include "event.h" +#include "ztimer/periodic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Timeout Event structure + */ +typedef struct { + ztimer_periodic_t timer; /**< ztimer object used for timeout */ + event_queue_t *queue; /**< event queue to post event to */ + event_t *event; /**< event to post after timeout */ +} event_periodic_t; + +/** + * @brief Initialize a periodic event timeout + * + * @param[in] event_periodic event_periodic object to initialize + * @param[in] clock the clock to configure this timer on + * @param[in] queue queue that the timed-out event will be + * added to + * @param[in] event event to add to queue after timeout + */ +void event_periodic_init(event_periodic_t *event_periodic, ztimer_clock_t *clock, + event_queue_t *queue, event_t *event); + +/** + * @brief Starts a periodic timeout + * + * This will make the event as configured in @p event_periodic be triggered + * at every interval ticks (based on event_periodic->clock). + * + * @note: the used event_periodic struct must stay valid until after the timeout + * event has been processed! + * + * @param[in] event_periodic event_timout context object to use + * @param[in] interval period length for the event + */ +static inline void event_periodic_start(event_periodic_t *event_periodic, + uint32_t interval) +{ + event_periodic->timer.interval = interval; + ztimer_periodic_start(&event_periodic->timer); +} + +/** + * @brief Stop a periodic timeout event + * + * Calling this function will cancel the timeout by removing its underlying + * timer. If the timer has already fired before calling this function, the + * connected event will be put already into the given event queue and this + * function does not have any effect. + * + * @param[in] event_periodic event_periodic_timeout context object to use + */ +static inline void event_periodic_stop(event_periodic_t *event_periodic) +{ + ztimer_periodic_stop(&event_periodic->timer); +} + +#ifdef __cplusplus +} +#endif +#endif /* EVENT_PERIODIC_H */ +/** @} */ From c505bb11d2f9068766a72a309fdf53056f66c3fb Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Thu, 3 Jun 2021 17:53:53 +0200 Subject: [PATCH 2/3] tests/event_ztimer: initial import --- tests/event_ztimer/Makefile | 9 +++ tests/event_ztimer/Makefile.ci | 9 +++ tests/event_ztimer/main.c | 124 +++++++++++++++++++++++++++++ tests/event_ztimer/tests/01-run.py | 19 +++++ 4 files changed, 161 insertions(+) create mode 100644 tests/event_ztimer/Makefile create mode 100644 tests/event_ztimer/Makefile.ci create mode 100644 tests/event_ztimer/main.c create mode 100755 tests/event_ztimer/tests/01-run.py diff --git a/tests/event_ztimer/Makefile b/tests/event_ztimer/Makefile new file mode 100644 index 0000000000..bce9ef00d5 --- /dev/null +++ b/tests/event_ztimer/Makefile @@ -0,0 +1,9 @@ +include ../Makefile.tests_common + +FORCE_ASSERTS = 1 +USEMODULE += event_thread +USEMODULE += event_callback +USEMODULE += event_timeout_ztimer +USEMODULE += event_periodic + +include $(RIOTBASE)/Makefile.include diff --git a/tests/event_ztimer/Makefile.ci b/tests/event_ztimer/Makefile.ci new file mode 100644 index 0000000000..b5de876337 --- /dev/null +++ b/tests/event_ztimer/Makefile.ci @@ -0,0 +1,9 @@ +BOARD_INSUFFICIENT_MEMORY := \ + arduino-duemilanove \ + arduino-leonardo \ + arduino-nano \ + arduino-uno \ + atmega328p \ + atmega328p-xplained-mini \ + nucleo-l011k4 \ + # diff --git a/tests/event_ztimer/main.c b/tests/event_ztimer/main.c new file mode 100644 index 0000000000..da1119f62c --- /dev/null +++ b/tests/event_ztimer/main.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2021 Inria + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief event_timeout application using ztimer + * + * @author Kaspar Schleiser + * @author Francisco Molina + * + * @} + */ + +#include + +#include "atomic_utils.h" +#include "test_utils/expect.h" +#include "timex.h" +#include "thread.h" +#include "mutex.h" +#include "event.h" +#include "event/timeout.h" +#include "event/periodic.h" +#include "event/thread.h" +#include "event/callback.h" +#include "ztimer.h" +#include "ztimer/periodic.h" + +#define EVENT_TIMEOUT_TIME (1 * US_PER_SEC) + +static void callback_never(void *arg); +static void callback_timed(void *arg); +static void callback_4times(void *arg); + +static uint8_t iter; +static event_timeout_t event_timeout; +static event_timeout_t event_timeout_cleared; +static event_periodic_t event_periodic; +static event_callback_t event_4times = EVENT_CALLBACK_INIT(callback_4times, &iter); +static event_callback_t event_timed = EVENT_CALLBACK_INIT(callback_timed, &iter); +static event_callback_t event_never = EVENT_CALLBACK_INIT(callback_never, 0); +static uint32_t before; +static mutex_t lock = MUTEX_INIT_LOCKED; + +static void callback_timed(void *arg) +{ + expect(arg == event_timed.arg); + uint32_t now = ztimer_now(ZTIMER_USEC); + expect((now - before) >= 1 * US_PER_SEC); + printf("triggered timed callback after %" PRIu32 "us\n", now - before); + mutex_unlock(&lock); +} + +static void callback_4times(void *arg) +{ + uint8_t *count = (uint8_t *)arg; + + *count = *count + 1; + uint32_t now = event_periodic.timer.last; + uint32_t elapsed = now - before; + before = now; + expect((elapsed) >= 1 * US_PER_SEC); + if (*count <= 4) { + printf("trigger %d of periodic timeout, elapsed time: %" PRIu32 " us\n", + *count, elapsed); + } + if (*count == 4) { + event_periodic_stop(&event_periodic); + mutex_unlock(&lock); + } + else if (*count > 4) { + /* this callback should never be called */ + puts("this should only be called 4 times"); + puts("[FAILED]"); + while (1) { + expect(false); + } + } +} + +static void callback_never(void *arg) +{ + (void)arg; + /* this callback should never be called */ + puts("this should never happen"); + puts("[FAILED]"); + while (1) { + expect(false); + } +} + +int main(void) +{ + iter = 0; + puts("posting periodic timed callback with timeout 1sec"); + event_periodic_init(&event_periodic, ZTIMER_USEC, EVENT_PRIO_MEDIUM, + &event_4times.super); + event_periodic_start(&event_periodic, EVENT_TIMEOUT_TIME); + before = event_periodic.timer.last; + puts("waiting for periodic callback to be triggered 4 times"); + mutex_lock(&lock); + puts("posting timed callback with timeout 0.5sec, clear right after"); + event_timeout_ztimer_init(&event_timeout_cleared, ZTIMER_USEC, + EVENT_PRIO_MEDIUM, &event_never.super); + event_timeout_set(&event_timeout_cleared, EVENT_TIMEOUT_TIME / 2); + event_timeout_clear(&event_timeout_cleared); + puts("posting timed callback with timeout 1sec"); + event_timeout_ztimer_init(&event_timeout, ZTIMER_USEC, EVENT_PRIO_MEDIUM, + &event_timed.super); + before = ztimer_now(ZTIMER_USEC); + event_timeout_set(&event_timeout, EVENT_TIMEOUT_TIME); + puts("waiting for timed callback to trigger"); + mutex_lock(&lock); + puts("[SUCCESS]"); + return 0; +} diff --git a/tests/event_ztimer/tests/01-run.py b/tests/event_ztimer/tests/01-run.py new file mode 100755 index 0000000000..a8c5d9b211 --- /dev/null +++ b/tests/event_ztimer/tests/01-run.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2016 Kaspar Schleiser +# 2017 Sebastian Meiling +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +import sys +from testrunner import run + + +def testfunc(child): + child.expect_exact(u"[SUCCESS]") + + +if __name__ == "__main__": + sys.exit(run(testfunc)) From b0396eec5a59b20cd978ff9973475be3b6755ba1 Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Thu, 3 Jun 2021 17:54:22 +0200 Subject: [PATCH 3/3] sys/include/event/timeout: add missing DOXYGEN Fix styling --- sys/include/event/timeout.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/include/event/timeout.h b/sys/include/event/timeout.h index 9f9f4c9040..6b2522facc 100644 --- a/sys/include/event/timeout.h +++ b/sys/include/event/timeout.h @@ -62,7 +62,7 @@ typedef struct { event_t *event; /**< event to post after timeout */ } event_timeout_t; -#if IS_USED(MODULE_EVENT_TIMEOUT_ZTIMER) +#if IS_USED(MODULE_EVENT_TIMEOUT_ZTIMER) || DOXYGEN /** * @brief Initialize timeout event object * @@ -71,7 +71,7 @@ typedef struct { * @param[in] queue queue that the timed-out event will be added to * @param[in] event event to add to queue after timeout */ -void event_timeout_ztimer_init(event_timeout_t *event_timeout, ztimer_clock_t* clock, +void event_timeout_ztimer_init(event_timeout_t *event_timeout, ztimer_clock_t *clock, event_queue_t *queue, event_t *event); #endif