Browse Source

remove socketcan

disinfection_machine
zhaohe 2 years ago
parent
commit
3f179aa396
  1. 300
      core/driver/sockcanpp/CanDriver.cpp
  2. 154
      core/driver/sockcanpp/CanDriver.hpp
  3. 247
      core/driver/sockcanpp/CanId.hpp
  4. 88
      core/driver/sockcanpp/CanMessage.hpp
  5. 130
      core/driver/sockcanpp/README.md
  6. 57
      core/driver/sockcanpp/exceptions/CanCloseException.hpp
  7. 62
      core/driver/sockcanpp/exceptions/CanException.hpp
  8. 57
      core/driver/sockcanpp/exceptions/CanInitException.hpp
  9. 62
      core/driver/sockcanpp/exceptions/InvalidSocketException.hpp
  10. 0
      core/driver/socketcan/socketcan.cpp
  11. 0
      core/driver/socketcan/socketcan.hpp
  12. 0
      core/driver/socketcan/socketcan_frame.hpp

300
core/driver/sockcanpp/CanDriver.cpp

@ -1,300 +0,0 @@
/**
* @file CanDriver.cpp
* @author Simon Cahill (simonc@online.de)
* @brief
* @version 0.1
* @date 2020-07-01
*
* @copyright Copyright (c) 2020 Simon Cahill
*
*
* Copyright 2020 Simon Cahill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//////////////////////////////
// SYSTEM INCLUDES //
//////////////////////////////
#include <fcntl.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
//////////////////////////////
// LOCAL INCLUDES //
//////////////////////////////
#include "CanDriver.hpp"
#include "CanId.hpp"
#include "CanMessage.hpp"
#include "exceptions/CanCloseException.hpp"
#include "exceptions/CanException.hpp"
#include "exceptions/CanInitException.hpp"
#include "exceptions/InvalidSocketException.hpp"
namespace sockcanpp {
using exceptions::CanCloseException;
using exceptions::CanException;
using exceptions::CanInitException;
using exceptions::InvalidSocketException;
using std::mutex;
using std::queue;
using std::string;
using std::strncpy;
using std::unique_lock;
using std::chrono::milliseconds;
using std::this_thread::sleep_for;
//////////////////////////////////////
// PUBLIC IMPLEMENTATION //
//////////////////////////////////////
const int32_t CanDriver::CAN_MAX_DATA_LENGTH = 8;
const int32_t CanDriver::CAN_SOCK_RAW = CAN_RAW;
const int32_t CanDriver::CAN_SOCK_SEVEN = 7;
CanDriver::CanDriver(string canInterface, int32_t canProtocol, const CanId defaultSenderId)
: CanDriver(canInterface, canProtocol, 0 /* match all */, defaultSenderId) {}
CanDriver::CanDriver(const string canInterface, const int32_t canProtocol, const int32_t filterMask, const CanId defaultSenderId)
: _defaultSenderId(defaultSenderId), _canProtocol(canProtocol), _canInterface(canInterface), _canFilterMask(filterMask), _socketFd(-1) {
initialiseSocketCan();
}
/**
* @brief Blocks until one or more CAN messages appear on the bus, or until the
* timeout runs out.
*
* @param timeout The time (in millis) to wait before timing out.
*
* @return true If messages are available on the bus.
* @return false Otherwise.
*/
bool CanDriver::waitForMessages(milliseconds timeout) {
if (_socketFd < 0) {
throw InvalidSocketException("Invalid socket!", _socketFd);
}
unique_lock<mutex> locky(_lock);
fd_set readFileDescriptors;
timeval waitTime;
waitTime.tv_sec = timeout.count() / 1000;
waitTime.tv_usec = timeout.count() * 1000;
FD_ZERO(&readFileDescriptors);
FD_SET(_socketFd, &readFileDescriptors);
_queueSize = select(_socketFd + 1, &readFileDescriptors, 0, 0, &waitTime);
return _queueSize > 0;
}
/**
* @brief Attempts to read a message from the associated CAN bus.
*
* @return CanMessage The message read from the bus.
*/
CanMessage CanDriver::readMessage() { return readMessageLock(); }
/**
* @brief readMessage deadlock guard, attempts to read a message from the
* associated CAN bus.
*
* @return CanMessage The message read from the bus.
*/
CanMessage CanDriver::readMessageLock(bool const lock) {
std::unique_ptr<std::unique_lock<std::mutex>> _lockLck{nullptr};
if (lock) _lockLck = std::unique_ptr<std::unique_lock<std::mutex>>{new std::unique_lock<std::mutex>{_lock}};
if (0 > _socketFd) throw InvalidSocketException("Invalid socket!", _socketFd);
int32_t readBytes{0};
can_frame canFrame;
memset(&canFrame, 0, sizeof(can_frame));
readBytes = read(_socketFd, &canFrame, sizeof(can_frame));
if (0 > readBytes) throw CanException(formatString("FAILED to read from CAN! Error: %d => %s", errno, strerror(errno)), _socketFd);
return CanMessage{canFrame};
}
/**
* @brief Attempts to send a CAN message on the associated bus.
*
* @param message The message to be sent.
* @param forceExtended Whether or not to force use of an extended ID.
*
* @return int32_t The amount of bytes sent on the bus.
*/
int32_t CanDriver::sendMessage(const CanMessage message, bool forceExtended) {
if (_socketFd < 0) {
throw InvalidSocketException("Invalid socket!", _socketFd);
}
unique_lock<mutex> locky(_lock);
int32_t bytesWritten = 0;
if (message.getFrameData().size() > CAN_MAX_DATA_LENGTH) {
throw CanException(formatString("INVALID data length! Message must be smaller than %d bytes!", CAN_MAX_DATA_LENGTH), _socketFd);
}
auto canFrame = message.getRawFrame();
if (forceExtended || (message.getCanId() > CAN_SFF_MASK)) {
canFrame.can_id |= CAN_EFF_FLAG;
}
bytesWritten = write(_socketFd, (const void *)&canFrame, sizeof(canFrame));
if (bytesWritten == -1) {
throw CanException(formatString("FAILED to write data to socket! Error: %d => %s", errno, strerror(errno)), _socketFd);
}
return bytesWritten;
}
/**
* @brief Attempts to send a queue of messages on the associated CAN bus.
*
* @param messages A queue containing the messages to be sent.
* @param delay If greater than 0, will delay the sending of the next message.
* @param forceExtended Whether or not to force use of an extended ID.
*
* @return int32_t The total amount of bytes sent.
*/
int32_t CanDriver::sendMessageQueue(queue<CanMessage> messages, milliseconds delay, bool forceExtended) {
if (_socketFd < 0) {
throw InvalidSocketException("Invalid socket!", _socketFd);
}
int32_t totalBytesWritten = 0;
while (!messages.empty()) {
totalBytesWritten += sendMessage(messages.front(), forceExtended);
messages.pop();
}
return totalBytesWritten;
}
/**
* @brief Attempts to read all messages stored in the buffer for the associated
* CAN bus.
*
* @return queue<CanMessage> A queue containing the messages read from the bus
* buffer.
*/
queue<CanMessage> CanDriver::readQueuedMessages() {
if (_socketFd < 0) throw InvalidSocketException("Invalid socket!", _socketFd);
unique_lock<mutex> locky(_lock);
queue<CanMessage> messages;
for (int32_t i = _queueSize; 0 < i; --i) messages.emplace(readMessageLock(false));
return messages;
}
/**
* @brief Attempts to set the filter mask for the associated CAN bus.
*
* @param mask The bit mask to apply.
*/
void CanDriver::setCanFilterMask(const int32_t mask) {
if (_socketFd < 0) {
throw InvalidSocketException("Invalid socket!", _socketFd);
}
unique_lock<mutex> locky(_lock);
can_filter canFilter;
canFilter.can_id = _defaultSenderId;
canFilter.can_mask = mask;
if (setsockopt(_socketFd, SOL_CAN_RAW, CAN_RAW_FILTER, &canFilter, sizeof(canFilter)) == -1) {
throw CanInitException(formatString("FAILED to set CAN filter mask %x on socket %d! Error: %d => %s", mask, _socketFd, errno, strerror(errno)));
}
_canFilterMask = mask;
}
//////////////////////////////////////
// PROTECTED IMPLEMENTATION //
//////////////////////////////////////
/**
* @brief Initialises the underlying CAN socket.
*/
void CanDriver::initialiseSocketCan() {
// unique_lock<mutex> locky(_lock);
struct sockaddr_can address;
struct ifreq ifaceRequest;
int64_t fdOptions = 0;
int32_t tmpReturn;
memset(&address, 0, sizeof(sizeof(struct sockaddr_can)));
memset(&ifaceRequest, 0, sizeof(sizeof(struct ifreq)));
_socketFd = socket(PF_CAN, SOCK_RAW, _canProtocol);
if (_socketFd == -1) {
throw CanInitException(formatString("FAILED to initialise socketcan! Error: %d => %s", errno, strerror(errno)));
}
strcpy(ifaceRequest.ifr_name, _canInterface.c_str());
if ((tmpReturn = ioctl(_socketFd, SIOCGIFINDEX, &ifaceRequest)) == -1) {
throw CanInitException(formatString("FAILED to perform IO control operation on socket %s! Error: %d => %s", _canInterface.c_str(), errno, strerror(errno)));
}
fdOptions = fcntl(_socketFd, F_GETFL);
fdOptions |= O_NONBLOCK;
tmpReturn = fcntl(_socketFd, F_SETFL, fdOptions);
address.can_family = AF_CAN;
address.can_ifindex = ifaceRequest.ifr_ifindex;
setCanFilterMask(_canFilterMask);
if ((tmpReturn = bind(_socketFd, (struct sockaddr *)&address, sizeof(address))) == -1) {
throw CanInitException(formatString("FAILED to bind to socket CAN! Error: %d => %s", errno, strerror(errno)));
}
}
/**
* @brief Closes the underlying CAN socket.
*/
void CanDriver::uninitialiseSocketCan() {
unique_lock<mutex> locky(_lock);
if (_socketFd <= 0) {
throw CanCloseException("Cannot close invalid socket!");
}
if (close(_socketFd) == -1) {
throw CanCloseException(formatString("FAILED to close CAN socket! Error: %d => %s", errno, strerror(errno)));
}
_socketFd = -1;
}
} // namespace sockcanpp

