├── 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 | } --------------------------------------------------------------------------------