We have a fairly large USSD application that uses Erlang's gen_fsm module to manage the menu options.
The current version has a single menus_fsm.erl
file that contains 5000+ lines gen_fsm related code. Our next version gives us an opportunity to split menus_fsm.erl
into separate files to make it more maintainable in the future.
In the old version, to display the help menu we do the following (help_menu/1
gets called from code not shown that displays the main menu):
-module(menus_fsm).
% Snipped some irrelvant code
help_menu(StateData) ->
% Display the first menu
send_menu(StateData, "Please Select:\n1. Option 1\n2. Option 2"),
{next_state, waitHelpMenuChoice, StateData, ?MENU_TOUT};
waitHelpMenuChoice(Params, StateData) ->
io:format("Got Help menu response: ~p", [Params]),
doTerminate(ok,"Help Menu", StateData).
I've left out a lot of code that shows the entry point into the FSM and so on.
In the new version, we'd want to move help_menu/1
and waitHelpMenuChoice/2
to a new module help_menu
, which gets called from menus_fsm
, like so:
-module( help_menu ).
% Snipped some irrelevant code
help_menu(StateData) ->
menus_fsm:send_menu(StateData, "Please Select:\n1. Option 1\n2. Option 2"),
{next_state, waitHelpMenuChoice, StateData, ?MENU_TOUT};
waitHelpMenuChoice(Params, StateData) ->
io:format("Got Help menu response: ~p", [Params]),
menus_fsm:doTerminate(ok,"Help Menu", StateData).
The problem is with the line {next_state, waitHelpMenuChoice, StateData, ?MENU_TOUT};
: gen_fsm
expects the waitHelpMenuChoice
to be in the module menus_fsm
which takes me back to where we started.
I've tried to replace the problematic line with
{next_state, fun help_menu:waitHelpMenuChoice/2, StateData, ?MENU_TOUT};
but that just leas to an error like the following:
{badarg,[{erlang,apply,[conv_fsm,#Fun<help_menu.waitHelpMenuChoice.2>,[]]}
Does anyone have any suggestions of how to get around this?
Maybe you could use http://www.erlang.org/doc/man/gen_fsm.html#enter_loop-6 to do that? Not sure if it would work to call it inside of another fsm, but it might be worth a try.
I managed to find a solution to my own question. If this seems obvious, it could be because I'm a bit new to Erlang.
I added a new function
wait_for_menu_response/2
to modulemenus_fsm
that handles state transitions on behalf of the other modules.Then the
help_menu
module was changed as follows:so
gen_fsm
stays within themenus_fsm
module when it invokeswait_for_menu_response
, butwait_for_menu_response
is now free to invokehelp_menu:waitHelpMenuChoice/2
.help_menu:waitHelpMenuChoice/2
did not need to be modified in any way.Actually, in my final version, the
menus_fsm:send_menu
function was modified to accept thefun waitHelpMenuChoice/2
as its third parameter, so that thehelp_menu
function simply becomes:but I think my explanation above illustrates the idea better.