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);
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 ";
27 oss <<
" DLC=" << std::dec << static_cast<int>(frame.can_dlc)
30 const auto length = std::min<int>(frame.can_dlc, CAN_MAX_DLEN);
31 for (
int i = 0; i < length; ++i) {
32 oss << std::format(
"{:02X}", frame.data[i]);
33 if (i + 1 < length) oss <<
' ';
37 return std::formatter<std::string>::format(oss.str(), ctx);
46 co_await asio::async_write(stream_, asio::buffer(data), asio::use_awaitable);
48 interface_name_{info.interface_name.data(),info.interface_name.length()}
50 int fd = ::socket(PF_CAN,SOCK_RAW,CAN_RAW);
52 throw std::runtime_error(
"socket() failed");
54 if (interface_name_.empty() || interface_name_.size() >= IFNAMSIZ) {
56 throw std::invalid_argument(
"invalid CAN interface name");
60 std::strncpy(ifr.ifr_name, interface_name_.c_str(), IFNAMSIZ);
61 if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
63 throw std::runtime_error(
"ioctl(SIOCGIFINDEX) failed");
66 struct sockaddr_can addr{};
67 addr.can_family = AF_CAN;
68 addr.can_ifindex = ifr.ifr_ifindex;
69 if (bind(fd, (
struct sockaddr*)&addr,
sizeof(addr)) < 0) {
71 throw std::runtime_error(
"bind() failed");
76 log_info(
"Can io {} created on {}", info.name, info.interface_name);
89 size_t pkg_size =
co_await stream_.async_read_some(asio::buffer(buffer_),asio::use_awaitable);
90 if (pkg_size !=
sizeof(can_frame)) {
91 log_warn(
"drop malformed CAN frame with {} bytes", pkg_size);
94 can_frame cf = utils::from_bytes<can_frame>(std::span{buffer_.data(),pkg_size});
96 can_id_type
id = cf.can_id;
97 size_t can_size= cf.can_dlc;
99 if (can_size > CAN_MAX_DLEN || (
id & (CAN_RTR_FLAG | CAN_ERR_FLAG))) {
100 log_warn(
"drop invalid CAN frame: {}", cf);
106 dispatch(
id,std::span{(std::byte*)cf.data,can_size});
112 if (data.size() > CAN_MAX_DLEN) {
113 throw std::invalid_argument(
"CAN payload cannot exceed 8 bytes");
115 if (
id & (CAN_RTR_FLAG | CAN_ERR_FLAG)) {
116 throw std::invalid_argument(
"CAN data frame ID cannot contain RTR or ERR flags");
121 frame.can_dlc =
static_cast<decltype(frame.can_dlc)
>(data.size());
122 std::memcpy(frame.data, data.data(), data.size());
127 can_write_key(
id, data.size()),
128 std::span<const std::byte>{reinterpret_cast<const std::byte*>(&frame), sizeof(frame)});