The example application here needs to handle two buttons: Button 1 and Button 2.
- Both buttons have a dedicated interrupt service routine (isr). If Button 1 is pressed, "isr_button_1();" is executed etc.
- The application needs to detect each button press.
- The application also needs to detect a button press combo 1-1-2.
The goal is to abstract the events from hardware level to software level efficiently. To separate the 'business logic' from hardware in a flexible way.
The Main-function to test and showcase the event system:
This outputs:
The Interrupt Service Routine (ISR) functions for the buttons:
These two ISR functions create a software event which is handled in the main loop. They pass a function pointer with the event. This is the event callback which in this case points to a function which tracks the button press combo.
This kind of software event system is very powerful tool to handle all kinds of events.. external or internal. Below is the eventlogger-module source.
- Both buttons have a dedicated interrupt service routine (isr). If Button 1 is pressed, "isr_button_1();" is executed etc.
- The application needs to detect each button press.
- The application also needs to detect a button press combo 1-1-2.
The goal is to abstract the events from hardware level to software level efficiently. To separate the 'business logic' from hardware in a flexible way.
The Main-function to test and showcase the event system:
C:
int main(void)
{
initialize_eventlogger();
initialize_uart(B38400);
printf("Reset\n");
/* Simulate button pushes by calling the interrupt service routines.
Combo 1-1-2 should be detected by the software event system */
isr_button_1();
isr_button_2();
isr_button_1();
isr_button_1();
isr_button_2(); /* Combo */
isr_button_2();
isr_button_1();
isr_button_1();
isr_button_1();
isr_button_2(); /* Combo */
isr_button_1();
/* Force combo event in software */
eventlogger_event(EVENT_BUTTON_COMBO);
/* Main loop */
while (1)
{
static struct event next_event;
/* Handle events */
while(eventlogger_get(&next_event))
{
if (next_event.type == EVENT_BUTTON_1) { printf("Button 1\n"); }
else if (next_event.type == EVENT_BUTTON_2) { printf("Button 2\n"); }
else if (next_event.type == EVENT_BUTTON_COMBO) { printf("COMBO!\n"); }
/* You can have as many different kinds of events you want.. */
/* Call the event callback */
next_event.callback(&next_event);
}
}
}
/******************************************************************************/
This outputs:
Code:
Reset
Button 1
Button 2
Button 1
Button 1
Button 2
Button 2
Button 1
Button 1
Button 1
Button 2
Button 1
COMBO!
COMBO!
COMBO!
The Interrupt Service Routine (ISR) functions for the buttons:
C:
void
isr_button_1(void)
{
/* Do debounce and other low level logic.
. . . */
/* Raise event */
eventlogger_create_event(EVENT_BUTTON_1, &combo_state_machine, NULL);
}
/******************************************************************************/
void
isr_button_2(void)
{
/* Do debounce and other low level logic.
. . . */
/* Raise event */
eventlogger_create_event(EVENT_BUTTON_2, &combo_state_machine, NULL);
}
/******************************************************************************/
C:
void
combo_state_machine(struct event *e)
{
static uint8_t state = 0;
/* Simple state machine to detect combo 1-1-2 */
if (state == 0) {
/* For combo, we expect button 1 */
if (e->type == EVENT_BUTTON_1) { state++; } else { state = 0; }
}
else if (state == 1) {
/* For combo, we expect button 1 */
if (e->type == EVENT_BUTTON_1) { state++; } else { state = 0; }
}
else if (state == 2) {
/* For combo, we expect button 2 */
if (e->type == EVENT_BUTTON_2) {
/* We have a combo! */
eventlogger_event(EVENT_BUTTON_COMBO);
state = 0;
}
}
/* Reset state machine by default */
else { state = 0; }
}
/******************************************************************************/
This kind of software event system is very powerful tool to handle all kinds of events.. external or internal. Below is the eventlogger-module source.
C:
/*
* eventlogger.h
*/
#ifndef EVENTLOGGER_H
#define EVENTLOGGER_H
/* Preprocessor includes */
#include <stdint.h>
/* Event type enums */
enum event_type {
EVENT_VOID,
EVENT_BUTTON_1,
EVENT_BUTTON_2,
EVENT_BUTTON_COMBO
};
/* Typedef for event callback function pointers.
This is a pointer to functions with prototype:
void callback(struct event *e); */
struct event;
typedef void (*event_callback)(struct event *e);
struct event {
uint32_t timestamp_sec;
enum event_type type;
event_callback callback;
};
void initialize_eventlogger(void);
/* Copies the event passed to the event queue
Does not make changes to the passed event (hard copy)
Return 0 on success, 1 on fail (buffer full) */
uint8_t eventlogger_put(struct event* e);
/* Copies the next event in the queue to given placeholder struct.
Return 1 if event was available, 0 if event buffer empty */
uint8_t eventlogger_get(struct event* e);
/* Helper function to create simple events.
Return 0 on success, 1 on fail (buffer full) */
uint8_t eventlogger_event(enum event_type type);
/* Helper function to create events.
Return 0 on success, 1 on fail (buffer full) */
uint8_t eventlogger_create_event(enum event_type type, event_callback callback, void *data);
#endif /* EVENTLOGGER_H */
C:
/*
* eventlogger.c
*/
/* Preprocessor includes */
#include <stdlib.h>
#include <stdint.h>
#include "eventlogger.h"
/*******************************************************************************
* Private variables and constants
*/
#define MAX_EVENTS (16)
volatile static struct event event_pool[MAX_EVENTS];
volatile static uint8_t fifo_head; /* write */
volatile static uint8_t fifo_tail; /* read */
/*******************************************************************************
* Private Function declarations
*/
/* Updates the head or tail variable to next data in fifo buffer
Returns 0 on success and 1 on failure (buffer full or empty) */
uint8_t next_head(void);
uint8_t next_tail(void);
/* Default callback function. Does nothing. */
void idle_event_callback(struct event *e);
/*******************************************************************************
* Function definitions
*/
void
initialize_eventlogger(void)
{
/* Initialize event pool */
uint8_t i = 0;
for(i=0; i<MAX_EVENTS; i++)
{
event_pool[i].timestamp_sec = 0;
event_pool[i].type = EVENT_VOID;
event_pool[i].callback = &idle_event_callback;
}
/* Initialize fifo */
fifo_head = 0;
fifo_tail = 0;
}
/*****************************************************************************/
uint8_t
eventlogger_get(struct event *e)
{
if(e == NULL) {
/* Null pointer */
return 0;
}
/* Advance the tail index */
if(next_tail()) {
/* Buffer empty, nothing to get */
return 0;
}
/* Copy the event */
e->timestamp_sec = event_pool[fifo_tail].timestamp_sec;
e->type = event_pool[fifo_tail].type;
e->callback = event_pool[fifo_tail].callback;
return 1;
}
/*****************************************************************************/
uint8_t
eventlogger_put(struct event* e)
{
if(e == NULL) {
/* Null pointer */
return 1;
}
/* Advance the head index */
if(next_head()) {
/* Buffer full */
return 1;
}
/* Create new event */
event_pool[fifo_head].timestamp_sec = e->timestamp_sec;
event_pool[fifo_head].type = e->type;
event_pool[fifo_head].callback = e->callback;
return 0;
}
/*****************************************************************************/
uint8_t
eventlogger_event(enum event_type type)
{
return eventlogger_create_event(type, &idle_event_callback, NULL);
}
/******************************************************************************/
uint8_t
eventlogger_create_event(enum event_type type, event_callback callback, void *data)
{
/* Advance the head index */
if(next_head()) {
/* Buffer full */
return 1;
}
if (callback == NULL) { callback = &idle_event_callback; }
/* Initialize new event */
event_pool[fifo_head].timestamp_sec = 0;
event_pool[fifo_head].type = type;
event_pool[fifo_head].callback = callback;
return 0;
}
/******************************************************************************/
uint8_t
next_head(void)
{
uint8_t head;
head = fifo_head + 1;
if(head >= MAX_EVENTS) {
/* The index overflows -> wrap */
head = 0;
}
if(head == fifo_tail) {
/* The buffer is full -> return with error */
return 1;
}
/* All is OK, update head and return success */
fifo_head = head;
return 0;
}
/*****************************************************************************/
uint8_t
next_tail(void)
{
if(fifo_head == fifo_tail) {
/* Buffer is empty -> return error */
return 1;
}
/* Find next tail */
fifo_tail++;
if(fifo_tail >= MAX_EVENTS) {
/* The index overflows -> wrap */
fifo_tail = 0;
}
return 0;
}
/*****************************************************************************/
void idle_event_callback(struct event *e)
{
}
/*****************************************************************************/
Last edited: