OOSMOS Introduction
1. What is OOSMOS?
2. Hierarchical State Machine Example
3. Object Threads Example
4. Quick Start

1. What is OOSMOS?

OOSMOS, the Object-Oriented State Machine Operating System, implements object and state based concurrency for C/C++.

Main Features:

  • Hierarchical State Machine - Draw a hierarchical state chart for each of your event-driven objects using the open source drawing tool UMLet and then use the OOSMOS code generator to generate C code.  Jump ahead to an example.
  • Object Threads - A lightweight thread that has object scope and is analogous to the async/await feature of recent versions of C# and JavaScript.  Jump ahead to an example.
  • State Threads - Like Object Threads, but only live for the life of each state -- created on entry to a state and deleted when exiting that state.  Jump ahead to an example.
  • Reusable Classes - Common classes found in embedded control systems are supplied. Classes like pin, button, switch, toggle, pwm, adc, pid, and more.
  • Portable - Runs on Arduino, ESP8266, ESP32, STM32, PIC32, TI, Windows, Linux/Raspberry Pi, etc.
  • Small - Core source files oosmos.h and oosmos.c total less than 1700 lines of C.
  • LINT - Thoroughly scrubbed using PC-LINT on OOSMOS and OOSMOS classes. We also provide an oosmos-user.lnt file with rules for applications that use OOSMOS.
  • It's Open Source:
Get
OOSMOS
from GitHub

2. Hierarchical State Machine Example

What follows is a complete example of an OOSMOS object and its hierarchical state machine that reacts to keystroke events. It demonstrates a feature unique to OOSMOS -- State Threads. That is, a simple thread of execution that you get for free when you enter a state. This powerful feature allows you do things that would otherwise require many states.
In the state chart below, find the Flashing state. While the object is in this state, the POLL event is called continuously by OOSMOS and the FlashingThread is serviced. Following the logic of the state chart, when either a 'b', 'r', or 'q' key is pressed, the Flashing state is exited and the thread is no longer active. State Threads can be nested in your hierarchical state charts. Note that the Flashing state is inside the Running state. Thus, both RunningThread and FlashingThread are active at the same time.
This is the code snippet for the FlashingThread function, which prints 'Flashing...' every 50 milliseconds as long as it is active (i.e., in the Flashing state.)
1
2
3
4
5
6
7
8
9
10
11
 
static void FlashingThread(oosmos_sState * pState)
{
oosmos_ThreadBegin();
for (;;) {
printf("Flashing...\n");
oosmos_ThreadDelayMS(50);
}
oosmos_ThreadEnd();
}
 
FlashingThread

2.1 State Chart That Uses State Threads

This state chart represents the exact behavior of your object and doubles as its formal behavioral requirements. Too often, projects will use a drawing tool to draw state charts intended to reflect behavior, but it doesn't reflect how the system actually behaves because code is not generated from the state chart like it is with OOSMOS.
State Chart Using Nested State Threads

2.2 Generated Code

Below is the entire .c file for the example object along with the main function that initializes and drives it. You supply the .c file with four code insertion markers into which the OOSMOS code generator injects its code from the state chart. Note: In this example, we gave the generator the debug option.
Click on the '+' signs to expand each collapsed snippet and view the generated code.
1
22
23
29
30
31
32
33
54
55
56
57
58
59
60
61
62
63
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
201
202
203
204
205
206
207
208
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
[GPLv2]
 
