Module: GV_FSM::Templates

Included in:
FSM
Defined in:
lib/templates.rb

Constant Summary collapse

HEADER =

_ _ _ _ __ _ __

| | | | ____|  / \  |  _ \| ____|  _ \ 
| |_| |  _|   / _ \ | | | |  _| | |_) |
|  _  | |___ / ___ \| |_| | |___|  _ < 
|_| |_|_____/_/   \_\____/|_____|_| \_\
"/******************************************************************************\nFinite State Machine\nProject: <%= @project_name or @dotfile %>\nDescription: <%= @description or \"<none given>\" %>\n  \nGenerated by gv_fsm ruby gem, see https://rubygems.org/gems/gv_fsm\ngv_fsm version <%= GV_FSM::VERSION %>\nGeneration date: <%= Time.now %>\nGenerated from: <%= @dotfile %>\nThe finite state machine has:\n  <%= @states.count %> states\n  <%= transition_functions_list.select {|e| e != 'NULL'}.count %> transition functions\n<% if @prefix != '' %>\nFunctions and types have been generated with prefix \"<%= @prefix %>\"\n<% end %>\n******************************************************************************/\n\n"
HH =
"<% if !@ino then %>\n#ifndef <%= File::basename(@cname).upcase %>_H\n#define <%= File::basename(@cname).upcase %>_H\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#include <stdlib.h>\n<% else -%>\n#include <arduino.h>\n<% end -%>\n\n// State data object\n// By default set to void; override this typedef or load the proper\n// header if you need\ntypedef void <%= @prefix %>state_data_t;\n<% if !@ino then -%>\n\n// NOTHING SHALL BE CHANGED AFTER THIS LINE!\n<% end -%>\n\n// List of states\ntypedef enum {\n<% @states.each_with_index do |s, i| -%>\n  <%= @prefix.upcase %>STATE_<%= s[:id].upcase %><%= i == 0 ? \" = 0\" : \"\" %>,  \n<% end -%>\n  <%= @prefix.upcase %>NUM_STATES,\n  <%= @prefix.upcase %>NO_CHANGE\n} <%= @prefix %>state_t;\n\n// State human-readable names\nextern const char *<%= @prefix %>state_names[];\n\n<% if transition_functions_list.count > 0 then -%>\n// State function and state transition prototypes\ntypedef <%= @prefix %>state_t state_func_t(<%= @prefix %>state_data_t *data);\ntypedef void transition_func_t(<%= @prefix %>state_data_t *data);\n<% else -%>\n// State function prototype\ntypedef <%= @prefix %>state_t state_func_t(<%= @prefix %>state_data_t *data);\n<%end -%>\n\n// State functions\n<% dest = destinations.dup -%>\n<% @states.each do |s| -%>\n<% stable = true if dest[s[:id]].include? s[:id] -%>\n<% dest[s[:id]].map! {|n| (@prefix+\"STATE_\"+n).upcase} -%>\n<% if dest[s[:id]].empty? or stable then\n  dest[s[:id]].unshift @prefix.upcase+\"NO_CHANGE\"\nend -%>\n// Function to be executed in state <%= s[:id] %>\n// valid return states: <%= dest[s[:id]].join(\", \") %>\n<%= @prefix %>state_t <%= s[:function] %>(<%= @prefix %>state_data_t *data);\n<% end -%>\n\n\n// List of state functions\nextern state_func_t *const <%= @prefix %>state_table[<%= @prefix.upcase %>NUM_STATES];\n\n\n<% if transition_functions_list.count > 0 then -%>\n// Transition functions\n<% transition_functions_list.each do |t| -%>\n<% next if t == \"NULL\" -%>\nvoid <%= t %>(<%= @prefix %>state_data_t *data);\n<% end -%>\n\n// Table of transition functions\nextern transition_func_t *const <%= @prefix %>transition_table[<%= @prefix.upcase %>NUM_STATES][<%= @prefix.upcase %>NUM_STATES];\n<% else -%>\n// No transition functions\n<% end -%>\n\n// state manager\n<%= @prefix %>state_t <%= @prefix %>run_state(<%= @prefix %>state_t cur_state, <%= @prefix %>state_data_t *data);\n\n<% if !@ino then -%>\n#ifdef __cplusplus\n}\n#endif\n#endif // <%= File::basename(@cname).upcase %>_H\n<% end -%>\n"
CC =
"<% if !@ino then -%>\n<% if @syslog then -%>\n<% log = :syslog %>\n#include <syslog.h>\n<% end -%>\n<% else -%>\n<% if @syslog then log = :ino end -%>\n<% end -%>\n#include \"<%= File::basename(@cname) %>.h\"\n\n<% if sigint then %>// Install signal handler: \n// SIGINT requests a transition to state <%= self.sigint %>\n#include <signal.h>\nstatic int _exit_request = 0;\nstatic void signal_handler(int signal) {\n  if (signal == SIGINT) {\n_exit_request = 1;<% if log == :syslog then %>\nsyslog(LOG_WARNING, \"[FSM] SIGINT transition to <%= sigint %>\");<% elsif log == :ino then %>\nSerial.println(\"[FSM] SIGINT transition to <%= sigint %>\");<% end %>\n  }\n}\n\n<% end -%>\n<% placeholder = \"Your Code Here\" -%>\n// SEARCH FOR <%= placeholder %> FOR CODE INSERTION POINTS!\n\n// GLOBALS\n// State human-readable names\nconst char *<%= @prefix %>state_names[] = {<%= states_list.map {|sn| '\"'+sn+'\"'}.join(\", \") %>};\n\n// List of state functions\n<% fw = state_functions_list.max {|a, b| a.length <=> b.length}.length -%>\nstate_func_t *const <%= @prefix %>state_table[<%= @prefix.upcase %>NUM_STATES] = {\n<% @states.each do |s| -%>\n  <%= (s[:function] + ',').ljust(fw+1) %> // in state <%= s[:id] %>\n<% end -%>\n};\n<% if transition_functions_list.count > 0 then -%>\n\n// Table of transition functions\ntransition_func_t *const <%= @prefix %>transition_table[<%= @prefix.upcase %>NUM_STATES][<%= @prefix.upcase %>NUM_STATES] = {\n<% sl = states_list -%>\n<% fw = transition_functions_list.max {|a, b| a.length <=> b.length}.length -%>\n<% sw = [states_list, \"states:\"].flatten.max {|a, b| a.length <=> b.length}.length -%>\n  /* <%= \"states:\".ljust(sw) %>     <%= sl.map {|e| e.ljust(fw) }.join(\", \") %> */\n<% transitions_map.each_with_index do |l, i| -%>\n  /* <%= sl[i].ljust(sw) %> */ {<%= l.map {|e| e.ljust(fw)}.join(\", \") %>}, \n<% end -%>\n};\n<% else -%>\n// No transition functions\n<% end -%>\n\n/*  ____  _        _       \n * / ___|| |_ __ _| |_ ___ \n * \\\\___ \\\\| __/ _` | __/ _ \\\\\n *  ___) | || (_| | ||  __/\n * |____/ \\\\__\\\\__,_|\\\\__\\\\___|\n *                         \n *   __                  _   _                 \n *  / _|_   _ _ __   ___| |_(_) ___  _ __  ___ \n * | |_| | | | '_ \\\\ / __| __| |/ _ \\\\| '_ \\\\/ __|\n * |  _| |_| | | | | (__| |_| | (_) | | | \\\\__ \\\\\n * |_|  \\\\__,_|_| |_|\\\\___|\\\\__|_|\\\\___/|_| |_|___/\n */                                             \n<% dest = destinations.dup -%>\n<% topo = self.topology -%>\n<% @states.each do |s| -%>\n<% stable = true if dest[s[:id]].include? s[:id] -%>\n<% dest[s[:id]].map! {|n| (@prefix+\"STATE_\"+n).upcase} -%>\n<% if dest[s[:id]].empty? or stable then\n  dest[s[:id]].unshift @prefix.upcase+\"NO_CHANGE\"\nend %>\n// Function to be executed in state <%= s[:id] %>\n// valid return states: <%= dest[s[:id]].join(\", \") %>\n<% if sigint && stable && topo[:sources][0] != s[:id] then -%>\n// SIGINT triggers an emergency transition to <%= self.sigint %>\n<% end -%>\n<%= @prefix %>state_t <%= s[:function] %>(<%= @prefix %>state_data_t *data) {\n  <%= @prefix %>state_t next_state = <%= dest[s[:id]].first -%>;\n<% if sigint && topo[:sources][0] == s[:id] then -%>\n  signal(SIGINT, signal_handler); \n  <% end -%>\n<% if log == :syslog then -%>\n  syslog(LOG_INFO, \"[FSM] In state <%= s[:id] %>\");\n<% elsif log == :ino then -%>\n  Serial.println(\"[FSM] In state <%= s[:id] %>\");\n<% end -%>\n  /* <%= placeholder %> */\n  \n  switch (next_state) {\n<% dest[s[:id]].each  do |str| -%>\n  case <%= str %>:\n<% end -%>\nbreak;\n  default:\n<% if log == :syslog then -%>\nsyslog(LOG_WARNING, \"[FSM] Cannot pass from <%= s[:id] %> to %s, remaining in this state\", <%= @prefix %>state_names[next_state]);\n<% elsif log == :ino then -%>\nSerial.print(\"[FSM] Cannot pass from <%= s[:id] %> to \");\nSerial.print(<%= @prefix %>state_names[next_state]);\nSerial.println(\", remaining in this state\");\n<% end -%>\nnext_state = <%= @prefix.upcase %>NO_CHANGE;\n  }\n<% if sigint && stable && topo[:sources][0] != s[:id] then -%>\n  // SIGINT transition override\n  if (_exit_request) \nnext_state = <%= (@prefix+\"STATE_\"+self.sigint ).upcase %>;\n<% end %>\n  return next_state;\n}\n\n<% end %>\n\n<% if transition_functions_list.count > 0 then -%>\n/*  _____                    _ _   _              \n * |_   _| __ __ _ _ __  ___(_) |_(_) ___  _ __   \n *   | || '__/ _` | '_ \\\\/ __| | __| |/ _ \\\\| '_ \\\\\n *   | || | | (_| | | | \\\\__ \\\\ | |_| | (_) | | | | \n *   |_||_|  \\\\__,_|_| |_|___/_|\\\\__|_|\\\\___/|_| |_| \n *                                                \n *   __                  _   _                 \n *  / _|_   _ _ __   ___| |_(_) ___  _ __  ___ \n * | |_| | | | '_ \\\\ / __| __| |/ _ \\\\| '_ \\\\/ __|\n * |  _| |_| | | | | (__| |_| | (_) | | | \\\\__ \\\\\n * |_|  \\\\__,_|_| |_|\\\\___|\\\\__|_|\\\\___/|_| |_|___/\n */    \n                                      \n<% transition_functions_list.each do |t| -%>\n<% next if t == \"NULL\" -%>\n<% tpaths = transitions_paths[t] -%>\n// This function is called in <%= tpaths.count %> transition<%= tpaths.count == 1 ? '' : 's' %>:\n<% tpaths.each_with_index do |e, i| -%>\n// <%= i+1 %>. from <%= e[:from] %> to <%= e[:to] %>\n<% end -%>\nvoid <%= t %>(<%= @prefix %>state_data_t *data) {\n<% if log == :syslog then -%>\n  syslog(LOG_INFO, \"[FSM] State transition <%= t %>\");\n<% elsif log == :ino then -%>\n  Serial.println(\"[FSM] State transition <%= t %>\");\n<% end -%>\n  /* <%= placeholder %> */\n}\n\n<% end -%>\n<% end -%>\n\n/*  ____  _        _        \n * / ___|| |_ __ _| |_ ___  \n * \\\\___ \\\\| __/ _` | __/ _ \\\\\n *  ___) | || (_| | ||  __/ \n * |____/ \\\\__\\\\__,_|\\\\__\\\\___| \n *                          \n *                                              \n *  _ __ ___   __ _ _ __   __ _  __ _  ___ _ __ \n * | '_ ` _ \\\\ / _` | '_ \\\\ / _` |/ _` |/ _ \\\\ '__|\n * | | | | | | (_| | | | | (_| | (_| |  __/ |   \n * |_| |_| |_|\\\\__,_|_| |_|\\\\__,_|\\\\__, |\\\\___|_|   \n *                              |___/           \n */\n\n<%= @prefix %>state_t <%= @prefix %>run_state(<%= @prefix %>state_t cur_state, <%= @prefix %>state_data_t *data) {\n  <%= @prefix %>state_t new_state = <%= @prefix %>state_table[cur_state](data);\n  if (new_state == <%= @prefix.upcase %>NO_CHANGE) new_state = cur_state;\n<% if transition_functions_list.count > 0 then %>\n  transition_func_t *transition = <%= @prefix %>transition_table[cur_state][new_state];\n  if (transition)\ntransition(data);\n<% end %>\n  return new_state;\n};\n\n<% if @ino then %>\n/* Example usage:\n<%= @prefix %>state_data_t data = {count: 1};\n\nvoid loop() {\n  static <%= @prefix %>state_t cur_state = <%= @prefix.upcase %>STATE_INIT;\n  cur_state = <%= @prefix %>run_state(cur_state, &data);\n}\n*/\n<% else %>\n<% nsinks = topology[:sinks].count %>\n#ifdef TEST_MAIN\n#include <unistd.h>\nint main() {\n  <%= @prefix %>state_t cur_state = <%= @prefix.upcase %>STATE_<%= @states.first[:id].upcase %>;\n<% if @syslog then %>\n  openlog(\"SM\", LOG_PID | LOG_PERROR, LOG_USER);\n  syslog(LOG_INFO, \"Starting SM\");\n<% end %>\n  do {\ncur_state = <%= @prefix %>run_state(cur_state, NULL);\nsleep(1);\n<% if nsinks == 1 %>\n  } while (cur_state != <%= @prefix.upcase %>STATE_<%= topology[:sinks][0].upcase %>);\n  <%= @prefix %>run_state(cur_state, NULL);\n<% else %>\n  } while (1);\n<% end %>\n  return 0;\n}\n#endif\n<% end %>\n"
HPP =
"#ifndef <%= File::basename(@cname).upcase %>_HPP\n#define <%= File::basename(@cname).upcase %>_HPP\n#include <functional>\n#include <iostream>\n#include <map>\n#include <string>\n#include <tuple>\n<% if @syslog then -%>\n<% log = :syslog -%>\n#include <syslog.h>\n<% end -%>\n<% if sigint then -%>\n// Install signal handler: \n// SIGINT requests a transition to state <%= self.sigint %>\n#include <csignal>\n<% end %>\n\nusing namespace std::string_literals;\n<% ns = @project_name || \"FSM\" -%>\nnamespace <%= ns %> {\nstatic bool <%= self.sigint %>_requested = false;\n\n// List of states\ntypedef enum {\n<% @states.each do |s| -%>\n  <%= @prefix.upcase %>STATE_<%= s[:id].upcase %>,\n<% end -%>\n  <%= @prefix.upcase %>NUM_STATES,\n  <%= @prefix.upcase %>NO_CHANGE,\n  <%= @prefix.upcase %>UNIMPLEMENTED\n} <%= @prefix %>state_t;\n\n// State human-readable names\nstd::map<<%= @prefix %>state_t, char const *> state_names = {\n<% @states.each do |s| -%>\n  {<%= @prefix.upcase %>STATE_<%= s[:id].upcase %>, \"<%= s[:id].upcase %>\"},\n<% end -%>\n  {<%= @prefix.upcase %>NUM_STATES, \"NUM_STATES\"},\n  {<%= @prefix.upcase %>NO_CHANGE, \"NO_CHANGE\"},\n  {<%= @prefix.upcase %>UNIMPLEMENTED, \"UNIMPLEMENTED\"}\n};\n\n// Custom state functions:\n<% @states.each do |s| -%>\ntemplate<class T> \n<%= @prefix %>state_t <%= s[:function] %>(T &data);\n<% end -%>\n\n<% if transition_functions_list.count > 0 then -%>\n// Custom transition functions:\n<% transition_functions_list.each do |t| -%>\ntemplate<class T>\nvoid <%= t %>(T &data);\n<% end -%>\n<% end -%>\n\n// Finite State Machine class\ntemplate <typename DATA_T> \nclass FiniteStateMachine {\n\n// Function templates\nusing state_fun = std::function<<%= @prefix %>state_t(DATA_T &data)>;\nusing transition_fun = std::function<void(DATA_T &data)>;\nusing operation_fun = std::function<void(DATA_T &data)>;\n\nprivate:\n  std::pair<<%= @prefix %>state_t, <%= @prefix %>state_t> _state{<%= @prefix.upcase %>STATE_<%= states[0][:id].upcase %>, <%= @prefix.upcase %>STATE_<%= states[0][:id].upcase %>};\n  std::map<<%= @prefix %>state_t, state_fun> _states;\n  std::map<<%= @prefix %>state_t, std::map<<%= @prefix %>state_t, transition_fun>> _transitions;\n  std::function<void()> _timing_func;\n  DATA_T *_data;\n\npublic:\n\n  FiniteStateMachine(DATA_T *data) : _data(data) {\n    install_functions();\n  }\n  ~FiniteStateMachine(){};\n\n  void set_timing_function(std::function<void()> timing_func) {\n    _timing_func = timing_func;\n  }\n\n  void add_state(<%= @prefix %>state_t name, state_fun func) { _states[name] = func; }\n\n  void add_transition(<%= @prefix %>state_t from, <%= @prefix %>state_t to, transition_fun func) {\n    _transitions[from][to] = func;\n  }\n\n  inline <%= @prefix %>state_t state() { return _state.second; }\n  inline std::string state_name() { return std::string(state_names[_state.second]); }\n  inline <%= @prefix %>state_t prev_state() { return _state.first; }\n\n  <%= @prefix %>state_t operator()(<%= @prefix %>state_t state) {\n    if (_states.find(state) == _states.end()) {\n      throw std::runtime_error(\"State not found: \"s + state_names[state]);\n    }\n    state_t next = _states[state](*_data);\n    if (next == NO_CHANGE) {\n      next = state;\n    }\n    return next;\n  }\n\n  void operator()(<%= @prefix %>state_t from, <%= @prefix %>state_t to) {\n    if (_transitions.find(from) != _transitions.end()) {\n      if (_transitions[from].find(to) != _transitions[from].end()) {\n        _transitions[from][to](*_data);\n      }\n    }\n  }\n\n\n  // Setup initial state links\n  void setup(state_t state) {\n    <%= ns %>::<%= self.sigint %>_requested = false;\n    _state.first = state;\n    _state.second = state;\n  }\n\n  // Evaluate the current state and update the next state\n  // to be used when main loop is customized (i.e., not using FSM::run())\n  state_t eval_state() {\n      (*this)(_state.first, _state.second);\n      _state.first = _state.second;\n      _state.second = (*this)(_state.second);\n      return _state.second;\n  }\n\n  // Run the FSM from a given state\n  void run(<%= @prefix %>state_t state, operation_fun operation = nullptr) {\n    setup(state);\n<% if sigint then -%>\n    std::signal(SIGINT, [](int signum) {\n<% if log == :syslog then -%>\n      syslog(LOG_WARNING, \"[FSM] SIGINT transition to <%= sigint %>\");\n<% end -%>\n      <%= ns %>::<%= self.sigint %>_requested = true; \n    });\n<% end -%>\n    do {\n      if (operation) {\n        operation(*_data);\n      }\n      eval_state();\n      if (_timing_func) {\n        _timing_func();\n      }\n    } while (_state.second != <%= @prefix.upcase %>STATE_<%= topology[:sinks][0].upcase %>);\n    // Call the exit state once more:\n    (*this)(<%= @prefix.upcase %>STATE_<%= topology[:sinks][0].upcase %>);\n<% if sigint then -%>\n    std::signal(SIGINT, SIG_DFL);\n<% end -%>\n  }\n\n  // Run the FSM from the initial state\n  void run(operation_fun operation = nullptr) { run(<%= @prefix.upcase %>STATE_<%= states[0][:id].upcase %>, operation); }\n\n  // install state and transition functions\n  void install_functions() {\n\n    // State functions\n<% dest = destinations.dup -%>\n<% @states.each do |s| -%>\n<% stable = true if dest[s[:id]].include? s[:id] -%>\n<% dest[s[:id]].map! {|n| (@prefix+\"STATE_\"+n).upcase} -%>\n<% if dest[s[:id]].empty? or stable then\n    dest[s[:id]].unshift @prefix.upcase+\"NO_CHANGE\"\nend -%>\n    add_state(<%= ns %>::<%= @prefix.upcase %>STATE_<%= s[:id].upcase %>, [](DATA_T &data) -> <%= ns %>::<%= @prefix %>state_t {\n<% if log == :syslog then -%>\n      syslog(LOG_INFO, \"[FSM] In state <%= s[:id].upcase %>\");\n<% end -%>\n      <%= ns %>::<%= @prefix %>state_t next_state = <%= @prefix%>do_<%= s[:id] %>(data);\n    \n      switch (next_state) {\n      case <%= ns %>::<%= @prefix.upcase %>UNIMPLEMENTED:\n        throw std::runtime_error(\"State function not fully implemented: \"s + \"<%= s[:id].upcase %>\");\n        break;\n<% dest[s[:id]].each  do |str| -%>\n      case <%= ns %>::<%= str %>:\n<% end -%>\n        break;\n      default:\n<% if log == :syslog then -%>\n        syslog(LOG_WARNING, \"[FSM] Cannot pass from <%= s[:id] %> to %s, remaining in this state\", state_names[next_state]);\n<% end -%>\n        next_state = <%= ns %>::<%= @prefix.upcase %>NO_CHANGE;\n      }\n<% if sigint && stable && self.topology[:sources][0] != s[:id] then -%>\n      // SIGINT transition override\n      if (<%= self.sigint %>_requested) next_state = <%= (@prefix+\"STATE_\"+self.sigint ).upcase %>;\n<% end -%>\n      return next_state;\n    });\n\n<% end -%>\n\n<% if transition_functions_list.count > 0 then -%>\n    // Transition functions\n<% transition_functions_list.each do |t| -%>\n    add_transition(<%= @prefix.upcase %>STATE_<%= transitions_paths[t][0][:from].upcase %>, <%= @prefix.upcase %>STATE_<%= transitions_paths[t][0][:to].upcase %>, [](DATA_T &data) {\n<% if log == :syslog then -%>\n      syslog(LOG_INFO, \"[FSM] State transition <%= t %>\");\n<% end -%>\n      <%= t %>(data);\n    });\n\n<% end -%>\n<% end -%>\n  }\n\n}; // class FiniteStateMachine\n\n}; // namespace <%= @project_name || \"FSM\" %>\n\n#endif // <%= File::basename(@cname).upcase %>_HPP\n\n"
CPP =
"<% if @syslog then -%>\n<% log = :syslog -%>\n#include <syslog.h>\n<% end -%>\n#include \"<%= File::basename(@cname) %>.hpp\"\n    \nusing namespace std;\n<% ns = @project_name || \"FSM\" -%>\n    \n<% placeholder = \"Your Code Here\" %>\n// SEARCH FOR <%= placeholder %> FOR CODE INSERTION POINTS!\n\n\nnamespace <%= @project_name || \"FSM\" %> {\n\n/*  ____  _        _       \n * / ___|| |_ __ _| |_ ___ \n * \\\\___ \\\\| __/ _` | __/ _ \\\\\n *  ___) | || (_| | ||  __/\n * |____/ \\\\__\\\\__,_|\\\\__\\\\___|\n *                         \n *   __                  _   _                 \n *  / _|_   _ _ __   ___| |_(_) ___  _ __  ___ \n * | |_| | | | '_ \\\\ / __| __| |/ _ \\\\| '_ \\\\/ __|\n * |  _| |_| | | | | (__| |_| | (_) | | | \\\\__ \\\\\n * |_|  \\\\__,_|_| |_|\\\\___|\\\\__|_|\\\\___/|_| |_|___/\n */                                             \n<% dest = destinations.dup -%>\n<% topo = self.topology -%>\n<% @states.each do |s| -%>\n<% stable = true if dest[s[:id]].include? s[:id] -%>\n<% dest[s[:id]].map! {|n| (@prefix+\"STATE_\"+n).upcase} -%>\n<% if dest[s[:id]].empty? or stable then\n  dest[s[:id]].unshift @prefix.upcase+\"NO_CHANGE\"\nend %>\n// Function to be executed in state STATE_<%= s[:id].upcase %>\n// valid return states: <%= dest[s[:id]].join(\", \") %>\n<% if sigint && stable && topo[:sources][0] != s[:id] then -%>\n// SIGINT triggers an emergency transition to STATE_<%= self.sigint.upcase %>\n<% end -%>\ntemplate<class T> \n<%= @prefix %>state_t <%= s[:function] %>(T &data) {\n  <%= @prefix %>state_t next_state = <%= ns %>::<%= @prefix.upcase %>UNIMPLEMENTED;\n  /* <%= placeholder %> */\n  \n  return next_state;\n}\n<% end -%>\n\n\n<% if transition_functions_list.count > 0 then -%>\n/*  _____                    _ _   _              \n * |_   _| __ __ _ _ __  ___(_) |_(_) ___  _ __   \n *   | || '__/ _` | '_ \\\\/ __| | __| |/ _ \\\\| '_ \\\\\n *   | || | | (_| | | | \\\\__ \\\\ | |_| | (_) | | | | \n *   |_||_|  \\\\__,_|_| |_|___/_|\\\\__|_|\\\\___/|_| |_| \n *                                                \n *   __                  _   _                 \n *  / _|_   _ _ __   ___| |_(_) ___  _ __  ___ \n * | |_| | | | '_ \\\\ / __| __| |/ _ \\\\| '_ \\\\/ __|\n * |  _| |_| | | | | (__| |_| | (_) | | | \\\\__ \\\\\n * |_|  \\\\__,_|_| |_|\\\\___|\\\\__|_|\\\\___/|_| |_|___/\n */                                              \n\n<% transition_functions_list.each do |t| -%>\n<% next if t == \"NULL\" -%>\n<% tpaths = transitions_paths[t] -%>\n// This function is called in <%= tpaths.count %> transition<%= tpaths.count == 1 ? '' : 's' %>:\n<% tpaths.each_with_index do |e, i| -%>\n// <%= i+1 %>. from <%= e[:from] %> to <%= e[:to] %>\n<% end -%>\ntemplate<class T>\nvoid <%= t %>(T &data) {\n  /* <%= placeholder %> */\n}\n\n<% end -%>\n<% end -%>\n\n}; // namespace <%= @project_name || \"FSM\" %>\n\n\n<% nsinks = topology[:sinks].count -%>\n// Example usage:\n#ifdef TEST_MAIN\n#include <unistd.h>\n#include <thread>\n\nstruct Data {\n  int count;\n};\n\nint main() {\n  Data data = {1};\n  auto fsm = <%= ns %>::FiniteStateMachine(&data);\n  fsm.set_timing_function([]() {\n    std::this_thread::sleep_for(std::chrono::seconds(1));\n  });\n  fsm.run([&](Data &s) {\n    std::cout << \"State: \" << fsm.state() << \" data: \" << s.count << std::endl;\n  });\n  return 0;\n}\n#endif // TEST_MAIN\n"