Skip to content

Commit

Permalink
[mle] add mechanism to track current attach duration (openthread#10923)
Browse files Browse the repository at this point in the history
This commit adds a new mechanism to track the current attach time
(the time duration since device was last attached to a Thread mesh).
This duration indicates how long the device has been connected,
regardless of its role(child, router, or leader).

A related public OT API and CLI command are also added. This
information can be used for debugging purposes and internally within
the OT core to wait for the device to stabilize before enabling
certain behaviors.
  • Loading branch information
abtink authored Dec 9, 2024
1 parent 7b72e97 commit 101eac0
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 10 deletions.
2 changes: 1 addition & 1 deletion include/openthread/instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (465)
#define OPENTHREAD_API_VERSION (466)

/**
* @addtogroup api-instance
Expand Down
17 changes: 17 additions & 0 deletions include/openthread/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,23 @@ const otMleCounters *otThreadGetMleCounters(otInstance *aInstance);
*/
void otThreadResetMleCounters(otInstance *aInstance);

/**
* Gets the current attach duration (number of seconds since the device last attached).
*
* Requires the `OPENTHREAD_CONFIG_UPTIME_ENABLE` feature.
*
* If the device is not currently attached, zero will be returned.
*
* Unlike the role-tracking variables in `otMleCounters`, which track the cumulative time the device is in each role,
* this function tracks the time since the last successful attachment, indicating how long the device has been
* connected to the Thread mesh (regardless of its role, whether acting as a child, router, or leader).
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @returns The number of seconds since last attached.
*/
uint32_t otThreadGetCurrentAttachDuration(otInstance *aInstance);

/**
* Pointer is called every time an MLE Parent Response message is received.
*
Expand Down
15 changes: 15 additions & 0 deletions src/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Done

## OpenThread Command List

- [attachtime](#attachtime)
- [ba](#ba)
- [bbr](#bbr)
- [br](README_BR.md)
Expand Down Expand Up @@ -137,6 +138,20 @@ Done

## OpenThread Command Details

### attachtime

Prints the attach time (duration since device was last attached).

Requires `OPENTHREAD_CONFIG_UPTIME_ENABLE`.

Duration is formatted as `{hh}:{mm}:{ss}` for hours, minutes, and seconds if it is less than one day. If the duration is longer than one day, the format is `{dd}d.{hh}:{mm}:{ss}`.

```bash
> attachtime
01:38:25
Done
```

### bbr

Show current Primary Backbone Router information for Thread 1.2 device.
Expand Down
31 changes: 31 additions & 0 deletions src/cli/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,34 @@ otError Interpreter::SetUserCommands(const otCliCommand *aCommands, uint8_t aLen

#if OPENTHREAD_FTD || OPENTHREAD_MTD

#if OPENTHREAD_CONFIG_UPTIME_ENABLE
/**
* @cli attachtime
* @code
* attachtime
* 01:38:25
* Done
* @endcode
* @par
* Prints the current attach time (duration since device was last attached). Requires `OPENTHREAD_CONFIG_UPTIME_ENABLE`.
* Duration is formatted as `{hh}:{mm}:{ss}` for hours, minutes, and seconds if it is less than one day. If the
* duration is longer than one day, the format is `{dd}d.{hh}:{mm}:{ss}`.
*/
template <> otError Interpreter::Process<Cmd("attachtime")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
char string[OT_DURATION_STRING_SIZE];

VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);

otConvertDurationInSecondsToString(otThreadGetCurrentAttachDuration(GetInstancePtr()), string, sizeof(string));
OutputLine("%s", string);

exit:
return error;
}
#endif

#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
template <> otError Interpreter::Process<Cmd("history")>(Arg aArgs[]) { return mHistory.Process(aArgs); }
#endif
Expand Down Expand Up @@ -8425,6 +8453,9 @@ otError Interpreter::ProcessCommand(Arg aArgs[])

