diff options
Diffstat (limited to 'plugins')
24 files changed, 1179 insertions, 340 deletions
diff --git a/plugins/cangenplugin/cangenplugin.cpp b/plugins/cangenplugin/cangenplugin.cpp index 73d32538..93d2e718 100644 --- a/plugins/cangenplugin/cangenplugin.cpp +++ b/plugins/cangenplugin/cangenplugin.cpp @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include <logger.h> #include <ambplugin.h> +#include <canbusimpl.h> #include "cangenplugin.h" @@ -203,7 +204,7 @@ bool CANGenPlugin::sendValue(const std::string& interface, AbstractPropertyType* auto& canBus = interfaces[interface]; if(!canBus){ - canBus = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this))); + canBus = std::shared_ptr<CANBus>(new CANBusImpl(*static_cast<CANObserver*>(this))); bool started(canBus->start(interface.c_str())); if(!started) return false; @@ -464,3 +465,8 @@ void CANGenPlugin::dataReceived(libwebsocket* socket, const char* data, size_t l } } } + +void CANGenPlugin::timeoutDetected(const can_frame& frame) +{ + // do nothing +} diff --git a/plugins/cangenplugin/cangenplugin.h b/plugins/cangenplugin/cangenplugin.h index 09e9c4e5..163cde0e 100644 --- a/plugins/cangenplugin/cangenplugin.h +++ b/plugins/cangenplugin/cangenplugin.h @@ -137,6 +137,12 @@ public: * \param frame RTR frame */ virtual void remoteTransmissionRequest(const can_frame& frame);/* remote transmission request (SFF/EFF is still present)*/ + /** + * Called when timeout was detected for a cyclic message. + * @fn timeoutDetected + * @param frame + */ + virtual void timeoutDetected(const can_frame& frame); /*! * Second phase of the plugin initialization. diff --git a/plugins/cansimplugin/cansimplugin.cpp b/plugins/cansimplugin/cansimplugin.cpp index b609b3f9..c8b99216 100644 --- a/plugins/cansimplugin/cansimplugin.cpp +++ b/plugins/cansimplugin/cansimplugin.cpp @@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include <ambplugin.h> #include <logger.h> +#include <canbusimpl.h> #include "cansimplugin.h" @@ -86,7 +87,7 @@ CANSimPlugin::CANSimPlugin(AbstractRoutingEngine* re, const map<string, string>& json_object* obj = (json_object*)array_list_get_idx(ifacelist,i); const char* str = obj ? json_object_get_string(obj) : nullptr; if(str){ - interfaces[str] = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this))); + interfaces[str] = std::shared_ptr<CANBus>(new CANBusImpl(*static_cast<CANObserver*>(this))); } } } @@ -94,7 +95,7 @@ CANSimPlugin::CANSimPlugin(AbstractRoutingEngine* re, const map<string, string>& } // Default interface if none has been configured. if(interfaces.empty()){ - interfaces[DEFAULT_CAN_IF_NAME] = std::shared_ptr<CANBus>(new CANBus(*static_cast<CANObserver*>(this))); + interfaces[DEFAULT_CAN_IF_NAME] = std::shared_ptr<CANBus>(new CANBusImpl(*static_cast<CANObserver*>(this))); } addPropertySupport( @@ -386,4 +387,7 @@ void CANSimPlugin::printFrame(const can_frame& frame) const LOG_INFO( "CANSimPlugin::printFrame can data" << ss.str() << endl ); } - +void CANSimPlugin::timeoutDetected(const can_frame& frame) +{ + // do nothing +} diff --git a/plugins/cansimplugin/cansimplugin.h b/plugins/cansimplugin/cansimplugin.h index 40b55d51..43b1f79e 100644 --- a/plugins/cansimplugin/cansimplugin.h +++ b/plugins/cansimplugin/cansimplugin.h @@ -126,6 +126,12 @@ public: * \param frame RTR frame */ virtual void remoteTransmissionRequest(const can_frame& frame);/* remote transmission request (SFF/EFF is still present)*/ + /** + * Called when timeout was detected for a cyclic message. + * @fn timeoutDetected + * @param frame + */ + virtual void timeoutDetected(const can_frame& frame); /*! * Second phase of the plugin initialization. diff --git a/plugins/common/CMakeLists.txt b/plugins/common/CMakeLists.txt index 052c2c56..407b281e 100644 --- a/plugins/common/CMakeLists.txt +++ b/plugins/common/CMakeLists.txt @@ -1,9 +1,9 @@ set(plugins_common_sources abstractio.hpp serialport.hpp bluetoothadapterproxy.c bluetooth.hpp bluetoothmanagerproxy.c bluetoothserialproxy.c bluetooth5.cpp - canadapter.cpp cansocket.cpp cansocketreader.cpp canbusimpl.cpp cansocketadapter.cpp logger.cpp mutex.cpp thread.cpp dbusexport.cpp dbusplugin.cpp - abstractdbusinterface.cpp dbussignaller.cpp varianttype.cpp) + canadapter.cpp cansocket.cpp cansocketraw.cpp cansocketbcm.cpp cansocketreader.cpp canbusimpl.cpp cansocketadapter.cpp logger.cpp mutex.cpp + thread.cpp dbusexport.cpp dbusplugin.cpp abstractdbusinterface.cpp dbussignaller.cpp varianttype.cpp) set(plugins_common_headers_install abstractio.hpp serialport.hpp bluetooth.hpp bluetoothadapterproxy.h bluetoothmanagerproxy.h bluetoothserialproxy.h - bluetooth5.h canbus.h canadapter.h cansocket.h cansocketreader.h canbusimpl.h cansocketadapter.h canobserver.h logger.h mutex.h thread.h - dbusexport.h dbusplugin.h abstractdbusinterface.h dbussignaller.h varianttype.h) + bluetooth5.h canframeinfo.h canbus.h canadapter.h cansocket.h cansocketraw.h cansocketbcm.h cansocketreader.h canbusimpl.h cansocketadapter.h + canobserver.h logger.h mutex.h thread.h dbusexport.h dbusplugin.h abstractdbusinterface.h dbussignaller.h varianttype.h) add_library(amb-plugins-common SHARED ${plugins_common_sources}) diff --git a/plugins/common/canadapter.h b/plugins/common/canadapter.h index fa78c102..2efffa03 100644 --- a/plugins/common/canadapter.h +++ b/plugins/common/canadapter.h @@ -1,5 +1,7 @@ /* Copyright (C) 2012 Intel Corporation +Copyright (C) 2015 Cogent Embedded Inc. +Copyright (C) 2015 Renesas Electronics Corporation This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -68,6 +70,22 @@ public: * @return True if frame was sent */ virtual bool sendFrame(const can_frame& frame) = 0; + /** + * Registers CAN ID of a cyclic message for receiving + * @fn registerCyclicMessageForReceive + * @param canId CAN ID of the message. + * @param minCycleTime Minimal interval between messages in seconds. Set to 0 if not used. + * @param maxCycleTime Maximum interval between messages for timeout detection in seconds. Set to 0 if no timeout detection is necessary. + * @return True if registration succeeds. + */ + virtual bool registerCyclicMessageForReceive(int canId, double minCycleTime, double maxCycleTime) = 0; + /** + * Un-registers CAN ID of a message used of receiving. Valid for cyclic and sporadic messages. + * @fn unregisterMessageForReceive + * @param canId CAN ID of the message. + * @return True if de-registration succeeds. + */ + virtual bool unregisterMessageForReceive(int canId) = 0; protected: /** diff --git a/plugins/common/canbus.h b/plugins/common/canbus.h index 319c856a..4d9d856c 100644 --- a/plugins/common/canbus.h +++ b/plugins/common/canbus.h @@ -1,5 +1,7 @@ /* Copyright (C) 2012 Intel Corporation +Copyright (C) 2015 Cogent Embedded Inc. +Copyright (C) 2015 Renesas Electronics Corporation This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,6 +18,8 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/* Refactored to an abstract interface. See http://stackoverflow.com/a/825365 */ + #ifndef CANBUS_H #define CANBUS_H @@ -35,47 +39,60 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA class CANBus { public: - /** - * @param observer Object derived from #CANObserver that will receive CAN bus frames - */ - CANBus(CANObserver& observer); - virtual ~CANBus(); - - /** - * Starts the CAN bus instance on the specified interface - * @fn start - * @param name Name of the CAN bus network interface - * @return True if no error occurs. - */ - virtual bool start(const char* name); - /** - * Stops the CAN bus instance - * @fn stop - */ - virtual void stop(); - /** - * Sends standard(11bit) CAN frame over the bus - * @fn sendStandardFrame - * @param frame CAN frame to be sent - * @return True if frame was sent - */ - virtual bool sendStandardFrame(const can_frame& frame); - /** - * Sends extended(29bit) CAN frame over the bus - * @fn sendExtendedFrame - * @param frame CAN frame to be sent - * @return True if frame was sent - */ - virtual bool sendExtendedFrame(const can_frame& frame); + virtual ~CANBus(){} /*LCOV_EXCL_LINE*/ - class Impl; -protected: - /** - * CANBus class private implementation - * @property d - * @protected - */ - Impl* d; + /** + * Starts the CAN bus instance on the specified interface + * @fn start + * @param name Name of the CAN bus network interface + * @return True if no error occurs. + */ + virtual bool start(const char* name) = 0; + /** + * Stops the CAN bus instance + * @fn stop + */ + virtual void stop() = 0; + /** + * Sends standard(11bit) CAN frame over the bus + * @fn sendStandardFrame + * @param frame CAN frame to be sent + * @return True if frame was sent + */ + virtual bool sendStandardFrame(const can_frame& frame) = 0; + /** + * Sends extended(29bit) CAN frame over the bus + * @fn sendExtendedFrame + * @param frame CAN frame to be sent + * @return True if frame was sent + */ + virtual bool sendExtendedFrame(const can_frame& frame) = 0; + /** + * Registers CAN ID of a cyclic message for receiving + * @fn registerCyclicMessageForReceive + * @param canId CAN ID of the message. + * @param minCycleTime Minimal interval between messages in seconds. Set to 0 if not used. + * @param maxCycleTime Maximum interval between messages for timeout detection in seconds. Set to 0 if no timeout detection is necessary. + * @return True if registration succeeds. + */ + virtual bool registerCyclicMessageForReceive(int canId, double minCycleTime, double maxCycleTime) = 0; + /** + * Registers CAN ID of a message for receiving with no timeout. Perfect for sporadic messages. + * @fn registerMessageForReceive + * @param canId CAN ID of the message. + * @return True if registration succeeds. + */ + virtual bool registerMessageForReceive(int canId) + { + return registerCyclicMessageForReceive(canId, 0, 0); + } + /** + * Un-registers CAN ID of a message used of receiving. Valid for cyclic and sporadic messages. + * @fn unregisterMessageForReceive + * @param canId CAN ID of the message. + * @return True if de-registration succeeds. + */ + virtual bool unregisterMessageForReceive(int canId) = 0; }; #endif // CANBUS_H diff --git a/plugins/common/canbusimpl.cpp b/plugins/common/canbusimpl.cpp index 993e4a0f..b0a0fa7d 100644 --- a/plugins/common/canbusimpl.cpp +++ b/plugins/common/canbusimpl.cpp @@ -1,5 +1,7 @@ /* Copyright (C) 2012 Intel Corporation +Copyright (C) 2015 Cogent Embedded Inc. +Copyright (C) 2015 Renesas Electronics Corporation This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -21,25 +23,21 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "canadapter.h" #include "logger.h" -//---------------------------------------------------------------------------- -// CANBusImpl -//---------------------------------------------------------------------------- - -CANBus::Impl::Impl(CANObserver& observer) : +CANBusImpl::CANBusImpl(CANObserver& observer) : mObserver(observer), mAdapter(NULL) { LOG_TRACE(""); } -CANBus::Impl::~Impl() +CANBusImpl::~CANBusImpl() { LOG_TRACE(""); stop(); } -bool CANBus::Impl::start(const char* name) +bool CANBusImpl::start(const char* name) { LOG_TRACE(""); @@ -49,7 +47,7 @@ bool CANBus::Impl::start(const char* name) return mAdapter ? mAdapter->start(name) : false; } -void CANBus::Impl::stop() +void CANBusImpl::stop() { LOG_TRACE(""); @@ -60,7 +58,7 @@ void CANBus::Impl::stop() } } -bool CANBus::Impl::sendStandardFrame(const can_frame& frame) +bool CANBusImpl::sendStandardFrame(const can_frame& frame) { LOG_TRACE(""); @@ -72,7 +70,7 @@ bool CANBus::Impl::sendStandardFrame(const can_frame& frame) return false; } -bool CANBus::Impl::sendExtendedFrame(const can_frame& frame) +bool CANBusImpl::sendExtendedFrame(const can_frame& frame) { LOG_TRACE(""); @@ -85,56 +83,24 @@ bool CANBus::Impl::sendExtendedFrame(const can_frame& frame) return false; } -void CANBus::Impl::init() +void CANBusImpl::init() { mAdapter = CANAdapter::createCANAdapter(mObserver); } -//---------------------------------------------------------------------------- -// CANBus -//---------------------------------------------------------------------------- - -CANBus::CANBus(CANObserver& observer) : - d(new CANBus::Impl(observer)) -{ - LOG_TRACE(""); -} - -CANBus::~CANBus() +bool CANBusImpl::registerCyclicMessageForReceive(int canId, double minCycleTime, double maxCycleTime) { - LOG_TRACE(""); - - if(d) { - delete d; - d = 0; + if(mAdapter) { + return mAdapter->registerCyclicMessageForReceive(canId, minCycleTime, maxCycleTime); } + return false; } -bool CANBus::start(const char* name) -{ - LOG_TRACE(""); - - return d ? d->start(name) : false; -} - -void CANBus::stop() -{ - LOG_TRACE(""); - - if(d) - d->stop(); -} - -bool CANBus::sendStandardFrame(const can_frame& frame) +bool CANBusImpl::unregisterMessageForReceive(int canId) { - LOG_TRACE(""); - - return d ? d->sendStandardFrame(frame) : false; + if(mAdapter) { + return mAdapter->unregisterMessageForReceive(canId); + } + return false; } -bool CANBus::sendExtendedFrame(const can_frame& frame) -{ - LOG_TRACE(""); - - return d ? d->sendExtendedFrame(frame) : false; -} diff --git a/plugins/common/canbusimpl.h b/plugins/common/canbusimpl.h index e2ccdd9c..c7698b80 100644 --- a/plugins/common/canbusimpl.h +++ b/plugins/common/canbusimpl.h @@ -1,5 +1,7 @@ /* Copyright (C) 2012 Intel Corporation +Copyright (C) 2015 Cogent Embedded Inc. +Copyright (C) 2015 Renesas Electronics Corporation This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -35,14 +37,14 @@ class CANAdapter; * @class CANBus::Impl */ -class CANBus::Impl +class CANBusImpl : public CANBus { public: /** - * @param observer \link #CANObserver Observer \endlink that will receives CAN bus frames + * @param observer \link #CANObserver Observer \endlink that will receive CAN bus frames */ - Impl(CANObserver& observer); - virtual ~Impl(); + CANBusImpl(CANObserver& observer); + virtual ~CANBusImpl(); /** * Starts the CAN bus instance on the specified interface @@ -70,6 +72,22 @@ public: * @return True if frame was sent */ bool sendExtendedFrame(const can_frame& frame); + /** + * Registers CAN ID of a cyclic message for receiving + * @fn registerCyclicMessageForReceive + * @param canId CAN ID of the message. + * @param minCycleTime Minimal interval between messages in seconds. Set to 0 if not used. + * @param maxCycleTime Maximum interval between messages for timeout detection in seconds. Set to 0 if no timeout detection is necessary. + * @return True if registration succeeds. + */ + virtual bool registerCyclicMessageForReceive(int canId, double minCycleTime, double maxCycleTime); + /** + * Un-registers CAN ID of a message used of receiving. Valid for cyclic and sporadic messages. + * @fn unregisterMessageForReceive + * @param canId CAN ID of the message. + * @return True if de-registration succeeds. + */ + virtual bool unregisterMessageForReceive(int canId); protected: /** diff --git a/plugins/common/canframeinfo.h b/plugins/common/canframeinfo.h new file mode 100644 index 00000000..6469a679 --- /dev/null +++ b/plugins/common/canframeinfo.h @@ -0,0 +1,72 @@ +/* +Copyright (C) 2015 Cogent Embedded Inc. +Copyright (C) 2015 Renesas Electronics Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CANFRAMEINFO_H +#define CANFRAMEINFO_H + +/** + * \addtogroup libcanbus + * @{ + */ + +#include <stdlib.h> +#include <linux/can.h> + +#include "timestamp.h" + +/** + * CAN frame with additional information + */ +struct CANFrameInfo +{ + CANFrameInfo(const can_frame &frame) + { + this->status = CANFrameInfo::CANMessageStatus::GOOD; + this->frame = frame; + this->timestamp = amb::currentTime(); + } + + CANFrameInfo() { } + + enum CANMessageStatus { + TIMEOUT = -2, + EMPTY = 0, + GOOD = 1, + }; + + /** + * The actual frame written or read from socket + */ + struct can_frame frame; + + /** + * Status of the message. + */ + CANFrameInfo::CANMessageStatus status; + + /** + * Timestamp of sending or receiving action + */ + double timestamp; +}; + +#endif // CANFRAMEINFO_H + +/** @} */ + diff --git a/plugins/common/canobserver.h b/plugins/common/canobserver.h index 0518bd49..549f0700 100644 --- a/plugins/common/canobserver.h +++ b/plugins/common/canobserver.h @@ -24,8 +24,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * @{ */ +#include <stdlib.h> #include <linux/can.h> +#include "canframeinfo.h" + /** * \brief Interface. Receives notifications about the CAN bus traffic and errors. * @@ -76,7 +79,12 @@ public: * @param frame RTR frame */ virtual void remoteTransmissionRequest(const can_frame& frame) = 0; /* remote transmission request (SFF/EFF is still present)*/ - + /** + * Called when timeout was detected for a cyclic message. + * @fn timeoutDetected + * @param frame + */ + virtual void timeoutDetected(const can_frame& frame) = 0; /* timeout */ }; #endif // CANOBSERVER_H diff --git a/plugins/common/cansocket.cpp b/plugins/common/cansocket.cpp index b59c6bd5..0b5ca9c0 100644 --- a/plugins/common/cansocket.cpp +++ b/plugins/common/cansocket.cpp @@ -24,135 +24,54 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "logger.h" #include "cansocket.h" - -CANSocket::CANSocket() : - mSocket(-1) +CANSocket::CANSocket() { + // default implementation doesn't do anything LOG_TRACE(""); } CANSocket::~CANSocket() { + // default implementation doesn't do anything LOG_TRACE(""); stop(); } -bool CANSocket::start(const char* ifName) -{ - LOG_TRACE(""); - - if(mSocket < 0) { - if(!createSocket()) { - LOG_ERROR("Socket error"); - } else { - can_err_mask_t errorMask = 0xFFFFFFFF; - if(!enableCANErrors(errorMask)) { - LOG_ERROR("Socket error"); - } else { - mPoll.fd = mSocket; - mPoll.events = POLLIN | POLLPRI; - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, ifName); - if(!locateInterfaceIndex(ifr)) { - LOG_ERROR("Socket error"); - stop(); - } else { - struct sockaddr_can addr; - memset(&addr, 0, sizeof(addr)); - addr.can_family = AF_CAN; - addr.can_ifindex = ifr.ifr_ifindex; - if(!bindSocket(addr)) { - LOG_ERROR("Socket error"); - stop(); - } else { - return true; - } - } - } - } - } - return false; -} - void CANSocket::stop() { - LOG_TRACE(""); - - if(mSocket >= 0) { - closeSocket(); - mSocket = -1; - } + // default implementation doesn't do anything } -bool CANSocket::write(const struct can_frame &frame, int &bytesWritten) +bool CANSocket::write(const struct CANFrameInfo &message) { + // default implementation doesn't do anything LOG_TRACE(""); - bytesWritten = (int)writeFrame(frame); - return bytesWritten == sizeof(struct can_frame); -} - -CANSocket::CANSocketReadSuccess CANSocket::read( - struct can_frame& frame, int &bytesRead, unsigned int timeout) -{ - LOG_TRACE("timeout: " << timeout); - - CANSocket::CANSocketReadSuccess success; - - switch(waitData(timeout)) { - case -1: - LOG_ERROR("reading error"); - success = CANSocket::READING_FAILED; - break; - case 0: - bytesRead = 0; - success = CANSocket::READING_TIMED_OUT; - break; - default: - bytesRead = (int)readFrame(frame); - success = bytesRead >= 0 ?CANSocket::READING_SUCCEEDED : CANSocket::READING_FAILED; - } - return success; -} - -bool CANSocket::createSocket() -{ - return ((mSocket = ::socket(PF_CAN, SOCK_RAW, CAN_RAW)) >= 0); + return false; } -bool CANSocket::enableCANErrors(can_err_mask_t errorMask) -{ - return (setsockopt(mSocket, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &errorMask, sizeof(errorMask)) == 0); -} -bool CANSocket::locateInterfaceIndex(struct ifreq& ifr) +CANSocket::CANSocketReadSuccess CANSocket::read(struct CANFrameInfo& message, unsigned int timeout) { - return (::ioctl(mSocket, SIOCGIFINDEX, &ifr) == 0); -} + // default implementation doesn't do anything + LOG_TRACE(""); -bool CANSocket::bindSocket(struct sockaddr_can& addr) -{ - return (::bind(mSocket, (struct sockaddr*)&addr, sizeof(addr)) == 0); + return CANSocketReadSuccess::READING_FAILED; } -bool CANSocket::closeSocket() +bool CANSocket::registerCyclicMessageForReceive(int canId, double minCycleTime, double maxCycleTime) { - return (::close(mSocket) == 0); -} + // default implementation doesn't do anything + LOG_TRACE(""); -int CANSocket::waitData(unsigned int timeout) -{ - return ::poll(&mPoll, 1, timeout); + return false; } -ssize_t CANSocket::writeFrame(const can_frame& frame) +bool CANSocket::unregisterMessageForReceive(int canId) { - return ::write(mSocket, &frame, sizeof(struct can_frame)); -} + // default implementation doesn't do anything + LOG_TRACE(""); -ssize_t CANSocket::readFrame(can_frame& frame) -{ - return ::recv(mSocket, &frame, sizeof(struct can_frame), 0); + return false; } diff --git a/plugins/common/cansocket.h b/plugins/common/cansocket.h index f6eaa50a..a201e5a4 100644 --- a/plugins/common/cansocket.h +++ b/plugins/common/cansocket.h @@ -24,13 +24,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * @{ */ -#include <net/if.h> -#include <sys/poll.h> -#include <string> -#include <linux/can/raw.h> +#include <linux/can.h> + +#include "canbus.h" /** -* \brief CAN Socket wrapper. +* \brief Wrapper around different implementations of SocketCAN. * @class CANSocket */ class CANSocket @@ -45,7 +44,7 @@ public: enum CANSocketReadSuccess { READING_FAILED = -1, READING_TIMED_OUT, - READING_SUCCEEDED + READING_SUCCEEDED, }; public: @@ -53,62 +52,49 @@ public: virtual ~CANSocket(); /** - * Opens and initialize CAN socket + * Opens and initializes CAN socket * @fn start * @param ifName Name of the CAN bus network interface. * @return True if no error occurs. */ - virtual bool start(const char* ifName); + virtual bool start(const char* ifName) = 0; /** - * Closes socket + * Closes the socket * @fn stop */ virtual void stop(); /** * Writes CAN frame using the socket * @fn write - * @param frame CAN frame buffer + * @param message CAN frame with additional information * @param bytesWritten Number of written bytes. * @return True if no error occurs. */ - virtual bool write(const struct can_frame &frame, int &bytesWritten); - + virtual bool write(const struct CANFrameInfo &message); /** * Try to read CAN frame * @fn read - * @param frame CAN frame buffer - * @param bytesRead Number of read bytes. - * @param timeout Timeout for reading. + * @param message Buffer for CAN frame with additional information + * @param timeout Timeout for reading in [ms]. * @return Reading operation status code. */ - virtual CANSocket::CANSocketReadSuccess read( struct can_frame& frame, int &bytesRead, unsigned int timeout = 1000); - -private: - /** - * @internal - */ - virtual bool createSocket(); - virtual bool enableCANErrors(can_err_mask_t errorMask); - virtual bool locateInterfaceIndex(struct ifreq& ifr); - virtual bool bindSocket(struct sockaddr_can &addr); - virtual bool closeSocket(); - virtual int waitData(unsigned int timeout); - virtual ssize_t writeFrame(const struct can_frame &frame); - virtual ssize_t readFrame(struct can_frame& frame); - -private: + virtual CANSocket::CANSocketReadSuccess read(struct CANFrameInfo& message, unsigned int timeout = 1000); /** - * Socket file descriptor. - * @property mSocket - * @private - */ - int mSocket; + * Registers CAN ID of a cyclic message for receiving + * @fn registerCyclicMessageForReceive + * @param canId CAN ID of the message. + * @param minCycleTime Minimal interval between messages in seconds. Set to 0 if not used. + * @param maxCycleTime Maximum interval between messages for timeout detection in seconds. Set to 0 if no timeout detection is necessary. + * @return True if registration succeeds. + */ + virtual bool registerCyclicMessageForReceive(int canId, double minCycleTime, double maxCycleTime); /** - * Data structure describing a polling request. - * @property mPoll - * @private - */ - struct pollfd mPoll; + * Un-registers CAN ID of a message used of receiving. Valid for cyclic and sporadic messages. + * @fn unregisterMessageForReceive + * @param canId CAN ID of the message. + * @return True if de-registration succeeds. + */ + virtual bool unregisterMessageForReceive(int canId); }; #endif // CANSOCKET_H diff --git a/plugins/common/cansocketadapter.cpp b/plugins/common/cansocketadapter.cpp index c2e660b7..3395038b 100644 --- a/plugins/common/cansocketadapter.cpp +++ b/plugins/common/cansocketadapter.cpp @@ -21,6 +21,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "canobserver.h" #include "cansocketreader.h" #include "logger.h" +#include "cansocketbcm.h" +#include "cansocketraw.h" // TODO: handle socket errors @@ -76,8 +78,8 @@ bool CANSocketAdapter::sendFrame(const can_frame& frame) LOG_TRACE(""); if(mSocket) { - int bytesWritten(0); - return mSocket->write(frame, bytesWritten); + CANFrameInfo message(frame); + return mSocket->write(message); } return false; } @@ -85,8 +87,23 @@ bool CANSocketAdapter::sendFrame(const can_frame& frame) void CANSocketAdapter::init() { if(!mSocket) - mSocket = new CANSocket(); + mSocket = new CANSocketBCM(); if(!mReader) mReader = new CANSocketReader(mObserver, *mSocket); } +bool CANSocketAdapter::registerCyclicMessageForReceive(int canId, double minCycleTime, double maxCycleTime) +{ + if(mSocket) + return mSocket->registerCyclicMessageForReceive(canId, minCycleTime, maxCycleTime); + else + return false; +} + +bool CANSocketAdapter::unregisterMessageForReceive(int canId) +{ + if(mSocket) + return mSocket->unregisterMessageForReceive(canId); + else + return false; +} diff --git a/plugins/common/cansocketadapter.h b/plugins/common/cansocketadapter.h index 350563ce..811d26a7 100644 --- a/plugins/common/cansocketadapter.h +++ b/plugins/common/cansocketadapter.h @@ -63,6 +63,22 @@ public: * @return True if frame was sent */ virtual bool sendFrame(const can_frame& frame); + /** + * Registers CAN ID of a cyclic message for receiving + * @fn registerCyclicMessageForReceive + * @param canId CAN ID of the message. + * @param minCycleTime Minimal interval between messages in seconds. Set to 0 if not used. + * @param maxCycleTime Maximum interval between messages for timeout detection in seconds. Set to 0 if no timeout detection is necessary. + * @return True if registration succeeds. + */ + virtual bool registerCyclicMessageForReceive(int canId, double minCycleTime, double maxCycleTime); + /** + * Un-registers CAN ID of a message used of receiving. Valid for cyclic and sporadic messages. + * @fn unregisterMessageForReceive + * @param canId CAN ID of the message. + * @return True if de-registration succeeds. + */ + virtual bool unregisterMessageForReceive(int canId); protected: /** diff --git a/plugins/common/cansocketbcm.cpp b/plugins/common/cansocketbcm.cpp new file mode 100644 index 00000000..d923ce3e --- /dev/null +++ b/plugins/common/cansocketbcm.cpp @@ -0,0 +1,279 @@ +/* +Copyright (C) 2012 Intel Corporation +Copyright (C) 2015 Cogent Embedded Inc. +Copyright (C) 2015 Renesas Electronics Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include <string.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <sys/socket.h> + +#include <timestamp.h> +#include "logger.h" +#include "cansocketbcm.h" +#include "timestamp.h" + +CANSocketBCM::CANSocketBCM() : + mSocket(-1) +{ + LOG_TRACE(""); +} + +bool CANSocketBCM::start(const char* ifName) +{ + LOG_TRACE(""); + + if(mSocket >= 0) + return false; + + if(!createSocket()) + { + LOG_ERROR("Socket error"); + return false; + } + + // can_err_mask_t errorMask = 0xFFFFFFFF; + // if(!enableCANErrors(errorMask)) { + // LOG_ERROR("Socket error"); + // return false; + // } + + mPoll.fd = mSocket; + mPoll.events = POLLIN | POLLPRI; + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, ifName); + if(!locateInterfaceIndex(ifr)) { + LOG_ERROR("Socket error"); + stop(); + return false; + } + + struct sockaddr_can addr; + memset(&addr, 0, sizeof(addr)); + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + if(!connectSocket(addr)) { + LOG_ERROR("Socket error"); + stop(); + return false; + } + + return true; +} + +void CANSocketBCM::stop() +{ + LOG_TRACE(""); + + if(mSocket >= 0) { + closeSocket(); + mSocket = -1; + } +} + +bool CANSocketBCM::write(const struct CANFrameInfo &message) +{ + LOG_TRACE(""); + + return writeFrameOneTime(message.frame); +} + +CANSocket::CANSocketReadSuccess CANSocketBCM::read(struct CANFrameInfo& message, unsigned int timeout) +{ + LOG_TRACE("timeout: " << timeout); + + CANSocket::CANSocketReadSuccess success; + memset(&message, 0, sizeof(message)); + + switch(waitData(timeout)) { + case -1: + LOG_ERROR("reading error"); + success = CANSocket::READING_FAILED; + break; + case 0: + success = CANSocket::READING_TIMED_OUT; + break; + default: + success = readMessage(message); + break; + } + + return success; +} + +bool CANSocketBCM::createSocket() +{ + return ((mSocket = ::socket(PF_CAN, SOCK_DGRAM, CAN_BCM)) >= 0); +} + +bool CANSocketBCM::locateInterfaceIndex(struct ifreq& ifr) +{ + return (::ioctl(mSocket, SIOCGIFINDEX, &ifr) == 0); +} + +bool CANSocketBCM::connectSocket(struct sockaddr_can& addr) +{ + return (::connect(mSocket, (struct sockaddr*)&addr, sizeof(addr)) == 0); +} + +bool CANSocketBCM::closeSocket() +{ + return (::close(mSocket) == 0); +} + +int CANSocketBCM::waitData(unsigned int timeout) +{ + return ::poll(&mPoll, 1, timeout); +} + +/** + * BCM header with one message. + * @note hdr.nframes must always be 0 or 1. + */ +struct __attribute__ ((__packed__)) bcm_msg_one{ + struct bcm_msg_head hdr; + struct can_frame frames[1]; +}; + +bool CANSocketBCM::writeFrameOneTime(const can_frame& frame) +{ + struct bcm_msg_one bcms; + + // fill in the header + memset(&bcms.hdr, 0, sizeof(bcms.hdr)); + bcms.hdr.opcode = TX_SEND; + bcms.hdr.nframes = 1; + bcms.hdr.can_id = frame.can_id; + + // copy the frame + memcpy(&bcms.frames[0], &frame, sizeof(frame)); + + // and write everything + ssize_t nbytes = ::write(mSocket, &bcms, sizeof(bcms)); + return nbytes == sizeof(bcms); +} + +CANSocket::CANSocketReadSuccess CANSocketBCM::readMessage(CANFrameInfo& message) +{ + struct bcm_msg_one bcms; + + // clear the destination + memset(&message, 0, sizeof(message)); + + // get data from socket + size_t nbytes = ::recv(mSocket, &bcms, sizeof(bcms), 0); + if ( nbytes < sizeof(bcms.hdr)) + { + LOG_ERROR("Socket error"); + return CANSocket::CANSocketReadSuccess::READING_FAILED; + } + //TODO: implement better timestamps + message.timestamp = amb::currentTime(); + + switch (bcms.hdr.opcode) + { + case RX_CHANGED: + if (bcms.hdr.nframes >= 1 && nbytes == sizeof(bcms)) + { + if (bcms.hdr.nframes > 1) + { + LOG_WARNING("Dropped " << bcms.hdr.nframes - 1 << " updates from CAN bus."); + } + + // copy the first frame + memcpy(&message.frame, &bcms.frames[0], sizeof(bcms.frames[0])); + message.status = CANFrameInfo::CANMessageStatus::GOOD; + return CANSocket::CANSocketReadSuccess::READING_SUCCEEDED; + } + else + { + LOG_ERROR("Unexpected data from the socket" + << " " << bcms.hdr.opcode + << " " << bcms.hdr.nframes + << " " << nbytes); + return CANSocket::CANSocketReadSuccess::READING_FAILED; + } + case RX_TIMEOUT: + memcpy(&message.frame, &bcms.frames[0], sizeof(bcms.frames[0])); + message.frame.can_id = bcms.hdr.can_id; //doubtful. Do we need to override this? + message.status = CANFrameInfo::CANMessageStatus::TIMEOUT; + return CANSocket::CANSocketReadSuccess::READING_SUCCEEDED; + + case TX_EXPIRED: + // do nothing + return CANSocket::CANSocketReadSuccess::READING_TIMED_OUT; + + default: + LOG_ERROR("Unexpected opcode " << bcms.hdr.opcode); + return CANSocket::CANSocketReadSuccess::READING_FAILED; + } +} + +/* + 4.2.5 Broadcast Manager receive filter timers + + The timer values ival1 or ival2 may be set to non-zero values at RX_SETUP. + When the SET_TIMER flag is set the timers are enabled: + + ival1: Send RX_TIMEOUT when a received message is not received again within + the given time. When START_TIMER is set at RX_SETUP the timeout detection + is activated directly - even without a former CAN frame reception. + + ival2: Throttle the received message rate down to the value of ival2. This + is useful to reduce messages for the application when the signal inside the + CAN frame is stateless as state changes within the ival2 periode may get + lost. +*/ + +bool CANSocketBCM::registerCyclicMessageForReceive(int canId, double minCycleTime, double maxCycleTime) +{ + struct bcm_msg_head hdr; + + // fill in the header + memset(&hdr, 0, sizeof(hdr)); + hdr.opcode = RX_SETUP; + // set RX_FILTER_ID | RX_CHECK_DLC because we don't differentiate messages by dlc or content yet. Only by id + // setting RX_ANNOUNCE_RESUME may lead to duplicates in data which should be filtered by amb core. + // However, we won't miss any data. + hdr.flags = RX_FILTER_ID | RX_CHECK_DLC | SETTIMER | STARTTIMER | RX_ANNOUNCE_RESUME; + hdr.nframes = 0; + hdr.can_id = canId; + hdr.ival1 = amb::Timestamp::toTimeval(maxCycleTime); + hdr.ival2 = amb::Timestamp::toTimeval(minCycleTime); + + // and write + ssize_t nbytes = ::write(mSocket, &hdr, sizeof(hdr)); + return nbytes == sizeof(hdr); +} + +bool CANSocketBCM::unregisterMessageForReceive(int canId) +{ + struct bcm_msg_head hdr; + + // fill in the header + memset(&hdr, 0, sizeof(hdr)); + hdr.opcode = RX_DELETE; + hdr.can_id = canId; + + // and write + ssize_t nbytes = ::write(mSocket, &hdr, sizeof(hdr)); + return nbytes == sizeof(hdr); +} + diff --git a/plugins/common/cansocketbcm.h b/plugins/common/cansocketbcm.h new file mode 100644 index 00000000..f5403bfc --- /dev/null +++ b/plugins/common/cansocketbcm.h @@ -0,0 +1,122 @@ +/* +Copyright (C) 2012 Intel Corporation +Copyright (C) 2015 Cogent Embedded Inc. +Copyright (C) 2015 Renesas Electronics Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CANSOCKETBCM_H +#define CANSOCKETBCM_H + +/** + * \addtogroup libcanbus + * @{ + */ + +#include <net/if.h> +#include <sys/poll.h> +#include <string> +#include <stdlib.h> +#include <linux/can/bcm.h> +#include <linux/can/raw.h> + +#include "cansocket.h" + +/** +* \brief CAN Socket wrapper. +* @class CANSocket +*/ +class CANSocketBCM : public CANSocket +{ +public: + CANSocketBCM(); + virtual ~CANSocketBCM(){} /*LCOV_EXCL_LINE*/ + + /** + * Opens and initialize CAN socket + * @fn start + * @param ifName Name of the CAN bus network interface. + * @return True if no error occurs. + */ + virtual bool start(const char* ifName); + /** + * Closes socket + * @fn stop + */ + virtual void stop(); + /** + * Writes CAN frame using the socket + * @fn write + * @param message CAN frame with additional information + * @param bytesWritten Number of written bytes. + * @return True if no error occurs. + */ + virtual bool write(const struct CANFrameInfo &message); + /** + * Try to read CAN frame + * @fn read + * @param message Buffer for CAN frame with additional information + * @param timeout Timeout for reading in [ms]. + * @return Reading operation status code. + */ + virtual CANSocket::CANSocketReadSuccess read(struct CANFrameInfo& message, unsigned int timeout = 1000); + /** + * Registers CAN ID of a cyclic message for receiving + * @fn registerCyclicMessageForReceive + * @param canId CAN ID of the message. + * @param minCycleTime Minimal interval between messages in seconds. Set to 0 if not used. + * @param maxCycleTime Maximum interval between messages for timeout detection in seconds. Set to 0 if no timeout detection is necessary. + * @return True if registration succeeds. + */ + virtual bool registerCyclicMessageForReceive(int canId, double minCycleTime, double maxCycleTime); + /** + * Unregisters CAN ID for receiving + * @fn unregisterMessageForReceive + * @param canId CAN ID of the message. + * @return True if de-registration succeeds. + */ + virtual bool unregisterMessageForReceive(int canId); + +private: + /** + * @internal + */ + bool createSocket(); + bool locateInterfaceIndex(struct ifreq& ifr); + bool connectSocket(struct sockaddr_can& addr); + bool closeSocket(); + int waitData(unsigned int timeout); + bool writeFrameOneTime(const can_frame& frame); + CANSocket::CANSocketReadSuccess readMessage(CANFrameInfo& message); + +private: + /** + * Socket file descriptor. + * @property mSocket + * @private + */ + int mSocket; + /** + * Data structure describing a polling request. + * @property mPoll + * @private + */ + struct pollfd mPoll; +}; + +#endif // CANSOCKETBCM_H + +/** @} */ diff --git a/plugins/common/cansocketraw.cpp b/plugins/common/cansocketraw.cpp new file mode 100644 index 00000000..2ab5d4f7 --- /dev/null +++ b/plugins/common/cansocketraw.cpp @@ -0,0 +1,199 @@ +/* +Copyright (C) 2012 Intel Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include <string.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <sys/socket.h> + +#include "logger.h" +#include "cansocket.h" +#include "cansocketraw.h" +#include "timestamp.h" + +CANSocketRaw::CANSocketRaw() : + mSocket(-1) +{ + LOG_TRACE(""); +} + +bool CANSocketRaw::start(const char* ifName) +{ + LOG_TRACE(""); + + if(mSocket < 0) { + if(!createSocket()) { + LOG_ERROR("Socket error"); + } else { + can_err_mask_t errorMask = 0xFFFFFFFF; + if(!enableCANErrors(errorMask)) { + LOG_ERROR("Socket error"); + } else + if(!enableTimestamps()) { + LOG_ERROR("Socket error"); + } else { + mPoll.fd = mSocket; + mPoll.events = POLLIN | POLLPRI; + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, ifName); + if(!locateInterfaceIndex(ifr)) { + LOG_ERROR("Socket error"); + stop(); + } else { + struct sockaddr_can addr; + memset(&addr, 0, sizeof(addr)); + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + if(!bindSocket(addr)) { + LOG_ERROR("Socket error"); + stop(); + } else { + return true; + } + } + } + } + } + return false; +} + +void CANSocketRaw::stop() +{ + LOG_TRACE(""); + + if(mSocket >= 0) { + closeSocket(); + mSocket = -1; + } +} + +bool CANSocketRaw::write(const struct CANFrameInfo &message) +{ + LOG_TRACE(""); + + return writeFrame(message.frame); +} + +CANSocket::CANSocketReadSuccess CANSocketRaw::read(struct CANFrameInfo& message, unsigned int timeout) +{ + LOG_TRACE("timeout: " << timeout); + + CANSocket::CANSocketReadSuccess success; + memset(&message, 0, sizeof(message)); + + switch(waitData(timeout)) { + case -1: + LOG_ERROR("reading error"); + success = CANSocket::READING_FAILED; + break; + case 0: + success = CANSocket::READING_TIMED_OUT; + break; + default: + ssize_t nbytes = (int)readFrame(message.frame, message.timestamp); + message.status = CANFrameInfo::CANMessageStatus::GOOD; + success = nbytes > 0 ? CANSocket::READING_SUCCEEDED : CANSocket::READING_FAILED; + } + + return success; +} + +bool CANSocketRaw::createSocket() +{ + return ((mSocket = ::socket(PF_CAN, SOCK_RAW, CAN_RAW)) >= 0); +} + +bool CANSocketRaw::enableTimestamps() +{ + const int timestamp = 1; + + return (setsockopt(mSocket, SOL_SOCKET, SO_TIMESTAMP, ×tamp, sizeof(timestamp)) == 0); +} + +bool CANSocketRaw::enableCANErrors(can_err_mask_t errorMask) +{ + return (setsockopt(mSocket, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &errorMask, sizeof(errorMask)) == 0); +} + +bool CANSocketRaw::locateInterfaceIndex(struct ifreq& ifr) +{ + return (::ioctl(mSocket, SIOCGIFINDEX, &ifr) == 0); +} + +bool CANSocketRaw::bindSocket(struct sockaddr_can& addr) +{ + return (::bind(mSocket, (struct sockaddr*)&addr, sizeof(addr)) == 0); +} + +bool CANSocketRaw::closeSocket() +{ + return (::close(mSocket) == 0); +} + +int CANSocketRaw::waitData(unsigned int timeout) +{ + return ::poll(&mPoll, 1, timeout); +} + +bool CANSocketRaw::writeFrame(const can_frame& frame) +{ + return ::write(mSocket, &frame, sizeof(frame)) == sizeof(frame); +} + +ssize_t CANSocketRaw::readFrame(can_frame& frame, double ×tamp) +{ + struct iovec io; + struct msghdr msgh; + struct cmsghdr *cmsg; + + // prepare buffers + memset(&msgh, 0, sizeof(msgh)); + io.iov_base=&frame; + io.iov_len=sizeof(can_frame); + msgh.msg_iov=&io; + msgh.msg_iovlen=1; + char buffer[1024]; + msgh.msg_control=&buffer; + msgh.msg_controllen=sizeof(buffer); + + // receive data + ssize_t nbytes = ::recvmsg(mSocket, &msgh, 0); + + if (nbytes > 0 ) + { + /* Receive auxiliary data in msgh */ + for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msgh, cmsg)) { + if (cmsg->cmsg_type == SO_TIMESTAMP) { + struct ::timeval *tv = (struct timeval*) CMSG_DATA(cmsg); + + // convert the timestamp + timestamp = amb::Timestamp::fromTimeval(*tv); + + break; + } + } + if (cmsg == NULL) { + /* No timestamp is provided by the socket. Use our own. */ + timestamp = amb::Timestamp::instance()->epochTime(); + } + } + + return nbytes; +} diff --git a/plugins/common/cansocketraw.h b/plugins/common/cansocketraw.h new file mode 100644 index 00000000..aca053df --- /dev/null +++ b/plugins/common/cansocketraw.h @@ -0,0 +1,103 @@ +/* +Copyright (C) 2012 Intel Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CANSOCKETRAW_H +#define CANSOCKETRAW_H + +/** + * \addtogroup libcanbus + * @{ + */ + +#include <net/if.h> +#include <sys/poll.h> +#include <string> +#include <linux/can/raw.h> + +#include "cansocket.h" + +/** +* \brief CAN Socket wrapper. +* @class CANSocket +*/ +class CANSocketRaw : public CANSocket +{ +public: + CANSocketRaw(); + virtual ~CANSocketRaw(){} /*LCOV_EXCL_LINE*/ + + /** + * Opens and initializes CAN socket + * @fn start + * @param ifName Name of the CAN bus network interface. + * @return True if no error occurs. + */ + virtual bool start(const char* ifName); + /** + * Closes socket + * @fn stop + */ + virtual void stop(); + /** + * Writes CAN frame using the socket + * @fn write + * @param message CAN frame with additional information + * @return True if no error occurs. + */ + virtual bool write(const struct CANFrameInfo &message); + /** + * Try to read CAN frame + * @fn read + * @param message Buffer for CAN frame with additional information + * @param timeout Timeout for reading in [ms]. + * @return Reading operation status code. + */ + virtual CANSocket::CANSocketReadSuccess read(struct CANFrameInfo& message, unsigned int timeout = 1000); + +private: + /** + * @internal + */ + bool createSocket(); + bool enableCANErrors(can_err_mask_t errorMask); + bool enableTimestamps(); + bool locateInterfaceIndex(struct ifreq& ifr); + bool bindSocket(struct sockaddr_can &addr); + bool closeSocket(); + int waitData(unsigned int timeout); + bool writeFrame(const struct can_frame &frame); + ssize_t readFrame(can_frame& frame, double ×tamp); + +private: + /** + * Socket file descriptor. + * @property mSocket + * @private + */ + int mSocket; + /** + * Data structure describing a polling request. + * @property mPoll + * @private + */ + struct pollfd mPoll; +}; + +#endif // CANSOCKETRAW_H + +/** @} */ diff --git a/plugins/common/cansocketreader.cpp b/plugins/common/cansocketreader.cpp index a9663e7f..e5bb42e8 100644 --- a/plugins/common/cansocketreader.cpp +++ b/plugins/common/cansocketreader.cpp @@ -1,5 +1,7 @@ /* Copyright (C) 2012 Intel Corporation +Copyright (C) 2015 Cogent Embedded Inc. +Copyright (C) 2015 Renesas Electronics Corporation This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -38,7 +40,11 @@ bool CANSocketReader::start() { LOG_TRACE(""); - return CUtil::Thread::start(); + bool res = CUtil::Thread::start(); + + // try to set higher priority + if (res) res = setPriority(4); + return res; } void CANSocketReader::stop() @@ -55,41 +61,71 @@ void CANSocketReader::run() while(isRunnable()) { - struct can_frame frame; - int bytesRead; + CANFrameInfo message; + CANSocket::CANSocketReadSuccess success = mSocket.read(message); + + switch(success) + { + case CANSocket::READING_SUCCEEDED: + dispatchMessage(message); + break; - CANSocket::CANSocketReadSuccess success = mSocket.read(frame, bytesRead); + case CANSocket::READING_TIMED_OUT: + // read again + break; - switch(success) { case CANSocket::READING_FAILED: + default: LOG_ERROR("reading failed"); mObserver.errorOccured(CANObserver::GENERAL_ERROR); - return; - case CANSocket::READING_TIMED_OUT: - // read again break; - default: //CANSocketWrapper::READING_SUCCEEDED - if(frame.can_id & CAN_ERR_FLAG) { - frame.can_id &= (CAN_ERR_FLAG|CAN_ERR_MASK); - mObserver.errorFrameReceived(frame); - } - else if(frame.can_id & CAN_RTR_FLAG){ - if(!(frame.can_id & CAN_EFF_FLAG)){ - frame.can_id &= CAN_SFF_MASK; - } - else{ - frame.can_id &= (~CAN_RTR_FLAG); - } - mObserver.remoteTransmissionRequest(frame); - } - else if(frame.can_id & CAN_EFF_FLAG){ - frame.can_id &= CAN_EFF_MASK; - mObserver.extendedFrameReceived(frame); + } + } +} + +void CANSocketReader::dispatchMessage(const CANFrameInfo &message) +{ + struct can_frame frame = message.frame; + + switch (message.status) + { + case CANFrameInfo::CANMessageStatus::GOOD: + if(frame.can_id & CAN_ERR_FLAG) { + frame.can_id &= (CAN_ERR_FLAG|CAN_ERR_MASK); + mObserver.errorFrameReceived(frame); + } + else if( frame.can_id & CAN_RTR_FLAG){ + if(!( frame.can_id & CAN_EFF_FLAG)){ + frame.can_id &= CAN_SFF_MASK; } else{ - frame.can_id &= CAN_SFF_MASK; - mObserver.standardFrameReceived(frame); + frame.can_id &= (~CAN_RTR_FLAG); } + mObserver.remoteTransmissionRequest(frame); } + else if(frame.can_id & CAN_EFF_FLAG){ + frame.can_id &= CAN_EFF_MASK; + mObserver.extendedFrameReceived(frame); + } + else{ + frame.can_id &= CAN_SFF_MASK; + mObserver.standardFrameReceived(frame); + } + break; + + case CANFrameInfo::CANMessageStatus::TIMEOUT: + if(frame.can_id & CAN_EFF_FLAG) + frame.can_id &= CAN_EFF_MASK; + else + frame.can_id &= CAN_SFF_MASK; + + mObserver.timeoutDetected(frame); + break; + + default: + LOG_ERROR("Unexpected CAN message status " << message.status); + mObserver.errorOccured(CANObserver::GENERAL_ERROR); + break; } } + diff --git a/plugins/common/cansocketreader.h b/plugins/common/cansocketreader.h index 623430ae..62d7ead7 100644 --- a/plugins/common/cansocketreader.h +++ b/plugins/common/cansocketreader.h @@ -66,6 +66,13 @@ private: */ virtual void run(); + /** + * Proceseses CAN message received from SocketCAN and notifies mObserver. + * @fn dispatchMessage + * @param message CAN message to be processed. Unchanged. + */ + virtual void dispatchMessage(const CANFrameInfo &message); + private: /** * #CANObserver instance reference diff --git a/plugins/common/thread.cpp b/plugins/common/thread.cpp index d9d9c999..504feb38 100644 --- a/plugins/common/thread.cpp +++ b/plugins/common/thread.cpp @@ -52,9 +52,9 @@ static void *PosixThreadProc(void *param) thread->run(); gMutex.lock(); - --gActiveThreadCount; - LOG_INFO("PosixThreadProc() - active threads: " << gActiveThreadCount); - gMutex.unlock(); + --gActiveThreadCount; + LOG_INFO("PosixThreadProc() - active threads: " << gActiveThreadCount); + gMutex.unlock(); return 0; } @@ -64,59 +64,84 @@ namespace CUtil{ //////////////////////////////////////////////// Thread::Thread() : - thread(0), - runnableFlag(false) + thread(0), + runnableFlag(false) { - pthread_cond_init( &cond, NULL ); - pthread_mutex_init( &mutex, NULL ); + pthread_cond_init( &cond, NULL ); + pthread_mutex_init( &mutex, NULL ); } bool Thread::start() { - pthread_mutex_lock(&mutex); - if (runnableFlag) {// already running - pthread_mutex_unlock(&mutex); - return false; - } - // try to run - if (pthread_create(&thread, NULL/*&thread_attr*/, PosixThreadProc, this) != 0) { + pthread_mutex_lock(&mutex); + if (runnableFlag) {// already running + pthread_mutex_unlock(&mutex); + return false; + } + // try to run + if (pthread_create(&thread, NULL/*&thread_attr*/, PosixThreadProc, this) != 0) { //pthread_attr_destroy(&thread_attr); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); return false; } //pthread_attr_destroy(&thread_attr); - runnableFlag = true; - pthread_mutex_unlock(&mutex); + runnableFlag = true; + pthread_mutex_unlock(&mutex); + return true; +} + + +bool Thread::setPriority(int priority) +{ + pthread_mutex_lock(&mutex); + if (!runnableFlag) {// not running yet or terminated already + pthread_mutex_unlock(&mutex); + return false; + } + + priority = priority < 1 ? 1 : priority; + priority = priority < 99 ? priority : 99; + + // set priority + struct sched_param pr; + pr.__sched_priority = priority; + if (pthread_setschedparam(thread, SCHED_FIFO, &pr) < 0) + { + pthread_mutex_unlock(&mutex); + return false; + } + + pthread_mutex_unlock(&mutex); return true; } Thread::~Thread() { stop(); - pthread_cond_destroy( &cond ); - pthread_mutex_destroy( &mutex ); - thread = 0; + pthread_cond_destroy( &cond ); + pthread_mutex_destroy( &mutex ); + thread = 0; } void Thread::stop() { if (setRunnableFlag(false) == true) { - if( thread != 0 ){ - if (thread == pthread_self()){ - int s = pthread_detach(thread); - ((void)s);// prevent compiler warning in RELEASE build - LOG_MESSAGE("Thread::stop() - thread " << std::hex << int(thread) << std::dec << " detached, returned value was " << s); - } - else{ - int s = pthread_join(thread, NULL); - if (s != 0){ - LOG_ERROR("Thread::stop() - Joined with thread " << std::hex << int(thread) << std::dec << ", returned value was " << s); - } - else{ - LOG_MESSAGE("Thread::stop() - Joined with thread " << std::hex << int(thread) << std::dec << ", returned value was " << s); - } - } - thread = 0; + if( thread != 0 ){ + if (thread == pthread_self()){ + int s = pthread_detach(thread); + ((void)s);// prevent compiler warning in RELEASE build + LOG_MESSAGE("Thread::stop() - thread " << std::hex << int(thread) << std::dec << " detached, returned value was " << s); + } + else{ + int s = pthread_join(thread, NULL); + if (s != 0){ + LOG_ERROR("Thread::stop() - Joined with thread " << std::hex << int(thread) << std::dec << ", returned value was " << s); + } + else{ + LOG_MESSAGE("Thread::stop() - Joined with thread " << std::hex << int(thread) << std::dec << ", returned value was " << s); + } + } + thread = 0; } } return; @@ -124,44 +149,44 @@ void Thread::stop() bool Thread::setRunnableFlag(bool flag) { - pthread_mutex_lock(&mutex); - bool retval(runnableFlag); - runnableFlag = flag; - - if(!runnableFlag) - pthread_cond_signal(&cond); - pthread_mutex_unlock(&mutex); - return retval; + pthread_mutex_lock(&mutex); + bool retval(runnableFlag); + runnableFlag = flag; + + if(!runnableFlag) + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + return retval; } bool Thread::isRunnable(long miliseconds) { - bool runnable(false); + bool runnable(false); - pthread_mutex_lock(&mutex); - if (miliseconds != 0){ - wait(miliseconds); - } - runnable = runnableFlag; + pthread_mutex_lock(&mutex); + if (miliseconds != 0){ + wait(miliseconds); + } + runnable = runnableFlag; - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); return runnable; } bool Thread::wait( long miliseconds ) { - struct timespec abstime; - clock_gettime(CLOCK_REALTIME, &abstime); - abstime.tv_sec += ( miliseconds / 1000 ); - miliseconds %= 1000; - abstime.tv_nsec += ( miliseconds * 1000000L ); // in nanoseconds - if ( abstime.tv_nsec > 1000000000L /* > 1s */ ){ - abstime.tv_sec += 1; // +1s - abstime.tv_nsec -= 1000000000L; // -1s - } - - int status = pthread_cond_timedwait( &cond, &mutex, &abstime ); - return ( status == ETIMEDOUT ); + struct timespec abstime; + clock_gettime(CLOCK_REALTIME, &abstime); + abstime.tv_sec += ( miliseconds / 1000 ); + miliseconds %= 1000; + abstime.tv_nsec += ( miliseconds * 1000000L ); // in nanoseconds + if ( abstime.tv_nsec > 1000000000L /* > 1s */ ){ + abstime.tv_sec += 1; // +1s + abstime.tv_nsec -= 1000000000L; // -1s + } + + int status = pthread_cond_timedwait( &cond, &mutex, &abstime ); + return ( status == ETIMEDOUT ); } } diff --git a/plugins/common/thread.h b/plugins/common/thread.h index 8879b5b4..7bc26f21 100644 --- a/plugins/common/thread.h +++ b/plugins/common/thread.h @@ -127,6 +127,15 @@ public: virtual bool start(); /** + * Sets the priority of the thread for FIFO scheduling. + * @fn set_priority + * @param priority Integer ranging from 1 (lowest) to 99 (highest). + * @return True if the operation was successful. + * @public + */ + bool setPriority(int priority); + + /** * Stops the thread * @fn stop * @public diff --git a/plugins/dbus/dbusinterfacemanager.cpp b/plugins/dbus/dbusinterfacemanager.cpp index 4006d50a..b556fd14 100644 --- a/plugins/dbus/dbusinterfacemanager.cpp +++ b/plugins/dbus/dbusinterfacemanager.cpp @@ -51,7 +51,7 @@ on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_d { DBusInterfaceManager* iface = static_cast<DBusInterfaceManager*>(user_data); - iface->connection = std::shared_ptr<GDBusConnection>(connection, [=](auto conn){ + iface->connection = std::shared_ptr<GDBusConnection>(connection, [=](GDBusConnection* conn){ amb::traits<GDBusConnection>::delete_functor functor; functor(conn); }); |