tcdrain()之后必须入睡吗?

时间:2019-06-21 19:46:31

标签: c linux serial-port termios

我正在测试我的串行端口库的写功能。首先,我将串行端口文件描述符安排为非阻塞文件描述符。 然后,在自定义写函数的结尾处调用tcdrain(fd)。但是,如果我不等待此自定义的写函数之后的sleep()并立即从应用程序返回,则实际上字节不会通过串行端口写入。

所以,我有两个问题。

  1. tcdrain()不保证发送字节吗?
  2. 如何在不调用sleep()函数的情况下实现自定义写入功能。

我尝试使用阻止文件描述符的相同功能。但是什么都没有改变。

首先,我使用以下代码初始化串行端口:

struct termios stermios;
tcgetattr ( fd, &stermios );
cfsetispeed ( &stermios, handle->baudrate );
cfsetospeed ( &stermios, handle->baudrate );

stermios.c_cflag &= ~(PARENB | CSTOPB | CRTSCTS );
stermios.c_cflag |= ( CLOCAL | CREAD );
stermios.c_cflag &= ~CSIZE;
stermios.c_cflag |= CS8;

stermios.c_iflag &= (IXON | IXOFF );
stermios.c_oflag &= ~OPOST;
stermios.c_lflag &= ~(ICANON | ECHO | ECHOE );

tcflush ( fd, TCIOFLUSH );
tcsetattr ( fd, TCSANOW, termios_p );

这是我的自定义写入功能:


static int32_t surely_tcdrain ( SerialPortHandle_t const * handle_p )
{
    int32_t retval = -1;
    int32_t try_cnt = 0;

    while ( ( ++try_cnt < MAX_TCDRAIN_TRY_CNT ) &&\
            ( -1 == (retval = tcdrain ( fd ) ) ) )
    {
        if ( EINTR == errno )
        {
            usleep ( TCDRAIN_DELAY );
        }
        else
        {
            fprintf (stderr, "tcdrain() FAILED, %d, %s\n",\
                    errno, strerror ( errno ) );
            try_cnt = MAX_TCDRAIN_TRY_CNT; // Dont try again, break the loop. //
        }
    }

    return retval;
}
int32_t write_to_serial_port( int32_t fd, void * buff, size_t size )
{
  uint8_t try_cnt = 0;
  size_t total_write_size = 0;

  while ( ( total_write_size < size ) && ( ++try_cnt < 10 ) )
  {
    ssize_t w_size = -1;
    w_size = write (fd, ( ( uint8_t * ) buff + total_write_size ),\
        ( size - total_write_size ) );

    if ( w_size == -1 )
    {
      if ( ( errno != EINTR ) && ( errno != EAGAIN ) &&\
             ( errno != EWOULDBLOCK ) )
      {
         try_cnt = MAX_WRITE_TRY_CNT;
      }
      else
      {
        usleep ( WRITE_DELAY );
      }
    }
    else
    {
      total_write_size += ( ( size_t ) w_size );
    }
  }

    return ( ( surely_tcdrain ( fd ) == 0 ) &&\
            ( ( total_write_size == size ) ) ) ? 0 : -1;
}

最后,我用以下函数关闭了串行端口文件描述符。

static void deinit_fd ( int32_t fd )
{
    if ( FD_INVALID != fd )
    {
        if ( 1 == isatty ( fd ) )
        {
            tcdrain ( fd ); // Wait for write all output process. //
        }
        else
        {
            // fd not referring terminal. So no need to call tcdrain(). //
        }

        close ( fd );
    }
    else
    {
        // fd is invalid. //
    }
}

我在main中调用此write函数,然后关闭文件描述符并立即从应用程序返回。

我希望所有字节都必须使用我的写入功能通过串行端口写入。但是我的功能无法正常工作。

1 个答案:

答案 0 :(得分:0)

听起来您没有在进程退出之前关闭文件。我知道您说过可以,但是不显示该代码。您的代码的那部分可能存在错误?