Чтение из последовательного порта с Boost Asio
Я хочу проверить входящие пакеты данных на последовательном порту, используя boost.asio
. Каждый пакет данных будет начинаться с заголовка длиной в один байт и будет указывать, какой тип сообщения был отправлен. Каждый тип сообщения имеет свою собственную длину. Функция, которую я хочу написать, должна постоянно прослушивать новые входящие сообщения, а когда она найдет одно, она должна прочитать его и вызвать какую-то другую функцию для его анализа. Мой текущий код выглядит следующим образом:
void check_for_incoming_messages()
{
boost::asio::streambuf response;
boost::system::error_code error;
std::string s1, s2;
if (boost::asio::read(port, response, boost::asio::transfer_at_least(0), error)) {
s1 = streambuf_to_string(response);
int msg_code = s1[0];
if (msg_code < 0 || msg_code >= NUM_MESSAGES) {
// Handle error, invalid message header
}
if (boost::asio::read(port, response, boost::asio::transfer_at_least(message_lengths[msg_code]-s1.length()), error)) {
s2 = streambuf_to_string(response);
// Handle the content of s1 and s2
}
else if (error != boost::asio::error::eof) {
throw boost::system::system_error(error);
}
}
else if (error != boost::asio::error::eof) {
throw boost::system::system_error(error);
}
}
Является boost::asio::streambuf
правильным инструментом использовать? И как извлечь из него данные, чтобы можно было разобрать сообщение? Я также хочу знать, нужно ли мне иметь отдельный поток, который только вызывает эту функцию, чтобы она вызывалась чаще. Должен ли я беспокоиться о потере данных между двумя вызовами функции из-за высокого трафика и переполнения буфера последовательного порта? Я использую библиотеки Qt для GUI, и я действительно не знаю, сколько времени требуется для обработки всех событий.
Edit: интересный вопрос: как могу ли я проверить, есть ли какие-либо входящие данные на последовательном порту? Если нет входящих данных, я не хочу, чтобы функция блокировалась...
2 ответа:
Я нашел эту статью действительно полезной для лучшего понимания того, как ASIO может использоваться асинхронно с последовательными портами: http://www.webalice.it/fede.tft/serial_port/serial_port.html
Джейсон,
Если он подходит для вашего приложения, я настоятельно рекомендую реализовать асинхронный последовательный RX на основе обратного вызова. Как выполнить неблокирующее чтение с помощью asio? есть отличный небольшой пример как реализовать асинхронный последовательный с тайм-аутом. Как вы уже поняли, это потребует многопоточной реализации, чтобы получить преимущества производительности, поэтому вам нужно будет подумать, где ваши полученные данные будут буферизованы, чтобы убедиться, что вы не делаете много копирование.
Что касается
boost::streambuff
материала, я лично предпочитаю просто блокировать некоторую память в виде массива символов -char m_RXBuffer[m_RXBuffSize]
и использоватьboost::asio::buffer(m_RXBuffer, m_RXBuffSize)
для передачи целевого буфера вasync_read_some
. В частности, для RS232 я всегда находил тот факт, что лежащие в основе данные представляют собой поток байтов, естественно, отображаемый намного лучше на простой массив символов, чем любая из более сложных структур данных.Удачи!