3

I'm creating a simple program in Delphi, to send character through COM port using 2 parameters, the first parameter is the port number and the second parameter is the character to be sent. So if i save it as p.exe, "p.exe 20 A" will send "A" through COM20.

try
   PhoneNumber := ParamStr(2);

   if(StrToInt(ParamStr(1))>=10)then
   CommPort := '\\.\COM'+ParamStr(1)
   else
   CommPort := 'COM'+ParamStr(1);
   hCommFile := CreateFile(PChar(CommPort),
                          GENERIC_WRITE,
                          0,
                          nil,
                          OPEN_EXISTING,
                          FILE_ATTRIBUTE_NORMAL,
                          0);
   if hCommFile=INVALID_HANDLE_VALUE then begin
      ShowMessage('Unable to open '+ CommPort);
   end;
  if WriteFile(hCommFile, PChar(PhoneNumber)^, Length(PhoneNumber),NumberWritten, nil)=false then
    showmessage('Unable to send');
  PurgeComm(hCommFile,PURGE_TXCLEAR);
  FlushFileBuffers(hCommFile);
  CloseHandle(hCommFile);
  Application.Terminate;
except
  PurgeComm(hCommFile,PURGE_TXCLEAR);
  FlushFileBuffers(hCommFile);
  Application.Terminate;
end;

And I also using hyperterminal with the same COM number baudrate=9600, flow_control=none and it gives the same result. The character sent well. The problem is, I cant run my program (p.exe) before I do the following steps each time i logged on to my Windows XP: Connect through hyperterminal to the designated COM, disconnect it. then my executable can be run. Otherwise, just like you run two session of hyperterminal in the same COM, it wouldn't work. Anybody got a hint bout this? Did I miss anything in my code?

PeskyGnat
  • 2,454
  • 19
  • 22
user1023791
  • 31
  • 1
  • 2
  • +1 for doing a sanity check with Hyperterminal. – Chris Thornton Nov 01 '11 at 14:21
  • So by "doesn't work", do you get your "unable to open..." error, "unable to send", or what? – Chris Thornton Nov 01 '11 at 14:23
  • you need to use setcommstate for baud rates. – sabri.arslan Nov 01 '11 at 14:37
  • Your exception handler reads `hCommFile` before it's necessarily been written. If the first command-line parameter is non-numeric, you purge and flush an invalid handle. Also, if `CreateFile` fails, you continue using `hCommFile` even though it's `Invalid_Handle_Value`. – Rob Kennedy Nov 01 '11 at 14:43
  • What baud rate, parity, and flow control (hardware/software/off) settings were you assuming would be used? If you're totally new to serial ports, may I suggest you use a component (TComPort, or AsyncPro). – Warren P Nov 01 '11 at 15:19

2 Answers2

4

I don't see any setup stuff in your code. So maybe you're relying on a side-effect of running HyperTerminal that "primes" the port for you. Have a look at this article where they go through that stuff: baud, parity, etc..

http://www.delphi-central.com/serial.aspx

It seems to be a full working example. See if you can get that working, and use as a base to build from.

Chris Thornton
  • 15,620
  • 5
  • 37
  • 62
4

You need to use setcommstate for setup baud rate and flow control.

Function OpenPort( Var fHandle: THandle; fPort: String): Boolean;
Const
 RxBufferSize       = 32;
 TxBufferSize       = 32;
Var
 dcb                : TDCB;
 tms                : TCOMMTIMEOUTS;
Begin
 Result := False;
 Try
  If fHandle <> INVALID_HANDLE_VALUE Then
   CloseHandle( fhandle );
 Except
 End;
 Try
  //fport must be \\.\ URN format
  fhandle := CreateFile( PChar( fPort ), GENERIC_WRITE or GENERIC_READ, FILE_SHARE_WRITE ,
                         Nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
  If ( fhandle = INVALID_HANDLE_VALUE ) Then
   Begin
    result := false;
    exit;
   End;
  SetupComm( fhandle, RxBufferSize, TxBufferSize );

  If pos( 'LPT', fPort ) > 0 Then
   //
  Else
   Begin
    GetCommState( fhandle, dcb );
    dcb.DCBlength := sizeof( dcb );
    dcb.BaudRate := cbr_9600;
    dcb.Flags := 1;                     // binary...
    if dtr_rts then
    begin
     dcb.flags := dcb.Flags Or $20;      //DTR HANDSHAKE
     dcb.Flags := dcb.Flags Or $1000;    //rts handshake
     dcb.Flags := dcb.Flags Or 4;        //Outx_CtsFlow
     dcb.Flags := dcb.Flags Or 8;        //Outx_DsrFlow
     dcb.Flags := dcb.Flags Or $40;      //DsrSensitivity
     //dcb.Flags := dcb.Flags or $100;//Outx_XonXoffFlow
     //dcb.Flags := dcb.Flags or $200;//Inx_XonXoffFlow
    end;
    dcb.ByteSize := 8;
    dcb.Parity := EVENPARITY;
    dcb.StopBits := ONESTOPBIT;
    SetCommState( fhandle, dcb );
    GetCommTimeouts( fhandle, tms );
    tms.ReadIntervalTimeout := 100;//you can change multipler values with
    tms.ReadTotalTimeoutMultiplier := 100;//your values
    tms.ReadTotalTimeoutConstant := 1;
    SetCommTimeOuts( fhandle, tms );
   End;
  EscapeCommFunction( fhandle, CLRRTS Or CLRDTR Or SETRTS Or SETDTR );//for handshaking
  Result := True;
 Except
  Result := False;
 End;
End;

usage

var 
    fporthandle:thandle;
   begin
    if OpenPort(fporthandle,'\\.\com1') then
      try
       writefile(fporthandle,pchar('TEST')...);
      finally
        closehandle(fporthandle);
      end;
sabri.arslan
  • 548
  • 2
  • 14
  • communication devices are receiving default DCB upon creation – Premature Optimization Nov 01 '11 at 14:47
  • @Premature: Exactly, but perhaps the default DCB baud rate, parity, flow control, etc, is not EXACTLY what the OP needs. It's best to explicitly set that stuff, and make it visible to the user. When you get finished writing all the UI stuff for com port baud, parity, flow control configuration, you may as well just download and use `TComPort`. http://sourceforge.net/projects/comport/ – Warren P Nov 01 '11 at 15:18
  • ugh sorry, scratch **creation**, i meant **opening** (`CreateFile(OPEN_EXISTING)`). @Warren P, yes, but defaults is intended to be used instead explicit. OP just need to preconfigure his port. BTW this link seems to be overengineering for me. – Premature Optimization Nov 01 '11 at 17:15