From ce1b92ca06225795b187ad8b27e686c62753da19 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Tue, 28 Jan 2020 06:37:38 +0100 Subject: add contrib/new_fsm.py Change-Id: I7781008dffc49dc9a279fa066ad2e0bb7da25dfe --- contrib/new_fsm.py | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100755 contrib/new_fsm.py 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 +#include + +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 ', + 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 ', + 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()) -- cgit v1.2.3