下面是一个fsm的例子,代码如下:
1 -module(code_lock2). 2 3 -behaviour(gen_fsm). 4 -export([start_link/1]). 5 -export([button/1]). 6 -export([init/1, locked/2, open/2]). 7 -export([code_change/4, handle_event/3, handle_info/3, handle_sync_event/4, terminate/3]). 8 9 -spec(start_link(Code::string()) -> {ok,pid()} | ignore | {error,term()}).10 start_link(Code) ->11 gen_fsm:start_link({local, code_lock2}, code_lock2, Code, []).12 13 -spec(button(Digit::string()) -> ok).14 button(Digit) ->15 gen_fsm:send_event(code_lock2, {button, Digit}).16 17 init(LockCode) ->18 io:format("init: ~p~n", [LockCode]),19 {ok, locked, {[], LockCode}}.20 21 locked({button, Digit}, {SoFar, Code}) ->22 io:format("buttion: ~p, So far: ~p, Code: ~p~n", [Digit, [SoFar|Digit], Code]),23 InputDigits = lists:append(SoFar, Digit),24 io:format("Right now the password is ~p~n", [InputDigits]),25 case InputDigits of26 Code ->27 do_unlock(),28 {next_state, open, {[], Code}, 10000};29 Incomplete when length(Incomplete)30 {next_state, locked, {Incomplete, Code}, 5000};31 Wrong ->32 io:format("wrong passwd: ~p~n", [Wrong]),33 {next_state, locked, {[], Code}}34 end;35 locked(timeout, {_SoFar, Code}) ->36 io:format("timout when waiting button inputting, clean the input, button again plz~n"),37 {next_state, locked, {[], Code}}.38 39 open(timeout, State) ->40 do_lock(),41 {next_state, locked, State}.42 43 code_change(_OldVsn, StateName, Data, _Extra) ->44 {ok, StateName, Data}.45 46 terminate(normal, _StateName, _Data) ->47 ok.48 49 handle_event(Event, StateName, Data) ->50 io:format("handle_event... ~n"),51 unexpected(Event, StateName),52 {next_state, StateName, Data}.53 54 handle_sync_event(Event, From, StateName, Data) ->55 io:format("handle_sync_event, for process: ~p... ~n", [From]),56 unexpected(Event, StateName),57 {next_state, StateName, Data}.58 59 handle_info(Info, StateName, Data) ->60 io:format("handle_info...~n"),61 unexpected(Info, StateName),62 {next_state, StateName, Data}.63 64 %% Unexpected allows to log unexpected messages65 unexpected(Msg, State) ->66 io:format("~p RECEIVED UNKNOWN EVENT: ~p, while FSM process in state: ~p~n",67 [self(), Msg, State]).68 %%69 %% actions70 do_unlock() ->71 io:format("passwd is right, open the DOOR.~n").72 73 do_lock() ->74 io:format("over, close the DOOR.~n").
开锁过程如下:
1 3> code_lock2:button([1]). 2 buttion: [1], So far: [], Code: [1,3,5,3,1,7] 3 Right now the password is [1] 4 ok 5 4> code_lock2:button([3]). 6 buttion: [3], So far: [1], Code: [1,3,5,3,1,7] 7 Right now the password is [1,3] 8 ok 9 5> code_lock2:button([5]).10 buttion: [5], So far: [1,3], Code: [1,3,5,3,1,7]11 Right now the password is [1,3,5]12 ok13 timout when waiting button inputting, clean the input, button again plz14 6> code_lock2:button([3]).15 buttion: [3], So far: [], Code: [1,3,5,3,1,7]16 Right now the password is [3]17 ok18 timout when waiting button inputting, clean the input, button again plz19 7> code_lock2:button([1]).20 buttion: [1], So far: [], Code: [1,3,5,3,1,7]21 Right now the password is [1]22 ok23 8> code_lock2:button([3]).24 buttion: [3], So far: [[1],3], Code: [1,3,5,3,1,7]25 Right now the password is [1,3]26 ok27 9> code_lock2:button([5]).28 buttion: [5], So far: [[1,3],5], Code: [1,3,5,3,1,7]29 Right now the password is [1,3,5]30 ok31 10> code_lock2:button([3]).32 buttion: [3], So far: [1,3,5], Code: [1,3,5,3,1,7]33 Right now the password is [1,3,5,3]34 ok35 11> code_lock2:button([1]).36 buttion: [1], So far: [1,3,5,3], Code: [1,3,5,3,1,7]37 Right now the password is [1,3,5,3,1]38 ok39 12> code_lock2:button([7]).40 buttion: [7], So far: [1,3,5,3,1], Code: [1,3,5,3,1,7]41 Right now the password is [1,3,5,3,1,7]42 ok43 passwd is right, open the DOOR.44 over, close the DOOR.45 13>
有一个地方解释一下,使用fsm:send_event(code_lock2, {button, Digit})相当于发送了一个消息,这个消息怎么处理呢?
如果没有fsm,这样的一个问题几乎没法回答!
这个消息先交给fsm,由fsm判断该交给谁去处理?众所周知,fsm是有限状态机的那种behaviour,当然有多个不同状态,按照fsm的约定这个消息会交给“当前的状态”。
因为start_link启动fsm,然后init执行后的状态是locked,所以,上面的消息就交道locked函数!
其他的代码,看起来就很明白,不说了。
抄代码,执行一下,纯玩。