Implement CAN_BCM support (SocketCAN)
authorPetr Nechaev <petr.nechaev@cogentembedded.com>
Thu, 12 Mar 2015 22:17:04 +0000 (01:17 +0300)
committerPetr Nechaev <petr.nechaev@cogentembedded.com>
Mon, 30 Mar 2015 11:52:19 +0000 (14:52 +0300)
CAN_BCM is better suited for handling cyclic messages than CAN_RAW
because all timeouts and intervals are handled by kernel code.

Made it a default choice.

32 files changed:
TODO
lib/timestamp.cpp
lib/timestamp.h
plugins/cangenplugin/cangenplugin.cpp
plugins/cangenplugin/cangenplugin.h
plugins/cansimplugin/cansimplugin.cpp
plugins/cansimplugin/cansimplugin.h
plugins/common/CMakeLists.txt
plugins/common/canadapter.h
plugins/common/canbus.h
plugins/common/canbusimpl.cpp
plugins/common/canbusimpl.h
plugins/common/canframeinfo.h [new file with mode: 0644]
plugins/common/canobserver.h
plugins/common/cansocket.cpp
plugins/common/cansocket.h
plugins/common/cansocketadapter.cpp
plugins/common/cansocketadapter.h
plugins/common/cansocketbcm.cpp [new file with mode: 0644]
plugins/common/cansocketbcm.h [new file with mode: 0644]
plugins/common/cansocketraw.cpp [new file with mode: 0644]
plugins/common/cansocketraw.h [new file with mode: 0644]
plugins/common/cansocketreader.cpp
plugins/common/cansocketreader.h
tools/AmbSignalMapper/TODO [new file with mode: 0644]
tools/AmbSignalMapper/bin/dbc2amb
tools/AmbSignalMapper/lib/Intel/IviPoc/AmbPluginGenerator.pm
tools/AmbSignalMapper/lib/Intel/IviPoc/MsgGrammar
tools/AmbSignalMapper/lib/Intel/IviPoc/templates/ambtmpl_cansignal.cpp
tools/AmbSignalMapper/lib/Intel/IviPoc/templates/ambtmpl_cansignal.h
tools/AmbSignalMapper/lib/Intel/IviPoc/templates/ambtmpl_plugin.cpp
tools/AmbSignalMapper/lib/Intel/IviPoc/templates/ambtmpl_plugin.h

diff --git a/TODO b/TODO
index 31fb46b..a9ee8d7 100644 (file)
--- a/TODO
+++ b/TODO
@@ -4,4 +4,6 @@
 - 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
 
index 33e0182..7b1f593 100644 (file)
@@ -1,5 +1,6 @@
 #include "timestamp.h"
 
+#include <math.h>
 #include <time.h>
 #include <iostream>
 #include <chrono>
@@ -36,6 +37,11 @@ double amb::Timestamp::epochTime(double time)
        return startTimeEpoch + time;
 }
 
+double amb::Timestamp::currentTime(double time)
+{
+    return time - startTimeEpoch;
+}
+
 double amb::Timestamp::epochTime()
 {
        auto tm = std::chrono::system_clock::now();
@@ -52,3 +58,13 @@ amb::Timestamp* amb::Timestamp::instance()
 
        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) };
+}
index 5300488..0495235 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _TIMESTAMP_H___
 #define _TIMESTAMP_H___
 
+#include <time.h>
 
 namespace amb {
 
@@ -13,11 +14,15 @@ protected:
 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();
 
index 73d3253..93d2e71 100644 (file)
@@ -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
+}
index 09e9c4e..163cde0 100644 (file)
@@ -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.
index b609b3f..c8b9921 100644 (file)
@@ -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
+}
index 40b55d5..43b1f79 100644 (file)
@@ -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.
index c57c8b3..6c2bbaa 100644 (file)
@@ -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})
 
index fa78c10..0f3a8d5 100644 (file)
@@ -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;
+    /**
+     * 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:
     /**
index 319c856..0627de6 100644 (file)
@@ -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);
+    }
+    /**
+    * 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
index 993e4a0..b0a0fa7 100644 (file)
@@ -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;
-}
index e2ccdd9..f8dcd20 100644 (file)
@@ -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);
+    /**
+     * 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:
     /**
diff --git a/plugins/common/canframeinfo.h b/plugins/common/canframeinfo.h
new file mode 100644 (file)
index 0000000..6469a67
--- /dev/null
@@ -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
+
+/** @} */
+
index 0518bd4..876998e 100644 (file)
@@ -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.
 *
@@ -36,46 +39,52 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 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 */
 
 };
 
index b59c6bd..0b5ca9c 100644 (file)
@@ -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;
 }
index f6eaa50..44dd8f4 100644 (file)
@@ -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;
+     * 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
index c2e660b..df92bb7 100644 (file)
@@ -21,72 +21,89 @@ 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
 
 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;
