在 Linux 上启用流控制的串行通信 - 不良行为

Serial communication on Linux with flow control enabled - bad behaviour

我为了管理串口写了常用函数,基于以下结构:

  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 秒)后阻塞。

但是,如果在 flowControl == 0 的情况下调用函数 setuart(),则测试不会阻塞并且 returns 预期的错误代码不会延迟。

我可能理解有误,尤其是在端口配置方面。这是做事的好方法吗?

您遇到的问题是正确的行为。

在启用流控制的情况下保持 CTS 未连接,意味着 DTE(又名 PC)无法向 DCE(从设备)发送数据。

当您尝试写入 UART 输出缓冲区时,它可能已满,应用程序暂时停止 运行 并等待缓冲区 space 可用。