Posix ioctl Системная ошибка 25 при чтении COM порта FTDI VCP на MacOS - PullRequest
0 голосов
/ 02 марта 2020

Я пытаюсь написать библиотеку 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;

Вопрос в том, что не так с этой частью моего кода и как ее исправить? Или есть другой способ узнать, сколько символов было получено?

...