Skip to content

Commit

Permalink
feat: moving logic to CanDriver class
Browse files Browse the repository at this point in the history
  • Loading branch information
Rui Rocha authored and rui-rocha-42 committed Jan 27, 2025
1 parent 91bd04a commit 129838a
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 56 deletions.
58 changes: 56 additions & 2 deletions com-middleware/can/CanDriver.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,69 @@
#include "CanDriver.hpp"

#include <linux/can.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>

#include <cstring>
#include <iostream>

#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<const char *>(&timeout),
sizeof(struct timeval));

if (bind(m_can_socket_fd, reinterpret_cast<struct sockaddr *>(&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<int32_t>(read(m_can_socket_fd, buffer, sizeof(struct can_frame)));
}
} // namespace candriver
11 changes: 9 additions & 2 deletions com-middleware/can/CanDriver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -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

Expand Down
28 changes: 28 additions & 0 deletions com-middleware/exceptions/CanCloseException.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef CAN_DRIVER_EXCEPTIONS_CANCLOSEEXCEPTION_HPP
#define CAN_DRIVER_EXCEPTIONS_CANCLOSEEXCEPTION_HPP

#include <exception>
#include <string>
#include <utility>

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
61 changes: 9 additions & 52 deletions com-middleware/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <cstdio>
#include <cstring>
#include <iostream>
#include <memory>
#include <string>
#include <zmq.hpp>

Expand All @@ -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':
Expand All @@ -57,53 +49,24 @@ 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<const char *>(&timeout),
sizeof(struct timeval));

if (bind(can_socket, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)) < 0) {
perror("Error Binding");
std::unique_ptr<candriver::CanDriver> can;
try {
can = std::make_unique<candriver::CanDriver>(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);
publisher.bind("ipc:///tmp/speed.ipc");

catch_signals();
while (true) {
numBytes = static_cast<int>(read(can_socket, &frame, sizeof(struct can_frame)));
numBytes = can->readMessage(&frame);

if (numBytes < 0) {
if (errno == EINTR) {
Expand Down Expand Up @@ -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;
}

0 comments on commit 129838a

Please sign in to comment.