GKD.RoboCtrl
RoboMaster Linux 电控:异步 IO、设备驱动与机器人控制
载入中...
搜索中...
未找到
serial.cpp
1#include "io/serial.h"
2#include "core/async.hpp"
3#include "io/base.hpp"
4#include "utils/utils.hpp"
5
6#include <cstddef>
7#include <cstdint>
8#include <cstring>
9#include <stdexcept>
10#include <string>
11#include <vector>
12
13using namespace roboctrl::io;
14
16 : keyed_io_base<uint8_t>{},
17 port_{roboctrl::io_context()},
18 write_queue_{[this](byte_span data) -> awaitable<void> {
19 co_await asio::async_write(port_, asio::buffer(data), asio::use_awaitable);
20 }},
21 info_{info}
22{
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));
29}
30
32 if (started_) {
33 return;
34 }
35 started_ = true;
37}
38
40{
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");
44 }
45
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);
52}
53
54roboctrl::awaitable<void> serial::send_raw(byte_span data)
55{
56 if (!info_.raw) throw std::logic_error("raw send requires serial.raw=true");
57 co_await write_queue_.send(data);
58}
59
60void serial::process_receive_buffer()
61{
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());
66 continue;
67 }
68
69 const auto key = std::to_integer<std::uint8_t>(receive_buffer_[2]);
70 const auto len = package_size(key);
71 if (!len) {
72 log_warn("drop serial frame with unknown key {}", key);
73 receive_buffer_.erase(receive_buffer_.begin());
74 continue;
75 }
76
77 if (*len > 1024) {
78 log_warn("drop serial key {} with oversized payload {}", key, *len);
79 receive_buffer_.erase(receive_buffer_.begin());
80 continue;
81 }
82
83 const auto frame_size = header_size + *len;
84 if (receive_buffer_.size() < frame_size) {
85 return;
86 }
87
88 dispatch(key, byte_span{receive_buffer_.data() + header_size, *len});
89 receive_buffer_.erase(receive_buffer_.begin(), receive_buffer_.begin() + frame_size);
90 }
91}
92
94{
95 try {
96 while(true){
97 const auto bytes = co_await port_.async_read_some(
98 asio::buffer(read_buffer_), asio::use_awaitable);
99 if (info_.raw) {
100 raw_callbacks_(make_shared_from(byte_span{read_buffer_.data(), bytes}));
101 continue;
102 }
103 receive_buffer_.insert(receive_buffer_.end(), read_buffer_.begin(), read_buffer_.begin() + bytes);
104 process_receive_buffer();
105 }
106 } catch (const asio::system_error& error) {
107 if (error.code() != asio::error::operation_aborted) {
108 log_warn("serial receive stopped: {}", error.what());
109 }
110 }
111}
异步任务上下文组件。
带 key 的 IO 基类,根据键值派发数据。
Definition base.hpp:157
void dispatch(const uint8_t &key, byte_span data)
将数据派发给对应 key 的回调。
Definition base.hpp:197
awaitable< void > send(key_type key, byte_span data)
发送字节数据。
Definition serial.cpp:39
serial(info_type info)
打开并配置串口。
Definition serial.cpp:15
void start()
启动串口接收协程;重复调用不会重复启动。
Definition serial.cpp:31
awaitable< void > task()
接收循环任务。
Definition serial.cpp:93
void log_warn(std::format_string< Args... > fmt, Args &&...args) const
输出warn日志
Definition logger.h:226
IO的基础组件。
std::span< const std::byte > byte_span
只读 byte span。
Definition base.hpp:45
data_ptr make_shared_from(const T &t)
将任意满足 byte_container 的数据拷贝到共享缓冲。
Definition base.hpp:94
auto spawn(task_context::task_type &&task)
添加一个协程任务到全局任务上下文中执行。
Definition async.hpp:191
asio::awaitable< T > awaitable
协程任务类型。
Definition async.hpp:46
auto & io_context()
获取全局任务上下文的io_context。
Definition async.hpp:278
串口裸 IO 封装。
串口初始化参数。
Definition serial.h:36
常用数值与字节工具集合。