static constexpr Command kCommands[] = {
#if OPENTHREAD_FTD || OPENTHREAD_MTD
#if OPENTHREAD_CONFIG_UPTIME_ENABLE
CmdEntry("attachtime"),
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
CmdEntry("ba"),
#endif
Expand Down
7 changes: 7 additions & 0 deletions src/core/api/thread_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,13 @@ const otMleCounters *otThreadGetMleCounters(otInstance *aInstance)

void otThreadResetMleCounters(otInstance *aInstance) { AsCoreType(aInstance).Get<Mle::MleRouter>().ResetCounters(); }

#if OPENTHREAD_CONFIG_UPTIME_ENABLE
uint32_t otThreadGetCurrentAttachDuration(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Mle::MleRouter>().GetCurrentAttachDuration();
}
#endif

#if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE
void otThreadRegisterParentResponseCallback(otInstance *aInstance,
otThreadParentResponseCallback aCallback,
Expand Down
23 changes: 22 additions & 1 deletion src/core/thread/mle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,15 @@ void Mle::Stop(StopMode aMode)
}
}

const Counters &Mle::GetCounters(void)
{
#if OPENTHREAD_CONFIG_UPTIME_ENABLE
UpdateRoleTimeCounters(mRole);
#endif

return mCounters;
}

void Mle::ResetCounters(void)
{
ClearAllBytes(mCounters);
Expand All @@ -249,6 +258,12 @@ void Mle::ResetCounters(void)
}

#if OPENTHREAD_CONFIG_UPTIME_ENABLE

uint32_t Mle::GetCurrentAttachDuration(void) const
{
return IsAttached() ? Uptime::MsecToSec(Get<Uptime>().GetUptime()) - mLastAttachTime : 0;
}

void Mle::UpdateRoleTimeCounters(DeviceRole aRole)
{
uint64_t currentUptimeMsec = Get<Uptime>().GetUptime();
Expand Down Expand Up @@ -277,7 +292,8 @@ void Mle::UpdateRoleTimeCounters(DeviceRole aRole)
break;
}
}
#endif

#endif // OPENTHREAD_CONFIG_UPTIME_ENABLE

void Mle::SetRole(DeviceRole aRole)
{
Expand All @@ -288,6 +304,11 @@ void Mle::SetRole(DeviceRole aRole)
LogNote("Role %s -> %s", RoleToString(oldRole), RoleToString(mRole));

#if OPENTHREAD_CONFIG_UPTIME_ENABLE
if ((oldRole == kRoleDetached) && IsAttached())
{
mLastAttachTime = Uptime::MsecToSec(Get<Uptime>().GetUptime());
}

UpdateRoleTimeCounters(oldRole);
#endif

Expand Down
20 changes: 12 additions & 8 deletions src/core/thread/mle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,19 +598,22 @@ class Mle : public InstanceLocator, private NonCopyable
*
* @returns A reference to the MLE counters.
*/
const Counters &GetCounters(void)
{
#if OPENTHREAD_CONFIG_UPTIME_ENABLE
UpdateRoleTimeCounters(mRole);
#endif
return mCounters;
}
const Counters &GetCounters(void);

/**
* Resets the MLE counters.
*/
void ResetCounters(void);

#if OPENTHREAD_CONFIG_UPTIME_ENABLE
/**
* Determines the current attach duration (number of seconds since the device last attached).
*
* @returns Current attach duration in seconds.
*/
uint32_t GetCurrentAttachDuration(void) const;
#endif

#if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE
/**
* Registers the client callback that is called when processing an MLE Parent Response message.
Expand Down Expand Up @@ -1477,10 +1480,11 @@ class Mle : public InstanceLocator, private NonCopyable
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
uint32_t mCslTimeout;
#endif
uint64_t mAlternateTimestamp;
#if OPENTHREAD_CONFIG_UPTIME_ENABLE
uint32_t mLastAttachTime;
uint64_t mLastUpdatedTimestamp;
#endif
uint64_t mAlternateTimestamp;

LeaderData mLeaderData;
Parent mParent;
Expand Down

0 comments on commit 101eac0

Please sign in to comment.