我正在尝试使用boost在我的桌面和arduino之间进行串行通信。在arduino空间中,我可以在尝试执行读操作之前询问串口是否有可用字节。
我无法找到boost :: asio :: serial_port的等价物。
答案 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来填充带有串行数据的缓冲区,然后缓冲区数据排队等待程序的其他部分进行处理。