mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-15 01:23:49 +01:00
158 lines
5.6 KiB
Markdown
158 lines
5.6 KiB
Markdown
---
|
|
title: Working with Event Queues
|
|
description: This tutorial provides a quick introduction to using event queues in RIOT OS.
|
|
code_folder: examples/guides/event_queue/
|
|
---
|
|
|
|
## Introduction
|
|
An event queue is a FIFO (First In First Out) data structure that holds events
|
|
to be processed by an event handler.
|
|
|
|
Each event has exactly one callback function called the `handler`,
|
|
that is executed when the event is processed.
|
|
Posting an event to a queue triggers the execution of the event's handler
|
|
on the thread that owns the event queue.
|
|
Posting an event to a queue can be done from any thread or interrupt context.
|
|
|
|
This guide will give a quick introduction to using event queues in RIOT OS.
|
|
We will cover the following topics:
|
|
- [Regular Events](#regular-events)
|
|
- [Custom Events](#custom-events)
|
|
- [Handling Events](#handling-events)
|
|
- [Periodic Events](#periodic-events)
|
|
|
|
:::note
|
|
The whole source code for this guide can be found
|
|
[HERE](https://github.com/RIOT-OS/RIOT/tree/master/examples/guides/event_queue).
|
|
|
|
If your project is not working as expected,
|
|
you can compare your code with the code in this repository to see if you missed anything.
|
|
:::
|
|
|
|
### Regular Events
|
|
Creating and posting regular events is straightforward in RIOT.
|
|
First, we define the event handler function:
|
|
```c title="main.c"
|
|
static void regular_handler(event_t *event)
|
|
{
|
|
(void) event;
|
|
printf("\tTriggered regular event.\n");
|
|
}
|
|
```
|
|
Then, we can create an instance of the event:
|
|
```c title="main.c"
|
|
static event_t event = { .handler = regular_handler };
|
|
```
|
|
This event can now be posted to an event queue:
|
|
```c title="main.c"
|
|
event_post(&my_queue, &event);
|
|
```
|
|
:::tip
|
|
See [Handling Events](#handling-events) for information about setting up an event queue.
|
|
:::
|
|
### Custom Events
|
|
Custom events allow us to pass additional data to the event handler.
|
|
To create a custom event, we need to define a new struct that contains
|
|
an `event_t` member and any additional data we want to pass.
|
|
For example, let's create a custom event that passes a string message:
|
|
```c time="main.c"
|
|
typedef struct {
|
|
event_t super;
|
|
const char *text;
|
|
} custom_event_t;
|
|
```
|
|
Next, we define the event handler function for the custom event:
|
|
```c title="main.c"
|
|
static void custom_handler(event_t *event)
|
|
{
|
|
/* The handler receives a pointer to the base event structure.
|
|
* We need to get the pointer to our custom event structure.
|
|
*/
|
|
custom_event_t *custom_event = container_of(event, custom_event_t, super);
|
|
printf("\tTriggered custom event with text: \"%s\".\n", custom_event->text);
|
|
}
|
|
```
|
|
Notice how we do not get passed the `custom_event_t` pointer directly,
|
|
but rather the embedded `event_t` pointer.
|
|
To access the additional fields of our custom event, we use the `container_of`
|
|
macro to access the parent structure.
|
|
|
|
Then, we can create an instance of our custom event:
|
|
```c title="main.c"
|
|
static custom_event_t custom_event = { .super.handler = custom_handler,
|
|
.text = "CUSTOM EVENT" };
|
|
```
|
|
|
|
Posting a custom event means posting the embedded `event_t` member:
|
|
```c title="main.c"
|
|
event_post(&my_queue, &custom_event.super);
|
|
```
|
|
:::tip
|
|
See [Handling Events](#handling-events) for information about setting up an event queue.
|
|
:::
|
|
### Handling Events
|
|
It is common to have a dedicated thread for handling events.
|
|
A simple thread function that processes incoming events looks like this:
|
|
```c title="main.c"
|
|
void *event_handler_thread(void *arg)
|
|
{
|
|
assert(arg != NULL);
|
|
event_queue_t *queue = (event_queue_t *)arg;
|
|
|
|
/* A thread must own an event queue to process its events.
|
|
* Ownership is initially assigned to the thread that initializes the queue.
|
|
* It can later be transferred by calling `event_queue_claim`.
|
|
*/
|
|
event_queue_init(queue);
|
|
|
|
puts("Event handler thread listening for events...");
|
|
event_loop(queue);
|
|
return NULL;
|
|
}
|
|
```
|
|
:::note
|
|
The thread calling `event_queue_init` becomes the owner of the event queue. Only the owner can
|
|
process events from the queue. The ownership can be transferred to another thread using the
|
|
`event_queue_claim` function.
|
|
:::
|
|
Once the thread is started and has initialized the event queue, we can post events to it
|
|
from any other thread or interrupt context.
|
|
The handler functions of the posted events will be executed on the event handler thread.
|
|
|
|
Since using a dedicated thread for handling events is common,
|
|
RIOT provides a module which sets up event queues and a handler thread for us.
|
|
|
|
To use it, add the module to your application's Makefile:
|
|
```makefile
|
|
USEMODULE += event_thread
|
|
```
|
|
|
|
Now we can post to the `EVENT_PRIO_HIGHEST`, `EVENT_PRIO_MEDIUM`, and `EVENT_PRIO_LOWEST` queues.
|
|
A single thread will be automatically created that handles events posted to the queues
|
|
according to their priority.
|
|
Posting an event to one of these queues is as simple as:
|
|
```c title="main.c"
|
|
event_post(EVENT_PRIO_MEDIUM, &event);
|
|
```
|
|
## Periodic Events
|
|
Periodic events are events that are posted to an event queue at regular intervals.
|
|
First we need to include the module in our application's Makefile:
|
|
```makefile
|
|
USEMODULE += event_periodic
|
|
```
|
|
|
|
To create a periodic event, we need to declare and initialize a `event_periodic_t` structure.
|
|
```c title="main.c"
|
|
/* This initializes the periodic event. We set the timer it should use,
|
|
* the queue it should post to, and the event it should post.
|
|
*/
|
|
event_periodic_init(&periodic_event, ZTIMER_SEC, EVENT_PRIO_MEDIUM, &event);
|
|
```
|
|
Once the periodic event is initialized, we can start it:
|
|
```c title="main.c"
|
|
event_periodic_start(&periodic_event, 1);
|
|
```
|
|
:::note
|
|
A periodic event can be set to repeat only a certain number of times using the
|
|
`event_periodic_set_count` function.
|
|
::: |