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