Serial unit: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: Serial unit
| Old | New | Line | |
|---|---|---|---|
| 1 | + | Unit **Serial** in FPC supports work with serial port. It provides many Ser* functions. | |
| 2 | + | ||
| 3 | + | ## Example of usage | |
| 4 | + | ||
| 5 | + | Note that this uses Windows-style device names, unix systems (Linux, SunOS etc.) have their own conventions. | |
| 6 | + | ||
| 7 | + | ``` pascal | |
| 8 | + | { | |
| 9 | + | Usage: | |
| 10 | + | TestSerialPortCom | |
| 11 | + | Uses default port COM1. | |
| 12 | + | TestSerialPortCom 8 'Hello' | |
| 13 | + | Uses COM8 and outputs 'Hello' before waiting for an answer. | |
| 14 | + | ||
| 15 | + | The program will open a serial port and output 'Hello', after that the code will wait until | |
| 16 | + | a CR (#13) is received, or a key is pressed. | |
| 17 | + | } | |
| 18 | + | program TestSerialPortCom; | |
| 19 | + | uses | |
| 20 | + | serial, crt; | |
| 21 | + | ||
| 22 | + | var | |
| 23 | + | serialhandle : LongInt; | |
| 24 | + | ComPortName : String; | |
| 25 | + | s,tmpstr,txt : String; | |
| 26 | + | ComIn : String; | |
| 27 | + | ComPortNr : Integer; | |
| 28 | + | writecount : Integer; | |
| 29 | + | status : LongInt; | |
| 30 | + | Flags : TSerialFlags; { set of (RtsCtsFlowControl); } | |
| 31 | + | ErrorCode : Integer; | |
| 32 | + | ||
| 33 | + | begin | |
| 34 | + | ComPortNr:= 1; | |
| 35 | + | tmpstr:= ''; | |
| 36 | + | txt:= ''; | |
| 37 | + | ||
| 38 | + | writeln('Parameters: ', ParamCount); | |
| 39 | + | if (ParamCount>0) then | |
| 40 | + | begin | |
| 41 | + | tmpstr:= ParamStr(1); | |
| 42 | + | val(tmpstr, ComPortNr, ErrorCode); | |
| 43 | + | ||
| 44 | + | if (ParamCount>1) then | |
| 45 | + | txt:= ParamStr(2); | |
| 46 | + | end; | |
| 47 | + | ||
| 48 | + | str(ComPortNr, tmpstr); | |
| 49 | + | ||
| 50 | + | ComPortName:= 'COM'+tmpstr+':'; | |
| 51 | + | writeln('Using: '+ComPortname); | |
| 52 | + | ||
| 53 | + | serialhandle := SerOpen(ComPortName); | |
| 54 | + | Flags:= []; // none | |
| 55 | + | SerSetParams(serialhandle, 9600, 8, NoneParity, 1, Flags); | |
| 56 | + | ||
| 57 | + | s:= txt; // use the input text | |
| 58 | + | writeln('Output: '+s); | |
| 59 | + | s:= s+#13+#10; // CR + LF | |
| 60 | + | writecount:= length(s); | |
| 61 | + | ||
| 62 | + | status:= SerWrite(serialhandle, s[1], writecount); | |
| 63 | + | ||
| 64 | + | // for debugging only | |
| 65 | + | writeln('Status: ', status, ', WriteCount: ', writecount); | |
| 66 | + | ||
| 67 | + | if status > 0 then | |
| 68 | + | begin | |
| 69 | + | writeln('Waiting for answer'); | |
| 70 | + | s:= ''; | |
| 71 | + | ComIn:= ''; | |
| 72 | + | while (Length(ComIn)<10) and (status>=0) and not KeyPressed do | |
| 73 | + | begin | |
| 74 | + | status:= SerRead(serialhandle, s[1], 10); | |
| 75 | + | if (s[1]=#13) then | |
| 76 | + | status:= -1; // CR => end serial read | |
| 77 | + | ||
| 78 | + | if (status>0) then | |
| 79 | + | begin | |
| 80 | + | ComIn:= ComIn+s[1]; | |
| 81 | + | writeln('Status: ', status, ', Len: ', length(ComIn), ', ASCII: ', ord(s[1]), ', Input: ', ComIn); | |
| 82 | + | end; | |
| 83 | + | end; | |
| 84 | + | end | |
| 85 | + | else | |
| 86 | + | writeln('Error: unable to send'); | |
| 87 | + | ||
| 88 | + | SerSync(serialhandle); // flush out any remaining before closure | |
| 89 | + | ||
| 90 | + | SerFlushOutput(serialhandle); // discard any remaining output | |
| 91 | + | ||
| 92 | + | SerClose(serialhandle); | |
| 93 | + | end. | |
| 94 | + | ``` | |
| 95 | + | ||
| 96 | + | ## Timeout values | |
| 97 | + | ||
| 98 | + | Q: I'm trying to figure out when the timeout timer in SerRead/SerReadTimeout starts. | |
| 99 | + | ||
| 100 | + | 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 - \[<https://learn.microsoft.com/en-us/previous-versions/ff547486(v=vs.85>) 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](https://linux.die.net/man/3/termios). | |
| 101 | + | ||
| 102 | + | 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](https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-commtimeouts) contains a read interval timeout and total timeouts for read & write operations. SerReadTimeout sets the ReadTotalTimeoutConstant value, so basically the total timeout duration. | |
| 103 | + | ||
| 104 | + | 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. | |
| 105 | + | ||
| 106 | + | While both OSs provide some functionality to specify inter character timeouts, FPC does not directly expose this functionality in the Serial unit. | |
| 107 | + | ||
| 108 | + | Note from last maintainer: SerReadTimeout() explicitly says "<https://github.com/MarkMLl/serialcomms>" 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 <https://github.com/MarkMLl/serialcomms> for examples, comments on known issues etc. | |
| 109 | + | ||
| 110 | + | --- | |
| 111 | + | *From the Free Pascal wiki, page "Serial unit", as it stood on 2023-04-25 after a change by MarkMLl, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
