我正在使用Boost::Asio处理串行端口例程。
我正在使用Boost::Asio提供的 Package 器配置端口。
在我的应用程序中,数据的结束由接收超时或\r\n
线路终止序列表示。
由于Boost::Asio没有提供 Package 器来访问和配置DCB
- Windows、termios
- Linux结构,以便配置超时和/或行结束;我正在访问通过native_handle
Package 器返回的本地端口句柄/文件描述符,并手动配置结构。
但是,我似乎无法正确配置端口。
即使我将数据的结尾配置为用\n
表示,数据也会以块的形式部分返回。
同样,在发生超时之前也会返回数据。
更新
系统有两种工作模式
1.行模式-〉逐行读取数据并处理。行尾字符\r
、\n
或\r\n
。
1.批量模式-〉读取多行数据。如果在预定时间间隔内没有接收到数据,则认为数据已完全接收。例如,如果在50毫秒内没有接收到新数据,则认为传输已完成。
编码
bool SerialPort::open_port(void)
{
try
{
this->port.open(this->port_name);
this->native_port = this->port.native_handle();
return true;
}
catch (const std::exception& ex)
{
PLOG_FATAL << ex.what();
}
return false;
}
bool SerialPort::open_port(const std::string& port_name, std::uint32_t baud_rate, std::uint8_t data_bits, std::uint8_t stop_bits,
parity_t parity, flow_control_t flow_control, std::uint32_t read_timeout, std::uint32_t read_inter_byte_timeout,
std::uint32_t write_timeout)
{
try
{
this->port_name = port_name;
if (not this->open_port())
return false;
if (not this->set_baud_rate(baud_rate).has_value())
return false;
if (not this->set_data_bits(data_bits).has_value())
return false;
if (not this->set_stop_bits(stop_bits).has_value())
return false;
if (not this->set_parity(parity).has_value())
return false;
if (not this->set_flow_control(flow_control).has_value())
return false;
this->read_timeout = read_timeout;
if (read_inter_byte_timeout <= 0)
this->read_inter_byte_timeout = 1;
#ifdef _WIN64
BOOL return_value;
DCB dcb = { 0 };
COMMTIMEOUTS timeouts = { 0 };
if (this->line_mode) //Set COM port to return data either at \n or \r
{
/*
* If the function succeeds, the return value is nonzero.
* If the function fails, the return value is zero. To get extended error information, call GetLastError.
*/
return_value = GetCommState(this->native_port, &dcb);
if (return_value)
{
if(this->new_line_character == '\r')
dcb.EofChar = '\r'; //Specify end of data character as carriage-return (\r)
else // --> Default
dcb.EofChar = '\n'; //Specify end of data character as new-line (\n)
}
else
{
PLOG_ERROR << "Error GetCommState : " << GetLastErrorAsString();
return false;
}
/*
* If the function succeeds, the return value is nonzero.
* If the function fails, the return value is zero. To get extended error information, call GetLastError.
*/
return_value = SetCommState(this->native_port, &dcb);
if (not return_value)
{
PLOG_ERROR << "Error SetCommState : " << GetLastErrorAsString();
return false;
}
}
else //Set COM port to return data on timeout
{
/*
* If the function succeeds, the return value is nonzero.
* If the function fails, the return value is zero. To get extended error information, call GetLastError.
*/
return_value = GetCommTimeouts(this->native_port, &timeouts);
if (return_value)
{
timeouts.ReadIntervalTimeout = this->read_inter_byte_timeout; // Timeout in miliseconds
//timeouts.ReadTotalTimeoutConstant = 0; //MAXDWORD; // in milliseconds - not needed
//timeouts.ReadTotalTimeoutMultiplier = 0; // in milliseconds - not needed
//timeouts.WriteTotalTimeoutConstant = 50; // in milliseconds - not needed
//timeouts.WriteTotalTimeoutMultiplier = write_timeout; // in milliseconds - not needed
}
else
{
PLOG_ERROR << "Error GetCommTimeouts : " << GetLastErrorAsString();
return false;
}
/*
* If the function succeeds, the return value is nonzero.
* If the function fails, the return value is zero. To get extended error information, call GetLastError.
*/
return_value = SetCommTimeouts(this->native_port, &timeouts);
if (not return_value)
{
PLOG_ERROR << "Error SetCommTimeouts : " << GetLastErrorAsString();
return false;
}
}
#else //For Linux termios
#endif // _WIN64
return true;
}
catch (const std::exception& ex)
{
PLOG_ERROR << ex.what();
return false;
}
}
void SerialPort::read_handler(const boost::system::error_code& error, std::size_t bytes_transferred)
{
this->read_async(); // I realized I was calling read_async before reading data
bool receive_complete{ false };
try
{
if (error not_eq boost::system::errc::success) //Error in serial port read
{
PLOG_ERROR << error.to_string();
this->async_signal.emit(this->port_number, SerialPortEvents::read_error, error.to_string());
return;
}
if (this->line_mode)
{
std::string temporary_recieve_data;
std::transform(this->read_buffer.begin(), this->read_buffer.begin() + bytes_transferred, //Data is added to temporary buffer
std::back_inserter(temporary_recieve_data), [](std::byte character) {
return static_cast<char>(character);
}
);
boost::algorithm::trim(temporary_recieve_data); // Trim handles space character, tab, carriage return, newline, vertical tab and form feed
//Data is further processed based on the Process logic
receive_complete = true;
}
else // Bulk-Data. Just append data to end of received_data string buffer.
// Wait for timeout to trigger recevive_complete
{
//Test Function
std::transform(this->read_buffer.begin(), this->read_buffer.begin() + bytes_transferred,
std::back_inserter(this->received_data), [](std::byte character) {
return static_cast<char>(character);
}
);
this->async_signal.emit(this->port_number, SerialPortEvents::read_data, this->received_data); //Data has been recieved send to server via MQTT
}
}
catch (const std::exception& ex)
{
PLOG_ERROR << ex.what();
this->async_signal.emit(this->port_number, SerialPortEvents::read_error, ex.what());
}
}
支持功能
std::optional<std::uint32_t> SerialPort::set_baud_rate(std::uint32_t baud_rate)
{
boost::system::error_code error;
std::uint32_t _baud_rate = 1200;
switch (baud_rate)
{
case 1200:
case 2400:
case 4800:
case 9600:
case 115200:
_baud_rate = baud_rate;
break;
default:
_baud_rate = 1200;
break;
}
this->port.set_option(boost::asio::serial_port_base::baud_rate(_baud_rate), error);
if (error)
{
PLOG_FATAL << error.message();
return std::nullopt;
}
return baud_rate;
}
std::optional<std::uint8_t> SerialPort::set_data_bits(std::uint8_t data_bits)
{
boost::system::error_code error;
std::uint32_t _data_bits = 8;
switch (data_bits)
{
case 7:
case 8:
_data_bits = data_bits;
break;
default:
_data_bits = 8;
break;
}
this->port.set_option(boost::asio::serial_port_base::character_size(_data_bits), error);
if (error)
{
PLOG_FATAL << error.message();
return std::nullopt;
}
return data_bits;
}
std::optional<std::uint8_t> SerialPort::set_stop_bits(std::uint8_t stop_bits)
{
boost::system::error_code error;
switch (stop_bits)
{
case 1:
this->port.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one), error);
break;
case 2:
this->port.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::two), error);
break;
default:
this->port.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one), error);
break;
}
if (error)
{
PLOG_FATAL << error.message();
return std::nullopt;
}
return stop_bits;
}
std::optional<parity_t> SerialPort::set_parity(parity_t parity)
{
boost::system::error_code error;
switch (parity)
{
case Parity::none:
this->port.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none), error);
break;
case Parity::even:
this->port.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::even), error);
break;
case Parity::odd:
this->port.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::odd), error);
break;
default:
this->port.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none), error);
break;
}
if (error)
{
PLOG_FATAL << error.message();
return std::nullopt;
}
return parity;
}
std::optional<flow_control_t> SerialPort::set_flow_control(flow_control_t flow_control)
{
boost::system::error_code error;
switch (flow_control)
{
case FlowControl::none:
this->port.set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::none), error);
break;
case FlowControl::hardware:
this->port.set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::hardware), error);
break;
case FlowControl::software:
this->port.set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::software), error);
break;
default:
this->port.set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::none), error);
break;
}
if (error)
{
PLOG_FATAL << error.message();
return std::nullopt;
}
return flow_control;
}
1条答案
按热度按时间a64a0gku1#
对你的评语:
输入数据是多行的,因此我在串行端口结构中设置了读取超时间隔
这有什么意义呢?在Asio中处理超时没有真实的的区别。
关于过载:
但是我得到E0304,没有重载函数“boost::asio::async_read_until”的示例与参数列表错误匹配。
这是我的十便士:
请注意,您需要动态缓冲区。我能想到的最简单的方法是close to your original:
现在,我们将更新读取处理程序以擦除“已使用”部分,因为接收缓冲区可能包含分隔符以外的数据。
完整列表:Live On Coliru
本地演示: