GKD.RoboCtrl
载入中...
搜索中...
未找到
can.cpp
1#include "io/can.h"
2#include "asio/use_awaitable.hpp"
3#include "core/async.hpp"
4#include "io/base.hpp"
5#include "linux/can.h"
6#include "utils/utils.hpp"
7#include <cstddef>
8#include <cstdlib>
9#include <stdexcept>
10#include <sys/socket.h>
11
12using namespace roboctrl::io;
13
14template <>
15struct std::formatter<can_frame> : std::formatter<std::string> {
16 auto format(const can_frame& frame, std::format_context& ctx) const {
17 std::ostringstream oss;
18 oss << std::hex << std::uppercase;
19 oss << "CAN ID=0x" << (frame.can_id & CAN_EFF_MASK);
20
21 oss << " [";
22 if (frame.can_id & CAN_EFF_FLAG) oss << "EFF ";
23 if (frame.can_id & CAN_RTR_FLAG) oss << "RTR ";
24 if (frame.can_id & CAN_ERR_FLAG) oss << "ERR ";
25 oss << "]";
26
27 oss << " DLC=" << std::dec << static_cast<int>(frame.can_dlc)
28 << " DATA=[";
29
30 for (int i = 0; i < frame.can_dlc; ++i) {
31 oss << std::format("{:02X}", frame.data[i]);
32 if (i + 1 < frame.can_dlc) oss << ' ';
33 }
34 oss << ']';
35
36 return std::formatter<std::string>::format(oss.str(), ctx);
37 }
38};
39
41 :info_{info},
43 stream_{roboctrl::io_context()},
44 can_name_{info.can_name.data(),info.can_name.length()}
45{
47 if(fd < 0)
48 throw std::runtime_error("socket() failed");
49
50 struct ifreq ifr{};
51 std::strncpy(ifr.ifr_name, can_name_.c_str(), IFNAMSIZ);
52 if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
53 throw std::runtime_error("ioctl(SIOCGIFINDEX) failed");
54
55 struct sockaddr_can addr{};
56 addr.can_family = AF_CAN;
57 addr.can_ifindex = ifr.ifr_ifindex;
58 if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
59 throw std::runtime_error("bind() failed");
60
61 stream_.assign(fd);
62
63 cf_ = (::can_frame*)std::malloc(sizeof(::can_frame) + 8);
64
65 log_info("Can io created on {}",info.can_name);
66
68}
69
70can::~can(){
71 std::free(cf_);
72}
73
75 while(true){
76 size_t pkg_size = co_await stream_.async_read_some(asio::buffer(buffer_),asio::use_awaitable);
77 can_frame cf = utils::from_bytes<can_frame>(std::span{buffer_.data(),pkg_size});
78
79 can_id_type id = cf.can_id;
80 size_t can_size= cf.can_dlc;
81
82 //log_debug("recv can frame: {}",cf);
83
84 dispatch(id,std::span{(std::byte*)cf.data,can_size});
85 }
86}
87
89 co_await stream_.async_write_some(
90 asio::buffer(frame.data(), frame.size()),
91 asio::use_awaitable
92 );
93}
94
95
97
98 if (data.size() > 8) {
99 throw std::invalid_argument("payload of can can't > 8");
100 }
101
102 cf_->can_id = id;
103 cf_->can_dlc = data.size();
104 std::memcpy(cf_->data, data.data(), data.size());
105
106 log_debug("send can frame: {}", *cf_);
107
108 co_await stream_.async_write_some(
109 asio::buffer(cf_, sizeof(can_frame)),
110 asio::use_awaitable
111 );
112}
异步任务上下文组件。
基于 Linux SocketCAN 的 CAN 总线封装。
can(const info_type &info)
打开 CAN 设备。
Definition can.cpp:40
awaitable< void > task()
接收循环任务。
Definition can.cpp:74
awaitable< void > send(byte_span data)
发送裸帧。
Definition can.cpp:88
带 key 的 IO 基类,根据键值派发数据。
Definition base.hpp:120
void dispatch(const std::uint32_t &key, byte_span data)
将数据派发给对应 key 的回调。
Definition base.hpp:152
void log_debug(std::format_string< Args... > fmt, Args &&...args) const
输出debug日志
Definition logger.h:202
void log_info(std::format_string< Args... > fmt, Args &&...args) const
输出info日志
Definition logger.h:214
IO的基础组件。
std::span< std::byte > byte_span
byte span,实际上就是一个std::span<std::byte>;
Definition base.hpp:42
auto spawn(task_context::task_type &&task)
添加一个协程任务到全局任务上下文中执行。
Definition async.hpp:151
asio::awaitable< T > awaitable
协程任务类型。
Definition async.hpp:42
auto & io_context()
获取全局任务上下文的io_context。
Definition async.hpp:218
CAN 初始化参数。
Definition can.h:29
常用数值与字节工具集合。