Skip to content

Commit 69fa94f

Browse files
glenn-andrewsnashif
authored andcommitted
Samples: SMF: Add sample for SMF framework
This PR adds a sample demonstrating the use of the State Machine Framework (SMF) Instructions are in the README.rst for the sample. Miro Samek was contacted and gave approval to use the state diagram in this demo. Signed-off-by: Glenn Andrews <[email protected]>
1 parent 249159f commit 69fa94f

File tree

9 files changed

+605
-0
lines changed

9 files changed

+605
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
project(smf_hsm_psicc2)
7+
8+
target_sources(app PRIVATE
9+
src/main.c
10+
src/hsm_psicc2_console_cmds.c
11+
src/hsm_psicc2_thread.c
12+
)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
.. zephyr:code-sample:: smf_hsm_psicc2
2+
:name: Hierarchical State Machine Demo based on example from PSiCC2
3+
:relevant-api: smf
4+
5+
Implement an event-driven hierarchical state machine using State Machine Framework (SMF).
6+
7+
Overview
8+
********
9+
10+
This sample demonstrates the :ref:`State Machine Framework <smf>` subsystem.
11+
12+
Building and Running
13+
********************
14+
15+
It should be possible to build and run this sample on almost any board or emulator.
16+
17+
Building and Running for ST Disco L475 IOT01 (B-L475E-IOT01A)
18+
=============================================================
19+
The sample can be built and executed for the :ref:`disco_l475_iot1_board` as follows:
20+
21+
.. zephyr-app-commands::
22+
:zephyr-app: samples/subsys/smf/psicc2
23+
:board: disco_l475_iot1
24+
:goals: build flash
25+
:compact:
26+
27+
For other boards just replace the board name.
28+
29+
Instructions for Use
30+
====================
31+
This application implements the statechart shown in Figure 2.11 of
32+
Practical UML Statecharts in C/C++, 2nd Edition, by Miro Samek (PSiCC2). Ebook available from
33+
https://www.state-machine.com/psicc2 This demo was chosen as it contains all possible transition
34+
topologies up to four levels of state nesting and is used with permission of the author.
35+
36+
For each state, the entry, run, and exit actions are logged to the console, as well as logging
37+
when a state handles an event, or explicitly ignores it and passes it up to the parent state.
38+
39+
There are two shell commands defined for controlling the operation.
40+
41+
* ``psicc2 event <event>`` sends the event (from A to I) to the state machine. These correspond to
42+
events A through I in PSiCC2 Figure 2.11
43+
* ``psicc2 terminate`` sends the ``EVENT_TERMINATE`` event to terminate the state machine. There
44+
is no way to restart the state machine once terminated, and future events are ignored.
45+
46+
Comparison to PSiCC2 Output
47+
===========================
48+
Not all transitions modelled in UML may be supported by the :ref:`State Machine Framework <smf>`.
49+
Unsupported transitions may lead to results different to the example run of the application in
50+
PSiCC2 Section 2.3.15. The differences will not be listed here as it is hoped :ref:`SMF <smf>`
51+
will support these transitions in the future and the list would become outdated.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CONFIG_LOG=y
2+
CONFIG_SHELL=y
3+
4+
# Needed for boards that enable RTT backends for logging
5+
# e.g. nrf52840dk/nrf52840 and any others that enable it
6+
CONFIG_LOG_BACKEND_RTT=n
7+
8+
# Enable the state machine framework
9+
CONFIG_SMF=y
10+
CONFIG_SMF_ANCESTOR_SUPPORT=y
11+
CONFIG_SMF_INITIAL_TRANSITION=y
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
sample:
2+
name: SMF HSM PSiCC2 Demo
3+
common:
4+
tags:
5+
- smf
6+
integration_platforms:
7+
- native_sim
8+
harness: console
9+
harness_config:
10+
type: multi_line
11+
ordered: true
12+
regex:
13+
- ".*<inf> hsm_psicc2_thread: initial_entry.*"
14+
- ".*<inf> hsm_psicc2_thread: s_entry.*"
15+
- ".*<inf> hsm_psicc2_thread: s2_entry.*"
16+
- ".*<inf> hsm_psicc2_thread: s21_entry.*"
17+
- ".*<inf> hsm_psicc2_thread: s211_entry.*"
18+
tests:
19+
sample.smf.hsm_psicc2: {}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright (c) 2023 Glenn Andrews
3+
* State Machine example copyright (c) Miro Samek
4+
*
5+
* Implementation of the statechart in Figure 2.11 of
6+
* Practical UML Statecharts in C/C++, 2nd Edition by Miro Samek
7+
* https://www.state-machine.com/psicc2
8+
* Used with permission of the author.
9+
*
10+
* SPDX-License-Identifier: Apache-2.0
11+
*/
12+
13+
#include <zephyr/kernel.h>
14+
#include <zephyr/shell/shell.h>
15+
#include "hsm_psicc2_thread.h"
16+
#include <stdlib.h>
17+
#include <ctype.h>
18+
19+
static int cmd_hsm_psicc2_event(const struct shell *sh, size_t argc, char **argv)
20+
{
21+
struct hsm_psicc2_event event;
22+
int event_id = toupper(argv[1][0]);
23+
24+
switch (event_id) {
25+
case 'A':
26+
event.event_id = EVENT_A;
27+
break;
28+
case 'B':
29+
event.event_id = EVENT_B;
30+
break;
31+
case 'C':
32+
event.event_id = EVENT_C;
33+
break;
34+
case 'D':
35+
event.event_id = EVENT_D;
36+
break;
37+
case 'E':
38+
event.event_id = EVENT_E;
39+
break;
40+
case 'F':
41+
event.event_id = EVENT_F;
42+
break;
43+
case 'G':
44+
event.event_id = EVENT_G;
45+
break;
46+
case 'H':
47+
event.event_id = EVENT_H;
48+
break;
49+
case 'I':
50+
event.event_id = EVENT_I;
51+
break;
52+
default:
53+
shell_error(sh, "Invalid argument %s", argv[1]);
54+
return -1;
55+
}
56+
57+
int rc = k_msgq_put(&hsm_psicc2_msgq, &event, K_NO_WAIT);
58+
59+
if (rc == 0) {
60+
shell_print(sh, "Event %c posted", event_id);
61+
} else {
62+
shell_error(sh, "error posting event: %d", rc);
63+
}
64+
return rc;
65+
}
66+
67+
static int cmd_hsm_psicc2_terminate(const struct shell *sh, size_t argc, char **argv)
68+
{
69+
struct hsm_psicc2_event event = {.event_id = EVENT_TERMINATE};
70+
int rc = k_msgq_put(&hsm_psicc2_msgq, &event, K_NO_WAIT);
71+
72+
if (rc == 0) {
73+
shell_print(sh, "Terminate event posted");
74+
} else {
75+
shell_error(sh, "error posting terminate event: %d", rc);
76+
}
77+
return rc;
78+
}
79+
80+
/* Creating subcommands (level 1 command) array for command "demo". */
81+
SHELL_STATIC_SUBCMD_SET_CREATE(sub_hsm_psicc2,
82+
SHELL_CMD_ARG(event, NULL, "Send event to State Machine",
83+
cmd_hsm_psicc2_event, 2, 0),
84+
SHELL_CMD_ARG(terminate, NULL,
85+
"Send terminate event to State Machine",
86+
cmd_hsm_psicc2_terminate, 1, 0),
87+
SHELL_SUBCMD_SET_END);
88+
89+
/* Creating root (level 0) command "demo" */
90+
SHELL_CMD_REGISTER(hsm_psicc2, &sub_hsm_psicc2, "PSICC2 demo hierarchical state machine commands",
91+
NULL);

0 commit comments

Comments
 (0)