Я пытаюсь написать библиотеку COM-порта для MacOS. У меня системная ошибка 25: «Несоответствующий ioctl для устройства», когда я пытаюсь прочитать, сколько символов было получено. Для этого я использую функцию ioctl.
Подключенное устройство - это чип FTDI в режиме VCP. В системе имеется два устройства:
- cu.usbserial-XXXXXXXX
- tty.usbserial-XXXXXXXX
XXXXXXXX - это серийный номер устройства, поэтому не имеет значения. Я пробовал на обоих устройствах с одинаковыми результатами. Драйверы FTDI VCP установлены, версия ОС 10.15.2. Права доступа к обоим устройствам 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;
Вопрос в том, что не так с этой частью моего кода и как ее исправить? Или есть другой способ узнать, сколько символов было получено?