Skip to content

Commit

Permalink
Merge pull request #3 from nhjschulz/development
Browse files Browse the repository at this point in the history
CFSM: resolves #1 Add user instance data
  • Loading branch information
nhjschulz authored Feb 17, 2024
2 parents ee174a8 + 12da756 commit 4b8b024
Show file tree
Hide file tree
Showing 18 changed files with 251 additions and 146 deletions.
17 changes: 17 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ project(CFSM
HOMEPAGE_URL "https://github.com/nhjschulz/cfsm"
)

# ******************************************************************************
# Build CFSM as a static link library which is used by example code.
# ******************************************************************************

add_library(cfsm
src/c_fsm.c
)
Expand All @@ -22,6 +26,19 @@ target_include_directories(cfsm
PUBLIC "src"
)

# ******************************************************************************
# Enable strict compiler warnings
# ******************************************************************************

if (MSVC)
# warning level 4
add_compile_options(/W4)
else()
# additional warnings
add_compile_options(-Wall -Wextra -Wpedantic)
endif()


set (CFSM_EXAMPLE_MARIO_SRC
"examples/mario/main.c"
"examples/mario/mario.c"
Expand Down
53 changes: 34 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,25 +58,34 @@ There are operations to execute
Each of these operations is represented as a function pointer in the CFSM
context data structure. CFSM takes care about calling leave and enter
operations during a state transition. The cyclic process and event signaling
gets triggered by the application through CFSM public API. The CFSM context
structure definition is:
gets triggered by the application through CFSM public API.

A void pointer called ```ctxPtr``` is part of the context in addition to
the operation function pointers. This pointer is set by ```cfm_init()``` and
can be used in an application specific way. FSM does not use it by itself.
The ```ctxPtr``` is intended to support multiple FSM instances with the same
handler functions. The handlers can use the pointer to access instance
specific data.

The CFSM context structure definition is:

```c
typedef void (*cfsm_TransitionFunction)(struct cfsm_Fsm * fsm);
typedef void (*cfsm_EventFunction)(struct cfsm_Fsm * fsm, int eventId);
typedef void (*cfsm_ProcessFunction)(struct cfsm_Fsm * fsm);
typedef void (*cfsm_TransitionFunction)(struct cfsm_Ctx * fsm);
typedef void (*cfsm_EventFunction)(struct cfsm_Ctx * fsm, int eventId);
typedef void (*cfsm_ProcessFunction)(struct cfsm_Ctx * fsm);
typedef void *cfsm_InstanceDataPtr;

/** CFSM context operations */
typedef struct cfsm_Fsm {
typedef struct cfsm_Ctx {
cfsm_InstanceDataPtr ctxPtr; /**< context instance data */
cfsm_TransitionFunction onEnter; /**< operation run on enter */
cfsm_TransitionFunction onLeave; /**< operation run on leave */
cfsm_ProcessFunction onProcess; /**< cyclic operations */
cfsm_EventFunction onEvent; /**< report event to the state */
} cfsm_Fsm;
} cfsm_Ctx;

```
Notes:
* All operations in a state are optional, with the exception of the enter
operation. A state that cannot be entered is pointless.
Expand All @@ -98,12 +107,12 @@ to also update the context function pointers. Below is an example of a
set of function that define a SuperMario state:
```c
static void SuperMario_onProcess(cfsm_Fsm * fsm) { /* ... */}
static void SuperMario_onLeave(cfsm_Fsm * fsm) { /* ... */}
static void SuperMario_onEvent(cfsm_Fsm * fsm, int eventId) { /* ...*/}
static void SuperMario_onProcess(cfsm_Ctx * fsm) { /* ... */}
static void SuperMario_onLeave(cfsm_Ctx * fsm) { /* ... */}
static void SuperMario_onEvent(cfsm_Ctx * fsm, int eventId) { /* ...*/}
void SuperMario_onEnter(cfsm_Fsm * fsm)
void SuperMario_onEnter(cfsm_Ctx * fsm)
{
fsm->onProcess = SuperMario_onProcess;
fsm->onEvent = SuperMario_onEvent;
Expand Down Expand Up @@ -189,7 +198,7 @@ This is the example application component design:
### The Main function

The main function implements the game simulation loop. It owns
a CFSM instance as a local cfsm_Fsm structure called ``marioFsm``.
a CFSM instance as a local cfsm_Ctx structure called ``marioFsm``.

The CFSM setup phase consists of initializing ``marioFsm`` and
then transition to Mario's start state "SmallMario". The simplified
Expand All @@ -201,14 +210,20 @@ codes looks like this:

int main(int argc, char **argv)
{
cfsm_Fsm marioFsm;
cfsm_Ctx marioFsm;

cfsm_init(&marioFsm);
cfsm_init(&marioFsm, NULL);
cfsm_transition(&marioFsm, SmallMario_onEnter);

/* ... */
```
This example doesn't use instance data and passes NULL for it
in the call to ```cfsm_init()```. Instance data could be used to
extend the game to support multiple players by adding
a Luigi. We can then run two FSMs in parallel with the same
handlers.
Transitioning to the start state is done by providing the
enter operation handler for this state to the API function
``cfsm_transition()``. CFSM then calls the leave operation
Expand Down Expand Up @@ -307,7 +322,7 @@ and the only one that needs to be public. This is necessary to allow
other modules to transition into it.

```c
void SmallMario_onEnter(cfsm_Fsm * fsm)
void SmallMario_onEnter(cfsm_Ctx * fsm)
{
puts("SmallMario_onEnter()...");

Expand Down Expand Up @@ -346,7 +361,7 @@ according to the Mario state machine. We just print a line to indicate
to the user that we got called.
```c
static void SmallMario_onLeave(cfsm_Fsm * fsm)
static void SmallMario_onLeave(cfsm_Ctx * fsm)
{
puts("SmallMario_onLeave() ...");
}
Expand All @@ -364,7 +379,7 @@ the event operation handler. If your logic follows a polling model,
you likely implement this in the processing operation instead.

```c
static void SmallMario_onProcess(cfsm_Fsm * fsm)
static void SmallMario_onProcess(cfsm_Ctx * fsm)
{
puts("SmallMario_onProces(): It's me, Mario!");
}
Expand All @@ -387,7 +402,7 @@ monster case. Here we also need to decrease the number of lives
and eventually transition into dead Mario if no more are left.
```c
static void SmallMario_onEvent(cfsm_Fsm * fsm, int eventId)
static void SmallMario_onEvent(cfsm_Ctx * fsm, int eventId)
{
mario_updateCoins(eventId);
Expand Down
6 changes: 3 additions & 3 deletions doc/mario_classdiagram.puml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ package "Mario Example" {
}

package "CFSM" {
class cfsm_Fsm {
class cfsm_Ctx {
+cfsm_init()
+cfsm_transition( enterFunc: cfsm_TransitionFunction)
+cfsm_process()
Expand All @@ -57,7 +57,7 @@ package "CFSM" {
}
}

cfsm_Fsm -- Operations
cfsm_Ctx -- Operations
SuperMario .u-|> Operations
CapeMario .u-|> Operations
FireMario .u-|> Operations
Expand All @@ -67,7 +67,7 @@ SmallMario .u-|> Operations
states .> Mario : update

SmallMario <.. Main
Main ..> cfsm_Fsm : init as SmallMario\nprocessing and\n event signalling
Main ..> cfsm_Ctx : init as SmallMario\nprocessing and\n event signalling

MarioVariant .l. MarioData
MarioEvent .r. MarioData
Expand Down
6 changes: 4 additions & 2 deletions examples/mario/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,14 @@

int main(int argc, char **argv)
{
(void)argc;
(void)argv;

cfsm_Fsm marioFsm;
cfsm_Ctx marioFsm;

puts ("Mario cfsm example: \n");

cfsm_init(&marioFsm);
cfsm_init(&marioFsm, NULL);
cfsm_transition(&marioFsm, SmallMario_onEnter);

for(;;)
Expand Down
4 changes: 4 additions & 0 deletions examples/mario/mario.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ void mario_updateCoins(MarioEvent e)

case MONSTER:
break;

case QUIT:
case NOP:
break;
}

if (mario.coins > 5000)
Expand Down
17 changes: 10 additions & 7 deletions examples/mario/states/cape_mario.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@
* Prototypes
*****************************************************************************/

static void CapeMario_onEvent(cfsm_Fsm * state, int eventId);
static void CapeMario_onProcess(cfsm_Fsm * state);
static void CapeMario_onLeave(cfsm_Fsm * state);
static void CapeMario_onEvent(cfsm_Ctx * state, int eventId);
static void CapeMario_onProcess(cfsm_Ctx * state);
static void CapeMario_onLeave(cfsm_Ctx * state);

/******************************************************************************
* Variables
Expand All @@ -70,7 +70,7 @@ static void CapeMario_onLeave(cfsm_Fsm * state);
* External functions
*****************************************************************************/

void CapeMario_onEnter(cfsm_Fsm * fsm)
void CapeMario_onEnter(cfsm_Ctx * fsm)
{
puts("CapeMario_onEnter()...");

Expand All @@ -85,8 +85,9 @@ void CapeMario_onEnter(cfsm_Fsm * fsm)
* Local functions
*****************************************************************************/

static void CapeMario_onEvent(cfsm_Fsm * fsm, int eventId)
static void CapeMario_onEvent(cfsm_Ctx * fsm, int eventId)
{
(void)fsm;
mario_updateCoins(eventId);

switch(eventId)
Expand All @@ -109,13 +110,15 @@ static void CapeMario_onEvent(cfsm_Fsm * fsm, int eventId)
}
}

static void CapeMario_onProcess(cfsm_Fsm * fsm)
static void CapeMario_onProcess(cfsm_Ctx * fsm)
{
(void)fsm;
puts("CapeMario_onProces(): Look, I can fly!");
}

static void CapeMario_onLeave(cfsm_Fsm * fsm)
static void CapeMario_onLeave(cfsm_Ctx * fsm)
{
(void)fsm;
puts("CapeMario_onLeave() ...");
}

Expand Down
2 changes: 1 addition & 1 deletion examples/mario/states/cape_mario.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
/******************************************************************************
* Functions
*****************************************************************************/
void CapeMario_onEnter(cfsm_Fsm * state);
void CapeMario_onEnter(cfsm_Ctx * state);


#endif /* SUPER_MARIO_H */
Expand Down
7 changes: 4 additions & 3 deletions examples/mario/states/dead_mario.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
* Prototypes
*****************************************************************************/

static void DeadMario_onProcess(cfsm_Fsm * state);
static void DeadMario_onProcess(cfsm_Ctx * state);

/******************************************************************************
* Variables
Expand All @@ -64,7 +64,7 @@ static void DeadMario_onProcess(cfsm_Fsm * state);
* External functions
*****************************************************************************/

void DeadMario_onEnter(cfsm_Fsm * fsm)
void DeadMario_onEnter(cfsm_Ctx * fsm)
{
puts("DeadMario_onEnter()...");

Expand All @@ -77,8 +77,9 @@ void DeadMario_onEnter(cfsm_Fsm * fsm)
* Local functions
*****************************************************************************/

static void DeadMario_onProcess(cfsm_Fsm * fsm)
static void DeadMario_onProcess(cfsm_Ctx * fsm)
{
(void)fsm;
puts("DeadMario_onProces(): He's dead Jim!");
}

Expand Down
2 changes: 1 addition & 1 deletion examples/mario/states/dead_mario.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
/******************************************************************************
* Functions
*****************************************************************************/
void DeadMario_onEnter(cfsm_Fsm * state);
void DeadMario_onEnter(cfsm_Ctx * state);


#endif /* DEAD_MARIO_H */
Expand Down
18 changes: 11 additions & 7 deletions examples/mario/states/fire_mario.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@
* Prototypes
*****************************************************************************/

static void FireMario_onEvent(cfsm_Fsm * state, int eventId);
static void FireMario_onProcess(cfsm_Fsm * state);
static void FireMario_onLeave(cfsm_Fsm * state);
static void FireMario_onEvent(cfsm_Ctx * state, int eventId);
static void FireMario_onProcess(cfsm_Ctx * state);
static void FireMario_onLeave(cfsm_Ctx * state);

/******************************************************************************
* Variables
Expand All @@ -72,7 +72,7 @@ static void FireMario_onLeave(cfsm_Fsm * state);
* External functions
*****************************************************************************/

void FireMario_onEnter(cfsm_Fsm * fsm)
void FireMario_onEnter(cfsm_Ctx * fsm)
{
puts("FireMario_onEnter()...");

Expand All @@ -87,7 +87,7 @@ void FireMario_onEnter(cfsm_Fsm * fsm)
* Local functions
*****************************************************************************/

void FireMario_onEvent(cfsm_Fsm * fsm, int eventId)
void FireMario_onEvent(cfsm_Ctx * fsm, int eventId)
{
mario_updateCoins(eventId);

Expand All @@ -111,13 +111,17 @@ void FireMario_onEvent(cfsm_Fsm * fsm, int eventId)
}
}

void FireMario_onProcess(cfsm_Fsm * fsm)
void FireMario_onProcess(cfsm_Ctx * fsm)
{
(void)fsm;

puts("FireMario_onProces(): I throw fire balls!");
}

void FireMario_onLeave(cfsm_Fsm * fsm)
void FireMario_onLeave(cfsm_Ctx * fsm)
{
(void)fsm;

puts("FireMario_onLeave() ...");
}

Expand Down
2 changes: 1 addition & 1 deletion examples/mario/states/fire_mario.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
/******************************************************************************
* Functions
*****************************************************************************/
void FireMario_onEnter(cfsm_Fsm * state);
void FireMario_onEnter(cfsm_Ctx * state);


#endif /* FIRE_MARIO_H */
Expand Down
Loading

0 comments on commit 4b8b024

Please sign in to comment.