diff --git a/include/can_wrap.h b/include/can_wrap.h index 014856d..2d8c480 100644 --- a/include/can_wrap.h +++ b/include/can_wrap.h @@ -1,7 +1,7 @@ #ifndef CAN_WRAP_H #define CAN_WRAP_H -#include +#include #include #include #include @@ -9,188 +9,128 @@ #include #include -#include -#include -#include -#include +#include +#include + +/** + * @brief Opens socket for CAN bus communication via socketcan. + * Returns socket identifier which is used as an argument for + * future can::read(), can::write() and can::close() calls. + * + * + * @param fd Open as normal CAN or CANFD. + * @param channel Network channel to use, e.g. can0 or vcan0. + * @return const int Socket identifier. + * @return -1 If socket creation failed. + * @return -2 If could not enable CANFD. + * @return -3 If could not bind socket. + */ +const int can_connect( const char* channel, const bool fd ) +{ + const int canSocket = socket( PF_CAN, SOCK_RAW, CAN_RAW ); + if( canSocket < 0 ) + return -1; + + struct ifreq ifr; + strncpy( ifr.ifr_name, channel, sizeof(ifr.ifr_name)-1 ); + ioctl( canSocket, SIOCGIFINDEX, &ifr ); + + struct sockaddr_can addr; + memset( &addr, 0, sizeof(addr) ); + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + + int enableCanFd = 1; + if( fd && setsockopt( canSocket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, + &enableCanFd, sizeof(enableCanFd) ) ) + return -2; + + if( bind( canSocket, (struct sockaddr*)&addr, sizeof(addr) ) < 0 ) + return -3; + + return canSocket; +} + +/** + * @brief Close specified socketcan socket. + * + * @param socket Socket identifer as returned from can::connect(). + * + * @return false If socket close failed + */ +bool can_close( const int socket ) +{ + return close( socket ) >= 0; +} + +/** + * @brief Passes call to can::_read() to read standard CAN frame. + * + * @pre must call connect() successfully first. + * @param socket Socket identifer as returned from can::connect(). + * @return const can_frame + */ +bool can_read( const int socket, struct can_frame* frame ) +{ + return read( socket, frame, sizeof(struct can_frame) ) >= 0; +} -namespace can +/** + * @brief Passes call to can::_read() to read CANFD frame. + * + * @pre must call connectfd() successfully first. + * @param socket Socket identifer as returned from can::connect(). + * @return const canfd_frame + */ +bool can_readfd( const int socket, struct canfd_frame* frame ) { - /** - * @brief Opens socket for CAN bus communication via socketcan. - * Returns socket identifier which is used as an argument for - * future can::read(), can::write() and can::close() calls. - * - * @throws std::runtime_error If socket creation failed. - * @throws std::runtime_error If could not enable CANFD. - * @throws std::runtime_error If could not bind socket. - * - * @param fd Open as normal CAN or CANFD. - * @param channel Network channel to use, e.g. can0 or vcan0. - * @return const int Socket identifier. - */ - const int _connect( const bool fd, const std::string& channel ) - { - const int canSocket = socket( PF_CAN, SOCK_RAW, CAN_RAW ); - if( canSocket < 0 ) - throw std::runtime_error( "Create socket failed" ); - - struct ifreq ifr; - std::strncpy( ifr.ifr_name, channel.c_str(), sizeof(ifr.ifr_name)-1 ); - ioctl( canSocket, SIOCGIFINDEX, &ifr ); - - struct sockaddr_can addr; - std::memset( &addr, 0, sizeof(addr) ); - addr.can_family = AF_CAN; - addr.can_ifindex = ifr.ifr_ifindex; - - int enableCanFd = 1; - if( fd && setsockopt( canSocket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, - &enableCanFd, sizeof(enableCanFd) ) ) - throw std::runtime_error( "Enable CAN FD failed" ); - - if( bind( canSocket, reinterpret_cast(&addr), sizeof(addr) ) < 0 ) - throw std::runtime_error( "Bind socket failed" ); - - return canSocket; - } - - /** - * @brief Passes call to can::_connect with fd argument as false. - */ - inline const int connect( const std::string channel="vcan0" ) - { - return _connect( false, channel ); - } - - /** - * @brief Passes call to can::_connect with fd argument as true. - */ - inline const int connectfd( const std::string channel="vcan0" ) - { - return _connect( true, channel ); - } - - /** - * @brief Close specified socketcan socket. - * - * @throws std::runtime_error If close failed. - * - * @param socket Socket identifer as returned from can::connect(). - */ - void close( const int socket ) - { - if( ::close( socket ) < 0 ) - throw std::runtime_error( "Socket close failed" ); - } - - /** - * @brief Read next frame from CAN bus. - * - * @warning This function will block until a frame is available. - * - * @throws std::runtime_error If read failed. - * - * @param socket Socket identifer as returned from can::connect(). - * @return const can_frame - */ - template - const FRAME _read( const int socket ) - { - FRAME frame; - - if( read( socket, &frame, sizeof(frame) ) < 0 ) - throw std::runtime_error( "Read failed" ); - - return frame; - } - - /** - * @brief Passes call to can::_read() to read standard CAN frame. - * - * @param socket Socket identifer as returned from can::connect(). - * @return const can_frame - */ - inline const can_frame read( const int socket ) - { - return _read( socket ); - } - - /** - * @brief Passes call to can::_read() to read CANFD frame. - * - * @param socket Socket identifer as returned from can::connect(). - * @return const canfd_frame - */ - inline const canfd_frame readfd( const int socket ) - { - return _read( socket ); - } - - /** - * @brief Send CAN frame. - * - * @throws std::runtime_error If write failed. - * - * @tparam FRAME can_frame or canfd_frame - * @param socket Socket identifer as returned from can::connect(). - * @param frame CAN or CANFD frame to be sent. - * @param numBytes Number of bytes to be written. - */ - template - void _write( const int socket, const FRAME& frame, const uint8_t numBytes ) - { - if( write( socket, &frame, numBytes ) != numBytes ) - std::runtime_error( "Write failed" ); - } - - /** - * @brief Passes call to can::_write() to write standard CAN frame. - * - * @param socket Socket identifer as returned from can::connect(). - * @param frame CAN frame to be sent. - */ - void write( const int socket, const can_frame& frame ) - { - // 8 bytes for the frame header and the rest for the actual data. - _write( socket, frame, sizeof(can_frame) ); - } - - /** - * @brief Passes call to can::_write() to write CANFD frame. - * - * @param socket Socket identifer as returned from can::connect(). - * @param frame CANFD frame to be sent. - */ - void write( const int socket, const canfd_frame& frame ) - { - // 8 bytes for the frame header and the rest for the actual data. - _write( socket, frame, sizeof(canfd_frame) ); - } - - - std::ostream& operator<<( std::ostream &os, const can_frame& frame ) - { - os << "0x" << std::setw(3) << std::hex << frame.can_id << - " [" << static_cast(frame.can_dlc) << ']'; - for( int i=0; i(frame.data[i]); - - return os; - } - - std::ostream& operator<<( std::ostream &os, const canfd_frame& frame ) - { - os << "0x" << std::setw(3) << std::hex << frame.can_id << - " [" << static_cast(frame.len) << ']'; - os << std::uppercase << std::setfill('0') << std::setw(2); - for( int i=0; i(frame.data[i]); - - return os; - } + return read( socket, frame, sizeof(struct canfd_frame) ) >= 0; } +/** + * @brief Passes call to can::_write() to write standard CAN frame. + * + * @param socket Socket identifer as returned from can::connect(). + * @param frame CAN frame to be sent. + */ +bool can_write( const int socket, struct can_frame* frame ) +{ + return write( socket, &frame, sizeof(struct can_frame) ) == sizeof(struct can_frame); +} + +/** + * @brief Passes call to can::_write() to write CANFD frame. + * + * @param socket Socket identifer as returned from can::connect(). + * @param frame CANFD frame to be sent. + */ +bool can_writefd( const int socket, struct canfd_frame* frame ) +{ + return write( socket, &frame, sizeof(struct canfd_frame) ) == sizeof(struct canfd_frame); +} + +/* +std::ostream& operator<<( std::ostream &os, const can_frame& frame ) +{ + os << "0x" << std::setw(3) << std::hex << frame.can_id << + " [" << static_cast(frame.can_dlc) << ']'; + for( int i=0; i(frame.data[i]); + + return os; +} + +std::ostream& operator<<( std::ostream &os, const canfd_frame& frame ) +{ + os << "0x" << std::setw(3) << std::hex << frame.can_id << + " [" << static_cast(frame.len) << ']'; + os << std::uppercase << std::setfill('0') << std::setw(2); + for( int i=0; i(frame.data[i]); + + return os; +}*/ + #endif diff --git a/include/can_wrap.hpp b/include/can_wrap.hpp new file mode 100644 index 0000000..b26bec9 --- /dev/null +++ b/include/can_wrap.hpp @@ -0,0 +1,198 @@ +#ifndef CAN_WRAP_HPP +#define CAN_WRAP_HPP + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace can +{ + /** + * @brief Opens socket for CAN bus communication via socketcan. + * Returns socket identifier which is used as an argument for + * future can::read(), can::write() and can::close() calls. + * + * @throws std::runtime_error If socket creation failed. + * @throws std::runtime_error If could not enable CANFD. + * @throws std::runtime_error If could not bind socket. + * + * @param fd Open as normal CAN or CANFD. + * @param channel Network channel to use, e.g. can0 or vcan0. + * @return const int Socket identifier. + */ + const int _connect( const bool fd, const std::string& channel ) + { + const int canSocket = socket( PF_CAN, SOCK_RAW, CAN_RAW ); + if( canSocket < 0 ) + throw std::runtime_error( "Create socket failed" ); + + struct ifreq ifr; + std::strncpy( ifr.ifr_name, channel.c_str(), sizeof(ifr.ifr_name)-1 ); + ioctl( canSocket, SIOCGIFINDEX, &ifr ); + + struct sockaddr_can addr; + std::memset( &addr, 0, sizeof(addr) ); + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + + int enableCanFd = 1; + if( fd && setsockopt( canSocket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, + &enableCanFd, sizeof(enableCanFd) ) ) + throw std::runtime_error( "Enable CAN FD failed" ); + + if( bind( canSocket, reinterpret_cast(&addr), sizeof(addr) ) < 0 ) + throw std::runtime_error( "Bind socket failed" ); + + return canSocket; + } + + /** + * @brief Passes call to can::_connect with fd argument as false. + */ + inline const int connect( const std::string channel="vcan0" ) + { + return _connect( false, channel ); + } + + /** + * @brief Passes call to can::_connect with fd argument as true. + */ + inline const int connectfd( const std::string channel="vcan0" ) + { + return _connect( true, channel ); + } + + /** + * @brief Close specified socketcan socket. + * + * @throws std::runtime_error If close failed. + * + * @param socket Socket identifer as returned from can::connect(). + */ + void close( const int socket ) + { + if( ::close( socket ) < 0 ) + throw std::runtime_error( "Socket close failed" ); + } + + /** + * @brief Read next frame from CAN bus. + * + * @warning This function will block until a frame is available. + * + * @throws std::runtime_error If read failed. + * + * @param socket Socket identifer as returned from can::connect(). + * @return const can_frame + */ + template + const FRAME _read( const int socket ) + { + FRAME frame; + + if( read( socket, &frame, sizeof(frame) ) < 0 ) + throw std::runtime_error( "Read failed" ); + + return frame; + } + + /** + * @brief Passes call to can::_read() to read standard CAN frame. + * + * @pre must call connect() successfully first. + * @param socket Socket identifer as returned from can::connect(). + * @return const can_frame + */ + inline const can_frame read( const int socket ) + { + return _read( socket ); + } + + /** + * @brief Passes call to can::_read() to read CANFD frame. + * + * @pre must call connectfd() successfully first. + * @param socket Socket identifer as returned from can::connect(). + * @return const canfd_frame + */ + inline const canfd_frame readfd( const int socket ) + { + return _read( socket ); + } + + /** + * @brief Send CAN frame. + * + * @throws std::runtime_error If write failed. + * + * @tparam FRAME can_frame or canfd_frame + * @param socket Socket identifer as returned from can::connect(). + * @param frame CAN or CANFD frame to be sent. + * @param numBytes Number of bytes to be written. + */ + template + void _write( const int socket, const FRAME& frame, const uint8_t numBytes ) + { + if( write( socket, &frame, numBytes ) != numBytes ) + std::runtime_error( "Write failed" ); + } + + /** + * @brief Passes call to can::_write() to write standard CAN frame. + * + * @param socket Socket identifer as returned from can::connect(). + * @param frame CAN frame to be sent. + */ + void write( const int socket, const can_frame& frame ) + { + // 8 bytes for the frame header and the rest for the actual data. + _write( socket, frame, sizeof(can_frame) ); + } + + /** + * @brief Passes call to can::_write() to write CANFD frame. + * + * @param socket Socket identifer as returned from can::connect(). + * @param frame CANFD frame to be sent. + */ + void write( const int socket, const canfd_frame& frame ) + { + // 8 bytes for the frame header and the rest for the actual data. + _write( socket, frame, sizeof(canfd_frame) ); + } + + + std::ostream& operator<<( std::ostream &os, const can_frame& frame ) + { + os << "0x" << std::setw(3) << std::hex << frame.can_id << + " [" << static_cast(frame.can_dlc) << ']'; + for( int i=0; i(frame.data[i]); + + return os; + } + + std::ostream& operator<<( std::ostream &os, const canfd_frame& frame ) + { + os << "0x" << std::setw(3) << std::hex << frame.can_id << + " [" << static_cast(frame.len) << ']'; + os << std::uppercase << std::setfill('0') << std::setw(2); + for( int i=0; i(frame.data[i]); + + return os; + } +} + +#endif