Skip to content

Commit ac91d0a

Browse files
author
Arto Kinnunen
committed
Squashed 'connectivity/nanostack/sal-stack-nanostack-eventloop/' changes from fdb818f341..86cf0cca08
86cf0cca08 Merge branch 'master' into release_for_mbed_os b560a9da36 Add SPDX-License-Identifier to Makefile db2f2136a3 Fix documentation of eventOS_event_timer_shortest_active_timer(). 798215b611 Add Doxygen module documentation for event system. git-subtree-dir: connectivity/nanostack/sal-stack-nanostack-eventloop git-subtree-split: 86cf0cca08e4bab62993d4445b37f4e775ef90ce
1 parent 975b1b8 commit ac91d0a

File tree

4 files changed

+193
-8
lines changed

4 files changed

+193
-8
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Copyright (c) 2019 ARM Limited
2+
# SPDX-License-Identifier: Apache-2.0
13
# Define compiler toolchain with CC or PLATFORM variables
24
# Example (GCC toolchains)
35
# make PLATFORM=arm-linux-gnueabi-

nanostack-event-loop/eventOS_event.h

Lines changed: 174 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,176 @@
1919
extern "C" {
2020
#endif
2121

22+
/**
23+
* \defgroup nanostack-eventloop Nanostack's event system.
24+
* Small event scheduler and timer system written in C.
25+
*
26+
* This event system is originating from project called Nanostack and developed within Arm. Therefore
27+
* some of the types and names within this library are prefixed with `ns_*` or `arm_*` or `eventOS*`.
28+
*
29+
* <h3>Concept</h3>
30+
*
31+
* Event loop uses a concept called tasklet, which is just a callback function that receives events.
32+
* There can be as many as 128 tasklets registered if memory allows. This is only limited by event ID being just 8-bits.
33+
* Each tasklet is first registered to the event system, which then gives 8 bit ID number for the tasklet.
34+
*
35+
* @startuml
36+
* package "eventOS" {
37+
* [eventOS_event.h] - event_handler_create
38+
* }
39+
* node "application" {
40+
* [tasklet1.cpp] ..> event_handler_create : register
41+
* [tasklet1.cpp] - tasklet1
42+
* [tasklet2.cpp] ..> event_handler_create : register
43+
* [tasklet2.cpp] - tasklet2
44+
* [tasklet3.cpp] ..> event_handler_create : register
45+
* [tasklet3.cpp] - tasklet3
46+
* }
47+
* @enduml
48+
*
49+
* Events are send to a specific tasklet, identified by its ID.
50+
* Each event is coded into a \ref arm_event_s structure which is then pushed into event loop by calling eventOS_event_send().
51+
*
52+
* @startuml
53+
* partition tasklet1.cpp {
54+
* (*) --> tasklet1
55+
* }
56+
* partition "eventOS" {
57+
* tasklet1 -->[event:\nreceiver: 3\nevent_id: 1] eventOS_event_send
58+
* }
59+
* partition tasklet3.cpp {
60+
* eventOS_event_send -->[event:\nreceiver: 3\nevent_id: 1] tasklet3
61+
* }
62+
* @enduml
63+
*
64+
* <h3>Usage</h3>
65+
*
66+
* To send or receive events, you first need to register your event handler.
67+
* \code
68+
* // In header
69+
* extern uint8_t my_eventhandler_id;
70+
* #define INITIALIZATION_EVENT 0
71+
* #define MY_EVENT 1
72+
*
73+
* // In my_handler.cpp
74+
* void my_event_handler(arm_event_t *e)
75+
* {
76+
* switch (e->event_type) {
77+
* case INITIALIZATION_EVENT:
78+
* // Initialize my module
79+
* break;
80+
* case MY_EVENT:
81+
* // Event received
82+
* break;
83+
* }
84+
* }
85+
*
86+
* // Register the handler
87+
* my_eventhandler_id = eventOS_event_handler_create(my_event_handler, INITIALIZATION_EVENT);
88+
* if (my_eventhandler_id < 0) {
89+
* // fail
90+
* }
91+
* \endcode
92+
*
93+
* Each event is basically a \ref arm_event_s structure. You need to fill in the arm_event_s::receiver field.
94+
* Rest of the fields are optional, and used only by the receiving callback. So you have different options to
95+
* deliver data to a receiving tasklet. The structure is copied by the event system, so temporary storage may be used,
96+
* and the structure may be freed after it has been pushed into event system.
97+
*
98+
* \code
99+
* // Send the event
100+
* arm_event_t e = {
101+
* .receiver = my_eventhandler_id,
102+
* .event_type = MY_EVENT
103+
* };
104+
*
105+
* if (eventOS_event_send(e) != 0) {
106+
* // fail
107+
* }
108+
* \endcode
109+
*
110+
* Where required, event system allows you to delay the event propagation.
111+
*
112+
* \code
113+
* // Wait 3 seconds before the event
114+
* #define MY_DELAY_MS 3000
115+
*
116+
* arm_event_t e = {
117+
* .receiver = my_eventhandler_id,
118+
* .event_type = MY_EVENT
119+
* };
120+
*
121+
* uint32_t delay = eventOS_event_timer_ms_to_ticks(MY_DELAY_MS);
122+
* eventOS_event_send_after(e, delay);
123+
* \endcode
124+
*
125+
* \sa eventOS_event.h
126+
* \sa eventOS_event_send_at
127+
* \sa eventOS_event_send_in
128+
* \sa eventOS_event_send_after
129+
* \sa eventOS_event_send_every
130+
*
131+
* <h3>Pre-allocated events</h3>
132+
*
133+
* Two options are provided to limit the heap usage. First option is to use recurring events with eventOS_event_send_every(),
134+
* so your event is only allocated once. This allows you to create application that does not use heap after initialization phase.
135+
*
136+
* Second option is to use pre-allocated or statically allocated event structure. In this model you create a space for
137+
* \ref arm_event_storage structure and send events using eventOS_event_send_user_allocated() call. This is also
138+
* very robust, as there is no allocation, so the sending of the event will never fail because of lack of memory.
139+
*
140+
* \code
141+
* static bool pending = false;
142+
* static arm_event_storage_t e;
143+
* static int8_t foo_tasklet_id;
144+
*
145+
* void notify_foo()
146+
* {
147+
* if (!pending) {
148+
* pending = true;
149+
* e.data.receiver = foo_tasklet_id;
150+
* e.data.type = MY_EVENT;
151+
* eventOS_event_send_user_allocated(&e);
152+
* }
153+
* }
154+
*
155+
* void foo_event_handler(arm_event_t *e)
156+
* {
157+
* pending = false;
158+
* // ...
159+
* }
160+
*
161+
* \endcode
162+
*
163+
* <h3>Initialization</h3>
164+
*
165+
* Event system does not use malloc(), free() or any system heap directly, but uses nsdynmemLIB.h library instead.
166+
* Event system must first be initialized by callind eventOS_scheduler_init(). This is usually done just after ns_dyn_mem_init() call.
167+
* Where porting is already provided, these both are initialized in function called ns_hal_init().
168+
*
169+
* After initialization, you can start the event loop by calling eventOS_scheduler_run() which will never return. This is usually
170+
* end of the `main()` function.
171+
*
172+
* \code
173+
* extern void my_event_handler(arm_event_t *e);
174+
* extern int8_t my_eventhandler_id;
175+
*
176+
* void main(void)
177+
* {
178+
* ns_dyn_mem_init(NULL, HEAP_SIZE, NULL, NULL);
179+
* eventOS_scheduler_init();
180+
* my_eventhandler_id = eventOS_event_handler_create(my_event_handler, INITIALIZATION_EVENT);
181+
* eventOS_scheduler_run()
182+
* }
183+
* \endcode
184+
*/
185+
186+
/**
187+
* \file eventOS_event.h
188+
* \ingroup nanostack-eventloop
189+
* \brief Nanostack's event loop.
190+
*/
191+
22192
#include "ns_types.h"
23193
#include "ns_list.h"
24194

@@ -100,10 +270,10 @@ extern int8_t eventOS_event_send(const arm_event_t *event);
100270

101271
/* Alternate names for timer function from eventOS_event_timer.h;
102272
* implementations may one day merge */
103-
#define eventOS_event_send_at(event, at) eventOS_event_timer_request_at(event, at)
104-
#define eventOS_event_send_in(event, in) eventOS_event_timer_request_in(event, in)
105-
#define eventOS_event_send_after(event, after) eventOS_event_timer_request_after(event, after)
106-
#define eventOS_event_send_every(event, every) eventOS_event_timer_request_every(event, every)
273+
#define eventOS_event_send_at(event, at) eventOS_event_timer_request_at(event, at) ///< \copydoc eventOS_event_timer_request_at
274+
#define eventOS_event_send_in(event, in) eventOS_event_timer_request_in(event, in) ///< \copydoc eventOS_event_timer_request_in
275+
#define eventOS_event_send_after(event, after) eventOS_event_timer_request_after(event, after) ///< \copydoc eventOS_event_timer_request_after
276+
#define eventOS_event_send_every(event, every) eventOS_event_timer_request_every(event, every) ///< \copydoc eventOS_event_timer_request_every
107277

108278
/**
109279
* \brief Send user-allocated event to event scheduler.

nanostack-event-loop/eventOS_event_timer.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@
1818
#ifdef __cplusplus
1919
extern "C" {
2020
#endif
21+
22+
/**
23+
* \file eventOS_event_timer.h
24+
* \ingroup nanostack-eventloop
25+
* \brief Functions for sending delayed events.
26+
*/
27+
28+
2129
#include "ns_types.h"
2230
#include "eventOS_event.h"
2331

@@ -208,9 +216,8 @@ extern int8_t eventOS_event_timer_cancel(uint8_t event_id, int8_t tasklet_id);
208216
/**
209217
* System Timer shortest time in milli seconds
210218
*
211-
* \param ticks Time in 10 ms resolution
212-
*
213-
* \return none
219+
* \return zero, if no timers are active.
220+
* \return time in milliseconds to next timer event.
214221
*
215222
* */
216223
extern uint32_t eventOS_event_timer_shortest_active_timer(void);

nanostack-event-loop/eventOS_scheduler.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,16 @@
1515
*/
1616
#ifndef EVENTOS_SCHEDULER_H_
1717
#define EVENTOS_SCHEDULER_H_
18-
1918
#ifdef __cplusplus
2019
extern "C" {
2120
#endif
21+
22+
/**
23+
* \file eventOS_scheduler.h
24+
* \ingroup nanostack-eventloop
25+
* \brief Event scheduler's control functions.
26+
*/
27+
2228
#include "ns_types.h"
2329

2430
/* Compatibility with older ns_types.h */

0 commit comments

Comments
 (0)