Blog Datasheets Home About me Clients My work Services Contact

G2Labs Grzegorz Grzęda

Exampe event handling library in C/CMake

April 19, 2024

Writing an Event Handling Library with Context and Payload in C as a CMake Project

Event handling is a crucial aspect of many software applications, allowing different components to communicate and react to specific events. In this blog post, we will explore how to write an event handling library in C that supports context and payload, and set it up as a CMake project with test cases.

Setting Up the Project with CMake

To begin, we need to set up our project using CMake. CMake is a cross-platform build system generator, enabling easy project configuration and management.

  1. Create a new directory for your project: $ mkdir event_handling_library
  2. Change into the project directory: $ cd event_handling_library
  3. Create a file named CMakeLists.txt with the following content:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
cmake_minimum_required(VERSION 3.10)
project(event_handling_library C)

# Add library source files
file(GLOB SRCS "src/*.c")

# Add library include directory
include_directories(include)

# Create a shared library
add_library(event_handling_library SHARED ${SRCS})

# Add test directory
add_subdirectory(test)
  1. Create a directory named src and another directory named include in the project directory.
  2. Add your library source files to the src directory and any necessary header files to the include directory.

Implementing the Event Handling Library

Now that our project structure is set up, let’s implement the event handling library. The library will support events with context and payload.

  1. Create a file named event.h in the include directory with the following content:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef EVENT_H
#define EVENT_H

// Define the maximum number of event listeners
#define MAX_EVENT_LISTENERS 10

// Define the event structure
typedef struct {
    void* context;
    void* payload;
} Event;

// Event listener function pointer type
typedef void (*EventListener)(Event*);

// Initialize the event handling library
void initialize_event_handling();

// Register an event listener
void register_event_listener(int event_type, EventListener listener);

// Trigger an event
void trigger_event(int event_type, void* context, void* payload);

#endif
  1. Create a file named event.c in the src directory with the following content:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "event.h"

// Define the array of event listeners
EventListener event_listeners[MAX_EVENT_LISTENERS];

// Initialize the event handling library
void initialize_event_handling() {
    // Clear the event listeners array
    for (int i = 0; i < MAX_EVENT_LISTENERS; i++) {
        event_listeners[i] = NULL;
    }
}

// Register an event listener
void register_event_listener(int event_type, EventListener listener) {
    if (event_type >= 0 && event_type < MAX_EVENT_LISTENERS) {
        event_listeners[event_type] = listener;
    }
}

// Trigger an event
void trigger_event(int event_type, void* context, void* payload) {
    if (event_type >= 0 && event_type < MAX_EVENT_LISTENERS && event_listeners[event_type] != NULL) {
        Event event;
        event.context = context;
        event.payload = payload;

        // Call the event listener with the event
        event_listeners[event_type](&event);
    }
}

Writing Test Cases

Writing test cases is crucial for ensuring the correctness of our library. CMake makes it easy to create and run test cases for our event handling library.

  1. Create a directory named test in the project directory.
  2. Change into the test directory: $ cd test
  3. Create a file named CMakeLists.txt with the following content:
1
2
3
4
add_executable(test_event_handling test_event_handling.c)

# Link the event_handling_library to the test executable
target_link_libraries(test_event_handling event_handling_library)
  1. Create a file named test_event_handling.c in the test directory with the test cases:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include "event.h"
#include <stdio.h>

void event_listener(Event* event) {
    printf("Event triggered with context: %p, payload: %p\n", event->context, event->payload);
}

int main() {
    // Initialize event handling
    initialize_event_handling();

    // Register event listener
    register_event_listener(0, event_listener);

    // Trigger event
    int context = 42;
    int payload = 10;
    trigger_event(0, &context, &payload);

    return 0;
}

Building and Running the Tests

With our test cases in place, let’s build and run the tests using CMake.

  1. Change back to the project directory: $ cd ..
  2. Create a directory named build: $ mkdir build
  3. Change into the build directory: $ cd build
  4. Generate the build files using CMake: $ cmake ..
  5. Build the project: $ cmake --build .
  6. Run the tests: $ ./test/test_event_handling

If the event handling library is implemented correctly, you should see the following output:

1
Event triggered with context: 0x7ffeede082dc, payload: 0x7ffeede082e0

Congratulations! You have successfully written an event handling library with context and payload in C, set it up as a CMake project, and executed test cases to verify its functionality.

Remember, this implementation is just a starting point, and you can extend and optimize it further to suit your specific requirements.

Happy coding!


➡️ Exploring the GPIOs in ESP32: Usage and Configuration


⬅️ ESP32 vs. Other Microcontrollers: Pros and Cons


Go back to Posts.