Open Lighting Architecture  Latest Git
OLA & Event Driven Programming

Table of Contents

Overview

This page describes event driven programming and how OLA uses it. It also provides pointers on how OLA's event driven model can be used with other event driven frameworks.

Background

Event Driven Programming is a programming style where actions within the program are triggered by various events. Event driven programs typically have a main event loop which then executes the required handlers when events occur.

The simplest event loop may look something like:

while ((c = getchar()) != EOF) {
switch (c) {
case 'q':
printf("'q' was pressed\n");
break;
default:
printf("Something other than 'q' was pressed\n");
}
}

While this works for key-presses, it doesn't support any other type of I/O event. To support more generic types of events, the select() call (or a variant thereof) is often used.

Event driven frameworks allow the programmer to register to receive notifications of certain events. Notifications are usually delivered by executing a callback function. For example, for a timer event, the code may look like:

app.RunAfter(1000, TimerFunction);

Usually after any initialization is performed, the application gives up control to the main event loop. This is usually done with a call to Run():

app.Run();

The Run() call will only return when the application shuts down.

While this appears limiting at first, the method is in fact very powerful. Event driven programming allows the programmer to focus on writing code to handle the events, rather than determining what action to take next.

A caveat however that is that callbacks triggered by events can't block. Doing so prevents control returning to the main event loop and will starve other event notifications. Typical approaches are to either use non-blocking I/O or perform blocking I/O in a separate thread.

OLA Event Management

In OLA, there are two main types of events:

C++

The ola::io::SelectServer is the core of OLA's event driven system. It invokes Callbacks when events occur.

For the OLA Client, the ola::OlaClientWrapper class encapsulates the SelectServer behind an easy to use interface. This is described in the C++ DMX Client API Tutorial.

Python

The Python classes are similar to the C++ ones. The ola.ClientWrapper module provides a basic SelectServer class.

As the in C++ clase, the ola.ClientWrapper.ClientWrapper class encapsulates this all so in the basic case you can just call:

from ola.ClientWrapper import ClientWrapper
wrapper = ClientWrapper()
wrapper.Run() # event loop is running

Integration with other frameworks

This section is for those who want to use the OLA client within another event management framework. The OLA client code does not use timers so the only events you need to handle are socket I/O.

There are two main approaches. For frameworks that allow file descriptors to be added to the main event loop, one can simply add the file descriptor for the OLA server and call the appropriate read/write methods when the event triggers.

For frameworks that do not support raw file descriptor access the best solution is to run the OLA client in a separate thread and use a callback queue to pass control between the threads.

The OLA clients are not thread safe, and must only be accessed from the thread in which the event loop is running.

Integration with GLib

GLib has a g_source_add_unix_fd function.

Integration with QT

Qt provides a QSocketNotifier which allows the OLA socket to be added to Qt's main loop.

Integration with Kivy

See https://github.com/jesseanderson/ola-rpiui for an example.

Integration with PyGame

See Example