下面是一个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 of 26 Code -> 27 do_unlock(), 28 {next_state, open, {[], Code}, 10000}; 29 Incomplete when length(Incomplete)<length(Code) -> 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 messages 65 unexpected(Msg, State) -> 66 io:format("~p RECEIVED UNKNOWN EVENT: ~p, while FSM process in state: ~p~n", 67 [self(), Msg, State]). 68 %% 69 %% actions 70 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 ok 13 timout when waiting button inputting, clean the input, button again plz 14 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 ok 18 timout when waiting button inputting, clean the input, button again plz 19 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 ok 23 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 ok 27 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 ok 31 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 ok 35 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 ok 39 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 ok 43 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函数!
其他的代码,看起来就很明白,不说了。
抄代码,执行一下,纯玩。