Add support for error, RTR, and EFF frames
Error frames, remote transmission request, and extended format frames
require some changes to the way that we set up our sockets.
Bug: 142655821
Bug: 144774939
Test: manual
Change-Id: I06212cb852d480c1c7093e8c509ca8aa9f85f81f
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
index 42d2e3c..86df5dc 100644
--- a/automotive/can/1.0/default/CanBus.cpp
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -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 {
@@ -220,6 +222,21 @@
}
/**
+ * 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.
*
* For details on the filters syntax, please see CanMessageFilter at
@@ -229,13 +246,16 @@
* \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;
@@ -247,11 +267,54 @@
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);
@@ -259,7 +322,9 @@
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";
@@ -274,15 +339,7 @@
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();