diff --git a/libuavcan/include/uavcan/transport/transfer_receiver.hpp b/libuavcan/include/uavcan/transport/transfer_receiver.hpp index aec331fc8a..124983dbf3 100644 --- a/libuavcan/include/uavcan/transport/transfer_receiver.hpp +++ b/libuavcan/include/uavcan/transport/transfer_receiver.hpp @@ -41,9 +41,12 @@ private: TransferID tid_; uint8_t iface_index_; uint8_t next_frame_index_; + uint8_t error_cnt_; bool isInitialized() const { return iface_index_ != IfaceIndexNotSet; } + void registerError(); + TidRelation getTidRelation(const RxFrame& frame) const; void updateTransferTimings(); @@ -60,12 +63,15 @@ public: , buffer_write_pos_(0) , iface_index_(IfaceIndexNotSet) , next_frame_index_(0) + , error_cnt_(0) { } bool isTimedOut(MonotonicTime current_ts) const; ResultCode addFrame(const RxFrame& frame, TransferBufferAccessor& tba); + uint8_t yieldErrorCount(); + MonotonicTime getLastTransferTimestampMonotonic() const { return prev_transfer_ts_; } UtcTime getLastTransferTimestampUtc() const { return first_frame_ts_; } diff --git a/libuavcan/src/transport/transfer_listener.cpp b/libuavcan/src/transport/transfer_listener.cpp index 95f937cbe3..15cf399ab7 100644 --- a/libuavcan/src/transport/transfer_listener.cpp +++ b/libuavcan/src/transport/transfer_listener.cpp @@ -114,7 +114,6 @@ void TransferListenerBase::handleReception(TransferReceiver& receiver, const RxF case TransferReceiver::ResultNotComplete: { return; - } case TransferReceiver::ResultSingleFrame: { @@ -122,7 +121,6 @@ void TransferListenerBase::handleReception(TransferReceiver& receiver, const RxF handleIncomingTransfer(it); return; } - case TransferReceiver::ResultComplete: { const ITransferBuffer* tbb = tba.access(); @@ -131,20 +129,17 @@ void TransferListenerBase::handleReception(TransferReceiver& receiver, const RxF UAVCAN_TRACE("TransferListenerBase", "Buffer access failure, last frame: %s", frame.toString().c_str()); return; } - if (!checkPayloadCrc(receiver.getLastTransferCrc(), *tbb)) { UAVCAN_TRACE("TransferListenerBase", "CRC error, last frame: %s", frame.toString().c_str()); return; } - MultiFrameIncomingTransfer it(receiver.getLastTransferTimestampMonotonic(), receiver.getLastTransferTimestampUtc(), frame, tba); handleIncomingTransfer(it); it.release(); return; } - default: { assert(0); diff --git a/libuavcan/src/transport/transfer_receiver.cpp b/libuavcan/src/transport/transfer_receiver.cpp index c665d61623..ad022690aa 100644 --- a/libuavcan/src/transport/transfer_receiver.cpp +++ b/libuavcan/src/transport/transfer_receiver.cpp @@ -17,6 +17,18 @@ const uint32_t TransferReceiver::MinTransferIntervalUSec; const uint32_t TransferReceiver::MaxTransferIntervalUSec; const uint32_t TransferReceiver::DefaultTransferIntervalUSec; +void TransferReceiver::registerError() +{ + if (error_cnt_ < 0xFF) + { + error_cnt_ += 1; + } + else + { + assert(0); + } +} + TransferReceiver::TidRelation TransferReceiver::getTidRelation(const RxFrame& frame) const { const int distance = tid_.computeForwardDistance(frame.getTransferID()); @@ -151,6 +163,7 @@ TransferReceiver::ResultCode TransferReceiver::receive(const RxFrame& frame, Tra { UAVCAN_TRACE("TransferReceiver", "Failed to access the buffer, %s", frame.toString().c_str()); prepareForNextTransfer(); + registerError(); return ResultNotComplete; } if (!writePayload(frame, *buf)) @@ -158,6 +171,7 @@ TransferReceiver::ResultCode TransferReceiver::receive(const RxFrame& frame, Tra UAVCAN_TRACE("TransferReceiver", "Payload write failed, %s", frame.toString().c_str()); tba.remove(); prepareForNextTransfer(); + registerError(); return ResultNotComplete; } next_frame_index_++; @@ -207,6 +221,11 @@ TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame, Tr if (need_restart) { + const bool error = !not_initialized && !receiver_timed_out; + if (error) + { + registerError(); + } UAVCAN_TRACE("TransferReceiver", "Restart [not_inited=%i, iface_timeout=%i, recv_timeout=%i, same_iface=%i, first_frame=%i, tid_rel=%i], %s", int(not_initialized), int(iface_timed_out), int(receiver_timed_out), int(same_iface), @@ -226,10 +245,18 @@ TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame, Tr if (!validate(frame)) { + registerError(); return ResultNotComplete; } return receive(frame, tba); } +uint8_t TransferReceiver::yieldErrorCount() +{ + const uint8_t ret = error_cnt_; + error_cnt_ = 0; + return ret; +} + } diff --git a/libuavcan/test/transport/transfer_receiver.cpp b/libuavcan/test/transport/transfer_receiver.cpp index 7ede87f30d..a7cfdcfd37 100644 --- a/libuavcan/test/transport/transfer_receiver.cpp +++ b/libuavcan/test/transport/transfer_receiver.cpp @@ -245,6 +245,9 @@ TEST(TransferReceiver, OutOfBufferSpace_32bytes) ASSERT_EQ(100000000, rcv.getLastTransferTimestampMonotonic().toUSec()); // Timestamp will not be overriden ASSERT_FALSE(bufmgr.access(gen.bufmgr_key)); // Buffer should be removed + + ASSERT_EQ(1, rcv.yieldErrorCount()); + ASSERT_EQ(0, rcv.yieldErrorCount()); } @@ -266,6 +269,9 @@ TEST(TransferReceiver, UnterminatedTransfer) ASSERT_EQ(1000, rcv.getLastTransferTimestampMonotonic().toUSec()); ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), std::string(content, 2))); ASSERT_EQ(0x3231, rcv.getLastTransferCrc()); + + ASSERT_EQ(1, rcv.yieldErrorCount()); + ASSERT_EQ(0, rcv.yieldErrorCount()); } @@ -287,6 +293,9 @@ TEST(TransferReceiver, OutOfOrderFrames) ASSERT_EQ(100000000, rcv.getLastTransferTimestampMonotonic().toUSec()); ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "345678qwertyuiabcd")); ASSERT_EQ(0x3231, rcv.getLastTransferCrc()); + + ASSERT_EQ(3, rcv.yieldErrorCount()); + ASSERT_EQ(0, rcv.yieldErrorCount()); } @@ -359,6 +368,9 @@ TEST(TransferReceiver, Restart) ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "3456781234567812345678")); ASSERT_EQ(0x3231, rcv.getLastTransferCrc()); + + ASSERT_EQ(3, rcv.yieldErrorCount()); + ASSERT_EQ(0, rcv.yieldErrorCount()); }