217
280
eval(STL) when list(STL) ->
218
281
eval(STL, #timers{}).
220
eval(STL, DMV) when record(DMV, 'DigitMapValue') ->
221
Timers = #timers{start = timer_to_millis(DMV#'DigitMapValue'.startTimer),
222
short = timer_to_millis(DMV#'DigitMapValue'.shortTimer),
223
long = timer_to_millis(DMV#'DigitMapValue'.longTimer)},
283
eval(STL, #'DigitMapValue'{startTimer = Start,
286
durationTimer = Duration}) ->
287
Timers = #timers{start = timer_to_millis(Start),
288
short = timer_to_millis(Short),
289
long = timer_to_millis(Long),
290
duration = duration_to_millis(Duration)},
224
291
eval(STL, Timers);
225
eval(STL, {ignore, DMV}) when record(DMV, 'DigitMapValue') ->
226
Timers = #timers{start = timer_to_millis(DMV#'DigitMapValue'.startTimer),
227
short = timer_to_millis(DMV#'DigitMapValue'.shortTimer),
228
long = timer_to_millis(DMV#'DigitMapValue'.longTimer),
292
eval(STL, {ignore, #'DigitMapValue'{startTimer = Start,
295
durationTimer = Duration}}) ->
296
Timers = #timers{start = timer_to_millis(Start),
297
short = timer_to_millis(Short),
298
long = timer_to_millis(Long),
299
duration = duration_to_millis(Duration),
229
300
unexpected = ignore},
230
301
eval(STL, Timers);
231
eval(STL, {reject, DMV}) when record(DMV, 'DigitMapValue') ->
232
Timers = #timers{start = timer_to_millis(DMV#'DigitMapValue'.startTimer),
233
short = timer_to_millis(DMV#'DigitMapValue'.shortTimer),
234
long = timer_to_millis(DMV#'DigitMapValue'.longTimer),
302
eval(STL, {reject, #'DigitMapValue'{startTimer = Start,
305
durationTimer = Duration}}) ->
306
Timers = #timers{start = timer_to_millis(Start),
307
short = timer_to_millis(Short),
308
long = timer_to_millis(Long),
309
duration = duration_to_millis(Duration),
235
310
unexpected = reject},
236
311
eval(STL, Timers);
237
312
eval(STL, Timers) when list(STL),
238
313
record(hd(STL), state_transition),
239
314
record(Timers, timers) ->
240
collect(start, mandatory_event, Timers, STL, []);
315
?d("eval -> entry with"
317
"~n Timers: ~p", [STL, Timers]),
318
case collect(start, mandatory_event, Timers, lists:reverse(STL), []) of
319
{error, _} = Error ->
321
"~n Error: ~p", [Error]),
241
328
eval(DigitMapBody, ignore) ->
242
329
eval(DigitMapBody, #timers{unexpected = ignore});
243
330
eval(DigitMapBody, reject) ->
340
%% full | unambiguous
253
342
collect(Event, State, Timers, STL, Letters) ->
343
?d("collect -> entry with"
347
"~n STL: ~p", [Event, State, Timers, STL]),
254
348
case handle_event(Event, State, Timers, STL, Letters) of
349
{completed_full, _Timers2, _STL2, Letters2} ->
350
completed(full, Letters2);
255
351
{completed, _Timers2, _STL2, Letters2} ->
352
completed(unambiguous, Letters2);
257
353
{State2, Timers2, STL2, Letters2} ->
357
"~n Letters2: ~p", [State2, Timers2, Letters2]),
258
358
MaxWait = choose_timer(State2, Event, Timers2),
259
%% ok = io:format("Timer: ~p ~p~n~p~n~p~n",
260
%% [State2, MaxWait, Timers2, STL2]),
359
?d("collect -> Timer choosen: "
360
"~n MaxWait: ~p", [MaxWait]),
262
362
{?MODULE, _FromPid, Event2} ->
263
%% ok = io:format("Got event: ~p~n", [Event2]),
363
?d("collect -> Got event: "
264
365
collect(Event2, State2, Timers2, STL2, Letters2)
266
collect(inter_event_timeout, State2, Timers2, STL2, Letters2)
367
?d("collect -> timeout after ~w", [MaxWait]),
368
collect(inter_event_timeout,
369
State2, Timers2, STL2, Letters2)
268
372
{error, Reason} ->
373
?d("collect -> error: "
374
"~n Reason: ~p", [Reason]),
272
choose_timer(State, start, T) ->
273
Extra = T#timers.start,
274
Timer = do_choose_timer(State, T),
276
Timer == infinity -> infinity;
277
Extra == infinity -> infinity;
278
true -> Timer + Extra
378
choose_timer(_State, start, #timers{start = 0}) ->
379
?d("choose_timer(start) -> entry", []),
381
choose_timer(_State, start, #timers{start = T}) ->
382
?d("choose_timer(start) -> entry with"
280
385
choose_timer(State, _Event, T) ->
386
?d("choose_timer(~p) -> entry with"
388
"~n T: ~p", [_Event, State, T]),
281
389
do_choose_timer(State, T).
283
do_choose_timer(State, T) ->
284
case T#timers.mode of
287
mandatory_event -> T#timers.long;
288
optional_event -> T#timers.short
391
do_choose_timer(mandatory_event, #timers{mode = state_dependent, long = T}) ->
393
do_choose_timer(optional_event, #timers{mode = state_dependent, short = T}) ->
395
do_choose_timer(_State, #timers{mode = use_short_timer, short = T}) ->
397
do_choose_timer(_State, #timers{mode = use_long_timer, long = T}) ->
296
timer_to_millis(asn1_NOVALUE) -> 0;
400
timer_to_millis(asn1_NOVALUE) -> infinity;
297
401
timer_to_millis(infinity) -> infinity;
298
402
timer_to_millis(Seconds) -> timer:seconds(Seconds).
300
completed(Letters) ->
301
{ok, lists:reverse(Letters)}.
404
%% Time for duration is in hundreds of milliseconds
405
duration_to_millis(asn1_NOVALUE) -> 100;
406
duration_to_millis(Time) when is_integer(Time) -> Time*100.
408
completed(Kind, {Letters, Event}) when is_list(Letters) ->
409
?d("completed -> entry with"
411
"~n Event: ~s", [Kind, [Event]]),
412
{ok, {Kind, duration_letter_cleanup(Letters, []), Event}};
413
completed(Kind, Letters) when is_list(Letters) ->
414
?d("completed -> entry with"
415
"~n Kind: ~p", [Kind]),
416
{ok, {Kind, duration_letter_cleanup(Letters, [])}}.
418
duration_letter_cleanup([], Acc) ->
420
duration_letter_cleanup([{long, Letter}|Letters], Acc) ->
421
duration_letter_cleanup(Letters, [$Z,Letter|Acc]);
422
duration_letter_cleanup([Letter|Letters], Acc) ->
423
duration_letter_cleanup(Letters, [Letter|Acc]).
303
425
unexpected_event(Event, STL, Letters) ->
304
Expected = [ST#state_transition.next || ST <- STL],
305
SoFar = lists:reverse(Letters),
306
Reason = {unexpected_event, Event, SoFar, Expected},
426
Expected = [Next || #state_transition{next = Next} <- STL],
427
SoFar = lists:reverse(Letters),
428
Reason = {unexpected_event, Event, SoFar, Expected},
309
432
%%----------------------------------------------------------------------
310
433
%% Handles a received event according to digit map
311
434
%% State ::= optional_event | mandatory_event
313
436
%% Returns {State, NewSTL, Letters} | {error, Reason}
314
437
%%----------------------------------------------------------------------
315
438
handle_event(inter_event_timeout, optional_event, Timers, STL, Letters) ->
316
{completed, Timers, STL, Letters};
439
{completed_full, Timers, STL, Letters}; % 7.1.14.5 2
317
440
handle_event(cancel, _State, _Timers, STL, Letters) ->
318
441
unexpected_event(cancel, STL, Letters);
319
442
handle_event(start, _State, Timers, STL, Letters) ->
320
443
{State2, Timers2, STL2} = compute(Timers, STL),
321
444
{State2, Timers2, STL2, Letters};
322
445
handle_event(Event, State, Timers, STL, Letters) ->
323
{STL2, Collect} = match_event(Event, STL, [], false),
446
?d("handle_event -> entry when"
450
"~n Letters: ~p", [Event, State, Timers, Letters]),
451
{STL2, Collect, KeepDur} = match_event(Event, STL),
452
?d("handle_event -> match event result: "
455
"~n STL2: ~p", [Collect, KeepDur, STL2]),
326
case Timers#timers.unexpected of
328
ok = io:format("<WARNING> Ignoring unexpected event: ~p~n"
331
{State, Timers, STL, Letters};
333
unexpected_event(Event, STL, Letters)
457
[] when State == optional_event -> % 7.1.14.5 5
458
?d("handle_event -> complete-full with event - 7.1.14.5 5", []),
459
{completed_full, Timers, [], {Letters, Event}};
460
[] when Timers#timers.unexpected == ignore ->
461
ok = io:format("<WARNING> Ignoring unexpected event: ~p~n"
464
{State, Timers, STL, Letters};
465
[] when Timers#timers.unexpected == reject ->
466
?d("handle_event -> unexpected (reject)", []),
467
unexpected_event(Event, STL, Letters);
336
469
{State3, Timers2, STL3} = compute(Timers, STL2),
470
?d("handle_event -> computed: "
473
"~n STL3: ~p", [State3, Timers2, STL3]),
338
true -> {State3, Timers2, STL3, [Event | Letters]};
339
false -> {State3, Timers2, STL3, Letters}
475
true when KeepDur == true ->
476
{State3, Timers2, STL3, [Event | Letters]};
479
{long, ActualEvent} ->
480
{State3, Timers2, STL3, [ActualEvent | Letters]};
482
{State3, Timers2, STL3, [Event | Letters]}
485
{State3, Timers2, STL3, Letters}
343
match_event(Event, [ST | OldSTL], NewSTL, Collect)
489
match_event(Event, STL) ->
490
MatchingDuration = matching_duration_event(Event, STL),
491
match_event(Event, STL, [], false, false, MatchingDuration).
493
match_event(Event, [ST | OldSTL], NewSTL, Collect, KeepDur, MatchingDuration)
344
494
when record(ST, state_transition) ->
495
?d("match_event -> entry with"
501
"~n MatchingDuration: ~p",
502
[Event, ST, NewSTL, Collect, KeepDur, MatchingDuration]),
345
503
case ST#state_transition.next of
346
504
{single, Event} ->
347
match_event(Event, OldSTL, [ST | NewSTL], true);
505
?d("match_event -> keep ST (1)", []),
506
match_event(Event, OldSTL, [ST | NewSTL], true, KeepDur,
508
{single, Single} when (Event == {long, Single}) and
509
(MatchingDuration == false) ->
510
%% Chap 7.1.14.5 point 4
511
?d("match_event -> keep ST - change to ordinary event (2)", []),
512
match_event(Event, OldSTL, [ST | NewSTL], true, KeepDur,
348
515
{range, From, To} when Event >= From, Event =< To ->
516
?d("match_event -> keep ST (3)", []),
349
517
ST2 = ST#state_transition{next = {single, Event}},
350
match_event(Event, OldSTL, [ST2 | NewSTL], true);
518
match_event(Event, OldSTL, [ST2 | NewSTL], true, KeepDur,
523
{long, R} when (R >= From) and (R =< To) and (MatchingDuration == false) ->
524
?d("match_event -> keep ST (4)", []),
525
ST2 = ST#state_transition{next = {single, R}},
526
match_event(Event, OldSTL, [ST2 | NewSTL], true, true,
529
?d("match_event -> drop ST - change to ordinary event (5)", []),
530
match_event(Event, OldSTL, NewSTL, Collect, KeepDur,
534
{duration_event, {single, Single}} when Event == {long, Single} ->
535
?d("match_event -> keep ST (5)", []),
536
match_event(Event, OldSTL, [ST | NewSTL], true, true,
539
{duration_event, {range, From, To}} ->
541
{long, R} when R >= From, R =< To ->
542
?d("match_event -> keep ST (6)", []),
543
match_event(Event, OldSTL, [ST | NewSTL], true, true,
546
?d("match_event -> drop ST (7)", []),
547
match_event(Event, OldSTL, NewSTL, Collect, KeepDur,
352
match_event(Event, OldSTL, [ST | NewSTL], Collect);
552
?d("match_event -> keep ST (8)", []),
553
match_event(Event, OldSTL, [ST | NewSTL], Collect, KeepDur,
354
match_event(Event, OldSTL, NewSTL, Collect)
557
?d("match_event -> drop ST (9)", []),
558
match_event(Event, OldSTL, NewSTL, Collect, KeepDur,
356
match_event(Event, [H | T], NewSTL, Collect) when list(H) ->
357
{NewSTL2, _Letters} = match_event(Event, H, NewSTL, Collect),
358
match_event(Event, T, NewSTL2, Collect);
359
match_event(_Event, [], NewSTL, Collect) ->
561
match_event(Event, [H | T], NewSTL, Collect, KeepDur0, MatchingDuration)
563
?d("match_event -> entry with"
569
"~n MatchingDuration: ~p",
570
[Event, H, NewSTL, Collect, KeepDur0, MatchingDuration]),
571
{NewSTL2, _Letters, KeepDur} =
572
match_event(Event, H, NewSTL, Collect, KeepDur0, MatchingDuration),
574
"~n NewSTLs: ~p", [NewSTL2]),
575
match_event(Event, T, NewSTL2, Collect, KeepDur,
577
match_event(_Event, [], NewSTL, Collect, KeepDur, _MatchingDuration) ->
578
?d("match_event -> entry with"
581
"~n KeepDur: ~p", [NewSTL, Collect, KeepDur]),
582
{lists:reverse(NewSTL), Collect, KeepDur}.
585
matching_duration_event({long, Event}, STL) ->
586
Nexts = [Next || #state_transition{next = Next} <- STL],
588
matching_duration_event(_Event, _STL) ->
594
mde(Event, [{duration_event, {single, Event}}|_]) ->
596
mde(Event, [{duration_event, {range, From, To}}|_])
597
when Event >= From, Event =< To ->
599
mde(Event, [_|Nexts]) ->
362
603
%%----------------------------------------------------------------------
363
604
%% Compute new state transitions
364
605
%% Returns {State, Timers, NewSTL}
365
606
%%----------------------------------------------------------------------
366
607
compute(Timers, OldSTL) ->
367
{State, GlobalMode, NewSTL} = compute(mandatory_event, state_dependent, OldSTL, []),
608
?d("compute -> entry with"
610
"~n OldSTL: ~p", [Timers, OldSTL]),
611
{State, GlobalMode, NewSTL} =
612
compute(mandatory_event, state_dependent, OldSTL, []),
616
"~n NewSTL: ~p", [State, GlobalMode, NewSTL]),
368
617
Timers2 = Timers#timers{mode = GlobalMode},
619
"~n Timers2: ~p", [Timers2]),
369
620
{State, Timers2, NewSTL}.
371
compute(State, GlobalMode, [ST | OldSTL], NewSTL) when record(ST, state_transition) ->
622
compute(State, GlobalMode, [ST | OldSTL], NewSTL)
623
when record(ST, state_transition) ->
624
?d("compute(~w) -> entry with"
627
"~n NewSTL: ~p", [State, GlobalMode, ST, NewSTL]),
372
628
Cont = ST#state_transition.cont,
373
629
Mode = ST#state_transition.mode,
374
630
{State2, GlobalMode2, NewSTL2} =
375
631
compute_cont(Cont, Mode, GlobalMode, State, NewSTL),
376
632
compute(State2, GlobalMode2, OldSTL, NewSTL2);
377
633
compute(State, GlobalMode, [H | T], NewSTL) when list(H) ->
634
?d("compute(~w) -> entry with"
637
"~n NewSTL: ~p", [State, GlobalMode, H, NewSTL]),
378
638
{State2, GlobalMode2, NewSTL2} = compute(State, GlobalMode, H, NewSTL),
379
639
compute(State2, GlobalMode2, T, NewSTL2);
380
640
compute(State, GlobalMode, [], NewSTL) ->
641
?d("compute(~w) -> entry with"
643
"~n NewSTL: ~p", [State, GlobalMode, NewSTL]),
382
645
[] -> {completed, GlobalMode, NewSTL};
383
646
_ -> {State, GlobalMode, NewSTL}
386
649
compute_cont([Next | Cont] = All, Mode, GlobalMode, State, STL) ->
650
?d("compute_cont -> entry with"
653
"~n GlobalMode: ~p", [Next, Mode, GlobalMode]),
655
%% Retain long timer if that has already been choosen
656
use_short_timer when GlobalMode == use_long_timer ->
657
compute_cont(Cont, Mode, GlobalMode, State, STL);
388
658
use_short_timer ->
389
659
Mode2 = use_short_timer,
390
660
compute_cont(Cont, Mode2, GlobalMode, State, STL);