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.
LEDs
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); | |
| } | |
LEDs.
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 Threads, 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 | |
| ------------------------------------------------------------------------------------ | |