1// -*- tab-width: 4; -*-
2//
3// The contents of this file are subject to the Mozilla Public
4// License Version 1.1 (the "License"); you may not use this file
5// except in compliance with the License. You may obtain a copy of
6// the License at http://www.mozilla.org/MPL/
7//
8// Software distributed under the License is distributed on an "AS
9// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10// implied. See the License for the specific language governing
11// rights and limitations under the License.
12//
13// The Original Code is State Machine Compiler (SMC).
14//
15// The Initial Developer of the Original Code is Charles W. Rapp.
16// Portions created by Charles W. Rapp are
17// Copyright (C) 2000 - 2003 Charles W. Rapp.
18// All Rights Reserved.
19//
20// Contributor(s):
21//      Port to Perl by Francois Perrad, francois.perrad@gadz.org
22//
23// Name
24//  Telephone.sm
25//
26// Description
27//  Runs a plain old telphone. That means the proper sounds at
28//  the proper time.
29//
30// RCS ID
31// $Id: Telephone.sm,v 1.1 2005/06/16 18:04:15 fperrad Exp $
32//
33// CHANGE LOG
34// $Log: Telephone.sm,v $
35// Revision 1.1  2005/06/16 18:04:15  fperrad
36// Added Perl examples 1 - 4 and 7.
37//
38//
39
40%class Telephone
41%start CallMap::OnHook
42%package smc_ex7
43
44%map CallMap
45%%
46
47OnHook
48Entry
49{
50    updateClock();
51    startClockTimer();
52}
53Exit
54{
55    stopTimer("ClockTimer");
56}
57{
58    // We are handling the caller's side of the connection.
59    OffHook
60        Dialing/push(PhoneNumber::DialTone)
61        {
62            clearDisplay();
63            setReceiver("Put down receiver");
64        }
65
66    // Time to update the clock's display.
67    ClockTimer
68        nil
69        {
70            updateClock();
71            startClockTimer();
72        }
73}
74
75// The number is being dialed.
76Dialing
77{
78    // Dialing successfully completed.
79    DialingDone($callType, $areaCode, $exchange, $local)
80        Routing
81        {
82            routeCall($callType, $areaCode, $exchange, $local);
83        }
84
85    // Dialing errors.
86    LeftOffHook
87        LeftOffHook
88        {}
89
90    InvalidDigit
91        InvalidDigit
92        {}
93}
94
95// The call is now being routed.
96Routing
97{
98    Emergency
99        PlayingMessage
100        {
101            playEmergency();
102        }
103
104    NYCTemp
105        NYCTemp
106        {}
107
108    Time
109        Time
110        {}
111
112    DepositMoney
113        DepositMoney
114        {}
115
116    LineBusy
117        BusySignal
118        {}
119
120    InvalidNumber
121        PlayingMessage
122        {
123            playInvalidNumber();
124        }
125}
126
127NYCTemp
128Entry
129{
130    loop("ringing");
131    startTimer("RingTimer", 10000);
132}
133Exit
134{
135    stopLoop("ringing");
136}
137{
138    RingTimer
139        PlayingMessage
140        {
141            playNYCTemp();
142        }
143}
144
145Time
146Entry
147{
148    loop("ringing");
149    startTimer("RingTimer", 10000);
150}
151Exit
152{
153    stopLoop("ringing");
154}
155{
156    RingTimer
157        PlayingMessage
158        {
159            playTime();
160        }
161}
162
163DepositMoney
164Entry
165{
166    loop("ringing");
167    startTimer("RingTimer", 5000);
168}
169Exit
170{
171    stopLoop("ringing");
172}
173{
174    RingTimer
175        PlayingMessage
176        {
177            playDepositMoney();
178        }
179}
180
181BusySignal
182Entry
183{
184    loop("busy");
185}
186Exit
187{
188    stopLoop("busy");
189}
190{
191    // Wait for on hook only.
192}
193
194PlayingMessage
195{
196    // If caller hangs up while a message is being played,
197    // be sure to stop the playback.
198    OnHook
199        OnHook
200        {
201            stopPlayback();
202            setReceiver("Pick up receiver");
203            clearDisplay();
204        }
205
206        PlaybackDone
207            MessagePlayed
208            {}
209}
210
211MessagePlayed
212Entry
213{
214    startTimer("OffHookTimer", 10000);
215}
216Exit
217{
218    stopTimer("OffHookTimer");
219}
220{
221    OffHookTimer
222        LeftOffHook
223        {}
224}
225
226//---------------------------------------------------------------
227// Error States.
228//
229// Let someone know the phone has been left off the hook.
230LeftOffHook
231Entry
232{
233    startTimer("LoopTimer", 10000);
234    loop("phone_off_hook");
235}
236Exit
237{
238    stopTimer("LoopTimer");
239    stopLoop("phone_off_hook");
240}
241{
242    LoopTimer
243        WaitForOnHook
244        {}
245
246    Default
247        nil
248        {}
249}
250
251InvalidDigit
252Entry
253{
254    startTimer("LoopTimer", 10000);
255    loop("fast_busy");
256}
257Exit
258{
259    stopTimer("LoopTimer");
260    stopLoop("fast_busy");
261}
262{
263    LoopTimer
264        WaitForOnHook
265        {}
266
267    Default
268        nil
269        {}
270}
271
272// Stay in this state until the telephone is on hook.
273WaitForOnHook
274{
275    Default
276        nil
277        {}
278}
279
280Default
281{
282    // Ignore any dialings after a phone number has been
283    // collected.
284    Digit($n)
285        nil
286        {}
287
288    InvalidDigit
289        InvalidDigit
290        {}
291
292    // No matter when it happens, when the phone is hung
293    // up, this call is OVER!
294    OnHook
295        OnHook
296        {
297            setReceiver("Pick up receiver");
298            clearDisplay();
299        }
300
301    // Ignore the clock timer outside of the OnHook state.
302    ClockTimer
303        nil
304        {}
305}
306%%
307
308// This map processes dialed digits. It either returns success
309// when
310%map PhoneNumber
311%%
312DialTone
313Entry
314{
315    loop("dialtone");
316    startTimer("OffHookTimer", 10000);
317}
318Exit
319{
320    stopTimer("OffHookTimer");
321    stopLoop("dialtone");
322}
323{
324    // If an invalid digit is dialed, give up collecting
325    // digits immediately.
326    Digit($n)
327      [$n lt "0" || $n gt "9"]
328        pop(InvalidDigit)
329        {
330            clearDisplay();
331        }
332
333    // If the first digit is 1, then this is a long distance
334    // phone call. Don't save this first digit.
335    Digit($n)
336      [$n eq "1"]
337        LongDistance
338        {
339            playTT($n);
340            setType(Telephone::LONG_DISTANCE());
341            saveAreaCode($n);
342            addDisplay("-");
343        }
344
345    // Check for 911.
346    Digit($n)
347      [$n eq "9"]
348        OneOneStart
349        {
350            playTT($n);
351            saveExchange($n);
352        }
353
354    Digit($n)
355        Exchange
356        {
357            playTT($n);
358            setType(Telephone::LOCAL());
359            saveExchange($n);
360        }
361}
362
363// Collect the area and then move on to the local number.
364LongDistance
365Entry
366{
367    startTimer("OffHookTimer", 10000);
368}
369Exit
370{
371    stopTimer("OffHookTimer");
372}
373{
374    // If an invalid digit is dialed, give up collecting
375    // digits immediately.
376    Digit($n)
377      [$n lt "0" || $n gt "9"]
378        pop(InvalidDigit)
379        {
380            clearDisplay();
381        }
382
383    Digit($n)
384      [length($ctxt->getAreaCode()) < 3]
385        nil
386        {
387            playTT($n);
388            saveAreaCode($n);
389            resetTimer("OffHookTimer", 10000);
390        }
391
392    Digit($n)
393        Exchange
394        {
395            playTT($n);
396            saveAreaCode($n);
397            addDisplay("-");
398        }
399}
400
401// Check if this is a 911 call.
402OneOneStart
403Entry
404{
405    startTimer("OffHookTimer", 10000);
406}
407Exit
408{
409    stopTimer("OffHookTimer");
410}
411{
412    // If an invalid digit is dialed, give up collecting
413    // digits immediately.
414    Digit($n)
415      [$n lt "0" || $n gt "9"]
416        pop(InvalidDigit)
417        {
418            clearDisplay();
419        }
420
421    Digit($n)
422      [$n eq "1"]
423        NineOne
424        {
425            playTT($n);
426            saveExchange($n);
427        }
428
429    Digit($n)
430        Exchange
431        {
432            playTT($n);
433            setType(Telephone::LOCAL());
434            saveExchange($n);
435        }
436}
437
438// Almost there.
439NineOne
440Entry
441{
442    startTimer("OffHookTimer", 10000);
443}
444Exit
445{
446    stopTimer("OffHookTimer");
447}
448{
449    // If an invalid digit is dialed, give up collecting
450    // digits immediately.
451    Digit($n)
452      [$n lt "0" || $n gt "9"]
453        pop(InvalidDigit)
454        {
455            clearDisplay();
456        }
457
458    Digit($n)
459      [$n eq "1"]
460        pop(DialingDone,
461                $ctxt->getType(),
462                $ctxt->getAreaCode(),
463                $ctxt->getExchange(),
464                $ctxt->getLocal())
465        {
466            playTT($n);
467            setType(Telephone::EMERGENCY());
468            saveExchange($n);
469        }
470
471    Digit($n)
472        LocalCall
473        {
474            playTT($n);
475            setType(Telephone::LOCAL());
476            saveExchange($n);
477            addDisplay("-");
478        }
479}
480
481// Collect the three digit exchange.
482Exchange
483Entry
484{
485    startTimer("OffHookTimer", 10000);
486}
487Exit
488{
489    stopTimer("OffHookTimer");
490}
491{
492    // If an invalid digit is dialed, give up collecting
493    // digits immediately.
494    Digit($n)
495      [$n lt "0" || $n gt "9"]
496        pop(InvalidDigit)
497        {
498            clearDisplay();
499        }
500
501    Digit($n)
502      [length($ctxt->getExchange()) < 2]
503        nil
504        {
505            playTT($n);
506            saveExchange($n);
507            resetTimer("OffHookTimer", 10000);
508        }
509
510    Digit($n)
511        LocalCall
512        {
513            playTT($n);
514            saveExchange($n);
515            addDisplay("-");
516        }
517}
518
519// Process a local call.
520LocalCall
521Entry
522{
523    startTimer("OffHookTimer", 10000);
524}
525Exit
526{
527    stopTimer("OffHookTimer");
528}
529{
530    // If an invalid digit is dialed, give up collecting
531    // digits immediately.
532    Digit($n)
533      [$n lt "0" || $n gt "9"]
534        pop(InvalidDigit)
535        {
536            clearDisplay();
537        }
538
539    Digit($n)
540      [length($ctxt->getLocal()) < 3]
541        nil
542        {
543            playTT($n);
544            saveLocal($n);
545            resetTimer("OffHookTimer", 10000);
546        }
547
548    Digit($n)
549        pop(DialingDone,
550                $ctxt->getType(),
551                $ctxt->getAreaCode(),
552                $ctxt->getExchange(),
553                $ctxt->getLocal())
554        {
555            playTT($n);
556            saveLocal($n);
557        }
558}
559
560Default
561{
562    // Caller has stopped dialing and left the phone
563    // off hook.
564    OffHookTimer
565        pop(LeftOffHook)
566        {
567            clearDisplay();
568        }
569
570    // Pass this event up.
571    OnHook
572        pop(OnHook)
573        {
574            clearDisplay();
575        }
576
577    InvalidDigit
578        pop(InvalidDigit)
579        {
580            clearDisplay();
581        }
582
583    // Ignore the clock timer outside of the OnHook state.
584    ClockTimer
585        nil
586        {}
587}
588
589%%
590