As hundreds of commercial and other RTOS offerings can attest, the greatest demand for third-party software in the embedded systems community is for the RTOS. But this is perhaps because most embedded developers believe that traditional preemptive RTOS on one end of the complexity spectrum and the customary superloop (main+ISRs) on the other are the only choices for the embedded software architecture.
However, a little less know alternative is *event-driven* software structure based on an event-driven framework and encapsulated state machines (called active objects in the UML). This active object-based architecture is not new, and in fact, has been in quite widespread use for at least two decades. Virtually all commercially successful design automation tools on the market today (Telelogic Rhapsody, Rose Real-Time, IAR visualSTATE, Mathworks StateFlow, and many others) are based on hierarchical state machines and incorporate internally a variant of an event-driven framework. For example, Rhapsody generates code either for the Object eXecution Framework (OXF) or the Interrupt-Driven Framework (IDF). OXF requires a traditional RTOS for preemptive scheduling, while IDF was created specifically to avoid the need for an RTOS.
Most developers are accustomed to the basic sequential control, in which a program (a task in an RTOS) waits for events in various places in its execution path by either actively polling for events or passively blocking on a semaphore or other such RTOS mechanism. Though this approach is functional in many situations, it doesn’t work very well when the system must timely react to multiple events whose arrival times and order one cannot predict. The fundamental problem is that while a sequential task is waiting on one kind of event, it is not doing any other work and is not *responsive* to other events.
Event-driven programming requires a distinctly different way of thinking than conventional sequential programs, such as “superloops” or tasks in a traditional RTOS. Event-driven systems are structured according to the Hollywood principle, which means “Don’t call us, we’ll call you”. So, an event-driven program is not in control while waiting for an event; in fact, it’s not even active. Only once the event arrives, the program is called to process the event and then it quickly relinquishes the control again. This arrangement allows an event-driven system to wait for many events in parallel, so the system remains *responsive* to all events it needs to handle.
This scheme has three important consequences. First, it implies that an event-driven system is naturally divided into the application, which actually handles the events, and the supervisory event-driven infrastructure (framework), which waits for events and dispatches them to the application. Second, the control resides in the event-driven infrastructure, so from the application standpoint, the control is inverted compared to a traditional sequential program. And third, the event-driven application must return control after handling each event, so the execution context cannot be preserved in the stack-based variables and the program counter as it is in a sequential task. Instead, the event-driven application becomes a *state machine*, or actually a set of collaborating state machines that preserve the context from one event to the next in the static variables.
Traditionally, event-driven programming was done with a specific design-automation tool, such as Rose-RT or Rhapsody (now both acquired by IBM). But recently, lightweight, open source event-driven frameworks became available. The lightweight frameworks allow direct coding of hierarchical state machines (UML statecharts) in C or C++ and then combining multiple concurrent state machines into systems, all without big tools (e.g., see www.state-machine.com).