-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathtiny_hsm.c
More file actions
123 lines (98 loc) · 2.7 KB
/
tiny_hsm.c
File metadata and controls
123 lines (98 loc) · 2.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*!
* @file
* @brief
*/
#include <stddef.h>
#include "tiny_hsm.h"
#define top NULL
static tiny_hsm_state_t parent_of(tiny_hsm_t* self, tiny_hsm_state_t child)
{
for(uint8_t i = 0; i < self->configuration->state_count; i++) {
if(self->configuration->states[i].state == child) {
return self->configuration->states[i].parent;
}
}
return top;
}
static uint8_t distance_between(tiny_hsm_t* self, tiny_hsm_state_t child, tiny_hsm_state_t parent)
{
uint8_t distance = 0;
tiny_hsm_state_t current = child;
while(current != parent) {
distance++;
current = parent_of(self, current);
}
return distance;
}
static tiny_hsm_state_t nth_parent(tiny_hsm_t* self, tiny_hsm_state_t state, uint8_t n)
{
tiny_hsm_state_t current = state;
for(uint8_t i = 0; i < n; i++) {
current = parent_of(self, current);
}
return current;
}
static void send_entries(tiny_hsm_t* self, tiny_hsm_state_t after, tiny_hsm_state_t to)
{
if(after == to) {
return;
}
for(uint8_t n = (uint8_t)(distance_between(self, to, after) - 1); n > 0; n--) {
nth_parent(self, to, n)(self, tiny_hsm_signal_entry, NULL);
}
to(self, tiny_hsm_signal_entry, NULL);
}
static void send_exits(tiny_hsm_t* self, tiny_hsm_state_t from, tiny_hsm_state_t before)
{
tiny_hsm_state_t current = from;
while(current != before) {
current(self, tiny_hsm_signal_exit, NULL);
current = parent_of(self, current);
}
}
static tiny_hsm_state_t nearest_common_ancestor_of(tiny_hsm_t* self, tiny_hsm_state_t a, tiny_hsm_state_t b)
{
while(a != top) {
tiny_hsm_state_t bb = b;
while(bb != top) {
if(a == bb) {
return a;
}
bb = parent_of(self, bb);
}
a = parent_of(self, a);
}
return top;
}
void tiny_hsm_init(
tiny_hsm_t* self,
const tiny_hsm_configuration_t* configuration,
tiny_hsm_state_t initial)
{
self->configuration = configuration;
self->current = initial;
send_entries(self, NULL, initial);
}
void tiny_hsm_send_signal(tiny_hsm_t* self, tiny_hsm_signal_t signal, const void* data)
{
tiny_hsm_state_t current = self->current;
while(current != top) {
if(current(self, signal, data) == tiny_hsm_result_signal_consumed) {
return;
}
current = parent_of(self, current);
}
}
void tiny_hsm_transition(tiny_hsm_t* self, tiny_hsm_state_t target)
{
if(self->current == target) {
self->current(self, tiny_hsm_signal_exit, NULL);
self->current(self, tiny_hsm_signal_entry, NULL);
}
else {
tiny_hsm_state_t nearest_common_ancestor = nearest_common_ancestor_of(self, self->current, target);
send_exits(self, self->current, nearest_common_ancestor);
self->current = target;
send_entries(self, nearest_common_ancestor, target);
}
}