gv_fsm 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/bin/gv_fsm +19 -0
  3. data/lib/gv_fsm.rb +80 -0
  4. data/lib/templates.rb +136 -0
  5. metadata +61 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6e22ea784bd92deabd21520f674e347e1edbebcdb3f1acba0256b62994c97a0f
4
+ data.tar.gz: ab0a2f310beed50a681582ce1b64fd32edb49ab5329150e7f152dbd8d6e99daf
5
+ SHA512:
6
+ metadata.gz: 9ee624e62959b91f95cf9d5ac3aa02a7172424f8738ea615bb8193aec2631a6a4d31354c60a9958470f9198105406c65f3658c3191d60c345ec0a4a799c76abe
7
+ data.tar.gz: da45ed138e0ae9d2f54937614ad91bd903aeac8b352761eb0c996b8888ad2079a73b280c09a4185d3dadde6d60fb4045723fd8156d589abd6ce535dfe8b6a8ae
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "gv_fsm"
4
+
5
+ SM = FSM.new(ARGV[0])
6
+ SM.project_name = "test project"
7
+ SM.description = "FSM designed to test the generator"
8
+ SM.cname = "test_fsm"
9
+
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
19
+
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ruby-graphviz'
4
+ require 'erb'
5
+
6
+ require './templates.rb'
7
+
8
+ class FSM
9
+ attr_reader :states, :transitions, :dotfile
10
+ attr_accessor :project_name, :description, :cname
11
+
12
+ def initialize(filename)
13
+ parse(filename)
14
+ end
15
+
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
36
+ end
37
+ @transitions << {from: from, to: to, function: label}
38
+ end
39
+ end
40
+ end
41
+
42
+ def state_functions_list
43
+ @states.map {|s| s[:function]}
44
+ end
45
+
46
+ def states_list
47
+ @states.map {|s| s[:id]}
48
+ end
49
+
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")
55
+ end
56
+ end
57
+ return lst
58
+ end
59
+
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")
67
+ end
68
+ map
69
+ end
70
+
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]
76
+ end
77
+ return dest
78
+ end
79
+ end
80
+
@@ -0,0 +1,136 @@
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 */
86
+
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;
96
+ }
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
136
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gv_fsm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Paolo Bosetti
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-08-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ruby-graphviz
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.2.5
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.2.5
27
+ description: A C/C++ code generator that creates code for a finite state machine given
28
+ a description in graphviz language.
29
+ email: paolo.bosetti@unitn.it
30
+ executables:
31
+ - gv_fsm
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - bin/gv_fsm
36
+ - lib/gv_fsm.rb
37
+ - lib/templates.rb
38
+ homepage: https://rubygems.org/gems/gv_fsm
39
+ licenses:
40
+ - MIT
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.1.2
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: Graphviz to Finite state machine
61
+ test_files: []