[Lazarus] Usage of Serial in a testing program?
Mark Morgan Lloyd
markMLl.lazarus at telemetry.co.uk
Sun Sep 23 11:11:56 CEST 2018
On 23/09/18 08:15, Bo Berglund via Lazarus wrote:
> On Sun, 23 Sep 2018 08:39:52 +0200, Bo Berglund via Lazarus<lazarus at lists.lazarus-ide.org> wrote:
>> I have now come as far in my application as I can test the way the>Serial unit opens and closes com ports.>It turns out that on Windows there are two port name syntaxes:>>Ports 1..9: COM1 to COM9 will work>Ports 10..255: Only \\.\COM10 to \\.\COM255 will work>>But one does not need to use different naming depending on the port>number, the second syntax \\.\COMx works also for ports 1..9
> Forgot to add a question regarding making this a cross-platformprogram:
> If I add a check for the platform inside my program, how sghould itlook like to work on both Windows and Linux?
> Something like this:
> function TWiFiCommTester.ConnectSerial(Port: byte; Baud: integer):boolean;var ComportName: string; Flags: TSerialFlags;begin FLastError := ''; {$IFDEF WINDOWS} ComPortName:= '\\.\COM' + IntToStr(Port); {$ENDIF} {$IFDEF UNIX} //What goes here? ComPortName := ???? {$ENDIF} FSerial := SerOpen(ComPortName); ....
Sorry Bo and Paul, I mailed you directly when I meant to reply here.
This rolls up the messages from earlier.
> Ports 1..9: COM1 to COM9 will workPorts 10..255: Only \\.\COM10
to \\.\COM255 will work
Which is something that I pointed out to you, although in my case I
think I only tested up to 12 (i.e. with an 8-port card).
What comes after 255: 0 or 1? If 0 which form or name does it require?
> I have yet to complete other parts of the application so I don't
yetknow if the data flow will wok as expected.
Note that that unit was specifically written to be usable either with or
without separate communications threads. If you're /not/ using threads
then there's a callback so that the read-with-timeout functions can
periodically call Application.ProcessMessages, and that the places that
it is used are OS-specific. You obviously /don't/ want to use that
callback if the comms functions are in their own threads, since APM
should only be called from the main thread.
I'm probably losing this email address on Tuesday, if there's anything
that you think I can possibly clarify please raise it sooner rather than
later.
> On 09/23/2018 02:39 AM, Bo Berglund via Lazarus wrote:...> Notice
that contrary to the wiki example adding a colon to the end> like COM32:
does NOT work so that is a wiki error.
> If I remember correctly the colon at the end is required for WinCE?--
OK, but this is something that the application programmer needs to be
aware of. I suppose it would be possible to modify the unit so that if
it sees a trailing : it changes it to a leading \\.\ if there isn't one
there already, but since the exact names are OS-specific and since we're
already insisting that the application programmer or user puts in /dev/
for unix I'm not sure that's justifiable.
In any event I'm not in a position to do any mods right now and am
probably about to lose access to Solaris (which is probably still worth
testing against) permanently.
(* If there are no serial ports on the system then return NIL, otherwise
a *)
(* TStringList.
*)
(*
*)
(* This returns an object, it is the caller's (eventual) responsibility
to free *)
(* this.
*)
//
FUNCTION EnumeratePorts: TStringList;
(* On a Linux system with udev or similar the /dev directory will only
contain *)
(* devices which have been detected as being present. On an older system
it *)
(* will probably contain all possible devices so we need to restrict the
list *)
(* to what's reasonable; the user should still be able to enter a device
name *)
(* manually if necessary, e.g. where a machine with 2x standard ports
plus a *)
(* 2-port card insists that it's got ttyS0, ttyS1, ttyS45 and ttyS46.
*)
CONST countTtyS= 12; (* Main board plus an 8-port
card *)
countTtyUSB= 8; (* Four dual-port adapters
*)
countTtyI= 4; (* A single 4-port ISDN card.
*)
VAR searchRec: TSearchRec;
counter: INTEGER;
BEGIN
RESULT:= TStringList.Create;
RESULT.Sorted:= TRUE;
counter:= countTtyS;
IF FindFirst('/dev/ttyS*', faSysFile, searchRec) = 0 THEN
REPEAT
RESULT.Append('/dev/' + searchRec.Name);
DEC(counter)
UNTIL (FindNext(searchRec) <> 0) OR (counter <= 0);
FindClose(searchRec);
counter:= countTtyUSB;
IF FindFirst('/dev/ttyUSB*', faSysFile, searchRec) = 0 THEN
REPEAT
RESULT.Append('/dev/' + searchRec.Name);
DEC(counter)
UNTIL (FindNext(searchRec) <> 0) OR (counter <= 0);
FindClose(searchRec);
counter:= countTtyI;
IF FindFirst('/dev/ttyI*', faSysFile, searchRec) = 0 THEN
REPEAT
RESULT.Append('/dev/' + searchRec.Name);
DEC(counter)
UNTIL (FindNext(searchRec) <> 0) OR (counter <= 0);
FindClose(searchRec);
IF Result.Count = 0 THEN
FreeAndNil(RESULT)
END { EnumeratePorts } ;
--
Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk
[Opinions above are the author's, not those of his employers or colleagues]
More information about the Lazarus
mailing list