OOSMOS
stands for:
OOSMOS
takes a novel approach to all three of these characteristics, described below.
OOSMOS
conventions promote strict encapsulation and information hiding.
module.h
and module.c
, below, show how it is done.
module.h
. This is a typedef
that declares a type called
module
that is of incomplete structure type
struct
moduleTag
. This line makes the type module
accessible to the user but not its size, so only pointers of type module
can
be created. See
this article
for a complete description of incomplete types.
module.c
. This declaration completes
the type, but it is inside the implementation file module.c
, not the
user-facing interface file module.h
. That way, all the implementation details
are hidden from the user. We think this approach is superior to the way a customary C++
class is organized. See section C vs C++ Encapsulation below for an example.
1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
#ifndef module_h | |
#define module_h | |
typedef struct moduleTag module; | |
extern module * moduleNew(void); | |
#endif | |
1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
#include <stdlib.h> | |
#include "module.h" | |
struct moduleTag { | |
int m_Member; | |
}; | |
extern module * moduleNew(void) | |
{ | |
module * pModule = malloc(sizeof(module)); | |
pModule->m_Member = 0; | |
return pModule; | |
} | |
OOSMOS
encapsulation structure
is superior to the same thing written in classic C++
.
module.hpp
, below, is a C++
header file
that defines a simple interface to a class called module.
Note that the implementation of module
in
file module.cpp
needs to retain a Windows
handle
in the class. Accordingly, a private member m_Handle
is
added in module.hpp
in a private
section of the
class. Because we refer to type HWND
, we need to include
Windows.h
. This is very unfortunate for at least two reasons:
Windows.h
is included in the module.h
header file,
anyone that includes module.h
will now get their namespace
polluted by all the symbols in Windows.h
.OOSMOS
-structured
C
.
1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
#ifndef module_hpp | |
#define module_hpp | |
#include "Windows.h" | |
class module | |
{ | |
public: | |
void Init(); | |
private: | |
HWND m_Handle; | |
}; | |
#endif | |
1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
#include <stddef.h> | |
#include "module.hpp" | |
void module::Init() | |
{ | |
m_Handle = NULL; | |
} | |
C
files module.h
and module.c
, below.
OOSMOS
-structured C
, we do not include Windows.h
in the header file. There is no need because all the implementation details are maintained
within module.c
, so module.c
includes Windows.h
,
not module.h
.
module.c
needs to be changed and
only that file needs to be recompiled.
1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
#ifndef module_h | |
#define module_h | |
typedef struct moduleTag module; | |
extern void moduleInit(module * pModule); | |
#endif | |
1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
#include <stddef.h> | |
#include "module.h" | |
#include "Windows.h" | |
struct moduleTag | |
{ | |
HWND m_Handle; | |
}; | |
extern void moduleInit(module * pModule) | |
{ | |
pModule->m_Handle = NULL; | |
} | |
OOSMOS
defines three types of objects:
LinearRegression
class
in the
Examples
directory.OOSMOS
control loop. They also support the creation of an arbitrary number
of Object Threads (see the toggle
class
for an example).
sw
in the Classes
directory.OOSMOS
which
gives you the ability to nest states, specify state entry and exit code and
use orthogonal states also known as "and" states.
threads
example.)OOSMOS
is no
different in this respect. Traditionally, the main loop is
implemented inside the OS. In OOSMOS
, the main loop
is in user space in order to provide maximum control and visibility.
OOSMOS
can be used in one of two ways:
OOSMOS
objects to be.
oosmos_RunStateMachines
in a tight loop dedicating 100%
of the CPU to OOSMOS
objects. Your system will be
maximally responsive in this situation.
1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
extern int main(void) | |
{ | |
// | |
// Create objects, many of which will have state machines... | |
// | |
for (;;) { | |
oosmos_RunStateMachines(); | |
} | |
} | |
setup
and loop
callbacks.
1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
extern void setup() | |
{ | |
// | |
// Create objects, many of which will have state machines... | |
// | |
} | |
extern void loop() | |
{ | |
oosmos_RunStateMachines(); | |
} | |
OOSMOS
is run under another operating
system like Linux or Windows, it would be impolite to
consume 100% of the CPU. Instead, we periodically "take a small sip"
from the processor and then issue a wait for a period of time.
1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
extern int main(void) | |
{ | |
// | |
// Create objects, many of which will have state machines... | |
// | |
for (;;) { | |
oosmos_RunStateMachines(); | |
oosmos_DelayMS(1); | |
} | |
} | |
OOSMOS
uses a dynamic memory allocation scheme which
is ideal for memory constrained environments. It has the following attributes and benefits:
OOSMOS
object allocation.
In this example, we implement the "New
" function for the toggle
object. It behaves very much like the new
function in C++
,
except that we will orchestrate the allocation of memory; in C++
that is handled automatically by the language and run-time.
toggleNew
. Its job is to allocate an object of type
toggle
, then initialize the members of the object.
oosmos_Allocate
, which takes
four arguments:
pToggle
is the name of pointer variable that will be set to point to the allocated
object.toggle
is the type of the object to be allocated.toggleMAX
specifies the number of objects
to pre-allocate.OutOfMemory
which is set to NULL
in this example,
is the address of a subroutine to call if memory is exhausted. NULL
specifies that oosmos_Allocate
should loop forever when memory is exhausted.1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
15 | |
16 | |
19 | |
20 | |
21 | |
22 | |
#ifndef toggleMAX | |
#define toggleMAX 4 | |
#endif | |
extern toggle * toggleNew(pin * pPin, uint32_t TimeOnMS, uint32_t TimeOffMS) | |
{ | |
oosmos_Allocate(pToggle, toggle, toggleMAX, NULL); | |
[State Machine Initialization]... | |
[Member Initialization]... | |
return pToggle; | |
} | |
oosmos_Allocate
with a
call to malloc
instead. Then you would also want to
create a toggleDelete
function in your object's interface
that accepts the object pointer
as the only argument and then calls free
.
OOSMOS
Object Threads allow you to
program much like you would when using an RTOS thread. That is,
in a natural, sequential manner.
LED
s
all at different rates using RTOS threads,
you'd likely create a thread per LED so you could write the following
natural pseudo-code:
1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
for (;;) { | |
pinOn(MyPin); | |
delay(OnTime); | |
pinOff(MyPin); | |
delay(OffTime); | |
} | |
LED
s.
OOSMOS
object threads, you can
program in a similarly natural way
but without the memory and processor overhead that comes with using
RTOS threads and their stacks. Take a look at lines
45-59 below
(from the toggle
class) to
see how you can do the same thing in OOSMOS with an object thread.
1 | |
---|---|
22 | |
23 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
[GPLv2] | |
[...] | |
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(); | |
} | |
protothreads
by
Adam Dunkels.
Running
, Initializing
,
Connecting
; that is, words that
end in ing
. There are also states that will reflect a physical
reality. For example, On
, Moving
,
Latched
, or Open
.
Ready
and an inner state
called Injecting
.
1 | |
---|---|
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
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 | |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | |
104 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | |
119 | |
120 | |
121 | |
122 | |
123 | |
124 | |
125 | |
126 | |
127 | |
[GPLv2] | |
#include "oosmos.h" | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
typedef struct testTag test; | |
typedef struct { | |
uint32_t m_BlinkCount; | |
} sBlink_Data; | |
struct testTag | |
{ | |
//>>>DECL | |
[Generated by OOSMOS] | |
//<<<DECL | |
sBlink_Data Blink_Data; | |
}; | |
static void BlinkThread(oosmos_sState * pState, sBlink_Data * pData) | |
{ | |
oosmos_ThreadBegin(); | |
for (;;) { | |
printf("Blink...\n"); | |
oosmos_ThreadDelayMS(500); | |
pData->m_BlinkCount += 1; | |
} | |
oosmos_ThreadEnd(); | |
} | |
static void BeepThread(oosmos_sState * pState) | |
{ | |
oosmos_ThreadBegin(); | |
for (;;) { | |
printf("Beep...\n"); | |
oosmos_ThreadDelayMS(1500); | |
} | |
oosmos_ThreadEnd(); | |
} | |
//>>>CODE | |
[Generated by OOSMOS] | |
//<<<CODE | |
static test * testNew(void) | |
{ | |
oosmos_Allocate(pTest, test, 1, NULL); | |
pTest->Blink_Data.m_BlinkCount = 0; | |
//>>>INIT | |
[Generated by OOSMOS] | |
//<<<INIT | |
return pTest; | |
} | |
extern int main(void) | |
{ | |
testNew(); | |
printf("Press CNTL-C to stop.\n\n"); | |
for (;;) { | |
oosmos_RunStateMachines(); | |
oosmos_DelayMS(1); | |
} | |
} |
OOSMOS
Thread APIs are:
1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
oosmos_ThreadBegin() | |
oosmos_ThreadDelayUS() | |
oosmos_ThreadDelayMS() | |
oosmos_ThreadDelaySeconds() | |
oosmos_ThreadWaitCond() | |
oosmos_ThreadWaitCond_TimeoutMS() | |
oosmos_ThreadWaitEvent() | |
oosmos_ThreadWaitEvent_TimeoutMS() | |
oosmos_ThreadYield() | |
oosmos_ThreadExit() | |
oosmos_ThreadFinally() | |
oosmos_ThreadEnd() | |
threads
on the
Examples page to see an example usage
of each one.
pState
argument from the event handling function must be passed to the thread and
it must be called pState
.oosmos_ThreadBegin
and oosmos_ThreadEnd
calls.matrix
class.switch
statements can be used inside the oosmos_ThreadBegin
and oosmos_ThreadEnd
calls. Use if/then/else
instead.oosmos/Tests/History.uxf
) oosmos/Tests
directory and then build and run the History.exe
executable. Following
the state chart above, press and release the s
key to exercise the shallow history logic. Press and
release the d
key to run the deep history logic. Pressing the q
key ends the program.
OOSMOS
, like oosmos_TIMEOUT
and
oosmos_ENTER
. Then there are events
that you create as you draw transitions in your state charts.
These events may be generated internally (e.g. oosmos_PushEventCode(pObject, evCode)
,
or generated by event publishers that you may have subscribed to. For example, you can subscribe to the
Open
and/or Close
events of a switch object.
A switch object publishes Open
and Close
events
to its subscribers.
(See the switch example).
OOSMOS
predefines six events that it generates internally. The
following sections explain what each of them does, along with
an example.
Final
state.
1 | |
---|---|
22 | |
23 | |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
[GPLv2] | |
[...] | |
static bool Ortho_State_Code(void * pObject, oosmos_sState * pState, const oosmos_sEvent * pEvent) | |
{ | |
test * pTest = (test *) pObject; | |
switch (oosmos_EventCode(pEvent)) { | |
case oosmos_COMPLETE: { | |
return oosmos_Transition(pTest, pState, Complete_State); | |
} | |
} | |
return false; | |
} | |
[...] |
oosmos_ENTER
event is generated once on entry to a
state.
toggle
class:
1 | |
---|---|
22 | |
23 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
[GPLv2] | |
[...] | |
static bool Off_State_Code(void * pObject, oosmos_sState * pState, const oosmos_sEvent * pEvent) | |
{ | |
toggle * pToggle = (toggle *) pObject; | |
switch (oosmos_EventCode(pEvent)) { | |
case oosmos_ENTER: { | |
return oosmos_StateTimeoutMS(pState, (uint32_t) pToggle->m_TimeOffMS); | |
} | |
case oosmos_TIMEOUT: { | |
return oosmos_Transition(pToggle, pState, On_State); | |
} | |
} | |
[...] |
oosmos_EXIT
event is generated once on exit from
a state.
toggle
class:
1 | |
---|---|
22 | |
23 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
[GPLv2] | |
[...] | |
static bool On_State_Code(void * pObject, oosmos_sState * pState, const oosmos_sEvent * pEvent) | |
{ | |
toggle * pToggle = (toggle *) pObject; | |
switch (oosmos_EventCode(pEvent)) { | |
case oosmos_ENTER: { | |
pinOn(pToggle->m_pPin); | |
return oosmos_StateTimeoutMS(pState, (uint32_t) pToggle->m_TimeOnMS); | |
} | |
case oosmos_EXIT: { | |
pinOff(pToggle->m_pPin); | |
return true; | |
} | |
case oosmos_TIMEOUT: { | |
return oosmos_Transition(pToggle, pState, Off_State); | |
} | |
} | |
return false; | |
} | |
[...] |
State Thread
s, we suggest that you use a function name
that ends in Thread
. Otherwise, we suggest that
the function name end with Poll
.
1 | |
---|---|
22 | |
23 | |
144 | |
145 | |
146 | |
147 | |
148 | |
149 | |
150 | |
151 | |
152 | |
153 | |
154 | |
155 | |
156 | |
157 | |
158 | |
159 | |
160 | |
161 | |
162 | |
[GPLv2] | |
[...] | |
static bool Ortho_State_Code(void * pObject, oosmos_sState * pState, const oosmos_sEvent * pEvent) | |
{ | |
test * pTest = (test *) pObject; | |
switch (oosmos_EventCode(pEvent)) { | |
case oosmos_POLL: { | |
OrthoPoll(pTest); | |
if (CheckCounts(pTest)) { | |
return oosmos_Transition(pTest, pState, TestNullTransitionWithPoll_State); | |
} | |
return true; | |
} | |
} | |
return false; | |
} | |
[...] |
oosmos_TIMEOUT
event is generated when the state's
timeout has expired. You must establish the state's timeout upon
entry to the state as shown in line 54 of code Snippet
4 below.
toggle
class:
1 | |
---|---|
22 | |
23 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
[GPLv2] | |
[...] | |
static bool Off_State_Code(void * pObject, oosmos_sState * pState, const oosmos_sEvent * pEvent) | |
{ | |
toggle * pToggle = (toggle *) pObject; | |
switch (oosmos_EventCode(pEvent)) { | |
case oosmos_ENTER: { | |
return oosmos_StateTimeoutMS(pState, (uint32_t) pToggle->m_TimeOffMS); | |
} | |
case oosmos_TIMEOUT: { | |
return oosmos_Transition(pToggle, pState, On_State); | |
} | |
} | |
return false; | |
} | |
[...] |
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 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | |
73 | |
74 | |
75 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
235 | |
236 | |
237 | |
238 | |
239 | |
240 | |
241 | |
242 | |
243 | |
244 | |
245 | |
246 | |
247 | |
248 | |
249 | |
250 | |
251 | |
252 | |
253 | |
254 | |
255 | |
256 | |
257 | |
258 | |
259 | |
260 | |
261 | |
262 | |
263 | |
264 | |
265 | |
266 | |
267 | |
268 | |
269 | |
270 | |
271 | |
272 | |
273 | |
274 | |
275 | |
276 | |
277 | |
278 | |
279 | |
280 | |
293 | |
294 | |
295 | |
296 | |
[GPLv2] | |
#include "oosmos.h" | |
#include "control.h" | |
#include "motor.h" | |
#include "pump.h" | |
#include "pin.h" | |
#include "sw.h" | |
#include <stdbool.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
//>>>EVENTS | |
enum { | |
evMovePressed = 1, | |
evOption1Pressed = 2, | |
evOption2Pressed = 3, | |
evPumpPressed = 4, | |
evQuitPressed = 5, | |
evStopPressed = 6, | |
evStopReleased = 7 | |
}; | |
[Debug Support...] | |
//<<<EVENTS | |
typedef union { | |
oosmos_sEvent Event; | |
} uEvents; | |
struct controlTag | |
{ | |
motor * m_pMotor; | |
pump * m_pPump; | |
bool m_Option1; | |
bool m_Option2; | |
//>>>DECL | |
[Code Generated by OOSMOS] | |
//<<<DECL | |
}; | |
static void ToggleOption1(control * pControl) | |
{ | |
pControl->m_Option1 = !(pControl->m_Option1); | |
oosmos_DebugPrint("Option1: %d\n", pControl->m_Option1); | |
} | |
static void ToggleOption2(control * pControl) | |
{ | |
pControl->m_Option2 = !(pControl->m_Option2); | |
oosmos_DebugPrint("Option2: %d\n", pControl->m_Option1); | |
} | |
//>>>CODE | |
[Code Generated by OOSMOS] | |
//<<<CODE | |
extern control * controlNew(void) | |
{ | |
oosmos_Allocate(pControl, control, 1, NULL); | |
oosmos_sQueue * const pControlEventQueue = &pControl->m_EventQueue; | |
pin * pStopPin = pinNew('s', pinActiveHigh); | |
sw * pStopSwitch = swNew(pStopPin); | |
swSubscribeCloseEvent(pStopSwitch, pControlEventQueue, evStopPressed, NULL); | |
swSubscribeOpenEvent(pStopSwitch, pControlEventQueue, evStopReleased, NULL); | |
pin * pMovePin = pinNew('m', pinActiveHigh); | |
sw * pMoveSwitch = swNew(pMovePin); | |
swSubscribeCloseEvent(pMoveSwitch, pControlEventQueue, evMovePressed, NULL); | |
pin * pQuitPin = pinNew('q', pinActiveHigh); | |
sw * pQuitSwitch = swNew(pQuitPin); | |
swSubscribeCloseEvent(pQuitSwitch, pControlEventQueue, evQuitPressed, NULL); | |
pin * pPumpPin = pinNew('p', pinActiveHigh); | |
sw * pPumpSwitch = swNew(pPumpPin); | |
swSubscribeCloseEvent(pPumpSwitch, pControlEventQueue, evPumpPressed, NULL); | |
pin * pOption1Pin = pinNew('1', pinActiveHigh); | |
sw * pOption1Switch = swNew(pOption1Pin); | |
swSubscribeCloseEvent(pOption1Switch, pControlEventQueue, evOption1Pressed, NULL); | |
pin * pOption2Pin = pinNew('2', pinActiveHigh); | |
sw * pOption2Switch = swNew(pOption2Pin); | |
swSubscribeCloseEvent(pOption2Switch, pControlEventQueue, evOption2Pressed, NULL); | |
pin * pUpPin = pinNew('u', pinActiveHigh); | |
sw * pUpSwitch = swNew(pUpPin); | |
pin * pDownPin = pinNew('d', pinActiveHigh); | |
sw * pDownSwitch = swNew(pDownPin); | |
pControl->m_pMotor = motorNew(); | |
pControl->m_pPump = pumpNew(pUpSwitch, pDownSwitch); | |
pControl->m_Option1 = false; | |
pControl->m_Option2 = false; | |
//>>>INIT | |
[Code Generated by OOSMOS] | |
//<<<INIT | |
return pControl; | |
} |
OOSMOS
uses queues to serialize work for an object and
supports two types of queues: Event queues
and Work queues.
OOSMOS
to post events to an object's state machine. The state machine
reacts to events based on the current state. If the current
state (or any of its parents) does not handle the event, the event
is thrown away. This is a fundamental difference between
event queues and work queues.
btn
object).
OOSMOS
does nothing implicitly; you push the
work and pop it when your logic dictates.
OOSMOS
main loop runs the UART object's state machine.
(See oosmos/Classes/PIC32/uart.c
.)
pumpOn()
is called when the pump is in the Pumping
state, the call will have no effect.
1 | |
---|---|
22 | |
23 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | |
119 | |
140 | |
141 | |
142 | |
143 | |
144 | |
145 | |
146 | |
147 | |
148 | |
149 | |
[GPLv2] | |
[...] | |
static bool Idle_State_Code(void * pObject, oosmos_sState * pState, const oosmos_sEvent * pEvent) | |
{ | |
pump * pPump = (pump *) pObject; | |
switch (oosmos_EventCode(pEvent)) { | |
case evStart: { | |
return oosmos_Transition(pPump, pState, Pumping_State); | |
} | |
} | |
return false; | |
} | |
static bool Pumping_State_Code(void * pObject, oosmos_sState * pState, const oosmos_sEvent * pEvent) | |
{ | |
pump * pPump = (pump *) pObject; | |
switch (oosmos_EventCode(pEvent)) { | |
case oosmos_POLL: { | |
Thread(pPump, pState); | |
return true; | |
} | |
case evUpPressed: { | |
pPump->PumpSpeed = oosmos_Min(10, pPump->PumpSpeed+1); | |
return true; | |
} | |
case evDownPressed: { | |
pPump->PumpSpeed = oosmos_Max(1, pPump->PumpSpeed-1); | |
return true; | |
} | |
case evStop: { | |
return oosmos_Transition(pPump, pState, Idle_State); | |
} | |
} | |
return false; | |
} | |
{...} | |
extern void pumpOn(const pump * pPump) | |
{ | |
oosmos_PushEventCode(pPump, evStart); | |
} | |
extern void pumpOff(const pump * pPump) | |
{ | |
oosmos_PushEventCode(pPump, evStop); | |
} |
OOSMOS
is a library; possibly one of many libraries in an application. Therefore
it is important that OOSMOS
not pollute the global namespace.
Accordingly, we prefix each externally visible name with either
oosmos_
or OOSMOS_
. Names that
start with oosmos_
are part of the formal user-facing API. Names that
begin with OOSMOS_
are names that are part of the internal
private API and should not be used directly by your applications, as they may
someday change or be removed.
oosmos\LINT
, run lint-oosmos.py
to LINT only
OOSMOS, and lint-all.py
to LINT OOSMOS as well as the examples and
tests.
oosmos-user.lnt
file to run against your code to limit LINT
messages to only your code and not OOSMOS.
oosmos.h
and oosmos.c
, and is around 1700 lines of
code combined.
1 | |
---|---|
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
> cloc oosmos.h oosmos.c | |
github.com/AlDanial/cloc v 1.80 T=0.50 s (4.0 files/s, 4702.0 lines/s) | |
------------------------------------------------------------------------------------ | |
File blank comment code | |
------------------------------------------------------------------------------------ | |
oosmos\source\oosmos.c 337 107 1184 | |
oosmos\source\oosmos.h 134 121 468 | |
------------------------------------------------------------------------------------ | |
SUM: 471 228 1652 | |
------------------------------------------------------------------------------------ | |