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 + -
显示快捷键?