asio_read_some 继续读取以获取所有数据

发布于 2025-01-12 07:22:01 字数 133 浏览 4 评论 0原文

我使用boost asio async_read_some,我要读取的数据是STXdataETXlrc, 如果不是lrc我会使用async_read_until,我怎样才能继续阅读直到得到ETXlrc? 感谢所有的帮助。

/huvcbo

I use boost asio async_read_some, the data I want to read STXdataETXlrc,
if it were not for lrc I would use async_read_until, how can I continue reading until I get ETXlrc?
appreciate all the help.

/huvcbo

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

独自←快乐 2025-01-19 07:22:01

从非常稀疏的信息来看,我假设您正在串行通信的背景下进行交谈。

在这种情况下,最简单的开始方法可能是使用 Asio 的组合读取操作(例如 readread_until 等)。

comm::read_until(sp, buf, '\x03');

通过一些语法糖,您可以更富有表现力地编写:

enum ControlCodes : uint8_t {
    STX = 2,
    ETX = 3,
};

例如:

#include <boost/asio.hpp>
#include <boost/asio/serial_port.hpp>
#include <iostream>
namespace comm = boost::asio;
enum ControlCodes : uint8_t {
    STX = 2,
    ETX = 3,
};

int main(int argc, char** argv) {
    comm::io_context ioc;
    comm::serial_port sp(ioc, argc > 1 ? argv[1] : "/dev/ttyS6");
    sp.set_option(comm::serial_port::baud_rate(115'200));

    std::vector<uint8_t> data;
    comm::read_until(sp, comm::dynamic_buffer(data), ETX);
}

然后您可以继续进行固定长度读取以获取校验和。更多涉及的 read_until 重载允许您编写 MatchCondition 来代替,这样您就可以将其全部组合在一个调用中:https://www.boost.org/doc/libs/1_78_0/doc/html/boost_asio/reference/read_until.html

这是一个使用 boost::regex 重载,显示消息以及校验和是否验证:

Live On Compiler Explorer

#include <boost/asio.hpp>
#include <boost/asio/serial_port.hpp>
#include <boost/regex.hpp>
#include <fmt/ranges.h>
#include <numeric>
namespace comm = boost::asio;
enum ControlCodes : uint8_t {
    STX = 2,
    ETX = 3,
};

int main(int argc, char** argv) {
    comm::io_context ioc;
    comm::serial_port sp(ioc, argc > 1 ? argv[1] : "/dev/ttyS6");
    sp.set_option(comm::serial_port::baud_rate(115'200));

    std::vector<uint8_t> buffer;
    auto n = comm::read_until(sp, comm::dynamic_buffer(buffer), boost::regex("\x03."));

    auto raw = buffer.data();
    bool ok  = n >= 3 && *raw == STX;
    if (ok) {
        auto b   = raw + 1;
        auto e   = b + n - 3; // payload excludes STX, ETX, LRC
        auto lrc = accumulate(b, e, uint8_t(0), std::bit_xor<>{});
        bool verified = raw[n - 1] == lrc;

        fmt::print("Checksum {} bytes verified {}, buffer {::#02x} (expected {:#02x})\n",
                   n, verified, buffer, lrc);
    } else {
        fmt::print("Message not wellformed {} bytes buffer {::#02x}\n", n, buffer);
    }
}

使用 socat 进行本地测试:

enter图片描述在这里

From the very sparse information, I'm assuming you are talking in the context of serial comms.

In that case, the simplest way to get started might be to use Asio's composed read operations (like read, read_until etc).

comm::read_until(sp, buf, '\x03');

With a bit of syntactic sugar you can write more expressively:

enum ControlCodes : uint8_t {
    STX = 2,
    ETX = 3,
};

E.g.:

#include <boost/asio.hpp>
#include <boost/asio/serial_port.hpp>
#include <iostream>
namespace comm = boost::asio;
enum ControlCodes : uint8_t {
    STX = 2,
    ETX = 3,
};

int main(int argc, char** argv) {
    comm::io_context ioc;
    comm::serial_port sp(ioc, argc > 1 ? argv[1] : "/dev/ttyS6");
    sp.set_option(comm::serial_port::baud_rate(115'200));

    std::vector<uint8_t> data;
    comm::read_until(sp, comm::dynamic_buffer(data), ETX);
}

You could then proceed to to a fixed-length read to get the checksum. More involved overloads of read_until allow you to write MatchCondition instead so you can combine it all in a single call: https://www.boost.org/doc/libs/1_78_0/doc/html/boost_asio/reference/read_until.html.

Here's an example that uses the boost::regex overload, that shows the message and whether the checksum verifies:

Live On Compiler Explorer

#include <boost/asio.hpp>
#include <boost/asio/serial_port.hpp>
#include <boost/regex.hpp>
#include <fmt/ranges.h>
#include <numeric>
namespace comm = boost::asio;
enum ControlCodes : uint8_t {
    STX = 2,
    ETX = 3,
};

int main(int argc, char** argv) {
    comm::io_context ioc;
    comm::serial_port sp(ioc, argc > 1 ? argv[1] : "/dev/ttyS6");
    sp.set_option(comm::serial_port::baud_rate(115'200));

    std::vector<uint8_t> buffer;
    auto n = comm::read_until(sp, comm::dynamic_buffer(buffer), boost::regex("\x03."));

    auto raw = buffer.data();
    bool ok  = n >= 3 && *raw == STX;
    if (ok) {
        auto b   = raw + 1;
        auto e   = b + n - 3; // payload excludes STX, ETX, LRC
        auto lrc = accumulate(b, e, uint8_t(0), std::bit_xor<>{});
        bool verified = raw[n - 1] == lrc;

        fmt::print("Checksum {} bytes verified {}, buffer {::#02x} (expected {:#02x})\n",
                   n, verified, buffer, lrc);
    } else {
        fmt::print("Message not wellformed {} bytes buffer {::#02x}\n", n, buffer);
    }
}

Tested locally using socat:

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文