mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-07-03 07:10:35 +08:00
TransferReceiver optimization
This commit is contained in:
@@ -19,31 +19,41 @@ class UAVCAN_EXPORT TransferReceiver
|
||||
public:
|
||||
enum ResultCode { ResultNotComplete, ResultComplete, ResultSingleFrame };
|
||||
|
||||
static const uint32_t MinTransferIntervalUSec = 1 * 1000UL;
|
||||
static const uint32_t MaxTransferIntervalUSec = 10 * 1000 * 1000UL;
|
||||
static const uint32_t DefaultTransferIntervalUSec = 1 * 1000 * 1000UL;
|
||||
static const uint16_t MinTransferIntervalMSec = 1;
|
||||
static const uint16_t MaxTransferIntervalMSec = 0xFFFF;
|
||||
static const uint16_t DefaultTransferIntervalMSec = 1000;
|
||||
|
||||
static MonotonicDuration getDefaultTransferInterval()
|
||||
{
|
||||
return MonotonicDuration::fromUSec(DefaultTransferIntervalUSec);
|
||||
return MonotonicDuration::fromMSec(DefaultTransferIntervalMSec);
|
||||
}
|
||||
static MonotonicDuration getMinTransferInterval() { return MonotonicDuration::fromUSec(MinTransferIntervalUSec); }
|
||||
static MonotonicDuration getMaxTransferInterval() { return MonotonicDuration::fromUSec(MaxTransferIntervalUSec); }
|
||||
static MonotonicDuration getMinTransferInterval() { return MonotonicDuration::fromMSec(MinTransferIntervalMSec); }
|
||||
static MonotonicDuration getMaxTransferInterval() { return MonotonicDuration::fromMSec(MaxTransferIntervalMSec); }
|
||||
|
||||
private:
|
||||
enum TidRelation { TidSame, TidRepeat, TidFuture };
|
||||
static const uint8_t IfaceIndexNotSet = 0xFF;
|
||||
|
||||
enum { IfaceIndexNotSet = MaxCanIfaces };
|
||||
|
||||
enum { BufferWritePosMask = 4095 };
|
||||
enum { ErrorCntMask = 15 };
|
||||
enum { IfaceIndexMask = MaxCanIfaces };
|
||||
|
||||
MonotonicTime prev_transfer_ts_;
|
||||
MonotonicTime this_transfer_ts_;
|
||||
UtcTime first_frame_ts_;
|
||||
uint32_t transfer_interval_usec_;
|
||||
uint16_t transfer_interval_msec_;
|
||||
uint16_t this_transfer_crc_;
|
||||
uint16_t buffer_write_pos_;
|
||||
TransferID tid_;
|
||||
uint8_t iface_index_;
|
||||
uint8_t next_frame_index_;
|
||||
mutable uint8_t error_cnt_;
|
||||
|
||||
// 2 byte aligned bitfields:
|
||||
uint16_t buffer_write_pos_ : 12;
|
||||
mutable uint16_t error_cnt_ : 4;
|
||||
|
||||
TransferID tid_; // 1 byte field
|
||||
|
||||
// 1 byte aligned bitfields:
|
||||
uint8_t next_frame_index_ : 6;
|
||||
uint8_t iface_index_ : 2;
|
||||
|
||||
bool isInitialized() const { return iface_index_ != IfaceIndexNotSet; }
|
||||
|
||||
@@ -59,14 +69,18 @@ private:
|
||||
ResultCode receive(const RxFrame& frame, TransferBufferAccessor& tba);
|
||||
|
||||
public:
|
||||
TransferReceiver()
|
||||
: transfer_interval_usec_(DefaultTransferIntervalUSec)
|
||||
, this_transfer_crc_(0)
|
||||
, buffer_write_pos_(0)
|
||||
, iface_index_(IfaceIndexNotSet)
|
||||
, next_frame_index_(0)
|
||||
, error_cnt_(0)
|
||||
{ }
|
||||
TransferReceiver() :
|
||||
transfer_interval_msec_(DefaultTransferIntervalMSec),
|
||||
this_transfer_crc_(0),
|
||||
buffer_write_pos_(0),
|
||||
error_cnt_(0),
|
||||
next_frame_index_(0),
|
||||
iface_index_(IfaceIndexNotSet)
|
||||
{
|
||||
#if UAVCAN_DEBUG
|
||||
StaticAssert<sizeof(TransferReceiver) == 32>::check();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isTimedOut(MonotonicTime current_ts) const;
|
||||
|
||||
@@ -79,7 +93,7 @@ public:
|
||||
|
||||
uint16_t getLastTransferCrc() const { return this_transfer_crc_; }
|
||||
|
||||
MonotonicDuration getInterval() const { return MonotonicDuration::fromUSec(transfer_interval_usec_); }
|
||||
MonotonicDuration getInterval() const { return MonotonicDuration::fromMSec(transfer_interval_msec_); }
|
||||
};
|
||||
UAVCAN_PACKED_END
|
||||
|
||||
|
||||
@@ -11,21 +11,13 @@
|
||||
namespace uavcan
|
||||
{
|
||||
|
||||
const uint32_t TransferReceiver::MinTransferIntervalUSec;
|
||||
const uint32_t TransferReceiver::MaxTransferIntervalUSec;
|
||||
const uint32_t TransferReceiver::DefaultTransferIntervalUSec;
|
||||
const uint8_t TransferReceiver::IfaceIndexNotSet;
|
||||
const uint16_t TransferReceiver::MinTransferIntervalMSec;
|
||||
const uint16_t TransferReceiver::MaxTransferIntervalMSec;
|
||||
const uint16_t TransferReceiver::DefaultTransferIntervalMSec;
|
||||
|
||||
void TransferReceiver::registerError() const
|
||||
{
|
||||
if (error_cnt_ < 0xFF)
|
||||
{
|
||||
error_cnt_ = static_cast<uint8_t>(error_cnt_ + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
UAVCAN_ASSERT(0);
|
||||
}
|
||||
error_cnt_ = static_cast<uint8_t>(error_cnt_ + 1) & ErrorCntMask;
|
||||
}
|
||||
|
||||
TransferReceiver::TidRelation TransferReceiver::getTidRelation(const RxFrame& frame) const
|
||||
@@ -51,10 +43,10 @@ void TransferReceiver::updateTransferTimings()
|
||||
|
||||
if ((!prev_prev_ts.isZero()) && (!prev_transfer_ts_.isZero()) && (prev_transfer_ts_ >= prev_prev_ts))
|
||||
{
|
||||
uint64_t interval_usec = uint64_t((prev_transfer_ts_ - prev_prev_ts).toUSec());
|
||||
interval_usec = min(interval_usec, uint64_t(MaxTransferIntervalUSec));
|
||||
interval_usec = max(interval_usec, uint64_t(MinTransferIntervalUSec));
|
||||
transfer_interval_usec_ = static_cast<uint32_t>((uint64_t(transfer_interval_usec_) * 7 + interval_usec) / 8);
|
||||
uint64_t interval_msec = uint64_t((prev_transfer_ts_ - prev_prev_ts).toMSec());
|
||||
interval_msec = min(interval_msec, uint64_t(MaxTransferIntervalMSec));
|
||||
interval_msec = max(interval_msec, uint64_t(MinTransferIntervalMSec));
|
||||
transfer_interval_msec_ = static_cast<uint16_t>((uint64_t(transfer_interval_msec_) * 7U + interval_msec) / 8U);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +110,7 @@ bool TransferReceiver::writePayload(const RxFrame& frame, ITransferBuffer& buf)
|
||||
const bool success = res == static_cast<int>(effective_payload_len);
|
||||
if (success)
|
||||
{
|
||||
buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + effective_payload_len);
|
||||
buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + effective_payload_len) & BufferWritePosMask;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -128,7 +120,7 @@ bool TransferReceiver::writePayload(const RxFrame& frame, ITransferBuffer& buf)
|
||||
const bool success = res == static_cast<int>(payload_len);
|
||||
if (success)
|
||||
{
|
||||
buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + payload_len);
|
||||
buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + payload_len) & BufferWritePosMask;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -186,12 +178,12 @@ TransferReceiver::ResultCode TransferReceiver::receive(const RxFrame& frame, Tra
|
||||
|
||||
bool TransferReceiver::isTimedOut(MonotonicTime current_ts) const
|
||||
{
|
||||
static const int64_t INTERVAL_MULT = (1 << TransferID::BitLen) / 2 + 1;
|
||||
static const int64_t IntervalMult = (1 << TransferID::BitLen) / 2 + 1;
|
||||
if (current_ts <= this_transfer_ts_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (current_ts - this_transfer_ts_).toUSec() > (int64_t(transfer_interval_usec_) * INTERVAL_MULT);
|
||||
return (current_ts - this_transfer_ts_).toUSec() > (int64_t(transfer_interval_msec_) * 1000 * IntervalMult);
|
||||
}
|
||||
|
||||
TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame, TransferBufferAccessor& tba)
|
||||
@@ -209,7 +201,7 @@ TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame, Tr
|
||||
const bool first_fame = frame.isFirst();
|
||||
const TidRelation tid_rel = getTidRelation(frame);
|
||||
const bool iface_timed_out =
|
||||
(frame.getMonotonicTimestamp() - this_transfer_ts_).toUSec() > (int64_t(transfer_interval_usec_) * 2);
|
||||
(frame.getMonotonicTimestamp() - this_transfer_ts_).toUSec() > (int64_t(transfer_interval_msec_) * 1000 * 2);
|
||||
|
||||
// FSM, the hard way
|
||||
const bool need_restart =
|
||||
@@ -230,7 +222,7 @@ TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame, Tr
|
||||
int(not_initialized), int(iface_timed_out), int(receiver_timed_out), int(same_iface),
|
||||
int(first_fame), int(tid_rel), frame.toString().c_str());
|
||||
tba.remove();
|
||||
iface_index_ = frame.getIfaceIndex();
|
||||
iface_index_ = frame.getIfaceIndex() & IfaceIndexMask;
|
||||
tid_ = frame.getTransferID();
|
||||
next_frame_index_ = 0;
|
||||
buffer_write_pos_ = 0;
|
||||
|
||||
@@ -144,8 +144,8 @@ TEST(TransferReceiver, Basic)
|
||||
|
||||
ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "345678abcdefgh"));
|
||||
ASSERT_EQ(0x789A, rcv.getLastTransferCrc());
|
||||
ASSERT_GT(TransferReceiver::getDefaultTransferInterval(), rcv.getInterval());
|
||||
ASSERT_LT(TransferReceiver::getMinTransferInterval(), rcv.getInterval());
|
||||
ASSERT_GE(TransferReceiver::getDefaultTransferInterval(), rcv.getInterval());
|
||||
ASSERT_LE(TransferReceiver::getMinTransferInterval(), rcv.getInterval());
|
||||
ASSERT_EQ(1000, rcv.getLastTransferTimestampMonotonic().toUSec());
|
||||
ASSERT_FALSE(rcv.isTimedOut(tsMono(1000)));
|
||||
ASSERT_FALSE(rcv.isTimedOut(tsMono(5000)));
|
||||
@@ -174,33 +174,47 @@ TEST(TransferReceiver, Basic)
|
||||
CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "", 0, true, 4, 3600), bk));
|
||||
ASSERT_EQ(3600, rcv.getLastTransferTimestampMonotonic().toUSec());
|
||||
|
||||
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
|
||||
|
||||
/*
|
||||
* Timeouts
|
||||
*/
|
||||
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwe", 0, true, 1, 100000), bk)); // Wrong iface - ignored
|
||||
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwe", 0, true, 1, 5000), bk)); // Wrong iface - ignored
|
||||
CHECK_SINGLE_FRAME(rcv.addFrame(gen(1, "qwe", 0, true, 6, 1500000), bk)); // Accepted due to iface timeout
|
||||
ASSERT_EQ(1500000, rcv.getLastTransferTimestampMonotonic().toUSec());
|
||||
|
||||
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
|
||||
|
||||
CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "qwe", 0, true, 7, 1500100), bk)); // Ignored - old iface 0
|
||||
CHECK_SINGLE_FRAME(rcv.addFrame(gen(1, "qwe", 0, true, 7, 1500100), bk));
|
||||
ASSERT_EQ(1500100, rcv.getLastTransferTimestampMonotonic().toUSec());
|
||||
|
||||
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
|
||||
|
||||
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwe", 0, true, 7, 1500100), bk)); // Old TID
|
||||
CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "qwe", 0, true, 7, 100000000), bk)); // Accepted - global timeout
|
||||
ASSERT_EQ(100000000, rcv.getLastTransferTimestampMonotonic().toUSec());
|
||||
|
||||
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
|
||||
|
||||
CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "qwe", 0, true, 0, 100000100), bk));
|
||||
ASSERT_EQ(100000100, rcv.getLastTransferTimestampMonotonic().toUSec());
|
||||
|
||||
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
|
||||
|
||||
ASSERT_TRUE(rcv.isTimedOut(tsMono(900000000)));
|
||||
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "\x78\x56" "345678", 0, false, 0, 900000000), bk)); // Global timeout
|
||||
CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "12345678", 0, false, 0, 900000100), bk)); // Wrong iface
|
||||
CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "qwe", 1, true, 0, 900000200), bk)); // Wrong iface
|
||||
CHECK_COMPLETE( rcv.addFrame(gen(1, "qwe", 1, true, 0, 900000200), bk));
|
||||
|
||||
ASSERT_EQ(900000000, rcv.getLastTransferTimestampMonotonic().toUSec());
|
||||
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
|
||||
|
||||
ASSERT_FALSE(rcv.isTimedOut(tsMono(1000)));
|
||||
ASSERT_FALSE(rcv.isTimedOut(tsMono(900000200)));
|
||||
ASSERT_TRUE(rcv.isTimedOut(tsMono(1000 * 1000000)));
|
||||
ASSERT_FALSE(rcv.isTimedOut(tsMono(900000300)));
|
||||
ASSERT_TRUE(rcv.isTimedOut(tsMono(990000000)));
|
||||
|
||||
ASSERT_LT(TransferReceiver::getDefaultTransferInterval(), rcv.getInterval());
|
||||
ASSERT_LE(TransferReceiver::getMinTransferInterval(), rcv.getInterval());
|
||||
ASSERT_GE(TransferReceiver::getMaxTransferInterval(), rcv.getInterval());
|
||||
|
||||
Reference in New Issue
Block a user