+}
index 350563c..3c8e46f 100644 (file)
@@ -38,53 +38,69 @@ class CANSocketReader;
 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
diff --git a/plugins/common/cansocketbcm.cpp b/plugins/common/cansocketbcm.cpp
new file mode 100644 (file)
index 0000000..d923ce3
--- /dev/null
@@ -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 (file)
index 0000000..fe7e9ad
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+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
+
+/** @} */
diff --git a/plugins/common/cansocketraw.cpp b/plugins/common/cansocketraw.cpp
new file mode 100644 (file)
index 0000000..2ab5d4f
--- /dev/null
@@ -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, &timestamp, 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 &timestamp)
+{
+    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 (file)
index 0000000..932813f
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+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 &timestamp);
+
+private:
+    /**
+    * Socket file descriptor.
+    * @property mSocket
+    * @private
+    */
+    int mSocket;
+    /**
+    * Data structure describing a polling request.
+    * @property mPoll
+    * @private
+    */
+    struct pollfd mPoll;
+};
+
+#endif // CANSOCKETRAW_H
+
+/** @} */
index b73c6fb..e5bb42e 100644 (file)
@@ -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
@@ -59,41 +61,71 @@ void CANSocketReader::run()
 
     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;
     }
 }
+
index 623430a..62d7ead 100644 (file)
@@ -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/tools/AmbSignalMapper/TODO b/tools/AmbSignalMapper/TODO
new file mode 100644 (file)
index 0000000..3504b81
--- /dev/null
@@ -0,0 +1,2 @@
+- get CycleTime for the message from *.dbc file
+
index 65aa24b..a6b0bbc 100755 (executable)
@@ -2,6 +2,7 @@
 
 #      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
@@ -194,6 +195,14 @@ sub selectSignals {
                                                }
                                        }
 
+                                       # 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);
index a7b977e..e208c84 100644 (file)
@@ -263,7 +263,7 @@ sub generateCppImplTypes {
             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 ) {
index 8ecadf2..eaf3051 100644 (file)
@@ -1,4 +1,5 @@
 #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
@@ -22,6 +23,7 @@
 MsgOutput: Line(s?) eofile
     {
        my %rcv_msg = ();
+       my %cycle_msg = ();
        my %send_msg = ();
 
        for my $msg (@receive) {
@@ -30,10 +32,16 @@ MsgOutput: Line(s?) eofile
            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;
@@ -53,20 +61,26 @@ Line: CommentPrefix /.*\n/
           # 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;
        }
 
@@ -81,6 +95,17 @@ MessageId: Identifier
          $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_\-]+/
@@ -88,6 +113,8 @@ Identifier: /[A-Za-z0-9_\-]+/
             $return = $item[1];
         }
 
+Value: Number | String
+
 Number: Integer | RealNumber | Sign
 
 Integer: /[-+]?[0-9]*/
@@ -98,3 +125,5 @@ CommentPrefix: '#'
 
 DoubleQuotation: "\""
 
+String: /\"[^\"]*\"/ 
+
index b44f36e..cd4b6d3 100644 (file)
@@ -84,6 +84,18 @@ void CANSignal::onMessage(const can_frame& frame, std::function<void (AbstractPr
     }
 }
 
+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;
index 2ea563f..1201c3f 100644 (file)
@@ -97,6 +97,7 @@ public:
     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 );
 
@@ -145,9 +146,10 @@ class CANMessage
 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)
     {
     }
 
@@ -159,6 +161,7 @@ public:
 
     void onMessage(const can_frame& frame, std::function<void (AbstractPropertyType*)> changeCallback)
     {
+        // sanity check
         if(frame.can_dlc != canDlc || frame.can_id != canId)
             return;
 
@@ -171,6 +174,21 @@ public:
         }
     }
 
+    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)
@@ -185,9 +203,15 @@ public:
         }
     }
 
+    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;
 };
 
index 6f6c889..3353c70 100644 (file)
@@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
 #include <logger.h>
 
+#include <canbusimpl.h>
 #include "ambtmpl_plugin.h"
 #include "ambtmpl_cansignals.h"
 
@@ -84,7 +85,7 @@ gboolean AmbTmplPlugin::timeoutCallback(gpointer data)
 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)
 {
@@ -125,6 +126,11 @@ AmbTmplPlugin::~AmbTmplPlugin()
 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 )
@@ -176,6 +182,18 @@ void AmbTmplPlugin::onMessage(const can_frame& frame)
     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)
@@ -214,6 +232,14 @@ void AmbTmplPlugin::extendedFrameReceived(const can_frame& frame)
     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()");
index af59323..2ce3b58 100644 (file)
@@ -117,6 +117,12 @@ public:
     * \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.
@@ -135,15 +141,15 @@ public:
 
 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;
@@ -153,20 +159,21 @@ protected:
             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();