home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / windows / modem / modem.pas < prev    next >
Pascal/Delphi Source File  |  1994-04-11  |  13KB  |  492 lines

  1. {$R Modem}
  2. uses WinTypes, WinProcs, WObjects, Strings;
  3. type
  4.   TEditLine = array[0..50] of Char;
  5. const
  6.   idEdit      = 100;
  7.   idDial      = 201;
  8.   idDialStart = 101;
  9.   idPhoneNum  = 102;
  10.   idConfigure = 202;
  11.   id1200      = 101;
  12.   id2400      = 102;
  13.   id4800      = 103;
  14.   id9600      = 104;
  15.   idOdd       = 105;
  16.   idEven      = 106;
  17.   idNone      = 107;
  18.   idComm1     = 108;
  19.   idComm2     = 109;
  20.   id1Stop     = 110;
  21.   id2Stop     = 111;
  22.   id7Data     = 112;
  23.   id8Data     = 113;
  24.  
  25.   LineWidth   = 80;  { Width of each line displayed.                 }
  26.   LineHeight  = 60;  { Number of line that are held in memory.       }
  27.  
  28.   { The configuration string bellow is used to configure the modem.  }
  29.   { It is set for communication port 2, 2400 baud, No parity, 8 data }
  30.   { bits, 1 stop bit.                                                }
  31.  
  32.   Comm  : Char = '2';
  33.   Baud  : Word = 24;
  34.   Parity: Char = 'n';
  35.   Stop  : Char = '1';
  36.   Data  : Char = '8';
  37.  
  38.   DialStart: TEditLine = 'ATDT';
  39.   PhoneNumber: TEditLine = '';
  40.  
  41.  
  42. type
  43.   TApp = object(TApplication)
  44.     procedure Idle; virtual;
  45.     procedure InitMainWindow; virtual;
  46.     procedure MessageLoop; virtual;
  47.   end;
  48.  
  49.   PBuffer = ^TBuffer;
  50.   TBuffer = object(TCollection)
  51.     Pos: Integer;
  52.     constructor Init(AParent: PWindow);
  53.     procedure FreeItem(Item: Pointer); virtual;
  54.     function PutChar(C: Char): Boolean;
  55.   end;
  56.  
  57.   PCommWindow = ^TCommWindow;
  58.   TCommWindow = object(TWindow)
  59.     Cid: Integer;
  60.     Buffer: PBuffer;
  61.     FontRec: TLogFont;
  62.     CharHeight: Integer;
  63.     constructor Init(AParent: PWindowsObject; ATitle: PChar);
  64.     destructor Done; virtual;
  65.     procedure Configure(var Message: TMessage);
  66.       virtual cm_First + idConfigure;
  67.     procedure Dial(var Message: TMessage);
  68.       virtual cm_First + idDial;
  69.     procedure Error(E: Integer; C: PChar);
  70.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  71.     procedure ReadChar; virtual;
  72.     procedure SetConfigure;
  73.     procedure SetHeight;
  74.     procedure SetUpWindow; virtual;
  75.     procedure wmChar(var Message: TMessage);
  76.       virtual wm_Char;
  77.     procedure wmSize(var Message: TMessage);
  78.       virtual wm_Size;
  79.     procedure WriteChar;
  80.   end;
  81.  
  82. { TBuffer }
  83. { The Buffer is use to hold each line that is displayed in the main    }
  84. { window.  The constance LineHeight determines the number of line that }
  85. { are stored.  The Buffer is prefilled with the LineHeight worth of    }
  86. { lines.                                                               }
  87. constructor TBuffer.Init(AParent: PWindow);
  88. var
  89.   P: PChar;
  90.   I: Integer;
  91. begin
  92.   TCollection.Init(LineHeight + 1, 10);
  93.   GetMem(P, LineWidth + 1);
  94.   P[0] := #0;
  95.   Pos := 0;
  96.   Insert(P);
  97.   for I := 1 to LineHeight do
  98.   begin
  99.     GetMem(P, LineWidth + 1);
  100.     P[0] := #0;
  101.     Insert(P);
  102.   end;
  103. end;
  104.  
  105. procedure TBuffer.FreeItem(Item: Pointer);
  106. begin
  107.   FreeMem(Item, LineWidth + 1);
  108. end;
  109.  
  110. { This procedure is process all incomming in formation from the com  }
  111. { port.  This procedure is called by TCommWindow.ReadChar.           }
  112.  
  113. function TBuffer.PutChar(C: Char): Boolean;
  114. var
  115.   Width: Integer;
  116.   P: PChar;
  117. begin
  118.   PutChar := False;
  119.   Case C of
  120.     #13: Pos := 0;                          { if a Carriage Return.  }
  121.     #10:                                    { if a Line Feed.        }
  122.       begin
  123.         GetMem(P, LineWidth + 1);
  124.         FillChar(P^, LineWidth + 1, ' ');
  125.         P[Pos] := #0;
  126.         Insert(P);
  127.       end;
  128.     #8:
  129.       if Pos > 0 then                       { if a Delete.           }
  130.       begin
  131.         Dec(Pos);
  132.         P := At(Count - 1);
  133.         P[Pos] := ' ';
  134.       end;
  135.    #32..#128:                               { else handle all other  }
  136.     begin                                   { displayable characters.}
  137.       P := At(Count - 1);
  138.       Width := StrLen(P);
  139.       if Width > LineWidth then             { if line is to wide     }
  140.       begin                                 { create a new line.     }
  141.         Pos := 1;
  142.         GetMem(P, LineWidth + 1);
  143.         P[0] := C;
  144.         P[1] := #0;
  145.         Insert(P);
  146.       end
  147.       else                                   { else add character    }
  148.       begin                                  { to current line.      }
  149.         P[Pos] := C;
  150.         Inc(Pos);
  151.         P[Pos] := #0;
  152.       end;
  153.     end;
  154.   end;
  155.   if Count > LineHeight then                 { if more to many lines }
  156.   begin                                      { have been added delete}
  157.     AtFree(0);                               { current line and let  }
  158.     PutChar := True;                         { the call procedure    }
  159.   end;                                       { know to scroll up.    }
  160. end;
  161.  
  162. { TCommWindow }
  163. { The CommWindow displays the incoming and out goinging text.  There  }
  164. { should be mention that the text type by the use is displayed by     }
  165. { being echo back to the ReadChar procedure.  So there is no need for }
  166. { wmChar to write a character to the screen.                          }
  167. constructor TCommWindow.Init(AParent: PWindowsObject; ATitle: PChar);
  168. begin
  169.   TWindow.Init(AParent, ATitle);
  170.   Attr.Style := Attr.Style or ws_VScroll;
  171.   Attr.Menu := LoadMenu(HInstance, 'Menu_1');
  172.   Scroller := New(PScroller, Init(@Self, 1, 1, 100, 100));
  173.   Buffer := New(PBuffer, Init(@Self));
  174. end;
  175.  
  176. { Close the Comm port and deallocate the Buffer.                      }
  177. destructor TCommWindow.Done;
  178. begin
  179.   Error(CloseComm(Cid), 'Close');
  180.   Dispose(Buffer, Done);
  181.   TWindow.Done;
  182. end;
  183.  
  184. procedure TCommWindow.Configure(var Message: TMessage);
  185. var
  186.   Trans: record
  187.     R1200,
  188.     R2400,
  189.     R4800,
  190.     R9600,
  191.     ROdd,
  192.     REven,
  193.     RNone,
  194.     RComm1,
  195.     RComm2,
  196.     R1Stop,
  197.     R2Stop,
  198.     R7Data,
  199.     R8Data: Word;
  200.   end;
  201.   D: TDialog;
  202.   P: PWindowsObject;
  203.   I: Integer;
  204. begin
  205.   D.Init(@Self, 'Configure');
  206.   For I := id1200 to id8Data do
  207.     P := New(PRadioButton, InitResource(@D, I));
  208.   With Trans do
  209.   begin
  210.     R1200 := Byte(Baud = 12);
  211.     R2400 := Byte(Baud = 24);
  212.     R4800 := Byte(Baud = 48);
  213.     R9600 := Byte(Baud = 96);
  214.  
  215.     ROdd  := Byte(Parity = 'o');
  216.     REven := Byte(Parity = 'e');
  217.     RNone := Byte(Parity = 'n');
  218.  
  219.     RComm1 := Byte(Comm = '1');
  220.     RComm2 := Byte(Comm = '2');
  221.  
  222.     R1Stop := Byte(Stop = '1');
  223.     R2Stop := Byte(Stop = '2');
  224.  
  225.     R7Data := Byte(Data = '7');
  226.     R8Data := Byte(Data = '8');
  227.   end;
  228.   D.TransferBuffer := @Trans;
  229.   if D.Execute = id_Ok then
  230.   begin
  231.     with Trans do
  232.     begin
  233.       Baud := (R1200 * 12) + (R2400 * 24) + (R4800 * 48) + (R9600 * 96);
  234.       if ROdd = bf_Checked then
  235.         Parity := 'o';
  236.       if REven = bf_Checked then
  237.         Parity := 'e';
  238.       if RNone = bf_Checked then
  239.         Parity := 'n';
  240.       if R1Stop = bf_Checked then
  241.         Stop := '1'
  242.       else
  243.         Stop := '2';
  244.       if RComm1 = bf_Checked then
  245.         Comm := '1'
  246.       else
  247.         Comm := '2';
  248.       if R7Data = bf_Checked then
  249.         Data := '7'
  250.       else
  251.         Data := '8';
  252.       SetConfigure;
  253.     end;
  254.   end;
  255.   D.Done;
  256. end;
  257.  
  258.  
  259. procedure TCommWindow.Dial(var Message: TMessage);
  260. var
  261.   Trans: record
  262.     Start: TEditLine;
  263.     Phone: TEditLine;
  264.   end;
  265.   D: TDialog;
  266.   P: PWindowsObject;
  267. begin
  268.   D.Init(@Self, 'Dial');
  269.   P := New(PEdit, InitResource(@D, idDialStart, SizeOf(TEditLine)));
  270.   P := New(PEdit, InitResource(@D, idPhoneNum, SizeOf(TEditLine)));
  271.   StrCopy(Trans.Start, DialStart);
  272.   StrCopy(Trans.Phone, PhoneNumber);
  273.   D.TransferBuffer := @Trans;
  274.   if D.Execute = id_Ok then
  275.   begin
  276.     StrCopy(DialStart, Trans.Start);
  277.     StrCopy(PhoneNumber, Trans.Phone);
  278.     StrCat(PhoneNumber, #13);
  279.     StrCat(PhoneNumber, #10);
  280.     if CID <> 0 then
  281.     begin
  282.       Error(WriteComm(CId, DialStart, StrLen(DialStart)), 'Writing');
  283.       Error(WriteComm(CId, PhoneNumber, StrLen(PhoneNumber)), 'Writing');
  284.     end;
  285.     PhoneNumber[StrLen(PhoneNumber) - 2] := #0;
  286.   end;
  287.   D.Done;
  288. end;
  289.  
  290.  
  291. { Checks for comm errors and writes any errors.                       }
  292. procedure TCommWindow.Error(E: Integer; C: PChar);
  293. var
  294.   S: array[0..100] of Char;
  295. begin
  296.   if E >= 0 then exit;
  297.   Str(E, S);
  298.   MessageBox(GetFocus, S, C, mb_Ok);
  299. end;
  300.  
  301. { Redraw all the lines in the buffer by using ForEach.                }
  302. procedure TCommWindow.Paint(PaintDC: HDC; var PaintInfo: TPaintStruct);
  303. var
  304.   I: Integer;
  305.   Font: HFont;
  306.  
  307.   procedure WriteOut(Item: PChar); far;
  308.   begin
  309.     TextOut(PaintDC, 0, CharHeight * I, Item, StrLen(Item));
  310.     inc(I);
  311.   end;
  312.  
  313. begin
  314.   I := 0;
  315.   Font := SelectObject(PaintDC, CreateFontIndirect(FontRec));
  316.   Buffer^.ForEach(@WriteOut);
  317.   DeleteObject(SelectObject(PaintDC, Font));
  318. end;
  319.  
  320. { Read a charecter from the comm port, if there is no error then call }
  321. { Buffer^.PutChar to add it to the buffer and write it to the screen. }
  322. procedure TCommWindow.ReadChar;
  323. var
  324.   Stat: TComStat;
  325.   I, Size: Integer;
  326.   C: Char;
  327. begin
  328.   GetCommError(CID, Stat);
  329.   for I := 1 to Stat.cbInQue do
  330.   begin
  331.     Size := ReadComm(CId, @C, 1);
  332.     Error(Size, 'Read Comm');
  333.     if C <> #0 then
  334.     begin
  335.       if Buffer^.PutChar(C) then
  336.       begin
  337.         ScrollWindow(HWindow, 0, -CharHeight, Nil, Nil);
  338.         UpDateWindow(HWindow);
  339.       end;
  340.       WriteChar;
  341.     end;
  342.   end;
  343. end;
  344.  
  345. procedure TCommWindow.SetConfigure;
  346. var
  347.   Config: array[0..20] of Char;
  348.   S: array[0..5] of Char;
  349.   DCB: TDCB;
  350. begin
  351.   StrCopy(Config, 'com?:??,?,?,?');
  352.   Config[3] := Comm;
  353.   Config[8] := Parity;
  354.   Config[10] := Data;
  355.   Config[12] := Stop;
  356.   Str(Baud, S);
  357.   Config[5] := S[0];
  358.   Config[6] := S[1];
  359.   BuildCommDCB(Config, DCB);
  360.   DCB.ID := CID;
  361.   Error(SetCommState(DCB), 'Set Comm State');
  362. end;
  363.  
  364. procedure TCommWindow.SetUpWindow;
  365. var
  366.   DCB: TDCB;
  367. begin
  368.   TWindow.SetUpWindow;
  369.   SetHeight;
  370.  
  371. { Open for Comm2 2400 Baud, No Parity, 8 Data Bits, 1 Stop Bit }
  372.  
  373.   Cid := OpenComm('COM2', 1024, 1024);
  374.   Error(Cid, 'Open');
  375.   SetConfigure;
  376.   WriteComm(Cid, 'ATZ'#13#10, 5);  { Send a reset to Modem. }
  377. end;
  378.  
  379. { Call back function used only in to get record structure for fixed   }
  380. { width font.                                                         }
  381. function GetFont(LogFont: PLogFont; TM: PTextMetric; FontType: Word;
  382.   P: PCommWindow): Integer; export;
  383. begin
  384.   if P^.CharHeight = 0 then
  385.   begin
  386.     P^.FontRec := LogFont^;
  387.     P^.CharHeight := P^.FontRec.lfHeight;
  388.   end;
  389. end;
  390.  
  391. { Get the a fix width font to use in the TCommWindow.  Use EnumFonts  }
  392. { to save work of create the FontRec by hand.                         }
  393. { The TScroller of the main window is also updated know that the font }
  394. { height is known.                                                    }
  395. procedure TCommWindow.SetHeight;
  396. var
  397.   DC: HDC;
  398.   ProcInst: Pointer;
  399. begin
  400.   DC := GetDC(HWindow);
  401.   CharHeight := 0;
  402.   ProcInst := MakeProcInstance(@GetFont, HInstance);
  403.   EnumFonts(DC, 'Courier', ProcInst, @Self);
  404.   FreeProcInstance(ProcInst);
  405.   ReleaseDC(HWindow, DC);
  406.  
  407.   Scroller^.SetUnits(CharHeight, CharHeight);
  408.   Scroller^.SetRange(LineWidth, LineHeight);
  409.   Scroller^.ScrollTo(0, LineHeight);
  410. end;
  411.  
  412.  
  413. { Write the character from the pressed key to the Comuniction Port.   }
  414. procedure TCommWindow.wmChar(var Message: TMessage);
  415. begin
  416.   if CID <> 0 then
  417.     Error(WriteComm(CId, @Message.wParam, 1), 'Writing');
  418. end;
  419.  
  420. procedure TCommWindow.wmSize(var Message: TMessage);
  421. begin
  422.   TWindow.wmSize(Message);
  423.   Scroller^.SetRange(LineWidth, LineHeight - (Message.lParamhi div CharHeight));
  424. end;
  425.  
  426. procedure TCommWindow.WriteChar;
  427. var
  428.   DC: HDC;
  429.   Font: HFont;
  430.   S: PChar;
  431.   APos: Integer;
  432. begin
  433.   APos := Buffer^.Count - 1;
  434.   S := Buffer^.AT(APos);
  435.   APos := (APos - Scroller^.YPos) * CharHeight;
  436.   if APos < 0 then exit;
  437.   if Hwindow <> 0 then
  438.   begin
  439.     DC := GetDC(HWindow);
  440.     Font := SelectObject(DC, CreateFontIndirect(FontRec));
  441.     TextOut(DC, 0, APos, S, StrLen(S));
  442.     DeleteObject(SelectObject(DC, Font));
  443.     ReleaseDC(HWindow, DC);
  444.   end;
  445. end;
  446.  
  447. { TApp }
  448. procedure TApp.Idle;
  449. var
  450.   Stat: TComStat;
  451.   I, Size: Integer;
  452.   C: Char;
  453. begin
  454.   if MainWindow <> Nil then
  455.     if MainWindow^.HWindow <> 0 then
  456.       PCommWindow(MainWindow)^.ReadChar;
  457. end;
  458.  
  459. procedure TApp.InitMainWindow;
  460. begin
  461.   MainWindow := New(PCommWindow, Init(Nil, 'Comm Test'));
  462. end;
  463.  
  464. { Add Idle loop to main message loop.                                 }
  465. procedure TApp.MessageLoop;
  466. var
  467.   Message: TMsg;
  468. begin
  469.   while True do
  470.   begin
  471.     if PeekMessage(Message, 0, 0, 0, pm_Remove) then
  472.     begin
  473.       if Message.Message = wm_Quit then Exit;
  474.       if not ProcessAppMsg(Message) then
  475.       begin
  476.         TranslateMessage(Message);
  477.         DispatchMessage(Message);
  478.       end;
  479.     end
  480.     else
  481.       Idle;
  482.   end;
  483.   Status := Message.WParam;
  484. end;
  485.  
  486. var
  487.   App: TApp;
  488. begin
  489.   App.Init('Comm');
  490.   App.Run;
  491.   App.Done;
  492. end.