gv_fsm 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/gv_fsm +39 -12
- data/lib/gv_fsm.rb +17 -3
- data/lib/templates.rb +47 -6
- data/lib/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3579818099a2f3e8d172c9534af08877f3e4b27f4fc09f9c9aa77c6275256ce3
|
4
|
+
data.tar.gz: 5b4acdd1da41b63fbac514f2a481766c5b5c08ba34881ef708d11871910e8d0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f481dacfc667927287eecc1b5f901fd915a593ab533b6de35f573e0cb1b66219c5cd37e24f9c54095e1049f8a7f3f67094530338a9c653cbb72585d1ccbcdf3
|
7
|
+
data.tar.gz: 4b835c1bc4f03a6d80e37f64f219b0801756ffaeeedbd7da20f53ffbc428b48efd92ac075c189b5379d30ef125ebaf4417e259b0729d1c9e9ac0a94db08b3e14
|
data/bin/gv_fsm
CHANGED
@@ -6,7 +6,7 @@ require 'optparse'
|
|
6
6
|
sm = GV_FSM::FSM.new
|
7
7
|
|
8
8
|
options = {header: true, source: true}
|
9
|
-
OptionParser.new do |parser|
|
9
|
+
op = OptionParser.new do |parser|
|
10
10
|
parser.banner =<<~EOB
|
11
11
|
Graphviz to Finite State Machine generator
|
12
12
|
Version: #{GV_FSM::VERSION}
|
@@ -40,21 +40,48 @@ OptionParser.new do |parser|
|
|
40
40
|
sm.prefix = p
|
41
41
|
end
|
42
42
|
|
43
|
-
|
43
|
+
parser.on("-i", "--ino", "Generate a single .ino file (for Arduino)") do
|
44
|
+
sm.ino = true
|
45
|
+
end
|
44
46
|
|
45
|
-
|
46
|
-
|
47
|
+
parser.on("-l", "--no-syslog", "Omit syslog calls in stub functions") do
|
48
|
+
sm.syslog = false
|
49
|
+
end
|
47
50
|
|
48
|
-
|
51
|
+
parser.on("-h", "--help", "Prints this help") do
|
52
|
+
puts parser
|
53
|
+
exit
|
54
|
+
end
|
49
55
|
|
50
|
-
puts "Parsed #{sm.dotfile}.\nGenerating C stub for states: #{sm.states_list.join(", ")}."
|
51
|
-
if options[:header] then
|
52
|
-
sm.generate_h
|
53
|
-
puts "Generated header #{sm.cname}.h"
|
54
56
|
end
|
55
|
-
|
56
|
-
|
57
|
-
|
57
|
+
|
58
|
+
op.parse!
|
59
|
+
|
60
|
+
unless ARGV[0]
|
61
|
+
STDERR.puts "ERROR: I need the path to a Graphviz file!\n\n"
|
62
|
+
STDERR.puts op
|
63
|
+
exit
|
64
|
+
end
|
65
|
+
unless File.extname(ARGV[0]) == ".dot"
|
66
|
+
STDERR.puts "ERROR: #{ARGV[0]} does not look like a Graphviz file!\n\n"
|
67
|
+
STDERR.puts op
|
68
|
+
exit
|
58
69
|
end
|
59
70
|
|
71
|
+
sm.parse(ARGV[0])
|
72
|
+
|
73
|
+
puts "Parsed #{sm.dotfile}.\nGenerating C stub for states: #{sm.states_list.join(", ")}."
|
74
|
+
if sm.ino then
|
75
|
+
sm.generate_ino
|
76
|
+
puts "Generated .ino file #{sm.cname}.ino"
|
77
|
+
else
|
78
|
+
if options[:header] then
|
79
|
+
sm.generate_h
|
80
|
+
puts "Generated header #{sm.cname}.h"
|
81
|
+
end
|
82
|
+
if options[:source] then
|
83
|
+
sm.generate_c
|
84
|
+
puts "Generated source #{sm.cname}.c"
|
85
|
+
end
|
86
|
+
end
|
60
87
|
|
data/lib/gv_fsm.rb
CHANGED
@@ -9,11 +9,13 @@ require File.expand_path("../version.rb", __FILE__)
|
|
9
9
|
module GV_FSM
|
10
10
|
class FSM
|
11
11
|
attr_reader :states, :transitions, :dotfile, :prefix
|
12
|
-
attr_accessor :project_name, :description, :cname
|
12
|
+
attr_accessor :project_name, :description, :cname, :syslog, :ino
|
13
13
|
include GV_FSM::Templates
|
14
14
|
|
15
15
|
def initialize(filename = nil)
|
16
16
|
@prefix = ""
|
17
|
+
@syslog = true
|
18
|
+
@ino = false
|
17
19
|
parse(filename) if filename
|
18
20
|
end
|
19
21
|
|
@@ -36,7 +38,10 @@ module GV_FSM
|
|
36
38
|
g.each_edge do |e|
|
37
39
|
from = e.node_one
|
38
40
|
to = e.node_two
|
39
|
-
|
41
|
+
unless e[:label] then
|
42
|
+
@transitions << {from: from, to: to, function: nil}
|
43
|
+
next
|
44
|
+
end
|
40
45
|
case e[:label].source
|
41
46
|
when ""
|
42
47
|
label = nil
|
@@ -61,7 +66,7 @@ module GV_FSM
|
|
61
66
|
def transition_functions_list
|
62
67
|
lst = []
|
63
68
|
@transitions.each do |t|
|
64
|
-
if !lst.include? t[:function] then
|
69
|
+
if t[:function] and !lst.include? t[:function] then
|
65
70
|
lst << (t[:function] or "NULL")
|
66
71
|
end
|
67
72
|
end
|
@@ -110,6 +115,15 @@ module GV_FSM
|
|
110
115
|
f.puts ERB.new(HH, 0, "<>").result(binding)
|
111
116
|
end
|
112
117
|
end
|
118
|
+
|
119
|
+
def generate_ino(filename=@cname)
|
120
|
+
@syslog = false
|
121
|
+
File.open("#{filename}.ino", "w") do |f|
|
122
|
+
f.puts ERB.new(HEADER, 0, "<>").result(binding)
|
123
|
+
f.puts ERB.new(HH, 0, "<>").result(binding)
|
124
|
+
f.puts ERB.new(CC, 0, "<>").result(binding)
|
125
|
+
end
|
126
|
+
end
|
113
127
|
end
|
114
128
|
|
115
129
|
end
|
data/lib/templates.rb
CHANGED
@@ -13,7 +13,6 @@ module GV_FSM
|
|
13
13
|
Generated from: <%= @dotfile %>
|
14
14
|
The finite state machine has:
|
15
15
|
<%= @states.count %> states
|
16
|
-
<%= @transitions.count %> transitions
|
17
16
|
<%= transition_functions_list.select {|e| e != 'NULL'}.count %> transition functions
|
18
17
|
<% if @prefix != '' %>
|
19
18
|
Functions and types have been generated with prefix "<%= @prefix %>"
|
@@ -23,16 +22,20 @@ module GV_FSM
|
|
23
22
|
EOHEADER
|
24
23
|
|
25
24
|
HH =<<~EOH
|
25
|
+
<% if !@ino then %>
|
26
26
|
#ifndef <%= @cname.upcase %>_H
|
27
27
|
#define <%= @cname.upcase %>_H
|
28
28
|
#include <stdlib.h>
|
29
|
+
<% end %>
|
29
30
|
|
30
31
|
// State data object
|
31
32
|
// By default set to void; override this typedef or load the proper
|
32
33
|
// header if you need
|
33
34
|
typedef void <%= @prefix %>state_data_t;
|
34
|
-
|
35
|
+
<% if !@ino then %>
|
36
|
+
|
35
37
|
// NOTHING SHALL BE CHANGED AFTER THIS LINE!
|
38
|
+
<% end %>
|
36
39
|
|
37
40
|
// List of states
|
38
41
|
typedef enum {
|
@@ -43,24 +46,41 @@ module GV_FSM
|
|
43
46
|
<%= @prefix.upcase %>NO_CHANGE
|
44
47
|
} <%= @prefix %>state_t;
|
45
48
|
|
49
|
+
// State human-readable names
|
46
50
|
const char *state_names[] = {<%= states_list.map {|sn| '"'+sn+'"'}.join(", ") %>};
|
47
|
-
|
51
|
+
|
52
|
+
<% if transition_functions_list.count > 0 then %>
|
48
53
|
// State function and state transition prototypes
|
49
54
|
typedef <%= @prefix %>state_t state_func_t(<%= @prefix %>state_data_t *data);
|
50
55
|
typedef void transition_func_t(<%= @prefix %>state_data_t *data);
|
56
|
+
<% else %>
|
57
|
+
// State function prototype
|
58
|
+
typedef <%= @prefix %>state_t state_func_t(<%= @prefix %>state_data_t *data);
|
59
|
+
<%end %>
|
51
60
|
|
52
61
|
// State functions
|
62
|
+
<% dest = destinations.dup %>
|
53
63
|
<% @states.each do |s| %>
|
64
|
+
<% stable = true if dest[s[:id]].include? s[:id] %>
|
65
|
+
<% dest[s[:id]].map! {|n| (@prefix+"STATE_"+n).upcase} %>
|
66
|
+
<% if dest[s[:id]].empty? or stable then
|
67
|
+
dest[s[:id]].unshift @prefix.upcase+"NO_CHANGE"
|
68
|
+
end %>
|
69
|
+
// Function to be executed in state <%= s[:id] %>
|
70
|
+
// valid return states: <%= dest[s[:id]].join(", ") %>
|
54
71
|
<%= @prefix %>state_t <%= s[:function] %>(<%= @prefix %>state_data_t *data);
|
55
72
|
<% end %>
|
56
73
|
|
74
|
+
|
57
75
|
// List of state functions
|
76
|
+
<% fw = state_functions_list.max {|a, b| a.length <=> b.length}.length %>
|
58
77
|
state_func_t *const <%= @prefix %>state_table[<%= @prefix.upcase %>NUM_STATES] = {
|
59
78
|
<% @states.each do |s| %>
|
60
|
-
<%= s[:function]
|
79
|
+
<%= (s[:function] + ',').ljust(fw+1) %> // in state <%= s[:id] %>
|
61
80
|
<% end %>
|
62
81
|
};
|
63
82
|
|
83
|
+
|
64
84
|
<% if transition_functions_list.count > 0 then %>
|
65
85
|
// Transition functions
|
66
86
|
<% transition_functions_list.each do |t| %>
|
@@ -85,12 +105,18 @@ module GV_FSM
|
|
85
105
|
// state manager
|
86
106
|
<%= @prefix %>state_t <%= @prefix %>run_state(<%= @prefix %>state_t cur_state, void *data);
|
87
107
|
|
108
|
+
<% if !@ino then %>
|
88
109
|
#endif
|
110
|
+
<% end %>
|
89
111
|
EOH
|
90
112
|
|
91
113
|
CC =<<~EOC
|
114
|
+
<% if !@ino then %>
|
115
|
+
<% if @syslog then %>
|
92
116
|
#include <syslog.h>
|
117
|
+
<% end %>
|
93
118
|
#include "<%= @cname %>.h"
|
119
|
+
<% end %>
|
94
120
|
|
95
121
|
<% placeholder = "Your Code Here" %>
|
96
122
|
// SEARCH FOR <%= placeholder %> FOR CODE INSERTION POINTS!
|
@@ -115,20 +141,24 @@ module GV_FSM
|
|
115
141
|
dest[s[:id]].unshift @prefix.upcase+"NO_CHANGE"
|
116
142
|
end %>
|
117
143
|
// Function to be executed in state <%= s[:id] %>
|
144
|
+
// valid return states: <%= dest[s[:id]].join(", ") %>
|
118
145
|
<%= @prefix %>state_t <%= s[:function] %>(<%= @prefix %>state_data_t *data) {
|
119
146
|
<%= @prefix %>state_t next_state = <%= dest[s[:id]].first %>;
|
120
147
|
|
148
|
+
<% if @syslog then %>
|
121
149
|
syslog(LOG_INFO, "[FSM] In state <%= s[:id] %>");
|
150
|
+
<% end %>
|
122
151
|
/* <%= placeholder %> */
|
123
152
|
|
124
|
-
// valid return states: <%= dest[s[:id]].join(", ") %>
|
125
153
|
switch (next_state) {
|
126
154
|
<% dest[s[:id]].each do |str| %>
|
127
155
|
case <%= str %>:
|
128
156
|
<% end %>
|
129
157
|
break;
|
130
158
|
default:
|
159
|
+
<% if @syslog then %>
|
131
160
|
syslog(LOG_WARNING, "[FSM] Cannot pass from <%= s[:id] %> to %s, remaining in this state", state_names[next_state]);
|
161
|
+
<% end %>
|
132
162
|
next_state = <%= @prefix.upcase %>NO_CHANGE;
|
133
163
|
}
|
134
164
|
return next_state;
|
@@ -158,7 +188,9 @@ module GV_FSM
|
|
158
188
|
// <%= i+1 %>. from <%= e[:from] %> to <%= e[:to] %>
|
159
189
|
<% end %>
|
160
190
|
void <%= t %>(<%= @prefix %>state_data_t *data) {
|
191
|
+
<% if @syslog then %>
|
161
192
|
syslog(LOG_INFO, "[FSM] State transition <%= t %>");
|
193
|
+
<% end %>
|
162
194
|
/* <%= placeholder %> */
|
163
195
|
}
|
164
196
|
|
@@ -188,20 +220,29 @@ module GV_FSM
|
|
188
220
|
return new_state == <%= @prefix.upcase %>NO_CHANGE ? cur_state : new_state;
|
189
221
|
};
|
190
222
|
|
191
|
-
|
223
|
+
<% if @ino then %>
|
224
|
+
/* Example usage:
|
225
|
+
<% else %>
|
192
226
|
#ifdef TEST_MAIN
|
193
227
|
#include <unistd.h>
|
194
228
|
int main() {
|
229
|
+
<% end %>
|
195
230
|
<%= @prefix %>state_t cur_state = <%= @prefix.upcase %>STATE_INIT;
|
231
|
+
<% if @syslog then %>
|
196
232
|
openlog("SM", LOG_PID | LOG_PERROR, LOG_USER);
|
197
233
|
syslog(LOG_INFO, "Starting SM");
|
234
|
+
<% end %>
|
198
235
|
do {
|
199
236
|
cur_state = <%= @prefix %>run_state(cur_state, NULL);
|
200
237
|
sleep(1);
|
201
238
|
} while (cur_state != <%= @prefix.upcase %>STATE_STOP);
|
239
|
+
<% if !@ino then %>
|
202
240
|
return 0;
|
203
241
|
}
|
204
242
|
#endif
|
243
|
+
<% else %>
|
244
|
+
*/
|
245
|
+
<% end %>
|
205
246
|
EOC
|
206
247
|
end
|
207
248
|
end
|
data/lib/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gv_fsm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paolo Bosetti
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-graphviz
|