154
core/driver/sockcanpp/CanDriver.hpp

@ -1,154 +0,0 @@
/**
* @file CanDriver.hpp
* @author Simon Cahill (simonc@online.de)
* @brief Contains the declarations for the SocketCAN wrapper in C++.
* @version 0.1
* @date 2020-07-01
*
* @copyright Copyright (c) 2020
*
* Copyright 2020 Simon Cahill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIBSOCKCANPP_INCLUDE_CANDRIVER_HPP
#define LIBSOCKCANPP_INCLUDE_CANDRIVER_HPP
//////////////////////////////
// SYSTEM INCLUDES //
//////////////////////////////
#include <mutex>
#include <queue>
#include <string>
#include <thread>
//////////////////////////////
// LOCAL INCLUDES //
//////////////////////////////
#include "CanId.hpp"
#include "CanMessage.hpp"
/**
* @brief Main library namespace.
*
* This namespace contains the library's main code.
*/
namespace sockcanpp {
using std::mutex;
using std::queue;
using std::string;
using std::chrono::milliseconds;
/**
* @brief CanDriver class; handles communication via CAN.
*
* This class provides the means of easily communicating with other devices via
* CAN in C++.
*
* @remarks
* This class may be inherited by other applications and modified to suit your
* needs.
*/
class CanDriver {
public: // +++ Static +++
static const int32_t CAN_MAX_DATA_LENGTH; ///!< The maximum amount of bytes
/// allowed in a single CAN frame
static const int32_t CAN_SOCK_RAW; ///!< The raw CAN protocol
static const int32_t CAN_SOCK_SEVEN; ///!< A separate CAN protocol, used by
/// certain embedded device OEMs.
public: // +++ Constructor / Destructor +++
CanDriver(const string canInterface, const int32_t canProtocol,
const CanId defaultSenderId = 0); ///!< Constructor
CanDriver(const string canInterface, const int32_t canProtocol, const int32_t filterMask, const CanId defaultSenderId = 0);
CanDriver() {}
virtual ~CanDriver() { uninitialiseSocketCan(); } ///!< Destructor
public: // +++ Getter / Setter +++
CanDriver &setDefaultSenderId(const CanId id) {
this->_defaultSenderId = id;
return *this;
} ///!< Sets the default sender ID
const CanId getDefaultSenderId() const { return this->_defaultSenderId; } ///!< Gets the default sender ID
const int32_t getFilterMask() const { return this->_canFilterMask; } ///!< Gets the filter mask used by this instance
const int32_t getMessageQueueSize() const {
return this->_queueSize;
} ///!< Gets the amount of CAN messages found after last calling
/// waitForMessages()
const int32_t getSocketFd() const { return this->_socketFd; } ///!< The socket file descriptor used by this instance.
public: // +++ I/O +++
virtual bool waitForMessages(milliseconds timeout = milliseconds(3000)); ///!< Waits for CAN messages to appear
virtual CanMessage readMessage(); ///!< Attempts to read a single message from the bus
virtual int32_t sendMessage(const CanMessage message,
bool forceExtended = false); ///!< Attempts to send a single CAN message
virtual int32_t sendMessageQueue(queue<CanMessage> messages, milliseconds delay = milliseconds(20),
bool forceExtended = false); ///!< Attempts to send a queue of messages
virtual queue<CanMessage> readQueuedMessages(); ///!< Attempts to read all queued messages from the bus
virtual void setCanFilterMask(const int32_t mask); ///!< Attempts to set a new CAN filter
/// mask to the BIOS
protected: // +++ Socket Management +++
virtual void initialiseSocketCan(); ///!< Initialises socketcan
virtual void uninitialiseSocketCan(); ///!< Uninitialises socketcan
private:
virtual CanMessage readMessageLock(bool const lock = true); ///!< readMessage deadlock guard
CanId _defaultSenderId; ///!< The ID to send messages with if no other ID was
/// set.
int32_t _canFilterMask; ///!< The bit mask used to filter CAN messages
int32_t _canProtocol; ///!< The protocol used when communicating via CAN
int32_t _socketFd; ///!< The CAN socket file descriptor
int32_t _queueSize; ////!< The size of the message queue read by waitForMessages()
mutex _lock; ///!< Mutex for thread-safety.
string _canInterface; ///!< The CAN interface used for communication (e.g.
/// can0, can1, ...)
};
/**
* @brief Formats a std string object.
*
* @remarks Yoinked from https://github.com/Beatsleigher/liblogpp :)
*
* @tparam Args The formatting argument types.
* @param format The format string.
* @param args The format arguments (strings must be converted to C-style
* strings!)
*
* @return string The formatted string.
*/
template <typename... Args>
string formatString(const string &format, Args... args) {
using std::unique_ptr;
auto stringSize = snprintf(NULL, 0, format.c_str(), args...) + 1; // +1 for \0
unique_ptr<char[]> buffer(new char[stringSize]);
snprintf(buffer.get(), stringSize, format.c_str(), args...);
return string(buffer.get(), buffer.get() + stringSize - 1); // std::string handles termination for us.
}
} // namespace sockcanpp
#endif // LIBSOCKCANPP_INCLUDE_CANDRIVER_HPP

