- Refactor obd2 plugin with AsyncQueue. Use thread-safe updateProperty.
- source export from database plugin does not reflect the source in the database
- grep all the TODOs in the code and do them
+- implement no-value for AbstractPropertyType
+- add timestamp processing for CAN data
#include "timestamp.h"
+#include <math.h>
#include <time.h>
#include <iostream>
#include <chrono>
return startTimeEpoch + time;
}
+double amb::Timestamp::currentTime(double time)
+{
+ return time - startTimeEpoch;
+}
+
double amb::Timestamp::epochTime()
{
auto tm = std::chrono::system_clock::now();
return mInstance;
}
+
+double amb::Timestamp::fromTimeval(const struct ::timeval &tv)
+{
+ return tv.tv_sec*1.0 + tv.tv_usec*1e-6;
+}
+
+struct ::timeval amb::Timestamp::toTimeval(const double time)
+{
+ return { (__time_t) time, (__suseconds_t)fmod(time*1e6, 1e6) };
+}
#ifndef _TIMESTAMP_H___
#define _TIMESTAMP_H___
+#include <time.h>
namespace amb {
public:
double currentTime();
+ double currentTime(double time);
double epochTime(double time);
double epochTime();
+ static double fromTimeval(const struct ::timeval& tv);
+ static struct ::timeval toTimeval(const double time);
+
public:
static Timestamp *instance();
#include <logger.h>
#include <ambplugin.h>
+#include <canbusimpl.h>
#include "cangenplugin.h"
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;
}
}
}
+
+void CANGenPlugin::timeoutDetected(const can_frame& frame)
+{
+ // do nothing
+}
* \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.
#include <ambplugin.h>
#include <logger.h>
+#include <canbusimpl.h>
#include "cansimplugin.h"
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)));
}
}
}
}
// 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(
LOG_INFO( "CANSimPlugin::printFrame can data" << ss.str() << endl );
}
-
+void CANSimPlugin::timeoutDetected(const can_frame& frame)
+{
+ // do nothing
+}
* \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.
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})
/*
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
* @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;
+ /**
+ * 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) = 0;
protected:
/**
/*
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
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
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);
+ }
+ /**
+ * 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) = 0;
};
#endif // CANBUS_H
/*
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
#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("");
return mAdapter ? mAdapter->start(name) : false;
}
-void CANBus::Impl::stop()
+void CANBusImpl::stop()
{
LOG_TRACE("");
}
}
-bool CANBus::Impl::sendStandardFrame(const can_frame& frame)
+bool CANBusImpl::sendStandardFrame(const can_frame& frame)
{
LOG_TRACE("");
return false;
}
-bool CANBus::Impl::sendExtendedFrame(const can_frame& frame)
+bool CANBusImpl::sendExtendedFrame(const can_frame& frame)
{
LOG_TRACE("");
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;
-}
/*
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
* @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
* @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);
+ /**
+ * 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);
protected:
/**
--- /dev/null
+/*
+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
+
+/** @} */
+
* @{
*/
+#include <stdlib.h>
#include <linux/can.h>
+#include "canframeinfo.h"
+
/**
* \brief Interface. Receives notifications about the CAN bus traffic and errors.
*
class CANObserver
{
public:
- /**
- * General CAN bus error. Currently only GENERAL_ERROR is specified.
- * @enum CANError
- * @public
- */
- enum CANError {
- GENERAL_ERROR = 0
- };
+ /**
+ * General CAN bus error. Currently only GENERAL_ERROR is specified.
+ * @enum CANError
+ * @public
+ */
+ enum CANError {
+ GENERAL_ERROR = 0
+ };
- virtual ~CANObserver(){} /*LCOV_EXCL_LINE*/
- /**
- * Called when error occurred on the bus.
- * @fn errorOccured
- * @param error Bus error code
- */
- virtual void errorOccured(CANObserver::CANError error) = 0; /* socket error */
- /**
- * Called when standard frame was is received from the bus.
- * @fn standardFrameReceived
- * @param frame Received frame
- */
- virtual void standardFrameReceived(const can_frame& frame) = 0; /* SFF was present */
- /**
- * Called when extended frame was is received from the bus.
- * @fn extendedFrameReceived
- * @param frame Received frame
- */
- virtual void extendedFrameReceived(const can_frame& frame) = 0; /* EFF was present */
- /**
- * Called when error frame was received from the bus.
- * @fn errorFrameReceived
- * @param frame Error frame
- */
- virtual void errorFrameReceived(const can_frame& frame) = 0; /* error frame */
- /**
- * Called when remote transmission frame was received from the bus.
- * @fn remoteTransmissionRequest
- * @param frame RTR frame
- */
- virtual void remoteTransmissionRequest(const can_frame& frame) = 0; /* remote transmission request (SFF/EFF is still present)*/
+ virtual ~CANObserver(){} /*LCOV_EXCL_LINE*/
+ /**
+ * Called when error occurred on the bus.
+ * @fn errorOccured
+ * @param error Bus error code
+ */
+ virtual void errorOccured(CANObserver::CANError error) = 0; /* socket error */
+ /**
+ * Called when standard frame was is received from the bus.
+ * @fn standardFrameReceived
+ * @param frame Received frame
+ */
+ virtual void standardFrameReceived(const can_frame& frame) = 0; /* SFF was present */
+ /**
+ * Called when extended frame was is received from the bus.
+ * @fn extendedFrameReceived
+ * @param frame Received frame
+ */
+ virtual void extendedFrameReceived(const can_frame& frame) = 0; /* EFF was present */
+ /**
+ * Called when error frame was received from the bus.
+ * @fn errorFrameReceived
+ * @param frame Error frame
+ */
+ virtual void errorFrameReceived(const can_frame& frame) = 0; /* error frame */
+ /**
+ * Called when remote transmission frame was received from the bus.
+ * @fn remoteTransmissionRequest
+ * @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 */
};
#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;
}
* @{
*/
-#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
enum CANSocketReadSuccess {
READING_FAILED = -1,
READING_TIMED_OUT,
- READING_SUCCEEDED
+ READING_SUCCEEDED,
};
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;
+ * 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);
};
#endif // CANSOCKET_H
#include "canobserver.h"
#include "cansocketreader.h"
#include "logger.h"
+#include "cansocketbcm.h"
+#include "cansocketraw.h"
// TODO: handle socket errors
CANSocketAdapter::CANSocketAdapter(CANObserver& observer) :
- CANAdapter(observer),
- mSocket(NULL),
- mReader(NULL)
+ CANAdapter(observer),
+ mSocket(NULL),
+ mReader(NULL)
{
- LOG_TRACE("");
+ LOG_TRACE("");
}
CANSocketAdapter::~CANSocketAdapter()
{
- LOG_TRACE("");
+ LOG_TRACE("");
- stop();
+ stop();
}
bool CANSocketAdapter::start(const char* ifName)
{
- LOG_TRACE("");
+ LOG_TRACE("");
- if(!mSocket || !mReader) {
- init();
- }
+ if(!mSocket || !mReader) {
+ init();
+ }
- if(mSocket && mReader && mSocket->start(ifName) && mReader->start()) {
+ if(mSocket && mReader && mSocket->start(ifName) && mReader->start()) {
return true;
}
stop();
- return false;
+ return false;
}
void CANSocketAdapter::stop()
{
- LOG_TRACE("");
-
- if(mReader) {
- mReader->stop();
- delete mReader;
- mReader = 0;
- }
- if(mSocket) {
- mSocket->stop();
- delete mSocket;
- mSocket = 0;
- }
+ LOG_TRACE("");
+
+ if(mReader) {
+ mReader->stop();
+ delete mReader;
+ mReader = 0;
+ }
+ if(mSocket) {
+ mSocket->stop();
+ delete mSocket;
+ mSocket = 0;
+ }
}
bool CANSocketAdapter::sendFrame(const can_frame& frame)
{
- LOG_TRACE("");
+ LOG_TRACE("");
- if(mSocket) {
- int bytesWritten(0);
- return mSocket->write(frame, bytesWritten);
- }
- return false;
+ if(mSocket) {
+ CANFrameInfo message(frame);
+ return mSocket->write(message);
+ }
+ return false;
}
void CANSocketAdapter::init()
{
- if(!mSocket)
- mSocket = new CANSocket();
- if(!mReader)
- mReader = new CANSocketReader(mObserver, *mSocket);
+ if(!mSocket)
+ 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);
+ }
+ return false;
+}
+
+bool CANSocketAdapter::unregisterMessageForReceive(int canId)
+{
+ if(mSocket) {
+ return mSocket->unregisterMessageForReceive(canId);
+ }
+ return false;
+}
class CANSocketAdapter : public CANAdapter
{
public:
- /**
- * @param observer @link CANObserver Observer @endlink that will receives CAN bus frames
- */
- CANSocketAdapter(CANObserver& observer);
- virtual ~CANSocketAdapter();
+ /**
+ * @param observer @link CANObserver Observer @endlink that will receives CAN bus frames
+ */
+ CANSocketAdapter(CANObserver& observer);
+ virtual ~CANSocketAdapter();
- /**
- * Creates connection the specified network interface and starts listening on it.
- * @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 connection and exits listening thread.
- * @fn stop
- */
- virtual void stop();
- /**
- * Sends CAN frame over the socket CAN interface
- * @fn sendFrame
- * @param frame CAN frame to be sent
- * @return True if frame was sent
- */
- virtual bool sendFrame(const can_frame& frame);
+ /**
+ * Creates connection the specified network interface and starts listening on it.
+ * @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 connection and exits listening thread.
+ * @fn stop
+ */
+ virtual void stop();
+ /**
+ * Sends CAN frame over the socket CAN interface
+ * @fn sendFrame
+ * @param frame CAN frame to be sent
+ * @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);
+ /**
+ * 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);
protected:
- /**
- * Socket initialization and starts reading thread
- * @fn init
- * @protected
- */
- virtual void init();
+ /**
+ * Socket initialization and starts reading thread
+ * @fn init
+ * @protected
+ */
+ virtual void init();
private:
- /**
- * @link CANSocket CAN Socket wrapper @endlink instance reference
- * @property mSocket
- * @protected
- */
- CANSocket* mSocket;
- /**
- * @link CANSocketReader CANSocket reader @endlink instance reference
- * @property mReader
- * @protected
- */
- CANSocketReader* mReader;
+ /**
+ * @link CANSocket CAN Socket wrapper @endlink instance reference
+ * @property mSocket
+ * @protected
+ */
+ CANSocket* mSocket;
+ /**
+ * @link CANSocketReader CANSocket reader @endlink instance reference
+ * @property mReader
+ * @protected
+ */
+ CANSocketReader* mReader;
};
#endif // CANSOCKETADAPTER_H
--- /dev/null
+/*
+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);
+}
+
--- /dev/null
+/*
+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();
+
+ /**
+ * 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
+
+/** @} */
--- /dev/null
+/*
+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;
+}
--- /dev/null
+/*
+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();
+
+ /**
+ * 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
+
+/** @} */
/*
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
while(isRunnable()) {
- struct can_frame frame;
- int bytesRead;
+ CANFrameInfo message;
+ CANSocket::CANSocketReadSuccess success = mSocket.read(message);
- CANSocket::CANSocketReadSuccess success = mSocket.read(frame, bytesRead);
+ switch(success)
+ {
+ case CANSocket::READING_SUCCEEDED:
+ dispatchMessage(message);
+ break;
+
+ 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;
}
}
+
*/
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
--- /dev/null
+- get CycleTime for the message from *.dbc file
+
# Copyright (C) 2014 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
}
}
+ # select 'cycle' property
+ if (exists $msg_root{'cycle'}->{$msg_id}) {
+ $msg_copy{'cycle'} = $msg_root{'cycle'}->{$msg_id};
+ }
+ else {
+ $msg_copy{'cycle'} = 0;
+ }
+
# add message only if not empty
if (exists $msg_copy{'signals'}) {
push(@{$add_ecu{'messages'}}, \%msg_copy);
my @messages = @{$engineControlUnits[$ecui]{'messages'}};
for my $msgi (0..scalar(@messages)-1) {
$hexValue = '0x' . uc ( sprintf( "%x", $messages[$msgi]{'canId'} ) );
- $registerMessageText .= " registerMessage($hexValue, $messages[$msgi]{'canDlc'}";
+ $registerMessageText .= " registerMessage($hexValue, $messages[$msgi]{'canDlc'}, $messages[$msgi]{'cycle'}";
my @signals = @{$messages[$msgi]{'signals'}};
foreach my $signal ( @signals ) {
#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
MsgOutput: Line(s?) eofile
{
my %rcv_msg = ();
+ my %cycle_msg = ();
my %send_msg = ();
for my $msg (@receive) {
for my $signal (@{$m{'signals'}}) {
$rcv_msg{$m{'id'}}->{$signal} += 1;
}
+
+ if (exists $m{'cycle'}) {
+ $cycle_msg{$m{'id'}} = $m{'cycle'} / 1000.0;
+ }
+
}
my %picked = ();
$picked{'receive'} = \%rcv_msg;
+ $picked{'cycle'} = \%cycle_msg;
$picked{'send'} = \%send_msg;
return \%picked;
# select the message for sending
push(@send, $item[2]);
}
- | <error: Invalid msg format at $thisline!>
+ | <error: Invalid msg format at $thisline!>
-MessageSpec: MessageId '.' SignalId ';'
+MessageSpec: MessageId '.' SignalId MessageProperties ';'
{
my %msg;
$msg{'id'} = $item[1];
@{$msg{'signals'}} = $item[3];
+ for my $p (@{$item[4]}) {
+ $msg{lc($p->{'name'})} = $p->{'value'};
+ }
$return = \%msg;
}
- | MessageId '{' SignalId(s? /,/) '}'
+ | MessageId MessageProperties '{' SignalId(s? /,/) '}'
{
my %msg;
$msg{'id'} = $item[1];
- $msg{'signals'} = $item[3];
+ $msg{'signals'} = $item[4];
+ for my $p (@{$item[2]}) {
+ $msg{lc($p->{'name'})} = $p->{'value'};
+ }
$return = \%msg;
}
$return = $item[2];
}
+MessageProperties: MessageProperty(s?)
+
+MessageProperty: Identifier '=' Value
+ {
+ # property of the message
+ my %prop;
+ $prop{'name'} = $item[1];
+ $prop{'value'} = $item[3];
+ $return = \%prop;
+ }
+
SignalId: Identifier|'*'
Identifier: /[A-Za-z0-9_\-]+/
$return = $item[1];
}
+Value: Number | String
+
Number: Integer | RealNumber | Sign
Integer: /[-+]?[0-9]*/
DoubleQuotation: "\""
+String: /\"[^\"]*\"/
+
}
}
+void CANSignal::onTimeout(const can_frame& frame, std::function<void (AbstractPropertyType*)> changeCallback)
+{
+ //TODO: implement <no-value> handling
+/* if (ambProperty->toString() != "none") {
+ ambProperty->setValue("none");
+ if(changeCallback)
+ changeCallback(ambProperty.get());
+ }
+*/
+}
+
+
void CANSignal::setAmbProperty(std::shared_ptr<AbstractPropertyType> ambProperty)
{
this->ambProperty = ambProperty;
virtual GVariant *processSignal( const can_frame& frame ) = 0;
virtual void onMessage( const can_frame& frame, std::function<void (AbstractPropertyType*)> changeCallback );
+ virtual void onTimeout( const can_frame& frame, std::function<void (AbstractPropertyType*)> changeCallback );
virtual bool updateFrame( can_frame* frame );
public:
CANMessage() = delete;
- CANMessage(canid_t canId, __u8 canDlc) :
+ CANMessage(canid_t canId, __u8 canDlc, double CycleTime) :
canId(canId),
- canDlc(canDlc)
+ canDlc(canDlc),
+ CycleTime(CycleTime)
{
}
void onMessage(const can_frame& frame, std::function<void (AbstractPropertyType*)> changeCallback)
{
+ // sanity check
if(frame.can_dlc != canDlc || frame.can_id != canId)
return;
}
}
+ void onTimeout(const can_frame& frame, std::function<void (AbstractPropertyType*)> changeCallback)
+ {
+ // sanity check
+ if(frame.can_id != canId)
+ return;
+
+ for ( auto it = canSignals.begin(); it != canSignals.end(); ++it ) {
+ std::shared_ptr<CANSignal> signal(it->second);
+
+ if ( signal ) {
+ signal->onTimeout(frame, changeCallback);
+ }
+ }
+ }
+
void setupFrame(can_frame* frame)
{
if(!frame)
}
}
+ bool registerOnCANBus(CANBus& canBus)
+ {
+ return canBus.registerCyclicMessageForReceive(canId, 0, CycleTime);
+ }
+
private:
canid_t canId;
__u8 canDlc;
+ double CycleTime;
std::map< VehicleProperty::Property , std::shared_ptr<CANSignal> > canSignals;
};
#include <logger.h>
+#include <canbusimpl.h>
#include "ambtmpl_plugin.h"
#include "ambtmpl_cansignals.h"
AmbTmplPlugin::AmbTmplPlugin(AbstractRoutingEngine* re, const map<string, string>& config, AbstractSource& parent) :
AmbPluginImpl(re, config, parent),
interface(DEFAULT_CAN_IF_NAME),
- canBus(new CANBus(*static_cast<CANObserver*>(this))),
+ canBus(new CANBusImpl(*static_cast<CANObserver*>(this))),
announcementIntervalTimer(1000),
announcementCount(20)
{
void AmbTmplPlugin::init()
{
canBus->start(interface.c_str());
+
+ for(auto iter = messages.begin(); iter != messages.end(); iter++) {
+ if (!iter->second.registerOnCANBus(*canBus))
+ LOG_ERROR("Cannot register a message with can_id=0x" << std::hex << iter->first);
+ }
}
AsyncPropertyReply *AmbTmplPlugin::setProperty(const AsyncSetPropertyRequest& request )
message.onMessage( frame, [&re, &guid](AbstractPropertyType* value){re->updateProperty(value, guid);} );
}
+void AmbTmplPlugin::onTimeout(const can_frame& frame)
+{
+ auto messageIt = messages.find(frame.can_id);
+ if(messageIt == messages.end())
+ return;
+
+ CANMessage& message(messageIt->second);
+ const std::string guid = uuid();
+ AbstractRoutingEngine* re = routingEngine;
+ message.onTimeout( frame, [&re, &guid](AbstractPropertyType* value){re->updateProperty(value, guid);} );
+}
+
bool AmbTmplPlugin::sendValue(AbstractPropertyType* value)
{
if(!value)
onMessage(frame);
}
+void AmbTmplPlugin::timeoutDetected(const can_frame& frame)
+{
+ LOG_INFO("testPlugin::timeoutDetected()");
+ printFrame( frame );
+
+ onTimeout(frame);
+}
+
void AmbTmplPlugin::errorFrameReceived(const can_frame& frame)
{
LOG_INFO("AmbTmplPlugin::errorFrameReceived()");
* \return True if frame was sent
*/
bool sendExtendedFrame(const can_frame& frame);
+ /**
+ * 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.
protected:
- void registerMessage(const canid_t& canId, const __u8& canDlc)
+ void registerMessage(const canid_t& canId, const __u8& canDlc, const double CycleTime)
{
LOG_MESSAGE("registered message: " << canId);
}
template<typename Signal, typename... Rest>
- void registerMessage(const canid_t& canId, const __u8& canDlc, Signal* canSignal, Rest... rest)
+ void registerMessage(const canid_t& canId, const __u8& canDlc, const double CycleTime, Signal* canSignal, Rest... rest)
{
- static_assert(std::is_base_of<CANSignal, Signal>::value, "CANSignal has to be a base of Signal");
+ static_assert(std::is_base_of<CANSignal, Signal>::value, "CANSignal has to be a base class of Signal");
if(!canSignal)
return;
canSignal->setAmbProperty(prop);
auto messageIt = messages.find(canId);
if(messageIt == messages.end()){
- messageIt = messages.insert(make_pair(canId, CANMessage(canId, canDlc))).first;
+ messageIt = messages.insert(make_pair(canId, CANMessage(canId, canDlc, CycleTime))).first;
}
auto& message = messageIt->second;
message.addSignal(prop->name, std::shared_ptr<CANSignal>(canSignal));
propertyToMessage[prop->name] = &message;
}
- registerMessage(canId, canDlc, rest...);
+ registerMessage(canId, canDlc, CycleTime, rest...);
}
private:
void printFrame(const can_frame& frame) const;
void onMessage(const can_frame& frame);
+ void onTimeout(const can_frame& frame);
bool sendValue(AbstractPropertyType* value);
void registerMessages();