1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 ICDIAG.CC                                 */
4 /*                                                                           */
5 /* (C) 1995-96  Ullrich von Bassewitz                                        */
6 /*              Wacholderweg 14                                              */
7 /*              D-70597 Stuttgart                                            */
8 /* EMail:       uz@ibb.schwaben.com                                          */
9 /*                                                                           */
10 /*****************************************************************************/
11 
12 
13 
14 // $Id$
15 //
16 // $Log$
17 //
18 //
19 
20 
21 
22 #include <stdio.h>
23 
24 #include "eventid.h"
25 #include "delay.h"
26 #include "strcvt.h"
27 #include "coll.h"
28 #include "datetime.h"
29 #include "menue.h"
30 #include "textitem.h"
31 #include "listbox.h"
32 #include "menuitem.h"
33 #include "progutil.h"
34 #include "settings.h"
35 #include "winmgr.h"
36 
37 #include "icobjid.h"
38 #include "icevents.h"
39 #include "icintcon.h"
40 #include "icmsg.h"
41 #include "devstate.h"
42 #include "icdlog.h"
43 #include "icdiag.h"
44 
45 
46 
47 // Register the class
48 LINK (MatrixWindow, ID_MatrixWindow);
49 
50 
51 
52 /*****************************************************************************/
53 /*                             Message constants                             */
54 /*****************************************************************************/
55 
56 
57 
58 const u16 msMatrixWindowTitle   = MSGBASE_ICDIAG +  0;
59 const u16 msMatrixWindowHeader  = MSGBASE_ICDIAG +  1;
60 
61 
62 
63 /*****************************************************************************/
64 /*                                   Data                                    */
65 /*****************************************************************************/
66 
67 
68 
69 // The name of the matrix window position in the settings file
70 static const String MatrixWindowBounds = "MatrixWindow.Bounds";
71 
72 // Width of the matrix window
73 static const unsigned MatrixWindowWidth = 64;
74 
75 
76 
77 /*****************************************************************************/
78 /*                      Explicit template instantiation                      */
79 /*****************************************************************************/
80 
81 
82 
83 #ifdef EXPLICIT_TEMPLATES
84 template class Collection<class DevStateInfo>;
85 template class SortedCollection<class DevStateInfo, unsigned char>;
86 template class ListBox<class DevStateInfo>;
87 #endif
88 
89 
90 
91 /*****************************************************************************/
92 /*                            class DevStateColl                             */
93 /*****************************************************************************/
94 
95 
96 
97 class DevStateColl: public SortedCollection<DevStateInfo, unsigned char> {
98 
99 protected:
100     virtual int Compare (const unsigned char* Key1, const unsigned char* Key2);
101     virtual const unsigned char* KeyOf (const DevStateInfo* Item);
102 
103 public:
104     DevStateColl ();
105     // Create a DevStateColl
106 
107     void DeleteDev (unsigned char Num);
108     // Delete the device with the given numer.
109 
110     DevStateInfo* NewDev (unsigned char Num);
111     // Create and insert a device with the given numer.
112 
113     DevStateInfo* GetDevStateInfo (unsigned char Num);
114     // Return a pointer to the entry. Calls FAIL if the entry does not exist
115 
116     void SetState (unsigned char Dev, unsigned NewState);
117     void ClrState (unsigned char Dev, unsigned NewState);
118     // Set/reset the device state bits
119 
120     DevStateInfo* At (int Index);
121     // Return a pointer to the item at position Index.
122     // OVERRIDE FOR DEBUGGING
123 
124     void SetSchleife (unsigned Dev, int State);
125     void SetAmt (unsigned Dev, int State, unsigned Amt);
126     void SetInt (unsigned Dev, int State, unsigned Int);
127     void SetTon (unsigned Dev, int State);
128     void SetWTon (unsigned Dev, int State);
129     void SetTFE (unsigned Dev, int State);
130     void SetRuf (unsigned Dev, int State);
131     // Set specific matrix states
132 
133     void AddDigit (unsigned Dev, char Digit);
134     // Add a digit to the phone number if the device is in a state where a digit
135     // is accepted (dialed)
136 };
137 
138 
139 
Compare(const unsigned char * Key1,const unsigned char * Key2)140 int DevStateColl::Compare (const unsigned char* Key1, const unsigned char* Key2)
141 {
142     if (*Key1 < *Key2) {
143         return -1;
144     } else if (*Key1 > *Key2) {
145         return 1;
146     } else {
147         return 0;
148     }
149 }
150 
151 
152 
KeyOf(const DevStateInfo * Item)153 const unsigned char* DevStateColl::KeyOf (const DevStateInfo* Item)
154 {
155     return &Item->DevNum;
156 }
157 
158 
159 
DevStateColl()160 DevStateColl::DevStateColl ():
161     SortedCollection <DevStateInfo, unsigned char> (10, 10, 1)
162 {
163     // Insert 8 devices (more devices are added dynamically if they are
164     // detected the first time)
165     for (unsigned char Dev = 0; Dev < 8; Dev++) {
166         NewDev (Dev);
167     }
168 }
169 
170 
171 
DeleteDev(unsigned char Num)172 void DevStateColl::DeleteDev (unsigned char Num)
173 // Delete the device with the given numer.
174 {
175     // Search for the device
176     int Index;
177     int Result = Search (&Num, Index);
178     CHECK (Result != 0);
179 
180     // Delete the entry
181     AtDelete (Index);
182 }
183 
184 
185 
NewDev(unsigned char Num)186 DevStateInfo* DevStateColl::NewDev (unsigned char Num)
187 // Create and insert a device with the given numer.
188 {
189     // Create a new entry
190     DevStateInfo* DI = new DevStateInfo (Num);
191 
192     // Insert the new entry
193     Insert (DI);
194 
195     // And return it
196     return DI;
197 }
198 
199 
200 
GetDevStateInfo(unsigned char Num)201 DevStateInfo* DevStateColl::GetDevStateInfo (unsigned char Num)
202 // Return a pointer to the entry. Creates an entry if none exists.
203 {
204     // Search for the entry
205     int Index;
206     if (Search (&Num, Index) == 0) {
207         // No entry til now, create one
208         return NewDev (Num);
209     } else {
210         // Found, return it
211         return At (Index);
212     }
213 }
214 
215 
216 
SetState(unsigned char Dev,unsigned NewState)217 void DevStateColl::SetState (unsigned char Dev, unsigned NewState)
218 // Set the device state bits
219 {
220     GetDevStateInfo (Dev)->SetState (NewState);
221 }
222 
223 
224 
ClrState(unsigned char Dev,unsigned NewState)225 void DevStateColl::ClrState (unsigned char Dev, unsigned NewState)
226 // Reset the device state bits
227 {
228     GetDevStateInfo (Dev)->ClrState (NewState);
229 }
230 
231 
232 
At(int Index)233 DevStateInfo* DevStateColl::At (int Index)
234 // Return a pointer to the item at position Index.
235 // OVERRIDE FOR DEBUGGING
236 {
237     // Check range
238     if (Index < 0 || Index >= Count) {
239         FAIL ("DevStateColl::At: Index out of bounds");
240         return NULL;
241     }
242 
243     return SortedCollection<DevStateInfo, unsigned char>::At (Index);
244 }
245 
246 
247 
SetSchleife(unsigned Dev,int State)248 void DevStateColl::SetSchleife (unsigned Dev, int State)
249 {
250     GetDevStateInfo (Dev)->SetSchleife (State);
251 }
252 
253 
254 
SetAmt(unsigned Dev,int State,unsigned Amt)255 void DevStateColl::SetAmt (unsigned Dev, int State, unsigned Amt)
256 {
257     GetDevStateInfo (Dev)->SetAmt (State, Amt);
258 }
259 
260 
261 
SetInt(unsigned Dev,int State,unsigned Int)262 void DevStateColl::SetInt (unsigned Dev, int State, unsigned Int)
263 {
264     GetDevStateInfo (Dev)->SetInt (State, Int);
265 }
266 
267 
268 
SetTon(unsigned Dev,int State)269 void DevStateColl::SetTon (unsigned Dev, int State)
270 {
271     GetDevStateInfo (Dev)->SetTon (State);
272 }
273 
274 
275 
SetWTon(unsigned Dev,int State)276 void DevStateColl::SetWTon (unsigned Dev, int State)
277 {
278     GetDevStateInfo (Dev)->SetWTon (State);
279 }
280 
281 
282 
SetTFE(unsigned Dev,int State)283 void DevStateColl::SetTFE (unsigned Dev, int State)
284 {
285     GetDevStateInfo (Dev)->SetTFE (State);
286 }
287 
288 
289 
SetRuf(unsigned Dev,int State)290 void DevStateColl::SetRuf (unsigned Dev, int State)
291 {
292     GetDevStateInfo (Dev)->SetRuf (State);
293 }
294 
295 
296 
AddDigit(unsigned Dev,char Digit)297 void DevStateColl::AddDigit (unsigned Dev, char Digit)
298 // Add a digit to the phone number if the device is in a state where a digit
299 // is accepted (dialed)
300 {
301     GetDevStateInfo (Dev)->AddDigit (Digit);
302 }
303 
304 
305 
306 static DevStateColl DevState;
307 
308 
309 
310 /*****************************************************************************/
311 /*                            class MatrixListBox                            */
312 /*****************************************************************************/
313 
314 
315 
316 class MatrixListBox: public ListBox<DevStateInfo> {
317 
318 protected:
319     virtual void Print (int Index, int X, int Y, u16 Attr);
320     // Display one of the listbox entries
321 
322 public:
323     MatrixListBox (i16 aID, const Point& aSize);
324     // Create a matrix listbox
325 
326     MatrixListBox (StreamableInit);
327     // Create an empty matrix listbox
328 
329     virtual ~MatrixListBox ();
330     // Destroy a MatrixListBox
331 
332     virtual u16 StreamableID () const;
333     // Return the streamable ID
334 
335     static Streamable* Build ();
336     // Build an empty object
337 };
338 
339 
340 
341 // Register the class
342 LINK (MatrixListBox, ID_MatrixListBox);
343 
344 
345 
MatrixListBox(i16 aID,const Point & aSize)346 MatrixListBox::MatrixListBox (i16 aID, const Point& aSize):
347     ListBox <DevStateInfo> ("", aID, aSize, atEditNormal, atEditBar, atEditNormal, NULL)
348 {
349     // Set the collection
350     SetColl (&DevState);
351 }
352 
353 
354 
MatrixListBox(StreamableInit)355 inline MatrixListBox::MatrixListBox (StreamableInit):
356     ListBox<DevStateInfo> (Empty)
357 // Create an empty matrix listbox
358 {
359     // Set the collection
360     SetColl (&DevState);
361 }
362 
363 
364 
~MatrixListBox()365 MatrixListBox::~MatrixListBox ()
366 // Destroy a MatrixListBox
367 {
368     // Beware: Before deleting, reset the collection pointer of the listbox
369     SetColl (NULL);
370 }
371 
372 
373 
Print(int Index,int X,int Y,u16 Attr)374 void MatrixListBox::Print (int Index, int X, int Y, u16 Attr)
375 {
376     // Get the line
377     String S = Coll->At (Index)->MatrixLine;
378 
379     // Pad the line to length
380     S.Pad (String::Right, Size.X);
381 
382     // Write out the string
383     Owner->Write (X, Y, S, Attr);
384 }
385 
386 
387 
StreamableID() const388 u16 MatrixListBox::StreamableID () const
389 // Return the streamable ID
390 {
391     return ID_MatrixListBox;
392 }
393 
394 
395 
Build()396 Streamable* MatrixListBox::Build ()
397 // Build an empty object
398 {
399     return new MatrixListBox (Empty);
400 }
401 
402 
403 
404 /*****************************************************************************/
405 /*                            class MatrixWindow                             */
406 /*****************************************************************************/
407 
408 
409 
HandleKey(Key & K)410 void MatrixWindow::HandleKey (Key& K)
411 // Key dispatcher used in Browse
412 {
413     // First call the derived function.
414     ItemWindow::HandleKey (K);
415 
416     // Maybe the listbox has some work
417     MatrixBox->HandleKey (K);
418 }
419 
420 
421 
MatrixWindow(const Point & Pos,unsigned aDevCount)422 MatrixWindow::MatrixWindow (const Point& Pos, unsigned aDevCount):
423     ItemWindow (Rect (Pos.X, Pos.Y, Pos.X+MatrixWindowWidth+2, Pos.Y+11),
424                 wfFramed | wfCanMove | wfCanResize | wfSaveVisible),
425     MatrixBox (NULL),
426     DevCount (aDevCount),
427     ZoomSize (OBounds)
428 {
429     // Count of windows must be zero, otherwise this is an error
430     CHECK (WindowCount == 0);
431 
432     // Lock window output
433     Lock ();
434 
435     // If there is a stored window size in the settings file, resize the
436     // window to the stored rectangle.
437     Rect StoredBounds = StgGetRect (MatrixWindowBounds, OBounds);
438     if (StoredBounds != OBounds) {
439         Resize (StoredBounds);
440     }
441 
442     // Set the window title
443     SetHeader (LoadAppMsg (msMatrixWindowTitle));
444 
445     // Create and insert the header line
446     TextItem* HdrItem = new TextItem (LoadAppMsg (msMatrixWindowHeader),
447                                       100, atTextNormal, NULL);
448     AddItem (HdrItem);
449     HdrItem->SetWidth (IXSize ());
450     HdrItem->SetPos (0, 0);
451 
452     // Create a listbox inside the window
453     Point Size (IXSize (), IYSize () - 1);
454     MatrixBox = new MatrixListBox (1, Size);
455     AddItem (MatrixBox);
456     MatrixBox->SetPos (0, 1);
457     MatrixBox->Draw ();
458 
459     // Redraw the window contents
460     DrawInterior ();
461 
462     // Unlock the window, allowing output
463     Unlock ();
464 
465     // Ok, we have the window now
466     WindowCount++;
467 
468     // Tell the application that the window count has changed
469     PostEvent (evMatrixWinChange, WindowCount);
470 }
471 
472 
473 
MatrixWindow(StreamableInit)474 inline MatrixWindow::MatrixWindow (StreamableInit):
475     ItemWindow (Empty)
476 {
477     // One window more
478     WindowCount++;
479 
480     // Tell the application that the window count has changed
481     PostEvent (evMatrixWinChange, WindowCount);
482 }
483 
484 
485 
~MatrixWindow()486 MatrixWindow::~MatrixWindow ()
487 {
488     // Store the current window position and size into the settings file
489     StgPutRect (OBounds, MatrixWindowBounds);
490 
491     // Decrease the window count and invalidate the global pointer
492     WindowCount--;
493 
494     // Tell the application that the window count has changed
495     PostEvent (evMatrixWinChange, WindowCount);
496 }
497 
498 
499 
Store(Stream & S) const500 void MatrixWindow::Store (Stream& S) const
501 // Store the object into a stream
502 {
503     // Before storing, be shure to reset the pointer for the device state
504     // collection
505     MatrixBox->SetColl (NULL);
506 
507     // Now use the inherited store
508     ItemWindow::Store (S);
509 
510     // Reset the collection pointer
511     MatrixBox->SetColl (&DevState);
512 
513     // Store additional data
514     S << DevCount << ZoomSize;
515 }
516 
517 
518 
Load(Stream & S)519 void MatrixWindow::Load (Stream& S)
520 // Load the object from a stream
521 {
522     // Load the derived data
523     ItemWindow::Load (S);
524 
525     // Load the device count
526     S >> DevCount >> ZoomSize;
527 
528     // Get a pointer to the listbox
529     MatrixBox = (MatrixListBox*) ForcedItemWithID (1);
530 
531     // Assign a pointer to the global collection
532     MatrixBox->SetColl (&DevState);
533 
534     // The inherited Load function did not draw the contents of the listbox
535     // since the listbox had no valid data collection at that time. Do the
536     // redraw now.
537     DrawMatrix ();
538 }
539 
540 
541 
StreamableID() const542 u16 MatrixWindow::StreamableID () const
543 // Return the streamable ID
544 {
545     return ID_MatrixWindow;
546 }
547 
548 
549 
Build()550 Streamable* MatrixWindow::Build ()
551 // Build an empty object
552 {
553     return new MatrixWindow (Empty);
554 }
555 
556 
557 
MinXSize() const558 unsigned MatrixWindow::MinXSize () const
559 // Return the minimum X size of the window. Override this to limit resizing.
560 {
561     return 7;           // Device number + online flag
562 }
563 
564 
565 
MinYSize() const566 unsigned MatrixWindow::MinYSize () const
567 // Return the minumim Y size of the window. Override this to limit resizing.
568 {
569     return 4;           // Header and one device
570 }
571 
572 
573 
Resize(const Rect & NewBounds)574 void MatrixWindow::Resize (const Rect& NewBounds)
575 // Resize the window to the new bounds (this can also be used to move the
576 // window but Move is faster if the window should not be resized).
577 {
578     // If we have already a matrix listbox, resize it to fit into the new
579     // window
580     if (MatrixBox) {
581         MatrixBox->SetWidth (NewBounds.XSize () - 2);
582         MatrixBox->SetHeight (NewBounds.YSize () - 3);
583     }
584 
585     // Now do the actual resize
586     ItemWindow::Resize (NewBounds);
587 }
588 
589 
590 
Zoom()591 void MatrixWindow::Zoom ()
592 // Zoom the window
593 {
594     // Get the desktop bounds
595     Rect Desktop = Background->GetDesktop ();
596 
597     // Check if we must zoom in or out
598     if (OBounds != Desktop) {
599         // Remember the old size, then zoom out
600         ZoomSize = OBounds;
601         Resize (Desktop);
602     } else {
603         // Zoom in
604         Resize (ZoomSize);
605     }
606 }
607 
608 
609 
DrawMatrix()610 void MatrixWindow::DrawMatrix ()
611 // Redraw the listbox after changes
612 {
613     MatrixBox->Draw ();
614 }
615 
616 
617 
HandleEvent(Event & E)618 void MatrixWindow::HandleEvent (Event& E)
619 // Handle incoming events
620 {
621     // Call the derived function
622     ItemWindow::HandleEvent (E);
623     if (E.Handled) {
624         return;
625     }
626 
627     // Switch on the type of event
628     switch (E.What) {
629 
630         case evMatrixChange:
631             // Redraw the complete matrix for now
632             DrawMatrix ();
633             break;
634 
635     }
636 }
637 
638 
639 
640 /*****************************************************************************/
641 /*                  Static variables of class MatrixWindow                   */
642 /*****************************************************************************/
643 
644 
645 
646 unsigned MatrixWindow::WindowCount = 0;
647 
648 
649 
650 /*****************************************************************************/
651 /*                             Helper functions                              */
652 /*****************************************************************************/
653 
654 
655 
MapDigit(unsigned Digit)656 static char MapDigit (unsigned Digit)
657 // Map a digit code into the corresponding character
658 {
659     // Remap the digit code to a real digit
660     switch (Digit) {
661         case  1:        return '1';
662         case  2:        return '2';
663         case  3:        return '3';
664         case  4:        return '4';
665         case  5:        return '5';
666         case  6:        return '6';
667         case  7:        return '7';
668         case  8:        return '8';
669         case  9:        return '9';
670         case 10:        return '0';
671         case 16:        return 'R';
672         default:        return '?';
673     }
674 }
675 
676 
677 
678 /*****************************************************************************/
679 /*                          Matrix update functions                          */
680 /*****************************************************************************/
681 
682 
683 
RedrawMatrixCol(unsigned Dev)684 static void RedrawMatrixCol (unsigned Dev)
685 {
686     // Post an event
687     PostEvent (evMatrixChange, (void*)DevState.GetDevStateInfo (Dev));
688 }
689 
690 
691 
WriteDialStatus(unsigned Dev,unsigned Digit)692 static void WriteDialStatus (unsigned Dev, unsigned Digit)
693 {
694     // Remember the digit, but only if we don't have already a connection
695     DevState.AddDigit (Dev, MapDigit (Digit));
696 
697     // Update the matrix window
698     RedrawMatrixCol (Dev);
699 }
700 
701 
702 
SetMatrix(unsigned Col,unsigned Dev,int State)703 static void SetMatrix (unsigned Col, unsigned Dev, int State)
704 {
705     // Check which matrix column to set
706     switch (Col) {
707 
708         case 0:
709             DevState.SetAmt (Dev, State, 1);
710             break;
711 
712         case 1:
713             DevState.SetAmt (Dev, State, 2);
714             break;
715 
716         case 2:
717             DevState.SetInt (Dev, State, 1);
718             break;
719 
720         case 3:
721             DevState.SetInt (Dev, State, 2);
722             break;
723 
724         case 4:
725             DevState.SetInt (Dev, State, 3);
726             break;
727 
728         case 5:
729             DevState.SetTon (Dev, State);
730             break;
731 
732         case 6:
733             DevState.SetWTon (Dev, State);
734             break;
735 
736         case 7:
737             DevState.SetTFE (Dev, State);
738             break;
739 
740         default:
741             WriteDebugLog (FormatStr ("Unknown matrix col: %d", Col));
742             break;
743 
744     }
745 
746     // Update the matrix column
747     RedrawMatrixCol (Dev);
748 }
749 
750 
751 
752 /*****************************************************************************/
753 /*                                   Code                                    */
754 /*****************************************************************************/
755 
756 
757 
MsgDesc(const char * S,unsigned Dev,unsigned State)758 static String MsgDesc (const char* S, unsigned Dev, unsigned State)
759 {
760     return FormatStr ("Device %d: %s %s", Dev+21, S, State? "on" : "off");
761 }
762 
763 
764 
DialDesc(const char * S,unsigned Dev,unsigned Digit)765 static String DialDesc (const char* S, unsigned Dev, unsigned Digit)
766 {
767     return FormatStr ("Device %d: %s '%c'", Dev+21, S, MapDigit (Digit));
768 }
769 
770 
771 
MatrixDesc(unsigned Dev,unsigned Code,unsigned State)772 static String MatrixDesc (unsigned Dev, unsigned Code, unsigned State)
773 {
774     // Map the code into a real action
775     char* Action;
776     switch (Code) {
777         case 0:         Action = "Line 1";              break;
778         case 1:         Action = "Line 2";              break;
779         case 2:         Action = "Int 1";               break;
780         case 3:         Action = "Int 2";               break;
781         case 4:         Action = "Int 3";               break;
782         case 5:         Action = "Tone";                break;
783         case 6:         Action = "Dial tone";           break;
784         case 7:         Action = "TFE";                 break;
785         default:        Action = "Unknown matrix col";  break;
786     }
787 
788     return FormatStr ("Device %d: %s %s", Dev+21, Action, State? "on" : "off");
789 }
790 
791 
792 
DiagMsgDesc(const unsigned char * Msg)793 String DiagMsgDesc (const unsigned char* Msg)
794 // Return a textual description of the given diagnostic message
795 {
796     switch (Msg [1]) {
797 
798         case 0x00:
799             return "Enable diag mode";
800 
801         case 0x01:
802             return "Disable diag mode";
803 
804         case 0x02:
805             // connection matrix
806             return MatrixDesc (Msg [3], Msg [2], Msg [4]);
807 
808         case 0x03:
809             // call
810             return MsgDesc ("Call", Msg [2], Msg [4]);
811 
812         case 0x04:
813             // Schleifenzustand
814             return MsgDesc ("Loop", Msg [2], Msg [4]);
815 
816         case 0x05:
817             // Pulse dial
818             return DialDesc ("Pulse dial", Msg [2], Msg [4]);
819 
820         case 0x06:
821             // Tone dial
822             return DialDesc ("Tone Dial", IntCon [Msg [2]], Msg [4]);
823 
824         case 0x07:
825             // LED state
826             return FormatStr ("LED state %s", Msg [4]? "on" : "off");
827 
828         case 0x08:
829             // Charges
830             return "";
831 
832         case 0x09:
833             // TFE amplifier
834             return "";
835 
836         case 0x0A:
837             // Door opener
838             return "";
839 
840         case 0x0D:
841             // Switch
842             return "";
843 
844         default:
845             // Unknown debug message!
846             return "Unknown diagnostic message!";
847 
848     }
849 }
850 
851 
852 
HandleDiagMsg(const unsigned char * Msg)853 void HandleDiagMsg (const unsigned char* Msg)
854 // Handle a diagnostic message from the istec
855 {
856     // Check the event type
857     String S;
858     switch (Msg [1]) {
859 
860         case 0x02:
861             // connection matrix
862             SetMatrix (Msg [2], Msg [3], Msg [4]);
863             break;
864 
865         case 0x03:
866             // call
867             DevState.SetRuf (Msg [2], Msg [4]);
868             RedrawMatrixCol (Msg [2]);
869             break;
870 
871         case 0x04:
872             // Schleifenzustand
873             DevState.SetSchleife (Msg [2], Msg [4]);
874             RedrawMatrixCol (Msg [2]);
875             break;
876 
877         case 0x05:
878             // Pulse dial
879             WriteDialStatus (Msg [2], Msg [4]);
880             break;
881 
882         case 0x06:
883             // Tone dial
884             WriteDialStatus (IntCon [Msg [2]], Msg [4]);
885             break;
886 
887         case 0x07:
888             // LED state
889             break;
890 
891         case 0x08:
892             // Charges
893             break;
894 
895         case 0x09:
896             // TFE amplifier
897             break;
898 
899         case 0x0A:
900             // Door opener
901             break;
902 
903         case 0x0D:
904             // Switch
905             break;
906 
907         default:
908             // Unknown debug message!
909             S = FormatStr ("%02x %02x %02x %02x %02x",
910                            Msg [1], Msg [2], Msg [3], Msg [4], Msg [5]);
911             WriteDebugLog ("Warning: Got unknown diagnostic message: " + S);
912             break;
913 
914     }
915 }
916 
917 
918 
919