[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 

 > 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;

   RESULT:= TStringList.Create;
   RESULT.Sorted:= TRUE;
   counter:= countTtyS;
   IF FindFirst('/dev/ttyS*', faSysFile, searchRec) = 0 THEN
       RESULT.Append('/dev/' + searchRec.Name);
     UNTIL (FindNext(searchRec) <> 0) OR (counter <= 0);
   counter:= countTtyUSB;
   IF FindFirst('/dev/ttyUSB*', faSysFile, searchRec) = 0 THEN
       RESULT.Append('/dev/' + searchRec.Name);
     UNTIL (FindNext(searchRec) <> 0) OR (counter <= 0);
   counter:= countTtyI;
   IF FindFirst('/dev/ttyI*', faSysFile, searchRec) = 0 THEN
       RESULT.Append('/dev/' + searchRec.Name);
     UNTIL (FindNext(searchRec) <> 0) OR (counter <= 0);
   IF Result.Count = 0 THEN
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