247
core/driver/sockcanpp/CanId.hpp

@ -1,247 +0,0 @@
/**
* @file CanId.hpp
* @author Simon Cahill (simonc@online.de)
* @brief Contains the implementation of a value-type representing a CAN
* identifier.
* @version 0.1
* @date 2020-07-01
*
* @copyright Copyright (c) 2020 Simon Cahill
*
* Copyright 2020 Simon Cahill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIBSOCKPP_INCLUDE_CANID_HPP
#define LIBSOCKPP_INCLUDE_CANID_HPP
//////////////////////////////
// SYSTEM INCLUDES //
//////////////////////////////
#include <linux/can.h>
#include <bitset>
#include <cmath>
#include <exception>
namespace sockcanpp {
using std::bitset;
using std::error_code;
using std::exception;
using std::generic_category;
using std::system_error;
/**
* @brief Represents a CAN ID in a simple and easy-to-use manner.
*/
struct CanId {
public: // +++ Constructors +++
CanId(const CanId &orig)
: _identifier(orig._identifier),
_isErrorFrame(orig._isErrorFrame),
_isRemoteTransmissionRequest(orig._isRemoteTransmissionRequest),
_isStandardFrameId(orig._isStandardFrameId),
_isExtendedFrameId(orig._isExtendedFrameId) { /* copy */
}
CanId(const uint32_t identifier) : _identifier(identifier) {
// TODO: Switch to using bitmasks!
if (isValidIdentifier(identifier)) {
if (((int32_t)log2(identifier) + 1) < 11) {
_isStandardFrameId = true;
} else {
_isExtendedFrameId = true;
}
} else if (isErrorFrame(identifier)) {
_isErrorFrame = true;
} else if (isRemoteTransmissionRequest(identifier)) {
_isRemoteTransmissionRequest = true;
}
}
CanId() : _identifier(0), _isStandardFrameId(true) {}
public: // +++ Operators +++
operator int16_t() const {
return isStandardFrameId() ? (int16_t)_identifier : throw system_error(error_code(0xbad1d, generic_category()), "INVALID CAST: ID is extended or invalid!");
}
operator uint16_t() const {
return isStandardFrameId() ? (uint16_t)_identifier
: throw system_error(error_code(0xbad1d, generic_category()), "INVALID CAST: ID is extended or invalid!");
}
operator int32_t() const { return _identifier; }
operator uint32_t() const { return _identifier; }
CanId operator&(CanId &x) const { return _identifier & x._identifier; }
CanId operator&(const CanId x) const { return _identifier & x._identifier; }
CanId operator&(const int16_t x) const { return _identifier & x; }
CanId operator&(const uint16_t x) const { return _identifier & x; }
CanId operator&(const int32_t x) const { return _identifier & x; }
CanId operator&(const uint32_t x) const { return _identifier & x; }
CanId operator&(const int64_t x) const { return _identifier & x; }
CanId operator&(const uint64_t x) const { return _identifier & x; }
CanId operator|(CanId &x) const { return _identifier | x._identifier; }
CanId operator|(const CanId x) const { return _identifier | x._identifier; }
CanId operator|(const int16_t x) const { return _identifier | x; }
CanId operator|(const uint16_t x) const { return _identifier | x; }
CanId operator|(const int32_t x) const { return _identifier | x; }
CanId operator|(const uint32_t x) const { return _identifier | x; }
CanId operator|(const int64_t x) const { return _identifier | x; }
CanId operator|(const uint64_t x) const { return _identifier | x; }
bool operator==(CanId &x) const { return _identifier == x._identifier; }
bool operator==(const CanId &x) const { return _identifier == x._identifier; }
bool operator==(const int16_t x) const { return int16_t(_identifier) == x; }
bool operator==(const uint16_t x) const { return uint16_t(_identifier) == x; }
bool operator==(const int32_t x) const { return int32_t(_identifier) == x; }
bool operator==(const uint32_t x) const { return uint32_t(_identifier) == x; }
bool operator==(const int64_t x) const { return (x > UINT32_MAX || x < INT32_MIN) ? false : x == int64_t(_identifier); }
bool operator==(const uint64_t x) const { return x > UINT32_MAX ? false : x == uint64_t(_identifier); }
bool operator!=(CanId &x) const { return _identifier != x._identifier; }
bool operator!=(const CanId &x) const { return _identifier != x._identifier; }
bool operator!=(const int16_t x) const { return int16_t(_identifier) != x; }
bool operator!=(const uint16_t x) const { return uint16_t(_identifier) != x; }
bool operator!=(const int32_t x) const { return int32_t(_identifier) != x; }
bool operator!=(const uint32_t x) const { return uint32_t(_identifier) != x; }
bool operator!=(const int64_t x) const { return (x > UINT32_MAX || x < INT32_MIN) ? false : x != _identifier; }
bool operator!=(const uint64_t x) const { return x > UINT32_MAX ? false : x != _identifier; }
bool operator<(CanId &x) const { return x._identifier < _identifier; }
bool operator<(int32_t x) const { return x < int32_t(_identifier); }
bool operator<(uint32_t x) const { return x < uint32_t(_identifier); }
bool operator<(int16_t x) const { return x < int16_t(_identifier); }
bool operator<(uint16_t x) const { return x < uint16_t(_identifier); }
bool operator<=(CanId &x) const { return x._identifier <= _identifier; }
bool operator>(CanId &x) const { return x._identifier > _identifier; }
bool operator>(int32_t x) const { return x > int32_t(_identifier); }
bool operator>(uint32_t x) const { return x > uint32_t(_identifier); }
bool operator>(int16_t x) const { return x > int16_t(_identifier); }
bool operator>(uint16_t x) const { return x > uint16_t(_identifier); }
bool operator>=(CanId &x) const { return x._identifier >= _identifier; }
bool operator<(const CanId &x) const { return x._identifier < _identifier; }
bool operator<=(const CanId &x) const { return x._identifier <= _identifier; }
bool operator>(const CanId &x) const { return x._identifier > _identifier; }
bool operator>=(const CanId &x) const { return x._identifier >= _identifier; }
CanId operator=(const int32_t val) {
uint32_t tmpVal = val;
auto tmp =
(isValidIdentifier(tmpVal) ? CanId(val) : throw system_error(error_code(0x5421, generic_category()), "INVALID CAST: ID is extended or invalid!"));
return tmp;
}
CanId operator=(const uint32_t val) {
uint32_t tmp = val;
return (isValidIdentifier(tmp) ? CanId(val) : throw system_error(error_code(0x5421, generic_category()), "INVALID CAST: ID is extended or invalid!"));
}
CanId operator=(const int64_t val) { return operator=((int32_t)val); }
CanId operator+(CanId &x) const { return _identifier + x._identifier; }
CanId operator+(const CanId &x) const { return _identifier + x._identifier; }
CanId operator+(const int16_t x) const { return _identifier + x; }
CanId operator+(const uint16_t x) const { return _identifier + x; }
CanId operator+(const int32_t x) const { return _identifier + x; }
CanId operator+(const uint32_t x) const { return _identifier + x; }
CanId operator+(const int64_t x) const { return _identifier + x; }
CanId operator+(const uint64_t x) const { return _identifier + x; }
CanId operator-(CanId &x) const { return _identifier - x._identifier; }
CanId operator-(const CanId &x) const { return _identifier - x._identifier; }
CanId operator-(const int16_t x) const { return _identifier - x; }
CanId operator-(const uint16_t x) const { return _identifier - x; }
CanId operator-(const int32_t x) const { return _identifier - x; }
CanId operator-(const uint32_t x) const { return _identifier - x; }
CanId operator-(const int64_t x) const { return _identifier - x; }
CanId operator-(const uint64_t x) const { return _identifier - x; }
public: // +++ Validity Checks +++
/**
* @brief Indicates whether or not a given integer is a valid CAN identifier.
*
* @param value The integer to check.
*
* @return true If value is a valid CAN identifier.
* @return false Otherwise.
*/
static bool isValidIdentifier(uint32_t value) {
int32_t tmpValue = ((int32_t)log2(value) + 2); // Get bit count
// Check for extended frame flag
if (tmpValue >= 29) {
value = (value & CAN_EFF_FLAG) ? (value & CAN_EFF_MASK) : (value & CAN_SFF_MASK);
tmpValue = ((int32_t)log2(value) + 1); // Get bit count again
}
return (value == 0) /* Default value, also valid ID */ || ((tmpValue <= 29 && tmpValue > 0));
}
/**
* @brief Indicates whether or not a given integer contains the error frame
* flag or not.
*
* @param value The integer to check.
*
* @return true If value has the error frame flag (bit) set to 1.
* @return false Otherwise.
*/
static bool isErrorFrame(uint32_t value) {
try {
return bitset<sizeof(int32_t)>(value).test(29);
} catch (...) {
return false; /* Brute-force, but works. */
}
}
/**
* @brief Indicates whether the received frame is a remote transmission
* request.
*
* @param value The integer to check.
*
* @return true If the frame is a remote transmission request.
* @return false Otherwise.
*/
static bool isRemoteTransmissionRequest(uint32_t value) {
try {
return bitset<sizeof(int32_t)>(value).test(30);
} catch (...) {
return false; /* Brute-force, but works. */
}
}
public: // +++ Getters +++
bool hasErrorFrameFlag() const { return _isErrorFrame; }
bool hasRtrFrameFlag() const { return _isRemoteTransmissionRequest; }
bool isStandardFrameId() const { return _isStandardFrameId; }
bool isExtendedFrameId() const { return _isExtendedFrameId; }
public: // +++ Equality Checks +++
bool equals(CanId otherId) const { return *this == otherId; }
private: // +++ Variables +++
bool _isErrorFrame = false;
bool _isRemoteTransmissionRequest = false;
bool _isStandardFrameId = false;
bool _isExtendedFrameId = false;
uint32_t _identifier = 0;
};
} // namespace sockcanpp
#endif // LIBSOCKPP_INCLUDE_CANID_HPP

