aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2020-01-28 06:37:38 +0100
committerNeels Hofmeyr <neels@hofmeyr.de>2020-03-03 15:36:27 +0100
commitce1b92ca06225795b187ad8b27e686c62753da19 (patch)
tree76eb9076e1b949a50f08e4253a670dcc16a98b93
parentb4052f640f42d8d18e0d7c15c7caa238c9683b7d (diff)
add contrib/new_fsm.py
-rwxr-xr-xcontrib/new_fsm.py208
1 files changed, 208 insertions, 0 deletions
diff --git a/contrib/new_fsm.py b/contrib/new_fsm.py
new file mode 100755
index 00000000..e584150c
--- /dev/null
+++ b/contrib/new_fsm.py
@@ -0,0 +1,208 @@
+#!/usr/bin/env python3
+import jinja2
+import sys
+
+def as_tuple(str_or_tuple):
+ if isinstance(str_or_tuple, str):
+ return (str_or_tuple,)
+ return tuple(str_or_tuple)
+
+class State:
+ def __init__(s, name, events, out_states, onenter=True):
+ s.name = name
+ s.const = name.upper()
+ s.events = as_tuple(events)
+ s.out_states = as_tuple(out_states)
+ s.onenter = onenter
+ def __eq__(s, name):
+ return s.name == name
+
+class Event:
+ def __init__(s, name):
+ s.name = name
+ s.const = name.upper()
+
+ def __eq__(s, name):
+ return s.name == name
+
+class FSM:
+ def NAME(s, name):
+ return '_'.join((s.prefix, name)).upper()
+
+ def name(s, name):
+ return '_'.join((s.prefix, name)).lower()
+
+ def state_const(s, name):
+ return s.NAME('ST_' + name)
+
+ def event_const(s, name):
+ return s.NAME('EV_' + name)
+
+ def __init__(s, prefix, priv, states, head=''):
+ s.head = head
+ s.prefix = prefix
+ s.priv = priv
+ s.states = states
+ for state in s.states:
+ state.const = s.state_const(state.name)
+
+ out_state_class_insts = []
+ for out_state in state.out_states:
+ out_state_class_insts.append(s.states[s.states.index(out_state)])
+ state.out_states = out_state_class_insts
+
+ s.events = []
+ for state in s.states:
+ state_event_class_insts = []
+ for event in state.events:
+ if event not in s.events:
+ ev = Event(event)
+ ev.const = s.event_const(event)
+ s.events.append(ev)
+ else:
+ ev = s.events[s.events.index(event)]
+ state_event_class_insts.append(ev)
+ state.events = state_event_class_insts
+
+ def to_c(s):
+ template = jinja2.Template(
+'''
+{{head}}
+#include <osmocom/core/utils.h>
+#include <osmocom/core/fsm.h>
+
+enum {{prefix}}_fsm_state {
+{% for state in states %} {{state.const}},
+{% endfor -%}
+};
+
+enum {{prefix}}_fsm_event {
+{% for event in events %} {{event.const}},
+{% endfor -%}
+};
+
+static const struct value_string {{prefix}}_fsm_event_names[] = {
+{% for event in events %} OSMO_VALUE_STRING({{event.const}}),
+{% endfor %} {}
+};
+
+static struct osmo_fsm {{prefix}}_fsm;
+
+struct {{priv}} *{{prefix}}_alloc(struct osmo_fsm_inst *parent_fi, uint32_t parent_event_term)
+{
+ struct {{priv}} *{{priv}};
+
+ struct osmo_fsm_inst *fi = osmo_fsm_inst_alloc_child(&{{prefix}}_fsm, parent_fi, parent_event_term);
+ OSMO_ASSERT(fi);
+
+ {{priv}} = talloc(fi, struct {{priv}});
+ OSMO_ASSERT({{priv}});
+ fi->priv = {{priv}};
+ *{{priv}} = (struct {{priv}}){
+ .fi = fi,
+ };
+
+ return {{priv}};
+}
+
+static int {{prefix}}_fsm_timer_cb(struct osmo_fsm_inst *fi)
+{
+ //struct {{priv}} *{{priv}} = fi->priv;
+ /* Return 1 to terminate FSM instance, 0 to keep running */
+ return 1;
+}
+{% for state in states %}
+{%- if state.onenter %}
+void {{prefix}}_{{state.name}}_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ //struct {{priv}} *{{priv}} = fi->priv;
+ // FIXME
+}
+{% endif %}
+static void {{prefix}}_{{state.name}}_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ //struct {{priv}} *{{priv}} = fi->priv;
+
+ switch (event) {
+ {% for event in state.events %}
+ case {{event.const}}:
+ // FIXME
+ break;
+ {% endfor %}
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+{% endfor %}
+#define S(x) (1 << (x))
+
+static const struct osmo_fsm_state {{prefix}}_fsm_states[] = {
+{% for state in states %} [{{state.const}}] = {
+ .name = "{{state.name}}",
+ .in_event_mask = 0
+{% for event in state.events %} | S({{event.const}})
+{% endfor %} ,
+ .out_state_mask = 0
+{% for out_state in state.out_states %} | S({{out_state.const}})
+{% endfor %} ,{% if state.onenter %}
+ .onenter = {{prefix}}_{{state.name}}_onenter,{% endif %}
+ .action = {{prefix}}_{{state.name}}_action,
+ },
+{% endfor -%}
+};
+
+static struct osmo_fsm {{prefix}}_fsm = {
+ .name = "{{prefix}}",
+ .states = {{prefix}}_fsm_states,
+ .num_states = ARRAY_SIZE({{prefix}}_fsm_states),
+ .log_subsys = DLGLOBAL, // FIXME
+ .event_names = {{prefix}}_fsm_event_names,
+ .timer_cb = {{prefix}}_fsm_timer_cb,
+};
+
+static __attribute__((constructor)) void {{prefix}}_fsm_register(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&{{prefix}}_fsm) == 0);
+}
+''')
+
+ return template.render(**vars(s))
+
+fsm = FSM(head='#include <osmocom/hlr/proxy.h>',
+ prefix = 'proxy_mm',
+ priv = 'proxy_subscr',
+ states = (
+ State('ready',
+ ('subscr_invalid', 'rx_gsup_lu', 'rx_gsup_sai', ),
+ ('wait_subscr_data', 'wait_gsup_isd_result', 'wait_auth_tuples',),
+ onenter=False,
+ ),
+ State('wait_subscr_data',
+ ('rx_subscr_data',),
+ ('wait_gsup_isd_result', 'ready'),
+ ),
+ State('wait_gsup_isd_result',
+ ('rx_gsup_isd_result',),
+ ('ready',),
+ ),
+ State('wait_auth_tuples',
+ ('rx_auth_tuples',),
+ ('ready',),
+ ),
+ )
+ )
+with open('proxy_mm.c', 'w') as f:
+ f.write(fsm.to_c())
+
+all_home_events = ('home_hlr_resolved',
+ 'rx_insert_subscriber_data_req', 'rx_update_location_result',
+ 'rx_send_auth_info_result',
+ 'check_tuples','confirm_lu',)
+all_home_states = ('wait_home_hlr_resolved', 'wait_update_location_result', 'wait_send_auth_info_result', 'idle', 'clear',)
+fsm = FSM(head='#include <osmocom/hlr/proxy.h>',
+ prefix = 'proxy_to_home',
+ priv = 'proxy_subscr',
+ states = [State(state, all_home_events, all_home_states) for state in all_home_states],
+ )
+with open('proxy_to_home.c', 'w') as f:
+ f.write(fsm.to_c())