Последовательная связь в Linux с включенным управлением потоком - плохое поведение

Я написал общие функции для управления последовательными портами, основываясь на следующей структуре:

  typedef struct
  {
     int  PHandle;
     unsigned int  Port;
     unsigned int  BaudRate;
     unsigned char Parity;
     unsigned char FlowControl;
     char Device[MAX_SIZE];
  } Tst_SPort;

Я вызываю эти функции (см. Ниже) в другом файле, чтобы протестировать последовательный порт RS232. Управление потоком должно быть включено.

  int iInit(Tst_SPort *port, const char *device, int baudRate, unsigned char parity, unsigned char flowControl)
  {
     strncpy(port->Device, device, MAX_SIZE);
     port->PHandle     = iOpen(port);
     port->Port        = -1;
     port->BaudRate    = baudRate;
     port->Parity      = parity;
     port->FlowControl = flowControl;
     if(port->PHandle > 0)
     {
        setuart(port, port->BaudRate);
     }
     return port->PHandle;
  }

  int iOpen(Tst_SPort *port)
  {
     port->PHandle = open(port->Device, O_RDWR | O_NOCTTY);
     if(port->PHandle < 0)
     {
        perror("open:");
        return (-1);
     }
     return (port->PHandle);
  }

  void setuart(Tst_SPort *port, int baudRate)
  {
     struct termios opt, optCmp;           
     struct serial_struct info;

     if(port->PHandle > 0)
     {
        bzero(&opt,    sizeof(opt));
        bzero(&optCmp, sizeof(optCmp));

        if(ioctl(port->PHandle, TIOCGSERIAL, &info) == 0) 
           port->Port = info.port;

        fcntl(port->PHandle, F_SETFL, O_NONBLOCK);

        if (tcgetattr(port->PHandle, &opt) < 0) 
           perror("tcgetattr Get:");

        if(baudRate > 0)
        {
           cfsetospeed (&opt, baudRate);
           cfsetispeed (&opt, baudRate);   
        }

        opt.c_iflag = IGNPAR;               
        opt.c_oflag &= ~OPOST
        opt.c_oflag &= ~ONLCR;
        opt.c_lflag = 0;                   
        opt.c_cflag |= (CLOCAL | CREAD); 
        opt.c_cflag &= ~(PARENB | PARODD); 
        opt.c_cflag |= port->Parity;
        opt.c_cflag &= ~CSTOPB;         
        opt.c_cflag &= ~CSIZE;
        opt.c_cflag |=  CS8;        
        if(!port->FlowControl)
           opt.c_cflag &= ~CRTSCTS;         
        else
           opt.c_cflag |= CRTSCTS;         

        opt.c_cc[VMIN] = 0;               
        opt.c_cc[VTIME] = 50; 

        if(tcsetattr(opt->PHandle, TCSANOW, &opt) < 0)
           perror("tcgetattr Update :");

        if (tcgetattr(opt->PHandle, &optCmp) < 0) 
           perror("tcgetattr Read:");

        /* Compare */
        if (memcmp((void *)&opt, (void *)&optCmp, sizeof(opt)) != 0)
           printf("Conf failed");         

        tcflush(port->PHandle, TCIFLUSH);
     }
  }

  int iRead(Tst_SPort *port, char *buffer, unsigned long buffLength)
  {
     struct  timeval tv;   
     fd_set  recv;
     int     s32Read = 0;
     int     s32Offset = 0;
     int     s32SRes = 0;

     tv.tv_sec = 0;
     tv.tv_usec = 100000; /* 100ms */

     if ((port) && (port->PHandle > 0)) 
     {
        while (s32Offset < buffLength)
        {
           FD_ZERO(&recv);
           FD_SET(port->PHandle, &recv);

           s32SRes = select(port->PHandle + 1, &recv, NULL, NULL, &tv);
           if ((s32SRes == -1) && (errno == EINTR)) 
           {
              continue; 
           }
           else if(s32SRes > 0)
           {
              if (FD_ISSET(port->PHandle, &recv))
              {
                 s32Read = read(port->PHandle, buffer + s32Offset, buffLength - s32Offset);
                 if(s32Read  > 0)
                 {
                    tv.tv_sec = 0;
                    tv.tv_usec = 5000;
                    s32Offset += s32Read;
                    continue;
                 }
              }
           }
           break;
        }
     }  
     return s32Offset;
  }

  int iClose(Tst_SPort *port)
  {
     return (close(port->Phandle));
  }

Для проверки реализации выводы Tx и Rx были соединены вместе, то есть для CTS и RTS. Все отлично работает, отправленное сообщение можно прочитать правильно. Кроме того, когда Tx отключен от Rx, ничто не читает как ожидалось.

Но когда CTS отключен от RTS, тестовые блоки после шага закрытия порта (~20 секунд).

Однако, если функция setuart() вызывается с flowControl == 0, тест не блокируется и возвращает ожидаемый код ошибки без задержки.

Я, наверное, что-то неправильно понял, особенно в конфигурации порта. Это хороший способ сделать?

1 ответ

Решение

Проблема, с которой вы сталкиваетесь, - это правильное поведение.

Если CTS не подключен с включенным управлением потоком, это означает, что DTE (AKA PC) не может отправлять данные в DCE (подчиненное устройство).

Когда вы пытаетесь записать в выходной буфер UART, он, вероятно, переполнен, и приложение временно прекращает работу и ждет, пока освободится некоторое пространство буфера.

Другие вопросы по тегам