├── README.md
├── package.xml
├── include
└── socket_can
│ └── socket_can.hpp
├── CMakeLists.txt
└── src
└── socket_can.cpp
/README.md:
--------------------------------------------------------------------------------
1 | Minimal implementation of the CAN protocol stack, with read and write features
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | socket_can
4 | 0.0.0
5 | The socket_can package
6 |
7 | Shivesh Khaitan
8 |
9 | MIT
10 |
11 |
12 | catkin
13 |
14 |
15 | ament_cmake
16 |
17 |
18 | catkin
19 | ament_cmake
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/include/socket_can/socket_can.hpp:
--------------------------------------------------------------------------------
1 | #ifndef SOCKET_CAN_SOCKET_CAN_HPP
2 | #define SOCKET_CAN_SOCKET_CAN_HPP
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | #include
18 | #include
19 |
20 | namespace socket_can
21 | {
22 | class SocketCAN
23 | {
24 | public:
25 | SocketCAN(const char * ifname);
26 |
27 | SocketCAN(const char * ifname, long timeout);
28 |
29 | ~SocketCAN();
30 |
31 | bool is_connected();
32 |
33 | bool write(uint32_t frame_id, uint8_t dlc, uint8_t * data);
34 |
35 | bool read(uint32_t * can_id, uint8_t * dlc, uint8_t * data);
36 |
37 | private:
38 | void init();
39 |
40 | const char * ifname_;
41 |
42 | int socket_;
43 |
44 | bool connected_;
45 |
46 | long timeout_;
47 | };
48 | }
49 |
50 | #endif //SOCKET_CAN_SOCKET_CAN_HPP
51 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | if($ENV{ROS_VERSION} EQUAL 1)
2 | cmake_minimum_required(VERSION 3.5)
3 | project(socket_can)
4 |
5 | find_package(catkin REQUIRED)
6 |
7 | catkin_package(
8 | INCLUDE_DIRS
9 | include
10 | LIBRARIES
11 | socket_can
12 | )
13 |
14 | include_directories(
15 | include
16 | )
17 |
18 | add_library(
19 | socket_can
20 | src/socket_can.cpp
21 | )
22 |
23 | install(
24 | TARGETS socket_can
25 | ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
26 | LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
27 | RUNTIME DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
28 | )
29 | else()
30 | cmake_minimum_required(VERSION 3.5)
31 | project(socket_can)
32 |
33 | add_compile_options(-std=c++14)
34 |
35 | find_package(ament_cmake REQUIRED)
36 |
37 | include_directories(include)
38 |
39 | add_library(${PROJECT_NAME} STATIC
40 | src/${PROJECT_NAME}.cpp
41 | )
42 |
43 |
44 | install(
45 | DIRECTORY include/
46 | DESTINATION include
47 | )
48 |
49 | install(
50 | TARGETS ${PROJECT_NAME}
51 | ARCHIVE DESTINATION lib
52 | LIBRARY DESTINATION lib
53 | RUNTIME DESTINATION bin
54 | )
55 |
56 | ament_export_include_directories(include)
57 | ament_export_libraries(${PROJECT_NAME})
58 | ament_package()
59 |
60 | endif()
61 |
--------------------------------------------------------------------------------
/src/socket_can.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | namespace socket_can
4 | {
5 | SocketCAN::SocketCAN(const char * ifname) :
6 | ifname_(ifname),
7 | connected_(false),
8 | timeout_(1000l)
9 | {
10 | init();
11 | }
12 |
13 | SocketCAN::SocketCAN(const char * ifname, long timeout) :
14 | ifname_(ifname),
15 | connected_(false),
16 | timeout_(timeout)
17 | {
18 | init();
19 | }
20 |
21 | SocketCAN::~SocketCAN()
22 | {
23 | if (close(socket_) < 0) {
24 | perror("Closing: ");
25 | printf("Error: %d", errno);
26 | }
27 | }
28 |
29 | void SocketCAN::init()
30 | {
31 | if ((socket_ = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
32 | perror("Error while opening socket");
33 | return;
34 | }
35 |
36 | struct ifreq ifr{};
37 | strcpy(ifr.ifr_name, ifname_);
38 | ioctl(socket_, SIOCGIFINDEX, &ifr);
39 |
40 | struct sockaddr_can addr{};
41 | addr.can_family = AF_CAN;
42 | addr.can_ifindex = ifr.ifr_ifindex;
43 |
44 | printf("%s at index %d\n", ifname_, ifr.ifr_ifindex);
45 |
46 | if (bind(socket_, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
47 | perror("Error in socket bind");
48 | return;
49 | }
50 |
51 | int error = 0;
52 | socklen_t len = sizeof (error);
53 | int retval = getsockopt (socket_, SOL_SOCKET, SO_ERROR, &error, &len);
54 | if (retval != 0) {
55 | /* there was a problem getting the error code */
56 | printf("Error getting socket error code: %s\n", strerror(retval));
57 | return;
58 | }
59 |
60 | if (error != 0) {
61 | /* socket has a non zero error status */
62 | printf("Socket error: %s\n", strerror(error));
63 | return;
64 | }
65 |
66 | struct timeval timeout{};
67 | timeout.tv_sec = (timeout_ / 1000);
68 | timeout.tv_usec = (timeout_ % 1000) * 1000;
69 |
70 | if (setsockopt(socket_, SOL_SOCKET, SO_RCVTIMEO, (char *) & timeout, sizeof(timeout)) < 0) {
71 | perror("Setting timeout failed");
72 | }
73 |
74 | connected_ = true;
75 | }
76 |
77 | bool SocketCAN::is_connected()
78 | {
79 | return connected_;
80 | }
81 |
82 | bool SocketCAN::write(uint32_t can_id, uint8_t dlc, uint8_t * data)
83 | {
84 | struct can_frame frame{};
85 |
86 | frame.can_id = can_id;
87 | frame.can_dlc = dlc;
88 | memcpy(frame.data, data, dlc * sizeof(uint8_t));
89 |
90 | auto num_bytes = ::write(socket_, &frame, sizeof(struct can_frame));
91 |
92 | return num_bytes > 0;
93 | }
94 |
95 | bool SocketCAN::read(uint32_t * can_id, uint8_t * dlc, uint8_t * data)
96 | {
97 | struct can_frame frame{};
98 | auto num_bytes = ::read(socket_, &frame, sizeof(struct can_frame));
99 | if (num_bytes != sizeof(struct can_frame)) {
100 | return false;
101 | }
102 |
103 | (* can_id) = frame.can_id;
104 | (* dlc) = frame.can_dlc;
105 | memcpy(data, frame.data, sizeof(frame.data));
106 |
107 | return true;
108 | }
109 | }
--------------------------------------------------------------------------------