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