gv_fsm 0.0.1 → 0.0.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.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/bin/gv_fsm +3 -11
  3. data/lib/gv_fsm.rb +78 -58
  4. data/lib/templates.rb +136 -132
  5. data/lib/version.rb +3 -0
  6. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e22ea784bd92deabd21520f674e347e1edbebcdb3f1acba0256b62994c97a0f
4
- data.tar.gz: ab0a2f310beed50a681582ce1b64fd32edb49ab5329150e7f152dbd8d6e99daf
3
+ metadata.gz: 1d793e3f46c8098f7fd5a5e9cdac035fc19ab6fb744886775dbc1e7a7757398c
4
+ data.tar.gz: bc16702d154fddd02a2c774b0f651ada1ece6e1e76cc9845e64dfbbb3811aba9
5
5
  SHA512:
6
- metadata.gz: 9ee624e62959b91f95cf9d5ac3aa02a7172424f8738ea615bb8193aec2631a6a4d31354c60a9958470f9198105406c65f3658c3191d60c345ec0a4a799c76abe
7
- data.tar.gz: da45ed138e0ae9d2f54937614ad91bd903aeac8b352761eb0c996b8888ad2079a73b280c09a4185d3dadde6d60fb4045723fd8156d589abd6ce535dfe8b6a8ae
6
+ metadata.gz: d06e75af4f4d1c3d1ebf2d80293d60cceae9a75859ddeaef11e44b02bab4829b248071805174d15f5818767f3ee04164ac573174cb39a76db55d196cf649ba11
7
+ data.tar.gz: bea055285d64501305796e2fb0d49d9a5e915f52facc45224c7eace99d801ebd5f4cc7b4a39e88587b262f779c250dac651beb7235826d2fb445aaca03cf2b3a
data/bin/gv_fsm CHANGED
@@ -2,18 +2,10 @@
2
2
 
3
3
  require "gv_fsm"
4
4
 
5
- SM = FSM.new(ARGV[0])
5
+ SM = GV_FSM::FSM.new(ARGV[0])
6
6
  SM.project_name = "test project"
7
7
  SM.description = "FSM designed to test the generator"
8
- SM.cname = "test_fsm"
9
8
 
10
- File.open("#{SM.cname}.h", "w") do |f|
11
- f.puts ERB.new(Templates::HEADER, 0, "<>").result
12
- f.puts ERB.new(Templates::HH, 0, "<>").result
13
- end
14
-
15
- File.open("#{SM.cname}.c", "w") do |f|
16
- f.puts ERB.new(Templates::HEADER, 0, "<>").result
17
- f.puts ERB.new(Templates::CC, 0, "<>").result
18
- end
9
+ SM.generate_h
10
+ SM.generate_c
19
11
 
@@ -3,78 +3,98 @@
3
3
  require 'ruby-graphviz'
4
4
  require 'erb'
5
5
 
6
- require './templates.rb'
6
+ require File.expand_path('../templates.rb', __FILE__)
7
+ require File.expand_path("../version.rb", __FILE__)
7
8
 
8
- class FSM
9
- attr_reader :states, :transitions, :dotfile
10
- attr_accessor :project_name, :description, :cname
9
+ module GV_FSM
10
+ class FSM
11
+ attr_reader :states, :transitions, :dotfile
12
+ attr_accessor :project_name, :description, :cname
13
+ include GV_FSM::Templates
11
14
 
12
- def initialize(filename)
13
- parse(filename)
14
- end
15
+ def initialize(filename)
16
+ raise ArgumentError, "File must be in .dot format" unless File.extname(filename) == ".dot"
17
+ @cname = File.basename(filename, ".dot")
18
+ parse(filename)
19
+ end
15
20
 
