diff --git a/com-middleware/can/CanDriver.cpp b/com-middleware/can/CanDriver.cpp index b91fb13f..3404f5bc 100644 --- a/com-middleware/can/CanDriver.cpp +++ b/com-middleware/can/CanDriver.cpp @@ -1,15 +1,69 @@ #include "CanDriver.hpp" +#include +#include +#include +#include +#include + +#include +#include + +#include "com-middleware/exceptions/CanCloseException.hpp" #include "com-middleware/exceptions/CanInitException.hpp" namespace candriver { -CanDriver::CanDriver(std::string can_interface, int32_t timeout) - : m_canInterface(std::move(can_interface)), m_timeout(timeout) {}; +CanDriver::CanDriver(std::string can_interface, int32_t timeout_s) + : m_canInterface(std::move(can_interface)), m_timeout_s(timeout_s) { + initializeCan(); +}; void CanDriver::initializeCan() { if (m_canInterface.empty()) { throw exceptions::CanInitException("Can interface is empty"); } + struct sockaddr_can addr {}; + struct ifreq ifr {}; // interface + + // opening a socket for communicating over a CAN network + // Since SocketCAN implements a new protocol family, we pass PF_CAN as the first argument to the + // socket(2) system call there are two CAN protocols to choose from, the raw socket protocol + // (SOCK_RAW) and the broadcast manager (CAN_BCM) + m_can_socket_fd = socket(PF_CAN, SOCK_RAW, CAN_RAW); + if (m_can_socket_fd < 0) { + throw exceptions::CanInitException("Error connecting to socket"); + } + + // Setting the can interface + strcpy(ifr.ifr_name, m_canInterface.c_str()); + // To determine the interface index an appropriate ioctl() has to be used (0 for all) + ioctl(m_can_socket_fd, SIOCGIFINDEX, &ifr); + + memset(&addr, 0, sizeof(addr)); + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + + // Timeout for read blocking + struct timeval timeout {}; + timeout.tv_sec = m_timeout_s; // Timeout in seconds + timeout.tv_usec = 0; // Microseconds + setsockopt(m_can_socket_fd, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&timeout), + sizeof(struct timeval)); + + if (bind(m_can_socket_fd, reinterpret_cast(&addr), sizeof(addr)) < 0) { + throw exceptions::CanInitException("Error binding socket"); + } +} + +void CanDriver::uninitializeCan() const { + std::cout << "Closing socket\n"; + if (close(m_can_socket_fd) < 0) { + throw exceptions::CanCloseException("Error closing socket"); + } +} + +auto CanDriver::readMessage(void *buffer) const -> int32_t { + return static_cast(read(m_can_socket_fd, buffer, sizeof(struct can_frame))); } } // namespace candriver \ No newline at end of file diff --git a/com-middleware/can/CanDriver.hpp b/com-middleware/can/CanDriver.hpp index 7bfb2e0d..a4931314 100644 --- a/com-middleware/can/CanDriver.hpp +++ b/com-middleware/can/CanDriver.hpp @@ -8,11 +8,14 @@ namespace candriver { class CanDriver { private: std::string m_canInterface; - int32_t m_timeout; + int32_t m_timeout_s; + int32_t m_can_socket_fd{}; public: - CanDriver(std::string can_interface, int32_t timeout); + CanDriver(std::string can_interface, int32_t timeout_s); + virtual ~CanDriver() noexcept(false) { uninitializeCan(); } + private: /** * @brief Initializes CAN socket * @@ -22,6 +25,10 @@ class CanDriver { * @throws CanInitException if it fails to initialize */ void initializeCan(); + void uninitializeCan() const; + + public: + auto readMessage(void* buffer) const -> int32_t; }; } // namespace candriver diff --git a/com-middleware/exceptions/CanCloseException.hpp b/com-middleware/exceptions/CanCloseException.hpp new file mode 100644 index 00000000..432d5b8a --- /dev/null +++ b/com-middleware/exceptions/CanCloseException.hpp @@ -0,0 +1,28 @@ +#ifndef CAN_DRIVER_EXCEPTIONS_CANCLOSEEXCEPTION_HPP +#define CAN_DRIVER_EXCEPTIONS_CANCLOSEEXCEPTION_HPP + +#include +#include +#include + +namespace candriver::exceptions { + +using std::exception; +using std::string; + +/** + * @brief An exception that may be thrown when an error occurred while closing a CAN socket. + */ +class CanCloseException : public exception { + public: // +++ Constructor / Destructor +++ + explicit CanCloseException(string message) : _message(std::move(message)) {} + virtual ~CanCloseException() {} + [[nodiscard]] auto what() const noexcept -> const char* override { return _message.c_str(); } + + private: + string _message; +}; + +} // namespace candriver::exceptions + +#endif // CAN_DRIVER_EXCEPTIONS_CANCLOSEEXCEPTION_HPP \ No newline at end of file diff --git a/com-middleware/main.cpp b/com-middleware/main.cpp index aee6748a..2c8dfe7a 100644 --- a/com-middleware/main.cpp +++ b/com-middleware/main.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -35,15 +36,6 @@ auto main(int argc, char **argv) -> int { int opt{}; std::string interface = "can0"; - try { - candriver::CanDriver can{interface, 1}; - can.initializeCan(); - } catch (const std::exception &myCustomException) { - std::cout << myCustomException.what() << std::endl; - } - - return 0; - while ((opt = getopt(argc, argv, "i:")) != -1) { // "i:" means -i takes an argument switch (opt) { case 'i': @@ -57,45 +49,16 @@ auto main(int argc, char **argv) -> int { } } - int can_socket{}; - int numBytes{}; - struct sockaddr_can addr {}; - struct ifreq ifr {}; // interface - struct can_frame frame {}; // Classical can frame - - std::cout << "CAN Sockets Receive Demo\r\n"; - - // opening a socket for communicating over a CAN network - // Since SocketCAN implements a new protocol family, we pass PF_CAN as the first argument to the - // socket(2) system call there are two CAN protocols to choose from, the raw socket protocol - // (SOCK_RAW) and the broadcast manager (CAN_BCM) - can_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW); - if (can_socket < 0) { - perror("Error connecting to Socket"); - return 1; - } - - // Setting the can interface - strcpy(ifr.ifr_name, interface.c_str()); - // To determine the interface index an appropriate ioctl() has to be used (0 for all) - ioctl(can_socket, SIOCGIFINDEX, &ifr); - - memset(&addr, 0, sizeof(addr)); - addr.can_family = AF_CAN; - addr.can_ifindex = ifr.ifr_ifindex; - - // Timeout for read blocking - struct timeval timeout {}; - timeout.tv_sec = 5; // Timeout in seconds - timeout.tv_usec = 0; // Microseconds - setsockopt(can_socket, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&timeout), - sizeof(struct timeval)); - - if (bind(can_socket, reinterpret_cast(&addr), sizeof(addr)) < 0) { - perror("Error Binding"); + std::unique_ptr can; + try { + can = std::make_unique(interface, 5); + } catch (const std::exception &myCustomException) { + std::cout << myCustomException.what() << std::endl; return 1; } + struct can_frame frame {}; // Classical can frame + int32_t numBytes{}; // Connect to zmq zmq::context_t ctx(1); zmq::socket_t publisher(ctx, zmq::socket_type::pub); @@ -103,7 +66,7 @@ auto main(int argc, char **argv) -> int { catch_signals(); while (true) { - numBytes = static_cast(read(can_socket, &frame, sizeof(struct can_frame))); + numBytes = can->readMessage(&frame); if (numBytes < 0) { if (errno == EINTR) { @@ -147,11 +110,5 @@ auto main(int argc, char **argv) -> int { std::cout << "Closing context\n"; ctx.close(); - std::cout << "Closing socket\n"; - if (close(can_socket) < 0) { - perror("Error closing can socket"); - return 1; - } - return 0; }