Serial unit

From Lazarus wiki
Jump to navigationJump to search

Unit Serial in FPC supports work with serial port. It provides many Ser* functions.

Example of usage

Note that this uses Windows-style device names, unix systems (Linux, SunOS etc.) have their own conventions.

    Uses default port COM1.
  TestSerialPortCom 8 'Hello'
    Uses COM8 and outputs 'Hello' before waiting for an answer.
  The program will open a serial port and output 'Hello', after that the code will wait until
  a CR (#13) is received, or a key is pressed.
program TestSerialPortCom;
  serial, crt;

  serialhandle : LongInt;
  ComPortName  : String;
  s,tmpstr,txt : String;
  ComIn        : String;
  ComPortNr    : Integer;
  writecount   : Integer;
  status       : LongInt;
  Flags        : TSerialFlags; { set of (RtsCtsFlowControl); }
  ErrorCode    : Integer;

  ComPortNr:= 1;
  tmpstr:= '';
  txt:= '';

  writeln('Parameters: ', ParamCount);
  if (ParamCount>0) then
    tmpstr:= ParamStr(1);
    val(tmpstr, ComPortNr, ErrorCode);

    if (ParamCount>1) then
      txt:= ParamStr(2);

  str(ComPortNr, tmpstr);
  ComPortName:= 'COM'+tmpstr+':';
  writeln('Using: '+ComPortname);

  serialhandle := SerOpen(ComPortName);
  Flags:= []; // none
  SerSetParams(serialhandle, 9600, 8, NoneParity, 1, Flags); 
  s:= txt; // use the input text
  writeln('Output: '+s);
  s:= s+#13+#10; // CR + LF
  writecount:= length(s);

  status:= SerWrite(serialhandle, s[1], writecount);

  // for debugging only
  writeln('Status: ', status, ', WriteCount: ', writecount);

  if status > 0 then
    writeln('Waiting for answer');
    s:= '';
    ComIn:= '';
    while (Length(ComIn)<10) and (status>=0) and not KeyPressed do 
      status:= SerRead(serialhandle, s[1], 10);
      if (s[1]=#13) then 
        status:= -1; // CR => end serial read

      if (status>0) then
        ComIn:= ComIn+s[1];
        writeln('Status: ', status, ', Len: ', length(ComIn), ', ASCII: ', ord(s[1]), ', Input: ', ComIn);
    writeln('Error: unable to send');

  SerSync(serialhandle); // flush out any remaining before closure

  SerFlushOutput(serialhandle); // discard any remaining output


Timeout values

Q: I'm trying to figure out when the timeout timer in SerRead/SerReadTimeout starts.

A (by FPC developer Christo Crause): FPC uses the OS provided functionality to interact with the serial port. On Windows the timeout seems to start when the read request is made - Link. On POSIX (at least Linux) it depends on the specific set of flags specified , scroll down to the discussion on canonical/noncanonical mode for the details - Link.

A bit more information after peeking into the source code: on Win32 the timeout information can be read or set using Get/SetCommTimeouts. The COMMTIMEOUTS structure contains a read interval timeout and total timeouts for read & write operations. SerReadTimeout sets the ReadTotalTimeoutConstant value, so basically the total timeout duration.

On Linux SerReadTimeout uses a fpSelect on the handle with the specified timeout, so in principle it is the same behaviour as on Windows, i.e. a total timeout.

While both OSs provide some functionality to specify inter character timeouts, FPC does not directly expose this functionality in the Serial unit.

Note from last maintainer: SerReadTimeout() explicitly says "" i.e. the intention is that timing starts when the function is called. Different lineages of unix handle fpSelect() differently, while not tested it's reasonable to assume that the Mac's OS-X behaves like SunOS/Solaris. See for examples, comments on known issues etc.