25#ifndef GOBY_MIDDLEWARE_IO_CAN_H
26#define GOBY_MIDDLEWARE_IO_CAN_H
30#include <linux/can/raw.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>
68 std::uint8_t source = 0)
70 return (pgn & 0x1FFFF) << 8 | (priority & 0x7) << 26 | CAN_EFF_FLAG | (source & 0xFF);
81inline std::tuple<std::uint32_t, std::uint8_t, std::uint8_t>
84 return std::make_tuple((can_id >> 8) & 0x1FFFF, (can_id >> 26) & 0x7, can_id & 0xFF);
94 bool use_indexed_groups =
false>
96 :
public detail::IOThread<line_in_group, line_out_group, publish_layer, subscribe_layer,
97 goby::middleware::protobuf::CanConfig,
98 boost::asio::posix::stream_descriptor, ThreadType, use_indexed_groups>
101 detail::IOThread<line_in_group, line_out_group, publish_layer, subscribe_layer,
103 boost::asio::posix::stream_descriptor, ThreadType, use_indexed_groups>;
110 :
Base(config, index,
std::string(
"can: ") + config.interface())
113 this->interthread().template publish<line_in_group>(ready);
119 void async_read()
override;
120 void async_write(std::shared_ptr<const goby::middleware::protobuf::IOData> io_msg)
override
125 void open_socket()
override;
127 void data_rec(
struct can_frame& receive_frame_, boost::asio::posix::stream_descriptor& stream);
130 struct can_frame receive_frame_;
140 bool use_indexed_groups>
142 ThreadType, use_indexed_groups>::open_socket()
146 struct sockaddr_can addr_
149 struct can_frame receive_frame_;
151 can_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW);
153 std::vector<struct can_filter> filters;
155 for (
auto x : this->cfg().filter())
157 auto id = x.can_id();
158 auto mask = x.has_can_mask_custom() ? x.can_mask_custom() : x.can_mask();
160 filters.push_back({id, mask});
163 for (std::uint32_t x : this->cfg().pgn_filter())
165 constexpr std::uint32_t one_byte = 8;
166 auto id = x << one_byte;
167 constexpr auto mask = protobuf::CanConfig::CanFilter::PGNOnly;
168 filters.push_back({id, mask});
173 setsockopt(can_socket, SOL_CAN_RAW, CAN_RAW_FILTER, filters.data(),
174 sizeof(can_filter) * filters.size());
176 std::strcpy(ifr_.ifr_name, this->cfg().interface().c_str());
178 ioctl(can_socket, SIOCGIFINDEX, &ifr_);
180 addr_.can_family = AF_CAN;
181 addr_.can_ifindex = ifr_.ifr_ifindex;
182 if (
bind(can_socket, (
struct sockaddr*)&addr_,
sizeof(addr_)) < 0)
183 throw(
goby::Exception(std::string(
"Error in socket bind to interface ") +
184 this->cfg().interface() +
": " + std::strerror(errno)));
186 this->mutable_socket().assign(can_socket);
188 this->interthread().template subscribe<line_out_group, can_frame>(
189 [
this](
const can_frame& frame)
191 auto io_msg = std::make_shared<goby::middleware::protobuf::IOData>();
192 std::string& bytes = *io_msg->mutable_data();
194 const int frame_size =
sizeof(can_frame);
196 for (
int i = 0; i < frame_size; ++i)
198 bytes += *(
reinterpret_cast<const char*
>(&frame) + i);
208 bool use_indexed_groups>
210 ThreadType, use_indexed_groups>::async_read()
212 boost::asio::async_read(this->mutable_socket(),
213 boost::asio::buffer(&receive_frame_,
sizeof(receive_frame_)),
214 boost::bind(&CanThread::data_rec,
this, boost::ref(receive_frame_),
215 boost::ref(this->mutable_socket())));
222 bool use_indexed_groups>
224 line_in_group, line_out_group, publish_layer, subscribe_layer, ThreadType,
225 use_indexed_groups>::data_rec(
struct can_frame& receive_frame_,
226 boost::asio::posix::stream_descriptor& stream)
229 this->interthread().template publish<line_in_group>(receive_frame_);
232 const int frame_size =
sizeof(can_frame);
234 for (
int i = 0; i < frame_size; ++i)
236 bytes += *(
reinterpret_cast<char*
>(&receive_frame_) + i);
239 this->handle_read_success(bytes.size(), bytes);
241 boost::asio::async_read(
242 stream, boost::asio::buffer(&receive_frame_,
sizeof(receive_frame_)),
243 boost::bind(&CanThread::data_rec,
this, boost::ref(receive_frame_), boost::ref(stream)));
simple exception class for goby applications
Class for grouping publications in the Goby middleware. Analogous to "topics" in ROS,...
CanThread(const goby::middleware::protobuf::CanConfig &config, int index=-1)
Constructs the thread.
void bind(ModemDriverBase &driver, QueueManager &queue_manager)
binds the driver link-layer callbacks to the QueueManager
constexpr int priority_index
constexpr int source_index
void basic_async_write(IOThreadImplementation *this_thread, std::shared_ptr< const goby::middleware::protobuf::IOData > io_msg)
std::uint32_t make_extended_format_can_id(std::uint32_t pgn, std::uint8_t priority, std::uint8_t source=0)
std::tuple< std::uint32_t, std::uint8_t, std::uint8_t > parse_extended_format_can_id(std::uint32_t can_id)
middleware::SimpleThread< Config, detail::InterProcessTag > SimpleThread
Zeromq-backed SimpleThread. Derives from middleware::SimpleThread using InterProcessTag.
The global namespace for the Goby project.