88
core/driver/sockcanpp/CanMessage.hpp

@ -1,88 +0,0 @@
/**
* @file CanMessage.hpp
* @author Simon Cahill (simonc@online.de)
* @brief Contains the implementation of a CAN message representation in C++.
* @version 0.1
* @date 2020-07-01
*
* @copyright Copyright (c) 2020 Simon Cahill
*
* Copyright 2020 Simon Cahill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIBSOCKCANPP_INCLUDE_CANMESSAGE_HPP
#define LIBSOCKCANPP_INCLUDE_CANMESSAGE_HPP
//////////////////////////////
// SYSTEM INCLUDES //
//////////////////////////////
#include <linux/can.h>
#include <cstring>
#include <exception>
#include <string>
#include <thread>
//////////////////////////////
// LOCAL INCLUDES //
//////////////////////////////
#include "CanId.hpp"
namespace sockcanpp {
using std::error_code;
using std::generic_category;
using std::memcpy;
using std::string;
using std::system_error;
/**
* @brief Represents a CAN message that was received.
*/
class CanMessage {
public: // +++ Constructor / Destructor +++
CanMessage(const struct can_frame frame) : _canIdentifier(frame.can_id), _frameData((const char *)frame.data, frame.can_dlc), _rawFrame(frame) {}
CanMessage(const CanId canId, const string frameData) : _canIdentifier(canId), _frameData(frameData) {
if (frameData.size() > 8) {
throw system_error(error_code(0xbadd1c, generic_category()), "Payload too big!");
}
struct can_frame rawFrame;
rawFrame.can_id = canId;
memcpy(rawFrame.data, frameData.data(), frameData.size());
rawFrame.can_dlc = frameData.size();
_rawFrame = rawFrame;
}
virtual ~CanMessage() {}
public: // +++ Getters +++
const CanId getCanId() const { return this->_canIdentifier; }
const string getFrameData() const { return this->_frameData; }
const can_frame getRawFrame() const { return this->_rawFrame; }
private:
CanId _canIdentifier;
string _frameData;
struct can_frame _rawFrame;
};
} // namespace sockcanpp
#endif // LIBSOCKCANPP_INCLUDE_CANMESSAGE_HPP

