如何确定是否有可从boost读取的字节:asio:serial_port

时间:2015-01-31 15:37:00

标签: boost serial-port arduino boost-asio

我正在尝试使用boost在我的桌面和arduino之间进行串行通信。在arduino空间中,我可以在尝试执行读操作之前询问串口是否有可用字节。

我无法找到boost :: asio :: serial_port的等价物。

2 个答案:

答案 0 :(得分:4)

虽然Boost.Asio没有为此提供直接支持,但仍然可以通过使用串行端口native_handle()进行系统特定调用来实现此目的。请参阅系统文档以确定如何查询准备读取的可用字节,但在Linux上通常为ioctl(..., FIONREAD, ...),在Windows上为ClearCommError()


这是一个完整的最小示例,它使用特定于系统的调用来获取可用的字节数。示例程序将继续查询串行端口,直到有超过20个字节可用,此时它将读取除5个字节之外的所有字节:

#include <iostream>
#include <vector>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

/// @brief Returns the number of bytes available for reading from a serial
///        port without blocking.
std::size_t get_bytes_available(
  boost::asio::serial_port& serial_port,
  boost::system::error_code& error)
{
  error = boost::system::error_code();
  int value = 0;
#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  COMSTAT status;
  if (0 != ::ClearCommError(serial_port.lowest_layer().native_handle(),
                            NULL, &status))
  {
    value = status.cbInQue;
  }
  // On error, set the error code.
  else
  {
    error = boost::system::error_code(::GetLastError(),
       boost::asio::error::get_system_category());
  }
#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  if (0 == ::ioctl(serial_port.lowest_layer().native_handle(),
                   FIONREAD, &value))
  {
    error = boost::system::error_code(errno,
       boost::asio::error::get_system_category());
  }
#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)

  return error ? static_cast<std::size_t>(0)
               : static_cast<size_t>(value);

}

/// @brief Returns the number of bytes available for reading from a serial
///        port without blocking.  Throws on error.
std::size_t get_bytes_available(boost::asio::serial_port& serial_port)
{
  boost::system::error_code error;
  std::size_t bytes_available = get_bytes_available(serial_port, error);
  if (error)
  {
    boost::throw_exception((boost::system::system_error(error)));
  }
  return bytes_available;
}

int main(int argc, char* argv[])
{
  if (argc < 2)
  {
    std::cerr << "Usage: " << argv[0] << " <device_name>" << std::endl;
    return 1;
  }

  // Create all I/O objects.
  boost::asio::io_service io_service;
  boost::asio::serial_port serial_port(io_service, argv[1]);

  // Continue quering the serial port until at least 20 bytes are available
  // to be read.
  std::size_t bytes_available = 0;
  while (bytes_available < 20)
  {
    bytes_available = get_bytes_available(serial_port);
    std::cout << "available: " << bytes_available << std::endl;
    boost::this_thread::sleep_for(::boost::chrono::seconds(3));
  }

  // Read all but 5 available bytes.
  std::vector<char> buffer(bytes_available - 5);
  std::size_t bytes_transferred =
      read(serial_port, boost::asio::buffer(buffer));
  bytes_available = get_bytes_available(serial_port);

  // Print results.
  std::cout << "Read " << bytes_transferred << " bytes\n";
  std::cout.write(&buffer[0], bytes_transferred);
  std::cout << "\navailable: " << bytes_available << std::endl;
}

使用socat创建虚拟串行端口:

$ socat -d -d PTY: PTY
2015/02/01 21:12:31 socat[3056] N PTY is /dev/pts/2
2015/02/01 21:12:31 socat[3056] N PTY is /dev/pts/3
2015/02/01 21:12:31 socat[3056] N starting data transfer loop
                                with FDs [3,3] and [5,5]

在一个终端启动程序后,我写到另一个终端的/dev/pts/3

$ echo -n "This is" > /dev/pts/3
$ echo -n " an example" > /dev/pts/3
$ echo -n " with asio." > /dev/pts/3

程序产生的结果:

$ ./a.out /dev/pts/2
available: 0
available: 7
available: 18
available: 29
Read 24 bytes
This is an example with
available: 5

答案 1 :(得分:0)

我不知道asio中有这样的事情,但正如上面的评论已经说过的那样,你真的不需要它。我有一个如何使用boost asio serial的示例:

https://github.com/cdesjardins/ComBomb/blob/master/TargetConnection/TgtSerialConnection.cpp

它使用async_read_some来填充带有串行数据的缓冲区,然后缓冲区数据排队等待程序的其他部分进行处理。