mirror of
https://github.com/espressif/openthread.git
synced 2026-07-27 22:37:45 +00:00
[timestamp] add IsValid() and comparison operator overloads (#10325)
This commit enhances the handling of `Timestamp`. Methods `SetToInvalid()` and `IsValid()` are added to the `Timestamp` class. The value where all bytes are set to `0xff` is used to represent an invalid `Timestamp`. This corresponds to max seconds, max ticks with the authoritative (`U`) flag set. This helps simplify `DatasetManager`, where we need to track local and network Active/Pending timestamps, which may not be present. These are now represented by setting the `Timestamp` to the invalid value (replacing the earlier model where a `Timestamp` pointer was used with `nullptr` representing an invalid timestamp). This allows us to simplify the `Timestamp::Compare()` method, now getting two `Timestamp &` instead of `Timestamp *`. With this, we can also define comparison operator overloads to compare two `Timestamp` objects, which helps make the code simpler and more readable.
This commit is contained in:
@@ -839,12 +839,12 @@ template <> inline const uint32_t &Dataset::Info::Get<Dataset::kChannelMask>(voi
|
||||
|
||||
template <> inline void Dataset::Info::Get<Dataset::kActiveTimestamp>(Timestamp &aTimestamp) const
|
||||
{
|
||||
aTimestamp.SetFromTimestamp(mActiveTimestamp);
|
||||
aTimestamp.SetFrom(mActiveTimestamp);
|
||||
}
|
||||
|
||||
template <> inline void Dataset::Info::Get<Dataset::kPendingTimestamp>(Timestamp &aTimestamp) const
|
||||
{
|
||||
aTimestamp.SetFromTimestamp(mPendingTimestamp);
|
||||
aTimestamp.SetFrom(mPendingTimestamp);
|
||||
}
|
||||
|
||||
template <> inline void Dataset::Info::Set<Dataset::kActiveTimestamp>(const Timestamp &aTimestamp)
|
||||
|
||||
@@ -60,19 +60,12 @@ DatasetManager::DatasetManager(Instance &aInstance, Type aType, Timer::Handler a
|
||||
: InstanceLocator(aInstance)
|
||||
, mType(aType)
|
||||
, mLocalSaved(false)
|
||||
, mLocalTimestampValid(false)
|
||||
, mNetworkTimestampValid(false)
|
||||
, mMgmtPending(false)
|
||||
, mLocalUpdateTime(0)
|
||||
, mTimer(aInstance, aTimerHandler)
|
||||
{
|
||||
mLocalTimestamp.Clear();
|
||||
mNetworkTimestamp.Clear();
|
||||
}
|
||||
|
||||
const Timestamp *DatasetManager::GetTimestamp(void) const
|
||||
{
|
||||
return mNetworkTimestampValid ? &mNetworkTimestamp : nullptr;
|
||||
mLocalTimestamp.SetToInvalid();
|
||||
mNetworkTimestamp.SetToInvalid();
|
||||
}
|
||||
|
||||
Error DatasetManager::Restore(void)
|
||||
@@ -94,8 +87,8 @@ void DatasetManager::Restore(const Dataset &aDataset)
|
||||
{
|
||||
mTimer.Stop();
|
||||
|
||||
mNetworkTimestampValid = false;
|
||||
mLocalTimestampValid = false;
|
||||
mNetworkTimestamp.SetToInvalid();
|
||||
mLocalTimestamp.SetToInvalid();
|
||||
|
||||
VerifyOrExit(aDataset.GetLength() != 0);
|
||||
|
||||
@@ -103,9 +96,7 @@ void DatasetManager::Restore(const Dataset &aDataset)
|
||||
|
||||
if (aDataset.ReadTimestamp(mType, mLocalTimestamp) == kErrorNone)
|
||||
{
|
||||
mLocalTimestampValid = true;
|
||||
mNetworkTimestampValid = true;
|
||||
mNetworkTimestamp = mLocalTimestamp;
|
||||
mNetworkTimestamp = mLocalTimestamp;
|
||||
}
|
||||
|
||||
if (IsActiveDataset())
|
||||
@@ -256,12 +247,10 @@ exit:
|
||||
|
||||
void DatasetManager::Clear(void)
|
||||
{
|
||||
mNetworkTimestamp.Clear();
|
||||
mLocalTimestamp.Clear();
|
||||
mNetworkTimestamp.SetToInvalid();
|
||||
mLocalTimestamp.SetToInvalid();
|
||||
|
||||
mNetworkTimestampValid = false;
|
||||
mLocalTimestampValid = false;
|
||||
mLocalSaved = false;
|
||||
mLocalSaved = false;
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
|
||||
DestroySecurelyStoredKeys();
|
||||
@@ -299,17 +288,12 @@ Error DatasetManager::Save(const Dataset &aDataset, bool aAllowOlderTimestamp)
|
||||
Error error = kErrorNone;
|
||||
int compare;
|
||||
|
||||
if (aDataset.ReadTimestamp(mType, mNetworkTimestamp) == kErrorNone)
|
||||
if ((aDataset.ReadTimestamp(mType, mNetworkTimestamp) == kErrorNone) && IsActiveDataset())
|
||||
{
|
||||
mNetworkTimestampValid = true;
|
||||
|
||||
if (IsActiveDataset())
|
||||
{
|
||||
SuccessOrExit(error = ApplyConfiguration(aDataset));
|
||||
}
|
||||
SuccessOrExit(error = ApplyConfiguration(aDataset));
|
||||
}
|
||||
|
||||
compare = Timestamp::Compare(GetTimestamp(), GetLocalTimestamp());
|
||||
compare = Timestamp::Compare(mNetworkTimestamp, mLocalTimestamp);
|
||||
|
||||
if ((compare > 0) || aAllowOlderTimestamp)
|
||||
{
|
||||
@@ -412,8 +396,12 @@ void DatasetManager::LocalSave(const Dataset &aDataset)
|
||||
LogInfo("%s dataset set", Dataset::TypeToString(mType));
|
||||
}
|
||||
|
||||
mLocalTimestampValid = (aDataset.ReadTimestamp(mType, mLocalTimestamp) == kErrorNone);
|
||||
mLocalUpdateTime = TimerMilli::GetNow();
|
||||
if (aDataset.ReadTimestamp(mType, mLocalTimestamp) != kErrorNone)
|
||||
{
|
||||
mLocalTimestamp.SetToInvalid();
|
||||
}
|
||||
|
||||
mLocalUpdateTime = TimerMilli::GetNow();
|
||||
|
||||
if (IsPendingDataset())
|
||||
{
|
||||
@@ -469,7 +457,7 @@ void DatasetManager::SyncLocalWithLeader(const Dataset &aDataset)
|
||||
VerifyOrExit(!mMgmtPending, error = kErrorBusy);
|
||||
VerifyOrExit(Get<Mle::MleRouter>().IsChild() || Get<Mle::MleRouter>().IsRouter(), error = kErrorInvalidState);
|
||||
|
||||
VerifyOrExit(Timestamp::Compare(GetTimestamp(), GetLocalTimestamp()) < 0, error = kErrorAlready);
|
||||
VerifyOrExit(mNetworkTimestamp < mLocalTimestamp, error = kErrorAlready);
|
||||
|
||||
if (IsActiveDataset())
|
||||
{
|
||||
@@ -478,8 +466,7 @@ void DatasetManager::SyncLocalWithLeader(const Dataset &aDataset)
|
||||
|
||||
IgnoreError(Get<PendingDatasetManager>().Read(pendingDataset));
|
||||
|
||||
if ((pendingDataset.Read<ActiveTimestampTlv>(timestamp) == kErrorNone) &&
|
||||
(Timestamp::Compare(×tamp, GetLocalTimestamp()) == 0))
|
||||
if ((pendingDataset.Read<ActiveTimestampTlv>(timestamp) == kErrorNone) && (timestamp == mLocalTimestamp))
|
||||
{
|
||||
// Stop registration attempts during dataset transition
|
||||
ExitNow(error = kErrorInvalidState);
|
||||
@@ -830,9 +817,9 @@ ActiveDatasetManager::ActiveDatasetManager(Instance &aInstance)
|
||||
{
|
||||
}
|
||||
|
||||
bool ActiveDatasetManager::IsPartiallyComplete(void) const { return mLocalSaved && !mNetworkTimestampValid; }
|
||||
bool ActiveDatasetManager::IsPartiallyComplete(void) const { return mLocalSaved && !mNetworkTimestamp.IsValid(); }
|
||||
|
||||
bool ActiveDatasetManager::IsComplete(void) const { return mLocalSaved && mNetworkTimestampValid; }
|
||||
bool ActiveDatasetManager::IsComplete(void) const { return mLocalSaved && mNetworkTimestamp.IsValid(); }
|
||||
|
||||
bool ActiveDatasetManager::IsCommissioned(void) const
|
||||
{
|
||||
@@ -914,7 +901,7 @@ void PendingDatasetManager::HandleDelayTimer(void)
|
||||
|
||||
SuccessOrExit(dataset.Read<ActiveTimestampTlv>(activeTimestamp));
|
||||
|
||||
if (Timestamp::Compare(&activeTimestamp, Get<ActiveDatasetManager>().GetTimestamp()) > 0)
|
||||
if (activeTimestamp > Get<ActiveDatasetManager>().GetTimestamp())
|
||||
{
|
||||
shouldReplaceActive = true;
|
||||
}
|
||||
|
||||
@@ -66,12 +66,12 @@ public:
|
||||
typedef otDatasetMgmtSetCallback MgmtSetCallback;
|
||||
|
||||
/**
|
||||
* Returns a pointer to the Timestamp.
|
||||
* Returns the network Timestamp.
|
||||
*
|
||||
* @returns A pointer to the Timestamp.
|
||||
* @returns The network Timestamp.
|
||||
*
|
||||
*/
|
||||
const Timestamp *GetTimestamp(void) const;
|
||||
const Timestamp &GetTimestamp(void) const { return mNetworkTimestamp; }
|
||||
|
||||
/**
|
||||
* Clears the Operational Dataset.
|
||||
@@ -316,8 +316,6 @@ private:
|
||||
const otMessageInfo *aMessageInfo,
|
||||
Error aError);
|
||||
|
||||
const Timestamp *GetLocalTimestamp(void) const { return mLocalTimestampValid ? &mLocalTimestamp : nullptr; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
|
||||
void MoveKeysToSecureStorage(Dataset &aDataset) const;
|
||||
void DestroySecurelyStoredKeys(void) const;
|
||||
@@ -334,8 +332,6 @@ private:
|
||||
|
||||
Type mType;
|
||||
bool mLocalSaved : 1;
|
||||
bool mLocalTimestampValid : 1;
|
||||
bool mNetworkTimestampValid : 1;
|
||||
bool mMgmtPending : 1;
|
||||
TimeMilli mLocalUpdateTime;
|
||||
Timestamp mLocalTimestamp;
|
||||
|
||||
@@ -110,11 +110,11 @@ Error DatasetManager::ProcessSetOrReplaceRequest(MgmtCommand aCommand,
|
||||
Timestamp pendingTimestamp;
|
||||
|
||||
SuccessOrExit(dataset.Read<PendingTimestampTlv>(pendingTimestamp));
|
||||
VerifyOrExit(Timestamp::Compare(&pendingTimestamp, GetLocalTimestamp()) > 0);
|
||||
VerifyOrExit(pendingTimestamp > mLocalTimestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(Timestamp::Compare(&activeTimestamp, GetLocalTimestamp()) > 0);
|
||||
VerifyOrExit(activeTimestamp > mLocalTimestamp);
|
||||
}
|
||||
|
||||
// Determine whether the new Dataset affects connectivity
|
||||
@@ -155,9 +155,7 @@ Error DatasetManager::ProcessSetOrReplaceRequest(MgmtCommand aCommand,
|
||||
|
||||
if (IsPendingDataset() && !aInfo.mAffectsNetworkKey)
|
||||
{
|
||||
const Timestamp *localActiveTimestamp = Get<ActiveDatasetManager>().GetTimestamp();
|
||||
|
||||
VerifyOrExit(Timestamp::Compare(&activeTimestamp, localActiveTimestamp) > 0);
|
||||
VerifyOrExit(activeTimestamp > Get<ActiveDatasetManager>().GetTimestamp());
|
||||
}
|
||||
|
||||
// Determine whether the request is from commissioner.
|
||||
@@ -299,7 +297,7 @@ Error ActiveDatasetManager::GenerateLocal(void)
|
||||
Dataset dataset;
|
||||
|
||||
VerifyOrExit(Get<Mle::MleRouter>().IsAttached(), error = kErrorInvalidState);
|
||||
VerifyOrExit(!mLocalTimestampValid, error = kErrorAlready);
|
||||
VerifyOrExit(!mLocalTimestamp.IsValid(), error = kErrorAlready);
|
||||
|
||||
IgnoreError(Read(dataset));
|
||||
|
||||
|
||||
@@ -88,11 +88,9 @@ Error DatasetUpdater::RequestUpdate(Dataset &aDataset, UpdaterCallback aCallback
|
||||
activeTimestamp.AdvanceRandomTicks();
|
||||
SuccessOrExit(error = aDataset.Write<ActiveTimestampTlv>(activeTimestamp));
|
||||
|
||||
if (Get<PendingDatasetManager>().GetTimestamp() != nullptr)
|
||||
{
|
||||
pendingTimestamp = *Get<PendingDatasetManager>().GetTimestamp();
|
||||
}
|
||||
else
|
||||
pendingTimestamp = Get<PendingDatasetManager>().GetTimestamp();
|
||||
|
||||
if (!pendingTimestamp.IsValid())
|
||||
{
|
||||
pendingTimestamp.Clear();
|
||||
pendingTimestamp.SetSeconds(1);
|
||||
@@ -204,7 +202,7 @@ void DatasetUpdater::HandleDatasetChanged(Dataset::Type aType)
|
||||
SuccessOrExit(newDataset.ReadTimestamp(aType, newTimestamp));
|
||||
SuccessOrExit(requestedDataset.ReadTimestamp(aType, requestedTimestamp));
|
||||
|
||||
if (Timestamp::Compare(newTimestamp, requestedTimestamp) >= 0)
|
||||
if (newTimestamp >= requestedTimestamp)
|
||||
{
|
||||
Finish(kErrorAlready);
|
||||
}
|
||||
|
||||
@@ -35,54 +35,78 @@
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/num_utils.hpp"
|
||||
#include "common/numeric_limits.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace MeshCoP {
|
||||
|
||||
void Timestamp::ConvertTo(otTimestamp &aTimestamp) const
|
||||
void Timestamp::ConvertTo(Info &aInfo) const
|
||||
{
|
||||
aTimestamp.mSeconds = GetSeconds();
|
||||
aTimestamp.mTicks = GetTicks();
|
||||
aTimestamp.mAuthoritative = GetAuthoritative();
|
||||
aInfo.mSeconds = GetSeconds();
|
||||
aInfo.mTicks = GetTicks();
|
||||
aInfo.mAuthoritative = GetAuthoritative();
|
||||
}
|
||||
|
||||
void Timestamp::SetFromTimestamp(const otTimestamp &aTimestamp)
|
||||
void Timestamp::SetFrom(const Info &aInfo)
|
||||
{
|
||||
SetSeconds(aTimestamp.mSeconds);
|
||||
SetTicks(aTimestamp.mTicks);
|
||||
SetAuthoritative(aTimestamp.mAuthoritative);
|
||||
SetSeconds(aInfo.mSeconds);
|
||||
SetTicks(aInfo.mTicks);
|
||||
SetAuthoritative(aInfo.mAuthoritative);
|
||||
}
|
||||
|
||||
int Timestamp::Compare(const Timestamp *aFirst, const Timestamp *aSecond)
|
||||
void Timestamp::SetToInvalid(void)
|
||||
{
|
||||
int rval;
|
||||
mSeconds16 = NumericLimits<uint16_t>::kMax;
|
||||
mSeconds32 = NumericLimits<uint32_t>::kMax;
|
||||
mTicksAndAuthFlag = NumericLimits<uint16_t>::kMax;
|
||||
}
|
||||
|
||||
if (aFirst == nullptr)
|
||||
{
|
||||
// When `aFirst` is null but `aSecond is not, we return -1,
|
||||
// (indicate `aFirst (null) < aSecond (non-null)`).
|
||||
ExitNow(rval = (aSecond == nullptr) ? 0 : -1);
|
||||
}
|
||||
bool Timestamp::IsValid(void) const
|
||||
{
|
||||
return (mSeconds16 != NumericLimits<uint16_t>::kMax) || (mSeconds32 != NumericLimits<uint32_t>::kMax) ||
|
||||
(mTicksAndAuthFlag != NumericLimits<uint16_t>::kMax);
|
||||
}
|
||||
|
||||
if (aSecond == nullptr)
|
||||
{
|
||||
// When `aFirst` is not null, but `aSecond` is, we return +1,
|
||||
// (indicate `aFirst (non-null) > aSecond (null)`).
|
||||
ExitNow(rval = 1);
|
||||
}
|
||||
void Timestamp::SetToOrphanAnnounce(void)
|
||||
{
|
||||
mSeconds16 = 0;
|
||||
mSeconds32 = 0;
|
||||
SetTicksAndAuthFlag(kAuthoritativeFlag);
|
||||
}
|
||||
|
||||
// Both are non-null.
|
||||
bool Timestamp::IsOrphanAnnounce(void) const
|
||||
{
|
||||
return (mSeconds16 == 0) && (mSeconds32 == 0) && (GetTicksAndAuthFlag() == kAuthoritativeFlag);
|
||||
}
|
||||
|
||||
rval = Compare(*aFirst, *aSecond);
|
||||
uint64_t Timestamp::GetSeconds(void) const
|
||||
{
|
||||
return (static_cast<uint64_t>(BigEndian::HostSwap16(mSeconds16)) << 32) + BigEndian::HostSwap32(mSeconds32);
|
||||
}
|
||||
|
||||
exit:
|
||||
return rval;
|
||||
void Timestamp::SetSeconds(uint64_t aSeconds)
|
||||
{
|
||||
mSeconds16 = BigEndian::HostSwap16(static_cast<uint16_t>(aSeconds >> 32));
|
||||
mSeconds32 = BigEndian::HostSwap32(static_cast<uint32_t>(aSeconds & 0xffffffff));
|
||||
}
|
||||
|
||||
void Timestamp::SetTicks(uint16_t aTicks)
|
||||
{
|
||||
SetTicksAndAuthFlag((GetTicksAndAuthFlag() & ~kTicksMask) | ((aTicks << kTicksOffset) & kTicksMask));
|
||||
}
|
||||
|
||||
void Timestamp::SetAuthoritative(bool aAuthoritative)
|
||||
{
|
||||
SetTicksAndAuthFlag((GetTicksAndAuthFlag() & kTicksMask) | (aAuthoritative ? kAuthoritativeFlag : 0));
|
||||
}
|
||||
|
||||
int Timestamp::Compare(const Timestamp &aFirst, const Timestamp &aSecond)
|
||||
{
|
||||
int rval;
|
||||
|
||||
rval = ThreeWayCompare(aFirst.IsValid(), aSecond.IsValid());
|
||||
VerifyOrExit(rval == 0);
|
||||
|
||||
rval = ThreeWayCompare(aFirst.GetSeconds(), aSecond.GetSeconds());
|
||||
VerifyOrExit(rval == 0);
|
||||
|
||||
|
||||
@@ -58,16 +58,58 @@ class Timestamp : public Clearable<Timestamp>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Converts the timestamp to `otTimestamp`.
|
||||
* Represents timestamp components.
|
||||
*
|
||||
*/
|
||||
void ConvertTo(otTimestamp &aTimestamp) const;
|
||||
typedef otTimestamp Info;
|
||||
|
||||
/**
|
||||
* Sets the timestamp from `otTimestamp`.
|
||||
* Copies the `Timestamp` information to `Timestamp::Info` data structure.
|
||||
*
|
||||
* @param[out] aInfo A reference to a `Timestamp::Info` to populate.
|
||||
*
|
||||
*/
|
||||
void SetFromTimestamp(const otTimestamp &aTimestamp);
|
||||
void ConvertTo(Info &aInfo) const;
|
||||
|
||||
/**
|
||||
* Sets the `Timestamp` from a given component-wise `Info` structure.
|
||||
*
|
||||
* @param[in] aInfo A `Timestamp::Info` structure.
|
||||
*
|
||||
*/
|
||||
void SetFrom(const Info &aInfo);
|
||||
|
||||
/**
|
||||
* Sets the `Timestamp` to invalid value.
|
||||
*
|
||||
*/
|
||||
void SetToInvalid(void);
|
||||
|
||||
/**
|
||||
* Indicates whether or not the `Timestamp` is valid.
|
||||
*
|
||||
* @retval TRUE The timestamp is valid.
|
||||
* @retval FALSE The timestamp is not valid.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const;
|
||||
|
||||
/**
|
||||
* Sets the `Timestamp` to value used in MLE Orphan Announce messages.
|
||||
*
|
||||
* Second and ticks fields are set to zero with Authoritative flag set.
|
||||
*
|
||||
*/
|
||||
void SetToOrphanAnnounce(void);
|
||||
|
||||
/**
|
||||
* Indicates whether the timestamp indicates an MLE Orphan Announce message.
|
||||
*
|
||||
* @retval TRUE The timestamp indicates an Orphan Announce message.
|
||||
* @retval FALSE The timestamp does not indicate an Orphan Announce message.
|
||||
*
|
||||
*/
|
||||
bool IsOrphanAnnounce(void) const;
|
||||
|
||||
/**
|
||||
* Returns the Seconds value.
|
||||
@@ -75,10 +117,7 @@ public:
|
||||
* @returns The Seconds value.
|
||||
*
|
||||
*/
|
||||
uint64_t GetSeconds(void) const
|
||||
{
|
||||
return (static_cast<uint64_t>(BigEndian::HostSwap16(mSeconds16)) << 32) + BigEndian::HostSwap32(mSeconds32);
|
||||
}
|
||||
uint64_t GetSeconds(void) const;
|
||||
|
||||
/**
|
||||
* Sets the Seconds value.
|
||||
@@ -86,11 +125,7 @@ public:
|
||||
* @param[in] aSeconds The Seconds value.
|
||||
*
|
||||
*/
|
||||
void SetSeconds(uint64_t aSeconds)
|
||||
{
|
||||
mSeconds16 = BigEndian::HostSwap16(static_cast<uint16_t>(aSeconds >> 32));
|
||||
mSeconds32 = BigEndian::HostSwap32(static_cast<uint32_t>(aSeconds & 0xffffffff));
|
||||
}
|
||||
void SetSeconds(uint64_t aSeconds);
|
||||
|
||||
/**
|
||||
* Returns the Ticks value.
|
||||
@@ -98,7 +133,7 @@ public:
|
||||
* @returns The Ticks value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetTicks(void) const { return BigEndian::HostSwap16(mTicks) >> kTicksOffset; }
|
||||
uint16_t GetTicks(void) const { return GetTicksAndAuthFlag() >> kTicksOffset; }
|
||||
|
||||
/**
|
||||
* Sets the Ticks value.
|
||||
@@ -106,11 +141,7 @@ public:
|
||||
* @param[in] aTicks The Ticks value.
|
||||
*
|
||||
*/
|
||||
void SetTicks(uint16_t aTicks)
|
||||
{
|
||||
mTicks = BigEndian::HostSwap16((BigEndian::HostSwap16(mTicks) & ~kTicksMask) |
|
||||
((aTicks << kTicksOffset) & kTicksMask));
|
||||
}
|
||||
void SetTicks(uint16_t aTicks);
|
||||
|
||||
/**
|
||||
* Returns the Authoritative value.
|
||||
@@ -118,7 +149,7 @@ public:
|
||||
* @returns The Authoritative value.
|
||||
*
|
||||
*/
|
||||
bool GetAuthoritative(void) const { return (BigEndian::HostSwap16(mTicks) & kAuthoritativeMask) != 0; }
|
||||
bool GetAuthoritative(void) const { return (GetTicksAndAuthFlag() & kAuthoritativeFlag) != 0; }
|
||||
|
||||
/**
|
||||
* Sets the Authoritative value.
|
||||
@@ -126,11 +157,7 @@ public:
|
||||
* @param[in] aAuthoritative The Authoritative value.
|
||||
*
|
||||
*/
|
||||
void SetAuthoritative(bool aAuthoritative)
|
||||
{
|
||||
mTicks = BigEndian::HostSwap16((BigEndian::HostSwap16(mTicks) & kTicksMask) |
|
||||
((aAuthoritative << kAuthoritativeOffset) & kAuthoritativeMask));
|
||||
}
|
||||
void SetAuthoritative(bool aAuthoritative);
|
||||
|
||||
/**
|
||||
* Increments the timestamp by a random number of ticks [0, 32767].
|
||||
@@ -138,33 +165,11 @@ public:
|
||||
*/
|
||||
void AdvanceRandomTicks(void);
|
||||
|
||||
/**
|
||||
* Indicates whether the timestamp indicates an MLE Orphan Announce message.
|
||||
*
|
||||
* @retval TRUE The timestamp indicates an Orphan Announce message.
|
||||
* @retval FALSE If the timestamp does not indicate an Orphan Announce message.
|
||||
*
|
||||
*/
|
||||
bool IsOrphanTimestamp(void) const { return GetSeconds() == 0 && GetTicks() == 0 && GetAuthoritative(); }
|
||||
|
||||
/**
|
||||
* Compares two timestamps.
|
||||
*
|
||||
* Either one or both @p aFirst or @p aSecond can be `nullptr`. A non-null timestamp is considered greater than
|
||||
* a null one. If both are null, they are considered as equal.
|
||||
*
|
||||
* @param[in] aFirst A pointer to the first timestamp to compare (can be nullptr).
|
||||
* @param[in] aSecond A pointer to the second timestamp to compare (can be nullptr).
|
||||
*
|
||||
* @retval -1 if @p aFirst is less than @p aSecond (`aFirst < aSecond`).
|
||||
* @retval 0 if @p aFirst is equal to @p aSecond (`aFirst == aSecond`).
|
||||
* @retval 1 if @p aFirst is greater than @p aSecond (`aFirst > aSecond`).
|
||||
*
|
||||
*/
|
||||
static int Compare(const Timestamp *aFirst, const Timestamp *aSecond);
|
||||
|
||||
/**
|
||||
* Compares two timestamps.
|
||||
* Either one or both @p aFirst or @p aSecond can be invalid. A valid timestamp is considered greater than an
|
||||
* invalid one. If both are invalid, they are considered as equal.
|
||||
*
|
||||
* @param[in] aFirst A reference to the first timestamp to compare.
|
||||
* @param[in] aSecond A reference to the second timestamp to compare.
|
||||
@@ -176,16 +181,27 @@ public:
|
||||
*/
|
||||
static int Compare(const Timestamp &aFirst, const Timestamp &aSecond);
|
||||
|
||||
// Comparison operator overloads for two `Timestamp` instances.
|
||||
bool operator==(const Timestamp &aOther) const { return Compare(*this, aOther) == 0; }
|
||||
bool operator!=(const Timestamp &aOther) const { return Compare(*this, aOther) != 0; }
|
||||
bool operator>(const Timestamp &aOther) const { return Compare(*this, aOther) > 0; }
|
||||
bool operator<(const Timestamp &aOther) const { return Compare(*this, aOther) < 0; }
|
||||
bool operator>=(const Timestamp &aOther) const { return Compare(*this, aOther) >= 0; }
|
||||
bool operator<=(const Timestamp &aOther) const { return Compare(*this, aOther) <= 0; }
|
||||
|
||||
private:
|
||||
uint16_t GetTicksAndAuthFlag(void) const { return BigEndian::HostSwap16(mTicksAndAuthFlag); }
|
||||
void SetTicksAndAuthFlag(uint16_t aValue) { mTicksAndAuthFlag = BigEndian::HostSwap16(aValue); }
|
||||
|
||||
static constexpr uint8_t kTicksOffset = 1;
|
||||
static constexpr uint16_t kTicksMask = 0x7fff << kTicksOffset;
|
||||
static constexpr uint8_t kAuthoritativeOffset = 0;
|
||||
static constexpr uint16_t kAuthoritativeMask = 1 << kAuthoritativeOffset;
|
||||
static constexpr uint16_t kAuthoritativeFlag = 1 << kAuthoritativeOffset;
|
||||
static constexpr uint16_t kMaxTicks = 0x7fff;
|
||||
|
||||
uint16_t mSeconds16; // bits 32-47
|
||||
uint32_t mSeconds32; // bits 0-31
|
||||
uint16_t mTicks;
|
||||
uint16_t mTicksAndAuthFlag;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
} // namespace MeshCoP
|
||||
|
||||
+19
-23
@@ -2227,8 +2227,7 @@ void Mle::SendAnnounce(uint8_t aChannel, const Ip6::Address &aDestination, Annou
|
||||
switch (aMode)
|
||||
{
|
||||
case kOrphanAnnounce:
|
||||
activeTimestamp.Clear();
|
||||
activeTimestamp.SetAuthoritative(true);
|
||||
activeTimestamp.SetToOrphanAnnounce();
|
||||
SuccessOrExit(error = Tlv::Append<ActiveTimestampTlv>(*message, activeTimestamp));
|
||||
break;
|
||||
|
||||
@@ -2938,7 +2937,7 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (MeshCoP::Timestamp::Compare(&activeTimestamp, Get<MeshCoP::ActiveDatasetManager>().GetTimestamp()) != 0)
|
||||
if (activeTimestamp != Get<MeshCoP::ActiveDatasetManager>().GetTimestamp())
|
||||
{
|
||||
// Send an MLE Data Request if the received timestamp
|
||||
// mismatches the local value and the message does not
|
||||
@@ -2966,7 +2965,7 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (MeshCoP::Timestamp::Compare(&pendingTimestamp, Get<MeshCoP::PendingDatasetManager>().GetTimestamp()) != 0)
|
||||
if (pendingTimestamp != Get<MeshCoP::PendingDatasetManager>().GetTimestamp())
|
||||
{
|
||||
VerifyOrExit(aRxInfo.mMessage.ContainsTlv(Tlv::kPendingDataset), dataRequest = true);
|
||||
savePendingDataset = true;
|
||||
@@ -3672,15 +3671,14 @@ exit:
|
||||
|
||||
void Mle::HandleAnnounce(RxInfo &aRxInfo)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
ChannelTlvValue channelTlvValue;
|
||||
MeshCoP::Timestamp timestamp;
|
||||
const MeshCoP::Timestamp *localTimestamp;
|
||||
uint8_t channel;
|
||||
uint16_t panId;
|
||||
bool isFromOrphan;
|
||||
bool channelAndPanIdMatch;
|
||||
int timestampCompare;
|
||||
Error error = kErrorNone;
|
||||
ChannelTlvValue channelTlvValue;
|
||||
MeshCoP::Timestamp timestamp;
|
||||
uint8_t channel;
|
||||
uint16_t panId;
|
||||
bool isFromOrphan;
|
||||
bool channelAndPanIdMatch;
|
||||
int timestampCompare;
|
||||
|
||||
Log(kMessageReceive, kTypeAnnounce, aRxInfo.mMessageInfo.GetPeerAddr());
|
||||
|
||||
@@ -3692,10 +3690,8 @@ void Mle::HandleAnnounce(RxInfo &aRxInfo)
|
||||
|
||||
aRxInfo.mClass = RxInfo::kPeerMessage;
|
||||
|
||||
localTimestamp = Get<MeshCoP::ActiveDatasetManager>().GetTimestamp();
|
||||
|
||||
isFromOrphan = timestamp.IsOrphanTimestamp();
|
||||
timestampCompare = MeshCoP::Timestamp::Compare(×tamp, localTimestamp);
|
||||
isFromOrphan = timestamp.IsOrphanAnnounce();
|
||||
timestampCompare = MeshCoP::Timestamp::Compare(timestamp, Get<MeshCoP::ActiveDatasetManager>().GetTimestamp());
|
||||
channelAndPanIdMatch = (channel == Get<Mac::Mac>().GetPanChannel()) && (panId == Get<Mac::Mac>().GetPanId());
|
||||
|
||||
if (isFromOrphan || (timestampCompare < 0))
|
||||
@@ -4732,10 +4728,10 @@ Error Mle::TxMessage::AppendXtalAccuracyTlv(void)
|
||||
Error Mle::TxMessage::AppendActiveTimestampTlv(void)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
const MeshCoP::Timestamp *timestamp = Get<MeshCoP::ActiveDatasetManager>().GetTimestamp();
|
||||
const MeshCoP::Timestamp ×tamp = Get<MeshCoP::ActiveDatasetManager>().GetTimestamp();
|
||||
|
||||
VerifyOrExit(timestamp != nullptr);
|
||||
error = Tlv::Append<ActiveTimestampTlv>(*this, *timestamp);
|
||||
VerifyOrExit(timestamp.IsValid());
|
||||
error = Tlv::Append<ActiveTimestampTlv>(*this, timestamp);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -4744,10 +4740,10 @@ exit:
|
||||
Error Mle::TxMessage::AppendPendingTimestampTlv(void)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
const MeshCoP::Timestamp *timestamp = Get<MeshCoP::PendingDatasetManager>().GetTimestamp();
|
||||
const MeshCoP::Timestamp ×tamp = Get<MeshCoP::PendingDatasetManager>().GetTimestamp();
|
||||
|
||||
VerifyOrExit(timestamp != nullptr && timestamp->GetSeconds() != 0);
|
||||
error = Tlv::Append<PendingTimestampTlv>(*this, *timestamp);
|
||||
VerifyOrExit(timestamp.IsValid() && timestamp.GetSeconds() != 0);
|
||||
error = Tlv::Append<PendingTimestampTlv>(*this, timestamp);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
|
||||
@@ -2020,7 +2020,7 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
|
||||
switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
|
||||
{
|
||||
case kErrorNone:
|
||||
if (MeshCoP::Timestamp::Compare(×tamp, Get<MeshCoP::ActiveDatasetManager>().GetTimestamp()) == 0)
|
||||
if (timestamp == Get<MeshCoP::ActiveDatasetManager>().GetTimestamp())
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -2038,7 +2038,7 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
|
||||
switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
|
||||
{
|
||||
case kErrorNone:
|
||||
if (MeshCoP::Timestamp::Compare(×tamp, Get<MeshCoP::PendingDatasetManager>().GetTimestamp()) == 0)
|
||||
if (timestamp == Get<MeshCoP::PendingDatasetManager>().GetTimestamp())
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -2503,7 +2503,7 @@ void MleRouter::HandleDataRequest(RxInfo &aRxInfo)
|
||||
switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
|
||||
{
|
||||
case kErrorNone:
|
||||
if (MeshCoP::Timestamp::Compare(×tamp, Get<MeshCoP::ActiveDatasetManager>().GetTimestamp()) == 0)
|
||||
if (timestamp == Get<MeshCoP::ActiveDatasetManager>().GetTimestamp())
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -2521,7 +2521,7 @@ void MleRouter::HandleDataRequest(RxInfo &aRxInfo)
|
||||
switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
|
||||
{
|
||||
case kErrorNone:
|
||||
if (MeshCoP::Timestamp::Compare(×tamp, Get<MeshCoP::PendingDatasetManager>().GetTimestamp()) == 0)
|
||||
if (timestamp == Get<MeshCoP::PendingDatasetManager>().GetTimestamp())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
+68
-22
@@ -115,40 +115,86 @@ void TestSteeringData(void)
|
||||
|
||||
void TestTimestamp(void)
|
||||
{
|
||||
MeshCoP::Timestamp t1;
|
||||
MeshCoP::Timestamp t2;
|
||||
MeshCoP::Timestamp t1;
|
||||
MeshCoP::Timestamp t2;
|
||||
MeshCoP::Timestamp::Info info;
|
||||
|
||||
t1.Clear();
|
||||
t2.Clear();
|
||||
|
||||
VerifyOrQuit(t1.GetSeconds() == 0);
|
||||
VerifyOrQuit(t1.GetTicks() == 0);
|
||||
VerifyOrQuit(!t1.GetAuthoritative());
|
||||
VerifyOrQuit(t1.IsValid());
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t1, t1) == 0);
|
||||
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(&t1, &t2) == 0);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(&t1, nullptr) > 0);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(nullptr, &t2) < 0);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(nullptr, nullptr) == 0);
|
||||
t1.ConvertTo(info);
|
||||
VerifyOrQuit(info.mSeconds == 0);
|
||||
VerifyOrQuit(info.mTicks == 0);
|
||||
VerifyOrQuit(!info.mAuthoritative);
|
||||
|
||||
t1.SetTicks(10);
|
||||
VerifyOrQuit(t1.GetTicks() == 10);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(&t1, &t2) > 0);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(&t2, &t1) < 0);
|
||||
t2.SetToInvalid();
|
||||
VerifyOrQuit(!t2.IsValid());
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t2, t2) == 0);
|
||||
|
||||
t2.SetTicks(10);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(&t1, &t2) == 0);
|
||||
t2.ConvertTo(info);
|
||||
VerifyOrQuit(info.mSeconds == 0xffffffffffff);
|
||||
VerifyOrQuit(info.mTicks == 0x7fff);
|
||||
VerifyOrQuit(info.mAuthoritative);
|
||||
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t1, t2) > 0);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t2, t1) < 0);
|
||||
|
||||
t2 = t1;
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t1, t2) == 0);
|
||||
VerifyOrQuit(t2.IsValid());
|
||||
VerifyOrQuit(t1.IsValid());
|
||||
|
||||
t1.SetSeconds(0x12345678abcd);
|
||||
VerifyOrQuit(t1.GetSeconds() == 0x12345678abcd);
|
||||
VerifyOrQuit(t1.IsValid());
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t1, t2) > 0);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t2, t1) < 0);
|
||||
|
||||
t2.SetSeconds(0x12345678abcd);
|
||||
VerifyOrQuit(t1.GetSeconds() == 0x12345678abcd);
|
||||
VerifyOrQuit(t2.IsValid());
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t1, t2) == 0);
|
||||
|
||||
t1.SetAuthoritative(true);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(&t1, &t2) > 0);
|
||||
VerifyOrQuit(t1.GetAuthoritative());
|
||||
VerifyOrQuit(t1.IsValid());
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t1, t2) > 0);
|
||||
|
||||
t1.SetSeconds(1);
|
||||
VerifyOrQuit(t1.GetSeconds() == 1);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(&t1, &t2) > 0);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(&t2, &t1) < 0);
|
||||
t1.SetAuthoritative(false);
|
||||
VerifyOrQuit(!t1.GetAuthoritative());
|
||||
VerifyOrQuit(t1.IsValid());
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t1, t2) == 0);
|
||||
|
||||
t2.SetSeconds(1);
|
||||
t2.SetAuthoritative(true);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(&t1, &t2) == 0);
|
||||
t1.SetTicks(0x7fff);
|
||||
VerifyOrQuit(t1.GetTicks() == 0x7fff);
|
||||
VerifyOrQuit(!t1.GetAuthoritative());
|
||||
VerifyOrQuit(t1.IsValid());
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t1, t2) > 0);
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t2, t1) < 0);
|
||||
|
||||
t2.SetTicks(0x7fff);
|
||||
VerifyOrQuit(t2.GetTicks() == 0x7fff);
|
||||
VerifyOrQuit(!t2.GetAuthoritative());
|
||||
VerifyOrQuit(t2.IsValid());
|
||||
VerifyOrQuit(MeshCoP::Timestamp::Compare(t1, t2) == 0);
|
||||
|
||||
t2.ConvertTo(info);
|
||||
VerifyOrQuit(info.mSeconds == 0x12345678abcd);
|
||||
VerifyOrQuit(info.mTicks == 0x7fff);
|
||||
VerifyOrQuit(!info.mAuthoritative);
|
||||
|
||||
t1.SetToOrphanAnnounce();
|
||||
VerifyOrQuit(t1.IsValid());
|
||||
VerifyOrQuit(t1.IsOrphanAnnounce());
|
||||
|
||||
t1.ConvertTo(info);
|
||||
VerifyOrQuit(info.mSeconds == 0);
|
||||
VerifyOrQuit(info.mTicks == 0);
|
||||
VerifyOrQuit(info.mAuthoritative);
|
||||
|
||||
printf("TestTimestamp() passed\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user