[ncp] notify host asynchronously upon a significant thread network time change (#3238)

This commit is contained in:
Joseph Newman
2018-11-07 22:32:31 -08:00
committed by Jonathan Hui
parent a5f1ed263d
commit 4f99bcfaf3
10 changed files with 223 additions and 24 deletions
+17
View File
@@ -63,6 +63,8 @@ typedef enum otNetworkTimeStatus
OT_NETWORK_TIME_SYNCHRONIZED = 1, ///< The device network time is synchronized.
} otNetworkTimeStatus;
typedef void (*otNetworkTimeSyncCallbackFn)(void *aCallbackContext);
/**
* zero is considered as invalid time synchronization sequence.
*
@@ -128,6 +130,21 @@ otError otNetworkTimeSetXtalThreshold(otInstance *aInstance, uint16_t aXTALThres
*/
uint16_t otNetworkTimeGetXtalThreshold(otInstance *aInstance);
/**
* Set a callback to be called when a network time sync or status change occurs
*
* This callback shall be called only when the network time offset jumps by
* OPENTHREAD_CONFIG_TIME_SYNC_JUMP_NOTIF_MIN_US or when the status changes.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aCallbackFn The callback function to be called
* @param[in] aCallbackContext The context to be passed to the callback function upon invocation
*
*/
void otNetworkTimeSyncSetCallback(otInstance * aInstance,
otNetworkTimeSyncCallbackFn aCallbackFn,
void * aCallbackContext);
/**
* @}
*
+8
View File
@@ -89,4 +89,12 @@ uint16_t otNetworkTimeGetXtalThreshold(otInstance *aInstance)
return instance.GetThreadNetif().GetTimeSync().GetXtalThreshold();
}
void otNetworkTimeSyncSetCallback(otInstance *aInstance, otNetworkTimeSyncCallbackFn aCallback, void *aCallbackContext)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetThreadNetif().GetTimeSync().SetTimeSyncCallback(aCallback, aCallbackContext);
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
+7
View File
@@ -587,6 +587,13 @@ template <> inline MeshCoP::PendingDataset &Instance::Get(void)
return GetThreadNetif().GetPendingDataset();
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
template <> inline TimeSync &Instance::Get(void)
{
return GetThreadNetif().GetTimeSync();
}
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP
template <> inline Coap::ApplicationCoap &Instance::Get(void)
{
+11
View File
@@ -1886,4 +1886,15 @@
#ifndef OPENTHREAD_CONFIG_IPV6_DEFAULT_MAX_DATAGRAM
#define OPENTHREAD_CONFIG_IPV6_DEFAULT_MAX_DATAGRAM 1280
#endif
/**
* @def OPENTHREAD_CONFIG_TIME_SYNC_JUMP_NOTIF_MIN_US
*
* This setting sets the minimum amount of time (in microseconds) that the network time must jump due to
* a time sync event for listeners to be notified of the new network time.
*
*/
#ifndef OPENTHREAD_CONFIG_TIME_SYNC_JUMP_NOTIF_MIN_US
#define OPENTHREAD_CONFIG_TIME_SYNC_JUMP_NOTIF_MIN_US 10000
#endif
#endif // OPENTHREAD_CORE_DEFAULT_CONFIG_H_
+93 -24
View File
@@ -43,6 +43,9 @@
#include "common/instance.hpp"
#include "common/logging.hpp"
#include "common/owner-locator.hpp"
#define ABS(value) (((value) >= 0) ? (value) : -(value))
namespace ot {
@@ -57,41 +60,28 @@ TimeSync::TimeSync(Instance &aInstance)
#endif
, mLastTimeSyncReceived(0)
, mNetworkTimeOffset(0)
, mTimeSyncCallback(NULL)
, mTimeSyncCallbackContext(NULL)
, mNotifierCallback(&TimeSync::HandleStateChanged, this)
, mTimer(aInstance, HandleTimeout, this)
, mCurrentStatus(OT_NETWORK_TIME_UNSYNCHRONIZED)
{
aInstance.GetNotifier().RegisterCallback(mNotifierCallback);
CheckAndHandleChanges(false);
}
otNetworkTimeStatus TimeSync::GetTime(uint64_t &aNetworkTime) const
{
otNetworkTimeStatus networkTimeStatus = OT_NETWORK_TIME_SYNCHRONIZED;
otDeviceRole role = GetInstance().GetThreadNetif().GetMle().GetRole();
switch (role)
{
case OT_DEVICE_ROLE_DISABLED:
case OT_DEVICE_ROLE_DETACHED:
networkTimeStatus = OT_NETWORK_TIME_UNSYNCHRONIZED;
break;
case OT_DEVICE_ROLE_CHILD:
case OT_DEVICE_ROLE_ROUTER:
if ((TimerMilli::GetNow() - mLastTimeSyncReceived) > 2 * TimerMilli::SecToMsec(mTimeSyncPeriod))
{
// The device hasnt received time sync for more than two periods time.
networkTimeStatus = OT_NETWORK_TIME_RESYNC_NEEDED;
}
break;
case OT_DEVICE_ROLE_LEADER:
break;
}
aNetworkTime = static_cast<uint64_t>(static_cast<int64_t>(otPlatTimeGet()) + mNetworkTimeOffset);
return networkTimeStatus;
return mCurrentStatus;
}
void TimeSync::HandleTimeSyncMessage(const Message &aMessage)
{
const int64_t origNetworkTimeOffset = mNetworkTimeOffset;
VerifyOrExit(aMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ);
if (mTimeSyncSeq != OT_TIME_SYNC_INVALID_SEQ && (int8_t)(aMessage.GetTimeSyncSeq() - mTimeSyncSeq) < 0)
@@ -113,6 +103,11 @@ void TimeSync::HandleTimeSyncMessage(const Message &aMessage)
mTimeSyncSeq = aMessage.GetTimeSyncSeq();
mNetworkTimeOffset = aMessage.GetNetworkTimeOffset();
mTimeSyncRequired = true;
// Only notify listeners of an update for network time offset jumps of more than
// OPENTHREAD_CONFIG_TIME_SYNC_JUMP_NOTIF_MIN_US but notify listeners regardless if the status changes.
CheckAndHandleChanges(ABS(mNetworkTimeOffset - origNetworkTimeOffset) >=
OPENTHREAD_CONFIG_TIME_SYNC_JUMP_NOTIF_MIN_US);
}
}
@@ -128,6 +123,14 @@ void TimeSync::IncrementTimeSyncSeq(void)
}
}
void TimeSync::NotifyTimeSyncCallback(void)
{
if (mTimeSyncCallback != NULL)
{
mTimeSyncCallback(mTimeSyncCallbackContext);
}
}
#if OPENTHREAD_FTD
void TimeSync::ProcessTimeSync(void)
{
@@ -151,6 +154,72 @@ exit:
}
#endif // OPENTHREAD_FTD
void TimeSync::HandleStateChanged(otChangedFlags aFlags)
{
if ((aFlags & OT_CHANGED_THREAD_ROLE) != 0)
{
CheckAndHandleChanges(false);
}
}
void TimeSync::HandleTimeout(void)
{
CheckAndHandleChanges(false);
}
void TimeSync::HandleStateChanged(Notifier::Callback &aCallback, otChangedFlags aFlags)
{
aCallback.GetOwner<TimeSync>().HandleStateChanged(aFlags);
}
void TimeSync::HandleTimeout(Timer &aTimer)
{
aTimer.GetOwner<TimeSync>().HandleTimeout();
}
void TimeSync::CheckAndHandleChanges(bool aTimeUpdated)
{
otNetworkTimeStatus networkTimeStatus = OT_NETWORK_TIME_SYNCHRONIZED;
const otDeviceRole role = GetInstance().GetThreadNetif().GetMle().GetRole();
const uint32_t resyncNeededThresholdMs = 2 * TimerMilli::SecToMsec(mTimeSyncPeriod);
const uint32_t timeSyncLastSyncMs = TimerMilli::GetNow() - mLastTimeSyncReceived;
mTimer.Stop();
switch (role)
{
case OT_DEVICE_ROLE_DISABLED:
case OT_DEVICE_ROLE_DETACHED:
networkTimeStatus = OT_NETWORK_TIME_UNSYNCHRONIZED;
break;
case OT_DEVICE_ROLE_CHILD:
case OT_DEVICE_ROLE_ROUTER:
if (timeSyncLastSyncMs > resyncNeededThresholdMs)
{
// The device hasnt received time sync for more than two periods time.
networkTimeStatus = OT_NETWORK_TIME_RESYNC_NEEDED;
}
else
{
// Schedule a check 1 millisecond after two periods of time
assert(resyncNeededThresholdMs >= timeSyncLastSyncMs);
mTimer.Start(resyncNeededThresholdMs - timeSyncLastSyncMs + 1);
}
break;
case OT_DEVICE_ROLE_LEADER:
break;
}
if (networkTimeStatus != mCurrentStatus || aTimeUpdated)
{
mCurrentStatus = networkTimeStatus;
NotifyTimeSyncCallback();
}
}
} // namespace ot
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
+66
View File
@@ -41,6 +41,7 @@
#include "common/locator.hpp"
#include "common/message.hpp"
#include "common/notifier.hpp"
#include "common/timer.hpp"
namespace ot {
@@ -137,13 +138,72 @@ public:
*/
uint16_t GetXtalThreshold(void) const { return mXtalThreshold; }
/**
* Set the time sync callback to be notified of a network time update.
*
* @param[in] aCallback The callback to be called when time sync is handled.
* @param[im] aCallbackContext The context to be passed to callback.
*
*/
void SetTimeSyncCallback(otNetworkTimeSyncCallbackFn aCallback, void *aCallbackContext)
{
mTimeSyncCallback = aCallback;
mTimeSyncCallbackContext = aCallbackContext;
}
/**
* Callback to be called when thread state changes.
*
* @param[in] aFlags Flags that denote the state change events.
*
*/
void HandleStateChanged(otChangedFlags aFlags);
/**
* Callback to be called when timer expires.
*
*/
void HandleTimeout(void);
private:
/**
* Callback to be called when thread state changes.
*
* @param[in] aCallback Callback context.
* @param[in] aFlags Flags that denote the state change events.
*
*/
static void HandleStateChanged(Notifier::Callback &aCallback, otChangedFlags aFlags);
/**
* Callback to be called when timer expires.
*
* @param[in] aTimer The corresponding timer.
*
*/
static void HandleTimeout(Timer &aTimer);
/**
* Check and handle any status change, and notify observers if applicable.
*
* @param[in] aNotifyTimeUpdated True to denote that observers should be notified due to a time change, false
* otherwise.
*
*/
void CheckAndHandleChanges(bool aNotifyTimeUpdated);
/**
* Increase the time synchronization sequence.
*
*/
void IncrementTimeSyncSeq(void);
/**
* Notify any listener of a network time sync update event.
*
*/
void NotifyTimeSyncCallback(void);
bool mTimeSyncRequired; ///< Indicate whether or not a time synchronization message is required.
uint8_t mTimeSyncSeq; ///< The time synchronization sequence.
uint16_t mTimeSyncPeriod; ///< The time synchronization period.
@@ -153,6 +213,12 @@ private:
#endif
uint32_t mLastTimeSyncReceived; ///< The time when the last time synchronization message was received.
int64_t mNetworkTimeOffset; ///< The time offset to the Thread Network time
otNetworkTimeSyncCallbackFn
mTimeSyncCallback; ///< The callback to be called when time sync is handled or status updated.
void * mTimeSyncCallbackContext; ///< The context to be passed to callback.
Notifier::Callback mNotifierCallback; ///< Callback for thread state changes.
TimerMilli mTimer; ///< Timer for checking if a resync is required.
otNetworkTimeStatus mCurrentStatus; ///< Current network time status.
};
/**
+3
View File
@@ -89,6 +89,9 @@ const ChangedPropsSet::Entry ChangedPropsSet::mSupportedProps[] = {
{SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_JOIN_RSP_TIMEOUT, false}, // 32
{SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_JOIN_SUCCESS, false}, // 33
#endif
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
{SPINEL_PROP_THREAD_NETWORK_TIME, SPINEL_STATUS_OK, false}, // 34
#endif
};
uint8_t ChangedPropsSet::GetNumEntries(void) const
+4
View File
@@ -40,6 +40,7 @@
#include <openthread/link.h>
#include <openthread/logging.h>
#include <openthread/ncp.h>
#include <openthread/network_time.h>
#include <openthread/platform/misc.h>
#include <openthread/platform/radio.h>
@@ -264,6 +265,9 @@ NcpBase::NcpBase(Instance *aInstance)
otSetStateChangedCallback(mInstance, &NcpBase::HandleStateChanged, this);
otIp6SetReceiveCallback(mInstance, &NcpBase::HandleDatagramFromStack, this);
otIp6SetReceiveFilterEnabled(mInstance, true);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
otNetworkTimeSyncSetCallback(mInstance, &NcpBase::HandleTimeSyncUpdate, this);
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
#if OPENTHREAD_ENABLE_UDP_FORWARD
otUdpForwardSetForwarder(mInstance, &NcpBase::HandleUdpForwardStream, this);
#endif
+3
View File
@@ -263,6 +263,9 @@ protected:
static void HandleStateChanged(otChangedFlags aFlags, void *aContext);
void ProcessThreadChangedFlags(void);
static void HandleTimeSyncUpdate(void *aContext);
void HandleTimeSyncUpdate(void);
#if OPENTHREAD_FTD
static void HandleChildTableChanged(otThreadChildTableEvent aEvent, const otChildInfo *aChildInfo);
void HandleChildTableChanged(otThreadChildTableEvent aEvent, const otChildInfo &aChildInfo);
+11
View File
@@ -2618,6 +2618,17 @@ template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_NETWORK_TIME>(
exit:
return error;
}
void NcpBase::HandleTimeSyncUpdate(void *aContext)
{
static_cast<NcpBase *>(aContext)->HandleTimeSyncUpdate();
}
void NcpBase::HandleTimeSyncUpdate(void)
{
mChangedPropsSet.AddProperty(SPINEL_PROP_THREAD_NETWORK_TIME);
mUpdateChangedPropsTask.Post();
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
void NcpBase::HandleActiveScanResult_Jump(otActiveScanResult *aResult, void *aContext)