130
core/driver/sockcanpp/README.md

@ -1,130 +0,0 @@
```
BaseOn:
https://github.com/SimonCahill/libsockcanpp
4d0e6a3e679a34dee4449a9d22b7f794a3cf9871
localGit
http://192.168.1.3:3000/z3rd_lib/libsockcanpp
Demo:
http://192.168.1.3:3000/z3rd_lib/libsockcanpp/src/branch/master/test/src/Main.cpp
```
# Usage
```cpp
/**
* @file Main.cpp
* @author Simon Cahill (simonc@online.de)
* @brief Contains the implementation of a test application using this library.
* @version 0.1
* @date 2020-07-02
*
* @copyright Copyright (c) 2020 Simon Cahill
*
* Copyright 2020 Simon Cahill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <iostream>
#include <string>
#include <CanDriver.hpp>
#include <exceptions/CanException.hpp>
#include <exceptions/CanInitException.hpp>
#include <exceptions/InvalidSocketException.hpp>
using sockcanpp::CanDriver;
using sockcanpp::CanId;
using sockcanpp::exceptions::CanException;
using sockcanpp::exceptions::CanInitException;
using sockcanpp::exceptions::InvalidSocketException;
using sockcanpp::CanMessage;
using std::cerr;
using std::cout;
using std::endl;
using std::string;
void printHelp(string);
int main(int32_t argCount, char** argValues) {
int32_t desiredCanSocket = 0;
string canInterface;
if (argCount > 2) {
for (int32_t i = 1; i < argCount; i++) {
if (argValues[i] == "--help" || argValues[i] == "-h") {
printHelp(argValues[0]);
return 0;
} else if (argValues[i] == "-protocol") {
desiredCanSocket = atoi(argValues[i + 1]);
i += 1;
continue;
} else if (argValues[i] == "-iface") {
canInterface = (argValues[i + 1]);
i += 1;
continue;
}
}
}
if (desiredCanSocket <= 0)
desiredCanSocket = CanDriver::CAN_SOCK_RAW;
if (canInterface == "")
canInterface = "can0";
CanDriver* canDriver;
try {
canDriver = new CanDriver(canInterface, CAN_RAW);
} catch (CanInitException& ex) {
cerr << "An error occurred while initialising CanDriver: " << ex.what() << endl;
delete canDriver;
return -1;
}
while (true) {
printf("Writing test message:\n");
try { canDriver->sendMessage(CanMessage(0x555, "abcdefg8")); }
catch (CanException& ex) { cerr << "Failed to send test message! " << ex.what() << endl; }
catch (InvalidSocketException& ex) { cerr << "Failed to send test message! " << ex.what() << endl; }
printf("Reading messages\n");
if (!canDriver->waitForMessages()) continue;
cout << "Reading queue..." << endl;
auto canMessages = canDriver->readQueuedMessages();
while (!canMessages.empty()) {
auto msg = canMessages.front();
canMessages.pop();
cout << "CAN ID: " << (int32_t)msg.getCanId() << endl
<< "CAN data: ";
for (auto byte : msg.getFrameData())
cout << std::hex << byte << " ";
cout << endl;
}
}
}
void printHelp(string appname) {
cout << appname << endl << endl
<< "-h\t\tPrints this menu" << endl
<< "--help\t\tPrints this menu" << endl
<< "-protocol <protocol_num>" << endl
<< "-iface <can_iface>" << endl;
}
```

