Loading automotive/can/1.0/default/CanBus.cpp +70 −13 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ #include <libnetdevice/can.h> #include <libnetdevice/libnetdevice.h> #include <linux/can.h> #include <linux/can/error.h> #include <linux/can/raw.h> namespace android { namespace hardware { Loading Loading @@ -219,6 +221,21 @@ bool CanBus::down() { return success; } /** * Helper function to determine if a flag meets the requirements of a * FilterFlag. See definition of FilterFlag in types.hal * * \param filterFlag FilterFlag object to match flag against * \param flag bool object from CanMessage object */ static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) { // TODO(b/144458917) add testing for this to VTS tests if (filterFlag == FilterFlag::DONT_CARE) return true; if (filterFlag == FilterFlag::REQUIRE) return flag; if (filterFlag == FilterFlag::EXCLUDE) return !flag; return false; } /** * Match the filter set against message id. * Loading @@ -229,13 +246,16 @@ bool CanBus::down() { * \param id Message id to filter * \return true if the message id matches the filter, false otherwise */ static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id) { static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id, bool isExtendedId, bool isRtr) { if (filter.size() == 0) return true; bool anyNonInvertedPresent = false; bool anyNonInvertedSatisfied = false; for (auto& rule : filter) { const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted; const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted && satisfiesFilterFlag(rule.rtr, isRtr) && satisfiesFilterFlag(rule.extendedFormat, isExtendedId); if (rule.inverted) { // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set. if (!satisfied) return false; Loading @@ -247,11 +267,54 @@ static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id) { return !anyNonInvertedPresent || anyNonInvertedSatisfied; } void CanBus::notifyErrorListeners(ErrorEvent err, bool isFatal) { std::lock_guard<std::mutex> lck(mErrListenersGuard); for (auto& listener : mErrListeners) { if (!listener->onError(err, isFatal).isOk()) { LOG(WARNING) << "Failed to notify listener about error"; } } } static ErrorEvent parseErrorFrame(const struct canfd_frame& frame) { // decode error frame (to a degree) if ((frame.can_id & (CAN_ERR_BUSERROR | CAN_ERR_BUSOFF)) != 0) { return ErrorEvent::BUS_ERROR; } if ((frame.data[1] & CAN_ERR_CRTL_TX_OVERFLOW) != 0) { return ErrorEvent::TX_OVERFLOW; } if ((frame.data[1] & CAN_ERR_CRTL_RX_OVERFLOW) != 0) { return ErrorEvent::RX_OVERFLOW; } if ((frame.data[2] & CAN_ERR_PROT_OVERLOAD) != 0) { return ErrorEvent::BUS_OVERLOAD; } if ((frame.can_id & CAN_ERR_PROT) != 0) { return ErrorEvent::MALFORMED_INPUT; } if ((frame.can_id & (CAN_ERR_CRTL | CAN_ERR_TRX | CAN_ERR_RESTARTED)) != 0) { // "controller restarted" constitutes a HARDWARE_ERROR imo return ErrorEvent::HARDWARE_ERROR; } return ErrorEvent::UNKNOWN_ERROR; } void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) { if ((frame.can_id & CAN_ERR_FLAG) != 0) { // error bit is set LOG(WARNING) << "CAN Error frame received"; // TODO(b/144458917) consider providing different values for isFatal, depending on error notifyErrorListeners(parseErrorFrame(frame), false); return; } CanMessage message = {}; message.id = frame.can_id; message.id = frame.can_id & CAN_EFF_MASK; // mask out eff/rtr/err flags message.payload = hidl_vec<uint8_t>(frame.data, frame.data + frame.len); message.timestamp = timestamp.count(); message.isExtendedId = (frame.can_id & CAN_EFF_FLAG) != 0; message.remoteTransmissionRequest = (frame.can_id & CAN_RTR_FLAG) != 0; if (UNLIKELY(kSuperVerbose)) { LOG(VERBOSE) << "Got message " << toString(message); Loading @@ -259,7 +322,9 @@ void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds ti std::lock_guard<std::mutex> lck(mMsgListenersGuard); for (auto& listener : mMsgListeners) { if (!match(listener.filter, message.id)) continue; if (!match(listener.filter, message.id, message.remoteTransmissionRequest, message.isExtendedId)) continue; if (!listener.callback->onReceive(message).isOk() && !listener.failedOnce) { listener.failedOnce = true; LOG(WARNING) << "Failed to notify listener about message"; Loading @@ -274,15 +339,7 @@ void CanBus::onError(int errnoVal) { mDownAfterUse = false; eventType = ErrorEvent::INTERFACE_DOWN; } { std::lock_guard<std::mutex> lck(mErrListenersGuard); for (auto& listener : mErrListeners) { if (!listener->onError(eventType, true).isOk()) { LOG(WARNING) << "Failed to notify listener about error"; } } } notifyErrorListeners(eventType, true); const auto errcb = mErrCb; if (errcb != nullptr) errcb(); Loading automotive/can/1.0/default/CanBus.h +2 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,8 @@ struct CanBus : public ICanBus { void clearMsgListeners(); void clearErrListeners(); void notifyErrorListeners(ErrorEvent err, bool isFatal); void onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp); void onError(int errnoVal); Loading automotive/can/1.0/default/libnetdevice/can.cpp +9 −0 Original line number Diff line number Diff line Loading @@ -24,12 +24,16 @@ #include <android-base/unique_fd.h> #include <linux/can.h> #include <linux/can/error.h> #include <linux/can/netlink.h> #include <linux/can/raw.h> namespace android { namespace netdevice { namespace can { static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK; base::unique_fd socket(const std::string& ifname) { struct sockaddr_can addr = {}; addr.can_family = AF_CAN; Loading @@ -45,6 +49,11 @@ base::unique_fd socket(const std::string& ifname) { return {}; } if (setsockopt(sock.get(), SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &kErrMask, sizeof(kErrMask)) < 0) { LOG(ERROR) << "Can't receive error frames, CAN setsockpt failed: " << strerror(errno); return {}; } if (0 != fcntl(sock.get(), F_SETFL, O_RDWR | O_NONBLOCK)) { LOG(ERROR) << "Couldn't put CAN socket in non-blocking mode"; return {}; Loading automotive/can/1.0/tools/canhaldump.cpp +6 −3 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <android/hidl/manager/1.2/IServiceManager.h> #include <hidl-utils/hidl-utils.h> #include <linux/can.h> #include <chrono> #include <iomanip> #include <iostream> Loading @@ -42,12 +43,14 @@ struct CanMessageListener : public V1_0::ICanMessageListener { CanMessageListener(std::string name) : name(name) {} virtual Return<void> onReceive(const V1_0::CanMessage& message) { std::cout << " " << name << " " << std::hex << std::uppercase << std::setw(3) int msgIdWidth = 3; if (message.isExtendedId) msgIdWidth = 8; std::cout << " " << name << " " << std::hex << std::uppercase << std::setw(msgIdWidth) << std::setfill('0') << message.id << std::setw(0); std::cout << " [" << message.payload.size() << "] "; if (message.remoteTransmissionRequest) { std::cout << " RTR"; std::cout << "remote request"; } else { std::cout << " [" << message.payload.size() << "] "; for (const auto byte : message.payload) { std::cout << " " << std::setfill('0') << std::setw(2) << unsigned(byte); } Loading automotive/can/1.0/types.hal +28 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,15 @@ struct CanMessage { * If this flag is set, payload must be empty. */ bool remoteTransmissionRequest; /** * Flag indicating if the message has an extended ID. * * Extended ID's are 29 bits long, as opposed to the standard 11 bit ID. * It can not simply be inferred from the length of the ID itself, as the * message ID 0x00000123 != message ID 0x123. */ bool isExtendedId; }; /** Loading @@ -70,11 +79,30 @@ struct CanMessage { * one) and all inverted filters must match. In other words: * - a single matching non-inverted filter makes the whole set matching; * - a single non-matching inverted filter makes the whole set non-matching. * * Additional less common options for filtering include: * rtr - Remote Transmission Request; another ECU requests DLC bytes of data on this message ID * extendedFormat - 29 bit message ID is used instead of 11 bits */ struct CanMessageFilter { CanMessageId id; uint32_t mask; bool inverted; FilterFlag rtr; FilterFlag extendedFormat; }; /** * Types of filter that can be applied to a CanMessageFilter */ enum FilterFlag : uint8_t { /** Default, FilterFlag doesn't effect what messages filtered */ DONT_CARE = 0, /** This FilterFlag MUST be present in received messages to pass though the filter */ REQUIRE, /** This FilterFlag must NOT be present in received messages to pass though the filter */ EXCLUDE, }; enum Result : uint8_t { Loading Loading
automotive/can/1.0/default/CanBus.cpp +70 −13 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ #include <libnetdevice/can.h> #include <libnetdevice/libnetdevice.h> #include <linux/can.h> #include <linux/can/error.h> #include <linux/can/raw.h> namespace android { namespace hardware { Loading Loading @@ -219,6 +221,21 @@ bool CanBus::down() { return success; } /** * Helper function to determine if a flag meets the requirements of a * FilterFlag. See definition of FilterFlag in types.hal * * \param filterFlag FilterFlag object to match flag against * \param flag bool object from CanMessage object */ static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) { // TODO(b/144458917) add testing for this to VTS tests if (filterFlag == FilterFlag::DONT_CARE) return true; if (filterFlag == FilterFlag::REQUIRE) return flag; if (filterFlag == FilterFlag::EXCLUDE) return !flag; return false; } /** * Match the filter set against message id. * Loading @@ -229,13 +246,16 @@ bool CanBus::down() { * \param id Message id to filter * \return true if the message id matches the filter, false otherwise */ static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id) { static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id, bool isExtendedId, bool isRtr) { if (filter.size() == 0) return true; bool anyNonInvertedPresent = false; bool anyNonInvertedSatisfied = false; for (auto& rule : filter) { const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted; const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted && satisfiesFilterFlag(rule.rtr, isRtr) && satisfiesFilterFlag(rule.extendedFormat, isExtendedId); if (rule.inverted) { // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set. if (!satisfied) return false; Loading @@ -247,11 +267,54 @@ static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id) { return !anyNonInvertedPresent || anyNonInvertedSatisfied; } void CanBus::notifyErrorListeners(ErrorEvent err, bool isFatal) { std::lock_guard<std::mutex> lck(mErrListenersGuard); for (auto& listener : mErrListeners) { if (!listener->onError(err, isFatal).isOk()) { LOG(WARNING) << "Failed to notify listener about error"; } } } static ErrorEvent parseErrorFrame(const struct canfd_frame& frame) { // decode error frame (to a degree) if ((frame.can_id & (CAN_ERR_BUSERROR | CAN_ERR_BUSOFF)) != 0) { return ErrorEvent::BUS_ERROR; } if ((frame.data[1] & CAN_ERR_CRTL_TX_OVERFLOW) != 0) { return ErrorEvent::TX_OVERFLOW; } if ((frame.data[1] & CAN_ERR_CRTL_RX_OVERFLOW) != 0) { return ErrorEvent::RX_OVERFLOW; } if ((frame.data[2] & CAN_ERR_PROT_OVERLOAD) != 0) { return ErrorEvent::BUS_OVERLOAD; } if ((frame.can_id & CAN_ERR_PROT) != 0) { return ErrorEvent::MALFORMED_INPUT; } if ((frame.can_id & (CAN_ERR_CRTL | CAN_ERR_TRX | CAN_ERR_RESTARTED)) != 0) { // "controller restarted" constitutes a HARDWARE_ERROR imo return ErrorEvent::HARDWARE_ERROR; } return ErrorEvent::UNKNOWN_ERROR; } void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) { if ((frame.can_id & CAN_ERR_FLAG) != 0) { // error bit is set LOG(WARNING) << "CAN Error frame received"; // TODO(b/144458917) consider providing different values for isFatal, depending on error notifyErrorListeners(parseErrorFrame(frame), false); return; } CanMessage message = {}; message.id = frame.can_id; message.id = frame.can_id & CAN_EFF_MASK; // mask out eff/rtr/err flags message.payload = hidl_vec<uint8_t>(frame.data, frame.data + frame.len); message.timestamp = timestamp.count(); message.isExtendedId = (frame.can_id & CAN_EFF_FLAG) != 0; message.remoteTransmissionRequest = (frame.can_id & CAN_RTR_FLAG) != 0; if (UNLIKELY(kSuperVerbose)) { LOG(VERBOSE) << "Got message " << toString(message); Loading @@ -259,7 +322,9 @@ void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds ti std::lock_guard<std::mutex> lck(mMsgListenersGuard); for (auto& listener : mMsgListeners) { if (!match(listener.filter, message.id)) continue; if (!match(listener.filter, message.id, message.remoteTransmissionRequest, message.isExtendedId)) continue; if (!listener.callback->onReceive(message).isOk() && !listener.failedOnce) { listener.failedOnce = true; LOG(WARNING) << "Failed to notify listener about message"; Loading @@ -274,15 +339,7 @@ void CanBus::onError(int errnoVal) { mDownAfterUse = false; eventType = ErrorEvent::INTERFACE_DOWN; } { std::lock_guard<std::mutex> lck(mErrListenersGuard); for (auto& listener : mErrListeners) { if (!listener->onError(eventType, true).isOk()) { LOG(WARNING) << "Failed to notify listener about error"; } } } notifyErrorListeners(eventType, true); const auto errcb = mErrCb; if (errcb != nullptr) errcb(); Loading
automotive/can/1.0/default/CanBus.h +2 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,8 @@ struct CanBus : public ICanBus { void clearMsgListeners(); void clearErrListeners(); void notifyErrorListeners(ErrorEvent err, bool isFatal); void onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp); void onError(int errnoVal); Loading
automotive/can/1.0/default/libnetdevice/can.cpp +9 −0 Original line number Diff line number Diff line Loading @@ -24,12 +24,16 @@ #include <android-base/unique_fd.h> #include <linux/can.h> #include <linux/can/error.h> #include <linux/can/netlink.h> #include <linux/can/raw.h> namespace android { namespace netdevice { namespace can { static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK; base::unique_fd socket(const std::string& ifname) { struct sockaddr_can addr = {}; addr.can_family = AF_CAN; Loading @@ -45,6 +49,11 @@ base::unique_fd socket(const std::string& ifname) { return {}; } if (setsockopt(sock.get(), SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &kErrMask, sizeof(kErrMask)) < 0) { LOG(ERROR) << "Can't receive error frames, CAN setsockpt failed: " << strerror(errno); return {}; } if (0 != fcntl(sock.get(), F_SETFL, O_RDWR | O_NONBLOCK)) { LOG(ERROR) << "Couldn't put CAN socket in non-blocking mode"; return {}; Loading
automotive/can/1.0/tools/canhaldump.cpp +6 −3 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <android/hidl/manager/1.2/IServiceManager.h> #include <hidl-utils/hidl-utils.h> #include <linux/can.h> #include <chrono> #include <iomanip> #include <iostream> Loading @@ -42,12 +43,14 @@ struct CanMessageListener : public V1_0::ICanMessageListener { CanMessageListener(std::string name) : name(name) {} virtual Return<void> onReceive(const V1_0::CanMessage& message) { std::cout << " " << name << " " << std::hex << std::uppercase << std::setw(3) int msgIdWidth = 3; if (message.isExtendedId) msgIdWidth = 8; std::cout << " " << name << " " << std::hex << std::uppercase << std::setw(msgIdWidth) << std::setfill('0') << message.id << std::setw(0); std::cout << " [" << message.payload.size() << "] "; if (message.remoteTransmissionRequest) { std::cout << " RTR"; std::cout << "remote request"; } else { std::cout << " [" << message.payload.size() << "] "; for (const auto byte : message.payload) { std::cout << " " << std::setfill('0') << std::setw(2) << unsigned(byte); } Loading
automotive/can/1.0/types.hal +28 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,15 @@ struct CanMessage { * If this flag is set, payload must be empty. */ bool remoteTransmissionRequest; /** * Flag indicating if the message has an extended ID. * * Extended ID's are 29 bits long, as opposed to the standard 11 bit ID. * It can not simply be inferred from the length of the ID itself, as the * message ID 0x00000123 != message ID 0x123. */ bool isExtendedId; }; /** Loading @@ -70,11 +79,30 @@ struct CanMessage { * one) and all inverted filters must match. In other words: * - a single matching non-inverted filter makes the whole set matching; * - a single non-matching inverted filter makes the whole set non-matching. * * Additional less common options for filtering include: * rtr - Remote Transmission Request; another ECU requests DLC bytes of data on this message ID * extendedFormat - 29 bit message ID is used instead of 11 bits */ struct CanMessageFilter { CanMessageId id; uint32_t mask; bool inverted; FilterFlag rtr; FilterFlag extendedFormat; }; /** * Types of filter that can be applied to a CanMessageFilter */ enum FilterFlag : uint8_t { /** Default, FilterFlag doesn't effect what messages filtered */ DONT_CARE = 0, /** This FilterFlag MUST be present in received messages to pass though the filter */ REQUIRE, /** This FilterFlag must NOT be present in received messages to pass though the filter */ EXCLUDE, }; enum Result : uint8_t { Loading