25 #ifndef GOBY_MIDDLEWARE_IO_CAN_H
26 #define GOBY_MIDDLEWARE_IO_CAN_H
29 #include <linux/can.h>
30 #include <linux/can/raw.h>
36 #include <sys/ioctl.h>
37 #include <sys/socket.h>
41 #include <boost/asio/buffer.hpp>
42 #include <boost/asio/posix/stream_descriptor.hpp>
43 #include <boost/asio/read.hpp>
44 #include <boost/bind/bind.hpp>
45 #include <boost/core/ref.hpp>
66 std::uint8_t source = 0)
68 return (pgn & 0x1FFFF) << 8 | (priority & 0x7) << 26 | CAN_EFF_FLAG | (source & 0xFF);
79 inline std::tuple<std::uint32_t, std::uint8_t, std::uint8_t>
82 return std::make_tuple((can_id >> 8) & 0x1FFFF, (can_id >> 26) & 0x7, can_id & 0xFF);
92 bool use_indexed_groups =
false>
94 :
public detail::IOThread<line_in_group, line_out_group, publish_layer, subscribe_layer,
95 goby::middleware::protobuf::CanConfig,
96 boost::asio::posix::stream_descriptor, ThreadType, use_indexed_groups>
99 detail::IOThread<line_in_group, line_out_group, publish_layer, subscribe_layer,
101 boost::asio::posix::stream_descriptor, ThreadType, use_indexed_groups>;
111 this->
interthread().template publish<line_in_group>(ready);
117 void async_read()
override;
118 void async_write(std::shared_ptr<const goby::middleware::protobuf::IOData> io_msg)
override
123 void open_socket()
override;
125 void data_rec(
struct can_frame& receive_frame_, boost::asio::posix::stream_descriptor& stream);
128 struct can_frame receive_frame_;
138 bool use_indexed_groups>
140 ThreadType, use_indexed_groups>::open_socket()
144 struct sockaddr_can addr_
147 struct can_frame receive_frame_;
149 can_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW);
151 std::vector<struct can_filter> filters;
153 for (
auto x : this->cfg().filter())
155 auto id = x.can_id();
156 auto mask = x.has_can_mask_custom() ? x.can_mask_custom() : x.can_mask();
158 filters.push_back({id, mask});
161 for (std::uint32_t x : this->cfg().pgn_filter())
163 constexpr std::uint32_t one_byte = 8;
164 auto id = x << one_byte;
165 constexpr
auto mask = protobuf::CanConfig::CanFilter::PGNOnly;
166 filters.push_back({id, mask});
171 setsockopt(can_socket, SOL_CAN_RAW, CAN_RAW_FILTER, filters.data(),
172 sizeof(can_filter) * filters.size());
174 std::strcpy(ifr_.ifr_name, this->cfg().interface().c_str());
176 ioctl(can_socket, SIOCGIFINDEX, &ifr_);
178 addr_.can_family = AF_CAN;
179 addr_.can_ifindex = ifr_.ifr_ifindex;
180 if (
bind(can_socket, (
struct sockaddr*)&addr_,
sizeof(addr_)) < 0)
181 throw(
goby::Exception(std::string(
"Error in socket bind to interface ") +
182 this->cfg().interface() +
": " + std::strerror(errno)));
184 this->mutable_socket().assign(can_socket);
186 this->interthread().template subscribe<line_out_group, can_frame>(
187 [
this](
const can_frame& frame)
189 auto io_msg = std::make_shared<goby::middleware::protobuf::IOData>();
190 std::string& bytes = *io_msg->mutable_data();
192 const int frame_size =
sizeof(can_frame);
194 for (
int i = 0; i < frame_size; ++i)
196 bytes += *(
reinterpret_cast<const char*
>(&frame) + i);
206 bool use_indexed_groups>
208 ThreadType, use_indexed_groups>::async_read()
210 boost::asio::async_read(this->mutable_socket(),
211 boost::asio::buffer(&receive_frame_,
sizeof(receive_frame_)),
212 boost::bind(&CanThread::data_rec,
this, boost::ref(receive_frame_),
213 boost::ref(this->mutable_socket())));
220 bool use_indexed_groups>
222 line_in_group, line_out_group, publish_layer, subscribe_layer, ThreadType,
223 use_indexed_groups>::data_rec(
struct can_frame& receive_frame_,
224 boost::asio::posix::stream_descriptor& stream)
227 this->interthread().template publish<line_in_group>(receive_frame_);
230 const int frame_size =
sizeof(can_frame);
232 for (
int i = 0; i < frame_size; ++i)
234 bytes += *(
reinterpret_cast<char*
>(&receive_frame_) + i);
237 this->handle_read_success(bytes.size(), bytes);
239 boost::asio::async_read(
240 stream, boost::asio::buffer(&receive_frame_,
sizeof(receive_frame_)),
241 boost::bind(&CanThread::data_rec,
this, boost::ref(receive_frame_), boost::ref(stream)));