57
core/driver/sockcanpp/exceptions/CanCloseException.hpp

@ -1,57 +0,0 @@
/**
* @file CanCloseException.hpp
* @author Simon Cahill (simonc@online.de)
* @brief Contains the implementation of an exception that may be thrown when an
* error occurs while closing a CAN socket.
* @version 0.1
* @date 2020-07-02
*
* @copyright Copyright (c) 2020 Simon Cahill
*
* Copyright 2020 Simon Cahill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIBSOCKCANPP_INCLUDE_EXCEPTIONS_CANCLOSEEXCEPTION_HPP
#define LIBSOCKCANPP_INCLUDE_EXCEPTIONS_CANCLOSEEXCEPTION_HPP
#include <exception>
#include <string>
namespace sockcanpp {
namespace exceptions {
using std::exception;
using std::string;
/**
* @brief An exception that may be thrown when an error occurs while closing a
* CAN socket.
*/
class CanCloseException : public exception {
public: // +++ Constructor / Destructor +++
CanCloseException(string message) : _message(message) {}
~CanCloseException() {}
public: // +++ Overrides +++
const char *what() { return _message.c_str(); }
private:
string _message;
};
} // namespace exceptions
} // namespace sockcanpp
#endif // LIBSOCKCANPP_INCLUDE_EXCEPTIONS_CANCLOSEEXCEPTION_HPP

