megaco_digit_map.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 773 行 · 第 1/2 页

ERL
773
字号
       "~n   State: ~p"       "~n   T:     ~p", [_Event, State, T]),    do_choose_timer(State, T).do_choose_timer(mandatory_event, #timers{mode = state_dependent, long = T}) ->    T;do_choose_timer(optional_event, #timers{mode = state_dependent, short = T}) ->    T;do_choose_timer(_State, #timers{mode = use_short_timer, short = T}) ->    T;do_choose_timer(_State, #timers{mode = use_long_timer, long = T}) ->    T.timer_to_millis(asn1_NOVALUE) -> infinity; timer_to_millis(infinity)     -> infinity;timer_to_millis(Seconds)      -> timer:seconds(Seconds).    %% Time for duration is in hundreds of millisecondsduration_to_millis(asn1_NOVALUE) -> 100;duration_to_millis(Time) when is_integer(Time) -> Time*100.completed(Kind, {Letters, Event}) when is_list(Letters) ->    ?d("completed -> entry with"       "~n   Kind:  ~p"       "~n   Event: ~s", [Kind, [Event]]),    {ok, {Kind, duration_letter_cleanup(Letters, []), Event}};completed(Kind, Letters) when is_list(Letters) ->    ?d("completed -> entry with"       "~n   Kind: ~p", [Kind]),    {ok, {Kind, duration_letter_cleanup(Letters, [])}}.duration_letter_cleanup([], Acc) ->    Acc;duration_letter_cleanup([{long, Letter}|Letters], Acc) ->    duration_letter_cleanup(Letters, [$Z,Letter|Acc]);duration_letter_cleanup([Letter|Letters], Acc) ->    duration_letter_cleanup(Letters, [Letter|Acc]).unexpected_event(Event, STL, Letters) ->    Expected = [Next || #state_transition{next = Next} <- STL],    SoFar    = lists:reverse(Letters),    Reason   = {unexpected_event, Event, SoFar, Expected},    {error, Reason}.    %%----------------------------------------------------------------------%% Handles a received event according to digit map%% State ::= optional_event | mandatory_event%% %% Returns {State, NewSTL, Letters} | {error, Reason}%%----------------------------------------------------------------------handle_event(inter_event_timeout, optional_event, Timers, STL, Letters) ->    {completed_full, Timers, STL, Letters}; % 7.1.14.5 2handle_event(cancel, _State, _Timers, STL, Letters) ->    unexpected_event(cancel, STL, Letters);handle_event(start, _State, Timers, STL, Letters) ->    {State2, Timers2, STL2} = compute(Timers, STL),    {State2, Timers2, STL2, Letters};handle_event(Event, State, Timers, STL, Letters) ->    ?d("handle_event -> entry when"       "~n   Event:   ~p"       "~n   State:   ~p"       "~n   Timers:  ~p"       "~n   Letters: ~p", [Event, State, Timers, Letters]),    {STL2, Collect, KeepDur} = match_event(Event, STL),     ?d("handle_event -> match event result: "       "~n   Collect: ~p"       "~n   KeepDur: ~p"       "~n   STL2:    ~p", [Collect, KeepDur, STL2]),    case STL2 of	[] when State == optional_event -> % 7.1.14.5 5	    ?d("handle_event -> complete-full with event - 7.1.14.5 5", []),	    {completed_full, Timers, [], {Letters, Event}};	[] when Timers#timers.unexpected == ignore ->	    ok = io:format("<WARNING> Ignoring unexpected event: ~p~n"			   "Expected: ~p~n",			   [Event, STL]),	    {State, Timers, STL, Letters};	[] when Timers#timers.unexpected == reject ->	    ?d("handle_event -> unexpected (reject)", []),	    unexpected_event(Event, STL, Letters);	_ ->	    {State3, Timers2, STL3} = compute(Timers, STL2),	    ?d("handle_event -> computed: "	       "~n   State3:  ~p"	       "~n   Timers2: ~p"	       "~n   STL3:    ~p", [State3, Timers2, STL3]),	    case Collect of		true when KeepDur == true -> 		    {State3, Timers2, STL3, [Event | Letters]};		true -> 		    case Event of			{long, ActualEvent} ->			    {State3, Timers2, STL3, [ActualEvent | Letters]};			_ ->			    {State3, Timers2, STL3, [Event | Letters]}		    end;		false -> 		    {State3, Timers2, STL3, Letters}	    end    end.match_event(Event, STL) ->    MatchingDuration = matching_duration_event(Event, STL),    match_event(Event, STL, [], false, false, MatchingDuration).match_event(Event, [ST | OldSTL], NewSTL, Collect, KeepDur, MatchingDuration)  when record(ST, state_transition) ->    ?d("match_event -> entry with"       "~n   Event:            ~p"       "~n   ST:               ~p"       "~n   NewSTL:           ~p"       "~n   Collect:          ~p"       "~n   KeepDur:          ~p"       "~n   MatchingDuration: ~p",        [Event, ST, NewSTL, Collect, KeepDur, MatchingDuration]),    case ST#state_transition.next of	{single, Event} ->	    ?d("match_event -> keep ST (1)", []),	    match_event(Event, OldSTL, [ST | NewSTL], true, KeepDur,			MatchingDuration);        {single, Single} when (Event == {long, Single}) and 			      (MatchingDuration == false) ->	    %% Chap 7.1.14.5 point 4	    ?d("match_event -> keep ST - change to ordinary event (2)", []),            match_event(Event, OldSTL, [ST | NewSTL], true, KeepDur,			MatchingDuration);	{range, From, To} when Event >= From, Event =< To ->	    ?d("match_event -> keep ST (3)", []),	    ST2 = ST#state_transition{next = {single, Event}},	    match_event(Event, OldSTL, [ST2 | NewSTL], true, KeepDur,			MatchingDuration);	{range, From, To} ->	    case Event of		{long, R} when (R >= From) and (R =< To) and (MatchingDuration == false) ->		    ?d("match_event -> keep ST (4)", []),		    ST2 = ST#state_transition{next = {single, R}},		    match_event(Event, OldSTL, [ST2 | NewSTL], true, true,				MatchingDuration);		_ ->		    ?d("match_event -> drop ST - change to ordinary event (5)", []),		    match_event(Event, OldSTL, NewSTL, Collect, KeepDur,				MatchingDuration) 	    end;        {duration_event, {single, Single}} when Event == {long, Single} ->	    ?d("match_event -> keep ST (5)", []),            match_event(Event, OldSTL, [ST | NewSTL], true, true,			MatchingDuration);        {duration_event, {range, From, To}} ->	    case Event of		{long, R} when R >= From, R =< To ->		    ?d("match_event -> keep ST (6)", []),		    match_event(Event, OldSTL, [ST | NewSTL], true, true,				MatchingDuration);		_ ->		    ?d("match_event -> drop ST (7)", []),		    match_event(Event, OldSTL, NewSTL, Collect, KeepDur,				MatchingDuration) 	    end;	Event ->	    ?d("match_event -> keep ST (8)", []),	    match_event(Event, OldSTL, [ST | NewSTL], Collect, KeepDur,			MatchingDuration);	_ ->	    ?d("match_event -> drop ST (9)", []),	    match_event(Event, OldSTL, NewSTL, Collect, KeepDur,			MatchingDuration)    end;match_event(Event, [H | T], NewSTL, Collect, KeepDur0, MatchingDuration)   when list(H) ->    ?d("match_event -> entry with"       "~n   Event:            ~p"       "~n   H:                ~p"       "~n   NewSTL:           ~p"       "~n   Collect:          ~p"       "~n   KeepDur0:         ~p"       "~n   MatchingDuration: ~p",        [Event, H, NewSTL, Collect, KeepDur0, MatchingDuration]),    {NewSTL2, _Letters, KeepDur} = 	match_event(Event, H, NewSTL, Collect, KeepDur0, MatchingDuration),    ?d("compute -> "       "~n   NewSTLs: ~p", [NewSTL2]),    match_event(Event, T, NewSTL2, Collect, KeepDur,		MatchingDuration);match_event(_Event, [], NewSTL, Collect, KeepDur, _MatchingDuration) ->    ?d("match_event -> entry with"       "~n   NewSTL:  ~p"       "~n   Collect: ~p"       "~n   KeepDur: ~p", [NewSTL, Collect, KeepDur]),    {lists:reverse(NewSTL), Collect, KeepDur}.    matching_duration_event({long, Event}, STL) ->    Nexts = [Next || #state_transition{next = Next} <- STL],    mde(Event, Nexts);matching_duration_event(_Event, _STL) ->    false.mde(_, []) ->    false;mde(Event, [{duration_event, {single, Event}}|_]) ->    true;mde(Event, [{duration_event, {range, From, To}}|_])   when Event >= From, Event =< To ->    true;mde(Event, [_|Nexts]) ->    mde(Event, Nexts).%%----------------------------------------------------------------------%% Compute new state transitions%% Returns {State, Timers, NewSTL}%%----------------------------------------------------------------------compute(Timers, OldSTL) ->    ?d("compute -> entry with"       "~n   Timers: ~p"       "~n   OldSTL: ~p", [Timers, OldSTL]),    {State, GlobalMode, NewSTL} = 	compute(mandatory_event, state_dependent, OldSTL, []),    ?d("compute -> "       "~n   State:      ~p"       "~n   GlobalMode: ~p"       "~n   NewSTL:     ~p", [State, GlobalMode, NewSTL]),    Timers2 = Timers#timers{mode = GlobalMode},    ?d("compute -> "       "~n   Timers2: ~p", [Timers2]),    {State, Timers2, NewSTL}.compute(State, GlobalMode, [ST | OldSTL], NewSTL)   when record(ST, state_transition) ->    ?d("compute(~w) -> entry with"       "~n   GlobalMode: ~p"       "~n   ST:         ~p"       "~n   NewSTL:     ~p", [State, GlobalMode, ST, NewSTL]),    Cont = ST#state_transition.cont,    Mode = ST#state_transition.mode,    {State2, GlobalMode2, NewSTL2} =	compute_cont(Cont, Mode, GlobalMode, State, NewSTL),    compute(State2, GlobalMode2, OldSTL, NewSTL2);compute(State, GlobalMode, [H | T], NewSTL) when list(H) ->    ?d("compute(~w) -> entry with"       "~n   GlobalMode: ~p"       "~n   H:          ~p"       "~n   NewSTL:     ~p", [State, GlobalMode, H, NewSTL]),    {State2, GlobalMode2, NewSTL2} = compute(State, GlobalMode, H, NewSTL),    compute(State2, GlobalMode2, T, NewSTL2);compute(State, GlobalMode, [], NewSTL) ->    ?d("compute(~w) -> entry with"       "~n   GlobalMode: ~p"       "~n   NewSTL:     ~p", [State, GlobalMode, NewSTL]),    case NewSTL of	[] -> {completed, GlobalMode, NewSTL};	_  -> {State,     GlobalMode, NewSTL}    end.compute_cont([Next | Cont] = All, Mode, GlobalMode, State, STL) ->    ?d("compute_cont -> entry with"       "~n   Next:       ~p"       "~n   Mode:       ~p"       "~n   GlobalMode: ~p", [Next, Mode, GlobalMode]),    case Next of	%% Retain long timer if that has already been choosen	use_short_timer when GlobalMode == use_long_timer ->	    compute_cont(Cont, Mode, GlobalMode, State, STL);	use_short_timer ->	    Mode2 = use_short_timer,	    compute_cont(Cont, Mode2, GlobalMode, State, STL);	use_long_timer ->	    Mode2 = use_long_timer,	    compute_cont(Cont, Mode2, GlobalMode, State, STL);	[] ->	    %% Skip empty list	    case Cont of		[zero_or_more | Cont2] ->		    compute_cont(Cont2, Mode, GlobalMode, State, STL);		_ ->		    compute_cont(Cont, Mode, GlobalMode, State, STL)	    end;	_ ->	    GlobalMode2 =		case Mode of		    state_dependent -> GlobalMode;		    _               -> Mode		end,	    case Cont of		[zero_or_more | Cont2] ->		    ST = make_cont(Mode, Next, All),		    compute_cont(Cont2, Mode, GlobalMode2, State, [ST | STL]);		_ ->		    ST = make_cont(Mode, Next, Cont),		    {State, GlobalMode2, [ST | STL]}	    end    end;compute_cont([], GlobalMode, _Mode, _State, STL) ->    {optional_event, GlobalMode, STL}.make_cont(Mode, [Next | Cont2], Cont) ->    #state_transition{mode = Mode, next = Next, cont = [Cont2 | Cont]};make_cont(Mode, Next, Cont) ->    #state_transition{mode = Mode, next = Next, cont = Cont}.%%----------------------------------------------------------------------%% Send one or more events to event collector process%% %% Events ::= Event* | Event%% Event  ::= $0-$9 | $a-$k | $A-$K | $S | $L | $Z%% $S means sleep one second%% $L means sleep ten seconds%% $Z means cancel%% Returns ok | {error, Reason}%%----------------------------------------------------------------------report(Pid, [H | T])->    case report(Pid, H) of	ok ->	    report(Pid, T);	{error, Reason} ->	    {error, Reason}    end;report(_Pid, [])->    ok;report(Pid, Event) when pid(Pid) ->    case Event of	I when I >= $0, I =< $9 -> cast(Pid, Event);	A when A >= $a, A =< $k -> cast(Pid, Event);	A when A >= $A, A =< $K -> cast(Pid, Event);	cancel                  -> cast(Pid, Event);	$Z                      -> cast(Pid, cancel);	$z                      -> cast(Pid, cancel);	$R                      -> timer:sleep(100);  % 100 ms	$r                      -> timer:sleep(100);  % 100 ms	$S                      -> sleep(1);  % 1 sec (1000 ms)	$s                      -> sleep(1);  % 1 sec (1000 ms)	$L                      -> sleep(10); % 10 sec (10000 ms)	$l                      -> sleep(10); % 10 sec (10000 ms)        {long, I} when (I >= $0) and (I =< $9) -> cast(Pid, {long, I});        {long, A} when (A >= $a) and (A =< $k) -> cast(Pid, {long, A});        {long, A} when (A >= $A) and (A =< $K) -> cast(Pid, {long, A});%%         {long, I} when (I >= $0) and (I =< $9) -> long(Pid, I);%%         {long, A} when (A >= $a) and (A =< $k) -> long(Pid, A);%%         {long, A} when (A >= $A) and (A =< $K) -> long(Pid, A); 	_                       -> {error, {illegal_event, Event}}    end.%% long(Pid, Event) ->%%     cast(Pid, long),%%     cast(Pid, Event).%% sleep(Sec) ->    timer:sleep(timer:seconds(Sec)),    ok.cast(Pid, Event) ->    Pid ! {?MODULE, self(), Event},    ok.%%----------------------------------------------------------------------%% Feed digit map collector with events%% Returns: {ok, Letters} | {error, Reason}%%----------------------------------------------------------------------test(DigitMap, Events) ->    Self = self(),    Pid = spawn_link(?MODULE, test_eval, [DigitMap, Self]),    report(Pid, Events),    receive	{Self, Pid, Res} ->	    Res;	{'EXIT', Pid, Reason} ->	    {error, {'EXIT', Reason}}    end.test_eval(DigitMap, Parent) ->    Res = eval(DigitMap),    unlink(Parent),    Parent ! {Parent, self(), Res},    exit(normal).

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?