[#includes...]
 
typedef struct testTag test;
 
//>>>EVENTS
[Code Generated by OOSMOS]
//<<<EVENTS
 
typedef union {
oosmos_sEvent Event;
} uEvents;
 
struct testTag
{
//>>>DECL
[Code Generated by OOSMOS]
//<<<DECL
};
 
static void RunningThread(oosmos_sState * pState)
{
oosmos_ThreadBegin();
for (;;) {
printf("RUNNING...\n");
oosmos_ThreadDelayMS(750);
}
oosmos_ThreadEnd();
}
 
static void FlashingThread(oosmos_sState * pState)
{
oosmos_ThreadBegin();
for (;;) {
printf("Flashing...\n");
oosmos_ThreadDelayMS(50);
}
oosmos_ThreadEnd();
}
 
static void BeepingThread(oosmos_sState * pState)
{
oosmos_ThreadBegin();
for (;;) {
printf("Beeping...\n");
oosmos_ThreadDelayMS(100);
}
oosmos_ThreadEnd();
}
 
//>>>CODE
[Code Generated by OOSMOS]
//<<<CODE
 
static test * testNew(void)
{
oosmos_Allocate(pTest, test, 1, NULL);
 
//>>>INIT
[Code Generated by OOSMOS]
//<<<INIT
 
return pTest;
}
 
extern int main(void)
{
test * pTest = testNew();
 
pin * p_r_Pin = pinNew('r', pinActiveHigh);
btn * p_r_Button = btnNew(p_r_Pin);
btnSubscribePressedEvent(p_r_Button, oosmos_EventQueue(pTest), ev_r_Pressed, NULL);
btnSubscribeReleasedEvent(p_r_Button, oosmos_EventQueue(pTest), ev_r_Released, NULL);
 
pin * p_b_Pin = pinNew('b', pinActiveHigh);
btn * p_b_Button = btnNew(p_b_Pin);
btnSubscribePressedEvent(p_b_Button, oosmos_EventQueue(pTest), ev_b_Pressed, NULL);
btnSubscribeReleasedEvent(p_b_Button, oosmos_EventQueue(pTest), ev_b_Released, NULL);
 
pin * p_q_Pin = pinNew('q', pinActiveHigh);
btn * p_q_Button = btnNew(p_q_Pin);
btnSubscribePressedEvent(p_q_Button, oosmos_EventQueue(pTest), ev_q_Pressed, NULL);
 
for (;;) {
oosmos_RunStateMachines();
oosmos_DelayMS(1);
}
}
NestedStateThreads.c

3. Object Threads Example

The following two code snippets are the interface and implementation of reusable class toggle implemented using an Object Thread.

toggle.h

Simple interface.
1
22
23
24
25
26
27
28
29
30
31
32
33
[GPLv2]
 
#ifndef toggle_h
#define toggle_h
 
#include "pin.h"
#include <stdint.h>
 
typedef struct toggleTag toggle;
 
extern toggle * toggleNew(pin * pPin, uint32_t TimeOnMS, uint32_t TimeOffMS);
 
#endif
oosmos/Classes/toggle.h

toggle.c

See lines 45-59 for the Object Thread's function and then lines 38 and 65 to see how to the thread is created.
1
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
[GPLv2]
 
#ifndef toggleMAX
#define toggleMAX 5
#endif
 
//===================================
 
#include "oosmos.h"
#include "toggle.h"
#include "pin.h"
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
 
struct toggleTag
{
oosmos_sObjectThread m_ObjectThread;
 
pin * m_pPin;
uint32_t m_TimeOnMS;
uint32_t m_TimeOffMS;
};
 
static void ToggleThread(const toggle * pToggle, oosmos_sState * pState)
{
oosmos_POINTER_GUARD(pToggle);
oosmos_POINTER_GUARD(pState);
 
oosmos_ThreadBegin();
for (;;) {
pinOn(pToggle->m_pPin);
oosmos_ThreadDelayMS(pToggle->m_TimeOnMS);
 
pinOff(pToggle->m_pPin);
oosmos_ThreadDelayMS(pToggle->m_TimeOffMS);
}
oosmos_ThreadEnd();
}
 
extern toggle * toggleNew(pin * pPin, uint32_t TimeOnMS, uint32_t TimeOffMS)
{
oosmos_Allocate(pToggle, toggle, toggleMAX, NULL);
 
oosmos_ObjectThreadInit(pToggle, m_ObjectThread, ToggleThread, true);
 
pToggle->m_pPin = pPin;
pToggle->m_TimeOnMS = TimeOnMS;
pToggle->m_TimeOffMS = TimeOffMS;
 
return pToggle;
}
oosmos/Classes/toggle.c
The underlying structure of OOSMOS threads is based on protothreads by Adam Dunkels.

4. Quick Start

4.1 On Windows

  1. From GitHub, you can either:
  2. Build NestedStateThreads.exe following these steps:
    1. Make sure that Python is installed and runnable from a command line. We use the latest version from https://www.python.org/.
    2. Make sure that you have a Microsoft C/C++ compiler that can be run from a command line. We use Visual Studio Community 2019 (free) but any Microsoft compiler that can compile c99 will work.
    3. Open a command line window that has the necessary environment variables to run the compiler and then change directory to oosmos\Examples\NestedStateThreads\Windows.
    4. Run the build script from the command line with this command:
      python bld.py
  3. Run NestedStateThreads.exe. Referring to the state chart above, press any of these keys: r, b, or q.
    To get the full effect, press and hold the r key, then keep pressing and releasing the b key. Then release the r key.
    Per the state chart, when in the Idle state, you must press the r key within 7 seconds or the program will terminate.

4.2 On an Embedded Device

  1. Clone OOSMOS from GitHub.
  2. Open a command line window and then change directory to oosmos.
  3. Run populate.py. (Python must be installed.)
  4. Change directory to oosmos\Examples\Blink.
  5. Build one of the Blink examples using the appropriate IDE. If you would like to see other mainstream boards supported, let us know.
Copyright © 2014-2024  OOSMOS, LLC