From 71b62ede9c47806439590bc295f9f2f6cec0428b Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Fri, 3 Jul 2015 10:41:39 +0300 Subject: [PATCH] CanIOFlagAbortOnError - automatically enforced by TransferSender if the node is in passive mode --- libuavcan/include/uavcan/driver/can.hpp | 10 +++++++++- libuavcan/include/uavcan/transport/transfer_sender.hpp | 4 ++++ libuavcan/src/transport/uc_transfer_sender.cpp | 7 ++++++- libuavcan/test/transport/can/can.hpp | 8 +++++++- libuavcan/test/transport/transfer_sender.cpp | 4 ++++ 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/libuavcan/include/uavcan/driver/can.hpp b/libuavcan/include/uavcan/driver/can.hpp index 64fab68599..3635499d64 100644 --- a/libuavcan/include/uavcan/driver/can.hpp +++ b/libuavcan/include/uavcan/driver/can.hpp @@ -114,9 +114,17 @@ struct UAVCAN_EXPORT CanSelectMasks /** * Special IO flags. + * + * @ref CanIOFlagLoopback - Send the frame back to RX with true TX timestamps. + * + * @ref CanIOFlagAbortOnError - Abort transmission on first bus error instead of retransmitting. This does not + * affect the case of arbitration loss, in which case the retransmission will work + * as usual. This flag is used together with anonymous messages which allows to + * implement CSMA bus access. Read the spec for details. */ typedef uint16_t CanIOFlags; -static const CanIOFlags CanIOFlagLoopback = 1; ///< Send the frame back to RX with true TX timestamps +static const CanIOFlags CanIOFlagLoopback = 1; +static const CanIOFlags CanIOFlagAbortOnError = 2; /** * Single non-blocking CAN interface. diff --git a/libuavcan/include/uavcan/transport/transfer_sender.hpp b/libuavcan/include/uavcan/transport/transfer_sender.hpp index 4bf673b58d..462e51ed39 100644 --- a/libuavcan/include/uavcan/transport/transfer_sender.hpp +++ b/libuavcan/include/uavcan/transport/transfer_sender.hpp @@ -100,6 +100,10 @@ public: /** * Send with automatic Transfer ID. + * + * Note that as long as the local node operates in passive mode, the + * flag @ref CanIOFlagAbortOnError will be set implicitly for all outgoing frames. + * * TID is managed by OutgoingTransferRegistry. */ int send(const uint8_t* payload, unsigned payload_len, MonotonicTime tx_deadline, diff --git a/libuavcan/src/transport/uc_transfer_sender.cpp b/libuavcan/src/transport/uc_transfer_sender.cpp index 198559680d..caec587996 100644 --- a/libuavcan/src/transport/uc_transfer_sender.cpp +++ b/libuavcan/src/transport/uc_transfer_sender.cpp @@ -69,10 +69,15 @@ int TransferSender::send(const uint8_t* payload, unsigned payload_len, Monotonic frame.setEndOfTransfer(true); UAVCAN_ASSERT(frame.isStartOfTransfer() && frame.isEndOfTransfer() && !frame.getToggle()); - return dispatcher_.send(frame, tx_deadline, blocking_deadline, qos_, flags_, iface_mask_); + const CanIOFlags flags = frame.getSrcNodeID().isUnicast() ? flags_ : (flags_ | CanIOFlagAbortOnError); + + return dispatcher_.send(frame, tx_deadline, blocking_deadline, qos_, flags, iface_mask_); } else // Multi Frame Transfer { + UAVCAN_ASSERT(!dispatcher_.isPassiveMode()); + UAVCAN_ASSERT(frame.getSrcNodeID().isUnicast()); + int offset = 0; { TransferCRC crc = crc_base_; diff --git a/libuavcan/test/transport/can/can.hpp b/libuavcan/test/transport/can/can.hpp index e0bf535d4e..d191064ff6 100644 --- a/libuavcan/test/transport/can/can.hpp +++ b/libuavcan/test/transport/can/can.hpp @@ -23,21 +23,25 @@ public: uavcan::CanFrame frame; uavcan::MonotonicTime time; uavcan::UtcTime time_utc; + uavcan::CanIOFlags flags; FrameWithTime(const uavcan::CanFrame& frame, uavcan::MonotonicTime time) : frame(frame) , time(time) + , flags(0) { } FrameWithTime(const uavcan::CanFrame& frame, uavcan::MonotonicTime time, uavcan::UtcTime time_utc) : frame(frame) , time(time) , time_utc(time_utc) + , flags(0) { } FrameWithTime(const uavcan::CanFrame& frame, uint64_t time_usec) : frame(frame) , time(uavcan::MonotonicTime::fromUSec(time_usec)) + , flags(0) { } }; @@ -115,6 +119,7 @@ public: return 0; } tx.push(FrameWithTime(frame, tx_deadline)); + tx.back().flags = flags; if (flags & uavcan::CanIOFlagLoopback) { loopback.push(FrameWithTime(frame, iclock.getMonotonic())); @@ -126,7 +131,6 @@ public: uavcan::UtcTime& out_ts_utc, uavcan::CanIOFlags& out_flags) { assert(this); - out_flags = uavcan::CanIOFlags(); if (loopback.empty()) { EXPECT_TRUE(rx.size()); // Shall never be called when not readable @@ -143,6 +147,7 @@ public: out_frame = frame.frame; out_ts_monotonic = frame.time; out_ts_utc = frame.time_utc; + out_flags = frame.flags; } else { @@ -151,6 +156,7 @@ public: loopback.pop(); out_frame = frame.frame; out_ts_monotonic = frame.time; + out_ts_utc = frame.time_utc; } // Let's just all pretend that this code is autogenerated, instead of being carefully designed by a human. diff --git a/libuavcan/test/transport/transfer_sender.cpp b/libuavcan/test/transport/transfer_sender.cpp index 3e007801ec..f1cbd55df4 100644 --- a/libuavcan/test/transport/transfer_sender.cpp +++ b/libuavcan/test/transport/transfer_sender.cpp @@ -257,6 +257,10 @@ TEST(TransferSender, PassiveMode) sender.send(Payload, sizeof(Payload), tsMono(1000), uavcan::MonotonicTime(), uavcan::TransferTypeServiceRequest, uavcan::NodeID(42))); + // Making sure the abort flag is set + ASSERT_FALSE(driver.ifaces.at(0).tx.empty()); + ASSERT_EQ(uavcan::CanIOFlagAbortOnError, driver.ifaces.at(0).tx.front().flags); + EXPECT_EQ(0, dispatcher.getTransferPerfCounter().getErrorCount()); EXPECT_EQ(1, dispatcher.getTransferPerfCounter().getTxTransferCount()); EXPECT_EQ(0, dispatcher.getTransferPerfCounter().getRxTransferCount());