62
core/driver/sockcanpp/exceptions/CanException.hpp

@ -1,62 +0,0 @@
/**
* @file CanException.hpp
* @author Simon Cahill (simonc@online.de)
* @brief Contains the implementation of a general-purpose exception which may
* be thrown when an error occurs when performing IO on a CAN socket.
* @version 0.1
* @date 2020-07-02
*
* @copyright Copyright (c) 2020 Simon Cahill
*
* Copyright 2020 Simon Cahill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIBSOCKCANPP_INCLUDE_EXCEPTIONS_CANEXCEPTION_HPP
#define LIBSOCKCANPP_INCLUDE_EXCEPTIONS_CANEXCEPTION_HPP
#include <exception>
#include <string>
namespace sockcanpp {
namespace exceptions {
using std::exception;
using std::string;
/**
* @brief An exception that may be thrown when an error occurs while closing a
* CAN socket.
*/
class CanException : public exception {
public: // +++ Constructor / Destructor +++
CanException(string message, int32_t socket) : _message(message), _socket(socket) {}
~CanException() {}
public: // +++ Overrides +++
const char *what() { return _message.c_str(); }
public: // +++ Getter +++
const int32_t getSocket() const { return _socket; }
private:
int32_t _socket;
string _message;
};
} // namespace exceptions
} // namespace sockcanpp
#endif // LIBSOCKCANPP_INCLUDE_EXCEPTIONS_CANEXCEPTION_HPP

