- Notifications
You must be signed in to change notification settings - Fork3k
events
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
parent directory.. | ||||
Thembed-events
library provides a flexible queue for scheduling events.
#include"mbed_events.h"#include<stdio.h>intmain() {// creates a queue with the default size EventQueue queue;// events are simple callbacks queue.call(printf,"called immediately\n"); queue.call_in(2000,printf,"called in 2 seconds\n"); queue.call_every(1000,printf,"called every 1 seconds\n");// events are executed by the dispatch method queue.dispatch();}
You can use thembed-events library
as a normal event loop, or you canbackground it on a single hardware timer or even another event loop. It isboth thread and IRQ safe and provides functions for easily composingindependent event queues.
Thembed-events
library can act as a drop-in scheduler, provide synchronizationbetween multiple threads or act as a mechanism for moving events out ofinterrupt contexts.
The core of thembed-events library
is theEventQueue class,which represents a single event queue. TheEventQueue::dispatch
functionruns the queue, providing the context for executing events.
// Creates an event queue enough buffer space for 32 Callbacks. This// is the default if no argument was provided. Alternatively the size// can just be specified in bytes.EventQueuequeue(32*EVENTS_EVENT_SIZE);// Events can be posted to the underlying event queue with dynamic// context allocated from the specified bufferqueue.call(printf,"hello %d %d %d %d\n",1,2,3,4);queue.call(&serial, &Serial::printf,"hi\n");// The dispatch function provides the context for the running the queue// and can take a millisecond timeout to run for a fixed time or to just// dispatch any pending eventsqueue.dispatch();
The EventQueue class provides several call functions for posting eventsto the underlying event queue. The call functions are thread and IRQ safe,don't need the underlying loop to be running and provide a mechanismfor moving events out of interrupt contexts.
// Simple call function registers events to be called as soon as possiblequeue.call(doit);queue.call(printf,"called immediately\n");// The call_in function registers events to be called after a delay// specified in millisecondsqueue.call_in(2000, doit_in_two_seconds);queue.call_in(300, printf,"called in 0.3 seconds\n");// The call_every function registers events to be called repeatedly// with a period specified in millisecondsqueue.call_every(2000, doit_every_two_seconds);queue.call_every(400, printf,"called every 0.4 seconds\n");
The call functions return an ID that uniquely represents the event in thethe event queue. You can pass this ID toEventQueue::cancel
to cancelan in-flight event prior to dispatch.
// The event id uniquely represents the event in the queueint id = queue.call_in(100, printf,"will this work?\n");// If there was not enough memory necessary to allocate the event,// an id of 0 is returned from the call functionsif (id) {error("oh no!");}// Events can be cancelled as long as they have not been dispatched. If the// event has already expired, cancel may have negative side-effects.queue.cancel(id);
For a more detailed control of event dispatch, you can manually instantiateand configure theEvent
class. AnEvent
represents an event asa C++ style function object, and you can directly pass it to other APIs thatexpect a callback.
// Creates an event bound to the specified event queueEventQueue queue;Event<void()>event(&queue, doit);// The event can be manually configured for special timing requirements// specified in millisecondsevent.delay(10);event.period(10000);// Posted events are dispatched in the context of the queue's// dispatch functionqueue.dispatch();// Events can also pass arguments to the underlying callback when both// initially constructed and posted.Event<void(int,int)>event(&queue, printf,"received %d and %d\n");// Events can be posted multiple times and enqueue gracefully until// the dispatch function is called.event.post(1,2);event.post(3,4);event.post(5,6);queue.dispatch();
Event queues easily align with module boundaries, where internal state canbe implicitly synchronized through event dispatch. Multiple modules canuse independent event queues but still be composed through theEventQueue::chain
function.
// Create some event queues with pending eventsEventQueue a;a.call(printf,"hello from a!\n");EventQueue b;b.call(printf,"hello from b!\n");EventQueue c;c.call(printf,"hello from c!\n");// Chain c and b onto a's event queue. Both c and b will be dispatched// in the context of a's dispatch function.c.chain(&a);b.chain(&a);// Dispatching a will in turn dispatch b and c, printing hello from// all three queuesa.dispatch();
Thembed-events
C++ library is the recommended library for scheduling events. However, for occasions where C++ cannot be used for a project (e.g bare metal), the underlying C APIequeue
used bymbed-events
can be accessed directly.
Theequeue
library is designed as a simple but powerful library for schedulingevents on composable queues.
#include"equeue.h"#include<stdio.h>intmain() {// creates a queue with space for 32 basic eventsequeue_tqueue;equeue_create(&queue,32*EQUEUE_EVENT_SIZE);// events can be simple callbacksequeue_call(&queue,print,"called immediately");equeue_call_in(&queue,2000,print,"called in 2 seconds");equeue_call_every(&queue,1000,print,"called every 1 seconds");// events are executed in equeue_dispatchequeue_dispatch(&queue,3000);print("called after 3 seconds");equeue_destroy(&queue);}
The equeue library can be used as a normal event loop, or it can bebackgrounded on a single hardware timer or even another event loop. Itis both thread and irq safe, and provides functions for easily composingmultiple queues.
The equeue library can act as a drop-in scheduler, provide synchronizationbetween multiple threads, or just act as a mechanism for moving eventsout of interrupt contexts.
The in-depth documentation on specific functions can be found inequeue.h.
The core of the equeue library is theequeue_t
type which represents asingle event queue, and theequeue_dispatch
function which runs the equeue,providing the context for executing events.
On top of this,equeue_call
,equeue_call_in
, andequeue_call_every
provide easy methods for posting events to execute in the context of theequeue_dispatch
function.
#include"equeue.h"#include"game.h"equeue_tqueue;structgamegame;// button_isr may be in interrupt contextvoidbutton_isr(void) {equeue_call(&queue,game_button_update,&game);}// a simple user-interface frameworkintmain() {equeue_create(&queue,4096);game_create(&game);// call game_screen_udpate at 60 Hzequeue_call_every(&queue,1000/60,game_screen_update,&game);// dispatch foreverequeue_dispatch(&queue,-1);}
In addition to simple callbacks, an event can be manually allocated withequeue_alloc
and posted withequeue_post
to allow passing an arbitraryamount of context to the execution of the event. This memory is allocated outof the equeue's buffer, and dynamic memory can be completely avoided.
The equeue allocator is designed to minimize jitter in interrupt contexts aswell as avoid memory fragmentation on small devices. The allocator achievesboth constant-runtime and zero-fragmentation for fixed-size events, howevergrows linearly as the quantity of differently-sized allocations increases.
#include"equeue.h"equeue_tqueue;// arbitrary data can be moved to a different contextintenet_consume(void*buffer,intsize) {if (size>512) {size=512; }void*data=equeue_alloc(&queue,512);memcpy(data,buffer,size);equeue_post(&queue,handle_data_elsewhere,data);returnsize;}
Additionally, in-flight events can be cancelled withequeue_cancel
. Eventsare given unique ids on post, allowing safe cancellation until dispatch.
#include"equeue.h"equeue_tqueue;intsonar_value;intsonar_timeout_id;voidsonar_isr(intvalue) {equeue_cancel(&queue,sonar_timeout_id);sonar_value=value;}voidsonar_timeout(void*) {sonar_value=-1;}voidsonar_read(void) {sonar_timeout_id=equeue_call_in(&queue,300,sonar_timeout,0);sonar_start();}
From an architectural standpoint, event queues easily align with moduleboundaries, where internal state can be implicitly synchronized throughevent dispatch.
On platforms where multiple threads are unavailable, multiple modulescan use independent event queues and still be composed through theequeue_chain
function.
#include"equeue.h"// run a simultaneous localization and mapping loop in one queuestructslam {equeue_tqueue;};voidslam_create(structslam*s,equeue_t*target) {equeue_create(&s->queue,4096);equeue_chain(&s->queue,target);equeue_call_every(&s->queue,100,slam_filter);}// run a sonar with it's own queuestructsonar {equeue_tequeue;structslam*slam;};voidsonar_create(structsonar*s,equeue_t*target) {equeue_create(&s->queue,64);equeue_chain(&s->queue,target);equeue_call_in(&s->queue,5,sonar_update,s);}// all of the above queues can be combined into a single thread of executionintmain() {equeue_tqueue;equeue_create(&queue,1024);structsonars1,s2,s3;sonar_create(&s1,&queue);sonar_create(&s2,&queue);sonar_create(&s3,&queue);structslamslam;slam_create(&slam,&queue);// dispatches events from all of the modulesequeue_dispatch(&queue,-1);}
The equeue library has a minimal porting layer that is flexible dependingon the requirements of the underlying platform. Platform specific declarationsand more information can be found inequeue_platform.h.
The equeue library uses a set of local tests based on the posix implementation.
Runtime tests are located intests.c:
maketest
Profiling tests based on rdtsc are located inprof.c:
make prof
To make profiling results more tangible, the profiler also supports percentagecomparison with previous runs:
make prof| tee results.txtcat results.txt| make prof