gv_fsm 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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: {}