16
- def parse(filename)
17
- @dotfile = filename
18
- @states = []
19
- @transitions = []
20
- GraphViz.parse(filename) do |g|
21
- g.each_node do |id|
22
- n = g.get_node(id)
23
- label = n[:label].source.empty? ? "do_#{id}" : n[:label].source
24
- @states << {id: id, function: label}
25
- end
26
- g.each_edge do |e|
27
- from = e.node_one
28
- to = e.node_two
29
- case e[:label].source
30
- when ""
31
- label = nil
32
- when /[#]/
33
- label = "#{from}_to_#{to}"
34
- else
35
- label = e[:label].source
21
+ def parse(filename)
22
+ @dotfile = filename
23
+ @states = []
24
+ @transitions = []
25
+ GraphViz.parse(filename) do |g|
26
+ g.each_node do |id|
27
+ n = g.get_node(id)
28
+ label = n[:label].source.empty? ? "do_#{id}" : n[:label].source
29
+ @states << {id: id, function: label}
30
+ end
31
+ g.each_edge do |e|
32
+ from = e.node_one
33
+ to = e.node_two
34
+ case e[:label].source
35
+ when ""
36
+ label = nil
37
+ when /[#]/
38
+ label = "#{from}_to_#{to}"
39
+ else
40
+ label = e[:label].source
41
+ end
42
+ @transitions << {from: from, to: to, function: label}
36
43
  end
37
- @transitions << {from: from, to: to, function: label}
38
44
  end
39
45
  end
40
- end
41
46
 
42
- def state_functions_list
43
- @states.map {|s| s[:function]}
44
- end
47
+ def state_functions_list
48
+ @states.map {|s| s[:function]}
49
+ end
45
50
 
46
- def states_list
47
- @states.map {|s| s[:id]}
48
- end
51
+ def states_list
52
+ @states.map {|s| s[:id]}
53
+ end
54
+
55
+ def transition_functions_list
56
+ lst = []
57
+ @transitions.each do |t|
58
+ if !lst.include? t[:function] then
59
+ lst << (t[:function] or "NULL")
60
+ end
61
+ end
62
+ return lst
63
+ end
49
64
 
50
- def transition_functions_list
51
- lst = []
52
- @transitions.each do |t|
53
- if !lst.include? t[:function] then
54
- lst << (t[:function] or "NULL")
65
+ def transitions_map
66
+ idx = {}
67
+ map = Array.new(@states.count)
68
+ map.map! {|e| e = Array.new(@states.count, "NULL")}
69
+ states_list.each_with_index {|s, i| idx[s] = i }
70
+ @transitions.each do |t|
71
+ map[idx[t[:from]]][idx[t[:to]]] = (t[:function] or "NULL")
55
72
  end
73
+ map
74
+ end
75
+
76
+ def destinations
77
+ dest = Hash[states_list.map {|x| [x, []]}]
78
+ @transitions.each do |t|
79
+ dest[t[:from]] = [] unless dest[t[:from]]
80
+ dest[t[:from]] << t[:to]
81
+ end
82
+ return dest
56
83
  end
57
- return lst
58
- end
59
84
 
60
- def transitions_map
61
- idx = {}
62
- map = Array.new(@states.count)
63
- map.map! {|e| e = Array.new(@states.count, "NULL")}
64
- states_list.each_with_index {|s, i| idx[s] = i }
65
- @transitions.each do |t|
66
- map[idx[t[:from]]][idx[t[:to]]] = (t[:function] or "NULL")
85
+ def generate_c(filename = @cname)
86
+ File.open("#{filename}.c", "w") do |f|
87
+ f.puts ERB.new(HEADER, 0, "<>").result(binding)
88
+ f.puts ERB.new(CC, 0, "<>").result(binding)
89
+ end
67
90
  end
68
- map
69
- end
70
91
 
71
- def destinations
72
- dest = Hash[states_list.map {|x| [x, []]}]
73
- @transitions.each do |t|
74
- dest[t[:from]] = [] unless dest[t[:from]]
75
- dest[t[:from]] << t[:to]
92
+ def generate_h(filename = @cname)
93
+ File.open("#{filename}.h", "w") do |f|
94
+ f.puts ERB.new(HEADER, 0, "<>").result(binding)
95
+ f.puts ERB.new(HH, 0, "<>").result(binding)
96
+ end
76
97
  end
77
- return dest
78
98
  end
79
- end
80
99
 
100
+ end
@@ -1,136 +1,140 @@
1
1
 
2
- module Templates
3
- HEADER =<<~EOHEADER
4
- // Finite State Machine
5
- // Project: <%= SM.project_name or SM.dotfile %>
6
- // Description: <%= SM.description or "<none given>" %>
7
- //
8
- // Generation date: <%= Time.now %>
9
- // Generated from: <%= SM.dotfile %>
10
- // The finite state machine has:
11
- // <%= SM.states.count %> states
12
- // <%= SM.transitions.count %> transitions
13
-
14
- EOHEADER
15
-
16
- HH =<<~EOH
17
- #ifndef <%= SM.cname.upcase %>_H
18
- #define <%= SM.cname.upcase %>_H
19
- #include <stdlib.h>
20
-
21
- // List of states
22
- typedef enum {
23
- <% SM.states.each_with_index do |s, i| %>
24
- STATE_<%= s[:id].upcase %><%= i == 0 ? " = 0" : "" %>,
25
- <% end %>
26
- NUM_STATES,
27
- NO_CHANGE
28
- } state_t;
29
-
30
- const char *state_names[] = {<%= SM.states_list.map {|sn| '"'+sn+'"'}.join(", ") %>};
31
-
32
- // State function and state transition prototypes
33
- typedef state_t state_func_t(void *data);
34
- typedef void transition_func_t(void *data);
35
-
36
- // state functions
37
- <% SM.states.each do |s| %>
38
- state_t <%= s[:function] %>(void *data);
39
- <% end %>
40
-
41
- // transition functions
42
- <% SM.transition_functions_list.each do |t| %>
43
- <% next if t == "NULL" %>
44
- void <%= t %>(void *data);
45
- <% end %>
46
-
47
- // List of state functions
48
- state_func_t *const state_table[NUM_STATES] = {
49
- <%= SM.state_functions_list.join(",\n ")%>
50
- };
51
-
52
- // Table of transition functions
53
- transition_func_t *const transition_table[NUM_STATES][NUM_STATES] = {
54
- <% sl = SM.states_list %>
55
- <% fw = SM.transition_functions_list.max {|a, b| a.length <=> b.length}.length %>
56
- <% sw = SM.states_list.max {|a, b| a.length <=> b.length}.length %>
57
- /* <%= "states:".ljust(sw) %> <%= sl.map {|e| e.ljust(fw) }.join(", ") %> */
58
- <% SM.transitions_map.each_with_index do |l, i| %>
59
- /* <%= sl[i].ljust(sw) %> */ {<%= l.map {|e| e.ljust(fw)}.join(", ") %>},
60
- <% end %>
61
- };
62
-
63
- // state manager
64
- state_t run_state(state_t cur_state, void *data);
65
-
66
- #endif
67
- EOH
68
-
69
- CC =<<~EOC
70
- #include <syslog.h>
71
- #include "<%= SM.cname %>.h"
72
-
73
- // State functions
74
- <% dest = SM.destinations.dup %>
75
- <% SM.states.each do |s| %>
76
- <% stable = true if dest[s[:id]].include? s[:id] %>
77
- <% dest[s[:id]].map! {|n| "STATE_"+n.upcase} %>
78
- <% if dest[s[:id]].empty? or stable then
79
- dest[s[:id]].unshift "NO_CHANGE"
80
- end %>
81
- state_t <%= s[:function] %>(void *data) {
82
- state_t next_state = <%= dest[s[:id]].first %>;
83
-
84
- syslog(LOG_INFO, "[FSM] In state <%= s[:id] %>");
85
- /* Your code here */
2
+ module GV_FSM
3
+ module Templates
4
+ HEADER =<<~EOHEADER
5
+ // Finite State Machine
6
+ // Project: <%= self.project_name or self.dotfile %>
7
+ // Description: <%= self.description or "<none given>" %>
8
+ //
9
+ // Generated by gv_fsm ruby gem, see https://rubygems.org/gems/gv_fsm
10
+ // gv_fsm version <%= GV_FSM::VERSION %>
11
+ // Generation date: <%= Time.now %>
12
+ // Generated from: <%= self.dotfile %>
13
+ // The finite state machine has:
14
+ // <%= self.states.count %> states
15
+ // <%= self.transitions.count %> transitions
16
+
17
+ EOHEADER
18
+
19
+ HH =<<~EOH
20
+ #ifndef <%= self.cname.upcase %>_H
21
+ #define <%= self.cname.upcase %>_H
22
+ #include <stdlib.h>
23
+
24
+ // List of states
25
+ typedef enum {
26
+ <% self.states.each_with_index do |s, i| %>
27
+ STATE_<%= s[:id].upcase %><%= i == 0 ? " = 0" : "" %>,
28
+ <% end %>
29
+ NUM_STATES,
30
+ NO_CHANGE
31
+ } state_t;
32
+
33
+ const char *state_names[] = {<%= self.states_list.map {|sn| '"'+sn+'"'}.join(", ") %>};
34
+
35
+ // State function and state transition prototypes
36
+ typedef state_t state_func_t(void *data);
37
+ typedef void transition_func_t(void *data);
38
+
39
+ // state functions
40
+ <% self.states.each do |s| %>
41
+ state_t <%= s[:function] %>(void *data);
42
+ <% end %>
43
+
44
+ // transition functions
45
+ <% self.transition_functions_list.each do |t| %>
46
+ <% next if t == "NULL" %>
47
+ void <%= t %>(void *data);
48
+ <% end %>
49
+
50
+ // List of state functions
51
+ state_func_t *const state_table[NUM_STATES] = {
52
+ <%= self.state_functions_list.join(",\n ")%>
53
+ };
54
+
55
+ // Table of transition functions
56
+ transition_func_t *const transition_table[NUM_STATES][NUM_STATES] = {
57
+ <% sl = self.states_list %>
58
+ <% fw = self.transition_functions_list.max {|a, b| a.length <=> b.length}.length %>
59
+ <% sw = self.states_list.max {|a, b| a.length <=> b.length}.length %>
60
+ /* <%= "states:".ljust(sw) %> <%= sl.map {|e| e.ljust(fw) }.join(", ") %> */
61
+ <% self.transitions_map.each_with_index do |l, i| %>
62
+ /* <%= sl[i].ljust(sw) %> */ {<%= l.map {|e| e.ljust(fw)}.join(", ") %>},
63
+ <% end %>
64
+ };
65
+
66
+ // state manager
67
+ state_t run_state(state_t cur_state, void *data);
86
68
 
87
- // valid return states: <%= dest[s[:id]].join(", ") %>
88
- switch (next_state) {
89
- <% dest[s[:id]].each do |str| %>
90
- case <%= str %>:
91
- <% end %>
92
- break;
93
- default:
94
- syslog(LOG_WARNING, "[FSM] Cannot pass from <%= s[:id] %> to %s, remaining in this state", state_names[next_state]);
95
- next_state = NO_CHANGE;
69
+ #endif
70
+ EOH
71
+
72
+ CC =<<~EOC
73
+ #include <syslog.h>
74
+ #include "<%= self.cname %>.h"
75
+
76
+ // State functions
77
+ <% dest = self.destinations.dup %>
78
+ <% self.states.each do |s| %>
79
+ <% stable = true if dest[s[:id]].include? s[:id] %>
80
+ <% dest[s[:id]].map! {|n| "STATE_"+n.upcase} %>
81
+ <% if dest[s[:id]].empty? or stable then
82
+ dest[s[:id]].unshift "NO_CHANGE"
83
+ end %>
84
+ state_t <%= s[:function] %>(void *data) {
85
+ state_t next_state = <%= dest[s[:id]].first %>;
86
+
87
+ syslog(LOG_INFO, "[FSM] In state <%= s[:id] %>");
88
+ /* Your code here */
89
+
90
+ // valid return states: <%= dest[s[:id]].join(", ") %>
91
+ switch (next_state) {
92
+ <% dest[s[:id]].each do |str| %>
93
+ case <%= str %>:
94
+ <% end %>
95
+ break;
96
+ default:
97
+ syslog(LOG_WARNING, "[FSM] Cannot pass from <%= s[:id] %> to %s, remaining in this state", state_names[next_state]);
98
+ next_state = NO_CHANGE;
99
+ }
100
+ return next_state;
101
+ }
102
+
103
+ <% end %>
104
+
105
+ // Transition functions
106
+ <% self.transition_functions_list.each do |t| %>
107
+ <% next if t == "NULL" %>
108
+ void <%= t %>(void *data) {
109
+ syslog(LOG_INFO, "[FSM] State transition <%= t %>");
110
+ /* Your code here */
111
+ }
112
+
113
+ <% end %>
114
+
115
+ // State manager
116
+ state_t run_state(state_t cur_state, void *data) {
117
+ state_t new_state = state_table[cur_state](data);
118
+ transition_func_t *transition = transition_table[cur_state][new_state];
119
+ if (transition)
120
+ transition(data);
121
+ return new_state == NO_CHANGE ? cur_state : new_state;
122
+ };
123
+
124
+
125
+ #ifdef TEST_MAIN
126
+ #include <unistd.h>
127
+ int main() {
128
+ state_t cur_state = STATE_INIT;
129
+ openlog("SM", LOG_PID | LOG_PERROR, LOG_USER);
130
+ syslog(LOG_INFO, "Starting SM");
131
+ do {
132
+ cur_state = run_state(cur_state, NULL);
133
+ sleep(1);
134
+ } while (cur_state != STATE_STOP);
135
+ return 0;
96
136
  }
97
- return next_state;
98
- }
99
-
100
- <% end %>
101
-
102
- // Transition functions
103
- <% SM.transition_functions_list.each do |t| %>
104
- <% next if t == "NULL" %>
105
- void <%= t %>(void *data) {
106
- syslog(LOG_INFO, "[FSM] State transition <%= t %>");
107
- /* Your code here */
108
- }
109
-
110
- <% end %>
111
-
112
- // State manager
113
- state_t run_state(state_t cur_state, void *data) {
114
- state_t new_state = state_table[cur_state](data);
115
- transition_func_t *transition = transition_table[cur_state][new_state];
116
- if (transition)
117
- transition(data);
118
- return new_state == NO_CHANGE ? cur_state : new_state;
119
- };
120
-
121
-
122
- #ifdef TEST_MAIN
123
- #include <unistd.h>
124
- int main() {
125
- state_t cur_state = STATE_INIT;
126
- openlog("SM", LOG_PID | LOG_PERROR, LOG_USER);
127
- syslog(LOG_INFO, "Starting SM");
128
- do {
129
- cur_state = run_state(cur_state, NULL);
130
- sleep(1);
131
- } while (cur_state != STATE_STOP);
132
- return 0;
133
- }
134
- #endif
135
- EOC
137
+ #endif
138
+ EOC
139
+ end
136
140
  end
@@ -0,0 +1,3 @@
1
+ module GV_FSM
2
+ VERSION = "0.0.2"
3
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gv_fsm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paolo Bosetti
@@ -35,7 +35,8 @@ files:
35
35
  - bin/gv_fsm
36
36
  - lib/gv_fsm.rb
37
37
  - lib/templates.rb
38
- homepage: https://rubygems.org/gems/gv_fsm
38
+ - lib/version.rb
39
+ homepage: https://github.com/pbosetti/gv_fsm
39
40
  licenses:
40
41
  - MIT
41
42
  metadata: {}