Posix ioctl System Error 25 when read FTDI VCP COM port on MacOS

  

I’m trying write COM port library for MacOS.
I have System Error 25: “Inappropriate ioctl for device” when i try read how many characters was received. To do that i’m using ioctl function.

Connected device is FTDI chip in VCP mode. There are two devices in system:

cu.usbserial-XXXXXXXX
tty.usbserial-XXXXXXXX

XXXXXXXX is device serial number, so it doesn’t matter. I’ve tried on both devices with same results. FTDI VCP Drivers are installed, OS version is 10.15.2. Access rights to both devices crw-rw-rw-

uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.IOUtils,
Posix.Fcntl, Posix.Unistd, Posix.Termios, Posix.StrOpts, FMX.DialogService.Async,
FMX.Controls.Presentation, FMX.StdCtrls;

[…]

procedure TfrmMain.DoCOMPortTest;
const
INVALID_HANDLE = -1;
BUFFER_LENGTH = 1024;
var
CPFile: String;
Handle: Integer;
tio: termios;
TxBuffer, RxBuffer: TBytes;
i, Avail, Sent, Readed, ioctlRet: Integer;
begin
SetLength(TxBuffer, 100);
SetLength(RxBuffer, BUFFER_LENGTH);
try
//
// Open port:
//
CPFile := TPath.Combine(‘/dev’, ‘cu.usbserial-XXXXXXXX’);
// CPFile := TPath.Combine(‘/dev’, ‘tty.usbserial-XXXXXXXX’);
Handle := __open(PAnsiChar(AnsiString(CPFile)), O_RDWR or O_NOCTTY or O_NONBLOCK);
if Handle <> INVALID_HANDLE then
begin
if isatty(Handle) <> 0 then
begin

//
// Port is open and it’s TTY.
// Setup port:
//
fcntl(Handle, F_SETFL, O_NONBLOCK);
tcgetattr(Handle, tio);
tio.c_iflag := tio.c_iflag and not(IGNBRK or BRKINT or ICRNL or INLCR or PARMRK or INPCK or ISTRIP or IXON);
tio.c_oflag := tio.c_oflag and not(OPOST);
tio.c_lflag := tio.c_lflag and not(ECHO or ECHONL or ICANON or IEXTEN or ISIG);
tio.c_cflag := tio.c_cflag and not(CSIZE or PARENB);
// No parity (8N1)
tio.c_cflag := tio.c_cflag or CLOCAL or CREAD;
tio.c_cflag := tio.c_cflag and not(PARENB or CSTOPB or CSIZE);
tio.c_cflag := tio.c_cflag or CS8;
// Baudrate – old style
tio.c_ispeed := 115200;
tio.c_ospeed := 115200;
// * 0.1 [sec]
tio.c_cc[VMIN] := 1;
tio.c_cc[VTIME] := 10;
// Baudrate – new style
cfsetispeed(tio, 115200);
cfsetospeed(tio, 115200);
// Apply settings
tcsetattr(Handle, TCSAFLUSH, tio);

//
// Write data
//

// Prepare sample data
for i := Low(TxBuffer) to High(TxBuffer) do
TxBuffer[i] := (i + 1) * 2;
Sent := __write(Handle, TxBuffer, Length(TxBuffer));

if (Sent <= 0) or (Sent > Length(TxBuffer)) then
RaiseLastOSError;

Sleep(100);

//
// Check received data length
//
ioctlRet := ioctl(Handle, FIONREAD, @Avail); // <<– System Error 25: inappropriate ioctl for device
if ioctlRet <> 0 then
RaiseLastOSError;

if Avail > 0 then
begin
//
// Read data
//
Readed := __read(Handle, RxBuffer, Length(RxBuffer));
if Readed > 0 then
begin
TDialogServiceAsync.ShowMessage(Format(‘Available %d[B], Readed %d[B]:%s%s’, [Avail, Readed, #13#10, BufferToString(RxBuffer, Readed)]));
end else
raise Exception.Create(Format(‘Available %d[B], but can”t read received data’, [Avail]));
end;

//
// Close port.
//
__close(Handle);
Handle := INVALID_HANDLE;

end else
begin
//
// Not TTY device
// Close port.
//
__close(Handle);
Handle := INVALID_HANDLE;
raise Exception.Create(‘Not TTY device’);
end;
end else
raise Exception.Create(‘Can”t open FTDI COM port’);
finally
SetLength(TxBuffer, 0);
SetLength(RxBuffer, 0);
end;
end;

The question is, what is wrong with that part of my code and how to fix it? Or is there another method to read how many characters was received?

Comments are closed.