13using namespace roboctrl::io;
19 co_await asio::async_write(port_, asio::buffer(data), asio::use_awaitable);
23 port_.open(std::string(info.device));
24 port_.set_option(asio::serial_port_base::baud_rate(info.baud_rate));
25 port_.set_option(asio::serial_port_base::character_size(8));
26 port_.set_option(asio::serial_port_base::parity(asio::serial_port_base::parity::none));
27 port_.set_option(asio::serial_port_base::stop_bits(asio::serial_port_base::stop_bits::one));
28 port_.set_option(asio::serial_port_base::flow_control(asio::serial_port_base::flow_control::none));
41 if (info_.raw)
throw std::logic_error(
"keyed send is unavailable on raw serial");
42 if (data.size() > 1024) {
43 throw std::invalid_argument(
"serial payload cannot exceed 1024 bytes");
46 std::vector<std::byte> frame;
47 frame.reserve(header_bytes.size() +
sizeof(
id) + data.size());
48 frame.insert(frame.end(), header_bytes.begin(), header_bytes.end());
49 frame.push_back(
static_cast<std::byte
>(
id));
50 frame.insert(frame.end(), data.begin(), data.end());
51 co_await write_queue_.send(frame);
56 if (!info_.raw)
throw std::logic_error(
"raw send requires serial.raw=true");
57 co_await write_queue_.send(data);
60void serial::process_receive_buffer()
62 constexpr std::size_t header_size = header_bytes.size() +
sizeof(std::uint8_t);
63 while (receive_buffer_.size() >= header_size) {
64 if (receive_buffer_[0] != header_bytes[0] || receive_buffer_[1] != header_bytes[1]) {
65 receive_buffer_.erase(receive_buffer_.begin());
69 const auto key = std::to_integer<std::uint8_t>(receive_buffer_[2]);
70 const auto len = package_size(key);
72 log_warn(
"drop serial frame with unknown key {}", key);
73 receive_buffer_.erase(receive_buffer_.begin());
78 log_warn(
"drop serial key {} with oversized payload {}", key, *len);
79 receive_buffer_.erase(receive_buffer_.begin());
83 const auto frame_size = header_size + *len;
84 if (receive_buffer_.size() < frame_size) {
89 receive_buffer_.erase(receive_buffer_.begin(), receive_buffer_.begin() + frame_size);
97 const auto bytes =
co_await port_.async_read_some(
98 asio::buffer(read_buffer_), asio::use_awaitable);
103 receive_buffer_.insert(receive_buffer_.end(), read_buffer_.begin(), read_buffer_.begin() + bytes);
104 process_receive_buffer();
106 }
catch (
const asio::system_error& error) {
107 if (error.code() != asio::error::operation_aborted) {
108 log_warn(
"serial receive stopped: {}", error.what());
void dispatch(const uint8_t &key, byte_span data)
将数据派发给对应 key 的回调。
awaitable< void > send(key_type key, byte_span data)
发送字节数据。
serial(info_type info)
打开并配置串口。
void start()
启动串口接收协程;重复调用不会重复启动。
awaitable< void > task()
接收循环任务。
void log_warn(std::format_string< Args... > fmt, Args &&...args) const
输出warn日志
std::span< const std::byte > byte_span
只读 byte span。
data_ptr make_shared_from(const T &t)
将任意满足 byte_container 的数据拷贝到共享缓冲。
auto spawn(task_context::task_type &&task)
添加一个协程任务到全局任务上下文中执行。
asio::awaitable< T > awaitable
协程任务类型。
auto & io_context()
获取全局任务上下文的io_context。