57
core/driver/sockcanpp/exceptions/CanInitException.hpp

@ -1,57 +0,0 @@
/**
* @file CanInitException.hpp
* @author Simon Cahill (simonc@online.de)
* @brief Contains the implementation of an exception that is thrown when a CAN
* socket couldn't be inintialised.
* @version 0.1
* @date 2020-07-02
*
* @copyright Copyright (c) 2020 Simon Cahill
*
* Copyright 2020 Simon Cahill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIBSOCKCANPP_INCLUDE_EXCEPTIONS_CANINITEXCEPTION_HPP
#define LIBSOCKCANPP_INCLUDE_EXCEPTIONS_CANINITEXCEPTION_HPP
#include <exception>
#include <string>
namespace sockcanpp {
namespace exceptions {
using std::exception;
using std::string;
/**
* @brief An exception that may be thrown when an error occurred while
* initialising a CAN socket.
*/
class CanInitException : public exception {
public: // +++ Constructor / Destructor +++
CanInitException(string message) : _message(message) {}
virtual ~CanInitException() {}
public: // +++ Override +++
const char *what() { return _message.c_str(); }
private:
string _message;
};
} // namespace exceptions
} // namespace sockcanpp
#endif // LIBSOCKCANPP_INCLUDE_EXCEPTIONS_CANINITEXCEPTION_HPP

62
core/driver/sockcanpp/exceptions/InvalidSocketException.hpp

@ -1,62 +0,0 @@
/**
* @file InvalidSocketException.hpp
* @author Simon Cahill (simonc@online.de)
* @brief Contains the implementation of an exception that may be thrown when an
* invalid CAN socket is detected.
* @version 0.1
* @date 2020-07-02
*
* @copyright Copyright (c) 2020 Simon Cahill
*
* Copyright 2020 Simon Cahill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIBSOCKCANPP_INCLUDE_EXCEPTIONS_INVALIDSOCKETEXCEPTION_HPP
#define LIBSOCKCANPP_INCLUDE_EXCEPTIONS_INVALIDSOCKETEXCEPTION_HPP
#include <exception>
#include <string>
namespace sockcanpp {
namespace exceptions {
using std::exception;
using std::string;
/**
* @brief An exception that may be thrown when an error occurs while closing a
* CAN socket.
*/
class InvalidSocketException : public exception {
public: // +++ Constructor / Destructor +++
InvalidSocketException(string message, int32_t socket) : _message(message), _socket(socket) {}
~InvalidSocketException() {}
public: // +++ Overrides +++
const char *what() { return _message.c_str(); }
public: // +++ Getter +++
const int32_t getSocket() const { return _socket; }
private:
int32_t _socket;
string _message;
};
} // namespace exceptions
} // namespace sockcanpp
#endif // LIBSOCKCANPP_INCLUDE_EXCEPTIONS_INVALIDSOCKETEXCEPTION_HPP

0
core/driver/socketcan/socketcan.cpp

0
core/driver/socketcan/socketcan.hpp

0
core/driver/socketcan/socketcan_frame.hpp

Loading…
Cancel
Save