mirror of
https://github.com/espressif/openthread.git
synced 2026-08-31 06:19:54 +00:00
[time-sync] network-wide time synchronization service (#2618)
OpenThread network-wide time synchronization service is an experimental feature, not part of the standard Thread protocol. Feature Overview: * All the nodes in the same Thread partition sync to the same Thread network-wide time; * Microsecond level time synchronization precision; * Flexible time accuracy and time sync period configuration; * APIs for application layer use case, support both CLI and NCP version. The feature is wrapped by OPENTHREAD_CONFIG_ENABLE_TIME_SYNC, there's no change to current Thread 1.1 implementation if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC is not enabled. If OPENTHREAD_CONFIG_ENABLE_TIME_SYNC is enabled, the node could: * Attach to a time sync enabled network, otherwise * Attach to a standard Thread 1.1 network, otherwise * Form a new time sync enabled network In addition, if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED is also enable, the node could only: * Attach to a time sync enabled network, otherwise * Form a new time sync enabled network Note: Currently, the feature is only supported on nRF52840 and posix platforms. And the network time is only synced among Routers and REEDs, the SEDs will be supported later as an optional feature.
This commit is contained in:
@@ -43,6 +43,7 @@
|
||||
#include <openthread/platform/alarm-micro.h>
|
||||
#include <openthread/platform/alarm-milli.h>
|
||||
#include <openthread/platform/diag.h>
|
||||
#include <openthread/platform/time.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
@@ -67,6 +68,8 @@
|
||||
#define US_PER_OVERFLOW (512UL * US_PER_S) ///< Time that has passed between overflow events. On full RTC speed, it occurs every 512 s.
|
||||
|
||||
#define MS_PER_S 1000UL
|
||||
|
||||
#define XTAL_ACCURACY 40 // The crystal used on nRF52840PDK has ±20ppm accuracy.
|
||||
// clang-format on
|
||||
|
||||
typedef enum { kMsTimer, kUsTimer, k802154Timer, kNumTimers } AlarmIndex;
|
||||
@@ -88,7 +91,8 @@ typedef struct
|
||||
static volatile uint32_t sOverflowCounter; ///< Counter of RTC overflowCounter, incremented by 2 on each OVERFLOW event.
|
||||
static volatile uint8_t sMutex; ///< Mutex for write access to @ref sOverflowCounter.
|
||||
static volatile uint64_t sTimeOffset = 0; ///< Time overflowCounter to keep track of current time (in millisecond).
|
||||
static AlarmData sTimerData[kNumTimers]; ///< Data of the timers.
|
||||
static AlarmData sTimerData[kNumTimers]; ///< Data of the timers.
|
||||
|
||||
static const AlarmChannelData sChannelData[kNumTimers] = //
|
||||
{ //
|
||||
[kMsTimer] =
|
||||
@@ -563,3 +567,15 @@ void RTC_IRQ_HANDLER(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
uint64_t otPlatTimeGet(void)
|
||||
{
|
||||
return nrf5AlarmGetCurrentTime();
|
||||
}
|
||||
|
||||
uint16_t otPlatTimeGetXtalAccuracy(void)
|
||||
{
|
||||
return XTAL_ACCURACY;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
@@ -158,15 +158,26 @@
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_HEAP_SIZE_NO_DTLS 2048
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
*
|
||||
* Define as 1 to enable the time synchronization service feature.
|
||||
*
|
||||
* @note If it's enabled, plaforms must support interrupt context and concurrent access AES.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_ENABLE_TIME_SYNC 0
|
||||
|
||||
/**
|
||||
* @def NRF_MBEDTLS_AES_ALT_INTERRUPT_CONTEXT
|
||||
*
|
||||
* Define as 1 to enable AES usage in interrupt context and AES-256, by introducing a software AES under platform layer.
|
||||
*
|
||||
* @note This feature must be enabled to support AES-256 used by Commissioner and Joiner.
|
||||
* @note This feature must be enabled to support AES-256 used by Commissioner and Joiner, and AES usage in interrupt context
|
||||
* used by time synchronization service.
|
||||
*
|
||||
*/
|
||||
#if OPENTHREAD_ENABLE_COMMISSIONER || OPENTHREAD_ENABLE_JOINER
|
||||
#if OPENTHREAD_ENABLE_COMMISSIONER || OPENTHREAD_ENABLE_JOINER || OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
#define NRF_MBEDTLS_AES_ALT_INTERRUPT_CONTEXT 1
|
||||
#else
|
||||
#define NRF_MBEDTLS_AES_ALT_INTERRUPT_CONTEXT 0
|
||||
|
||||
@@ -495,15 +495,17 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def NRF_MBEDTLS_AES_ALT_INTERRUPT_CONTEXT
|
||||
* @def NRF_802154_TX_STARTED_NOTIFY_ENABLED
|
||||
*
|
||||
* Define as 1 to enable AES usage in interrupt context.
|
||||
* If notification of started transmission should be enabled in the driver.
|
||||
*
|
||||
* @note A software AES is enabled to support AES usage in interrupt context.
|
||||
* @note This feature is enabled by default if OpenThread time synchronization service is enabled.
|
||||
*
|
||||
*/
|
||||
#ifndef NRF_MBEDTLS_AES_ALT_INTERRUPT_CONTEXT
|
||||
#define NRF_MBEDTLS_AES_ALT_INTERRUPT_CONTEXT 0
|
||||
#ifndef NRF_802154_TX_STARTED_NOTIFY_ENABLED
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
#define NRF_802154_TX_STARTED_NOTIFY_ENABLED 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // PLATFORM_CONFIG_H_
|
||||
|
||||
@@ -43,9 +43,11 @@
|
||||
|
||||
#include <common/code_utils.hpp>
|
||||
#include <platform-config.h>
|
||||
#include <openthread/platform/alarm-micro.h>
|
||||
#include <openthread/platform/diag.h>
|
||||
#include <openthread/platform/logging.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
#include <openthread/platform/time.h>
|
||||
|
||||
#include "platform-nrf5.h"
|
||||
#include "platform.h"
|
||||
@@ -78,6 +80,12 @@ static otRadioFrame sReceivedFrames[NRF_802154_RX_BUFFERS];
|
||||
static otRadioFrame sTransmitFrame;
|
||||
static uint8_t sTransmitPsdu[OT_RADIO_FRAME_MAX_SIZE + 1];
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
static otRadioIeInfo sTransmitIeInfo;
|
||||
static otRadioIeInfo sReceivedIeInfos[NRF_802154_RX_BUFFERS];
|
||||
static otInstance * sInstance = NULL;
|
||||
#endif
|
||||
|
||||
static otRadioFrame sAckFrame;
|
||||
|
||||
static int8_t sDefaultTxPower;
|
||||
@@ -103,6 +111,9 @@ static void dataInit(void)
|
||||
sDisabled = true;
|
||||
|
||||
sTransmitFrame.mPsdu = sTransmitPsdu + 1;
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
sTransmitFrame.mIeInfo = &sTransmitIeInfo;
|
||||
#endif
|
||||
|
||||
sReceiveError = OT_ERROR_NONE;
|
||||
|
||||
@@ -322,7 +333,9 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
|
||||
|
||||
otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
|
||||
{
|
||||
(void)aInstance;
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
sInstance = aInstance;
|
||||
#endif
|
||||
|
||||
otError result = OT_ERROR_NONE;
|
||||
|
||||
@@ -661,7 +674,11 @@ void nrf5RadioProcess(otInstance *aInstance)
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
void nrf_802154_received_timestamp_raw(uint8_t *p_data, int8_t power, uint8_t lqi, uint32_t time)
|
||||
#else
|
||||
void nrf_802154_received_raw(uint8_t *p_data, int8_t power, uint8_t lqi)
|
||||
#endif
|
||||
{
|
||||
otRadioFrame *receivedFrame = NULL;
|
||||
|
||||
@@ -670,14 +687,17 @@ void nrf_802154_received_raw(uint8_t *p_data, int8_t power, uint8_t lqi)
|
||||
if (sReceivedFrames[i].mPsdu == NULL)
|
||||
{
|
||||
receivedFrame = &sReceivedFrames[i];
|
||||
|
||||
memset(receivedFrame, 0, sizeof(*receivedFrame));
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
receivedFrame->mIeInfo = &sReceivedIeInfos[i];
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(receivedFrame != NULL);
|
||||
|
||||
memset(receivedFrame, 0, sizeof(*receivedFrame));
|
||||
|
||||
receivedFrame->mPsdu = &p_data[1];
|
||||
receivedFrame->mLength = p_data[0];
|
||||
receivedFrame->mInfo.mRxInfo.mRssi = power;
|
||||
@@ -688,6 +708,12 @@ void nrf_802154_received_raw(uint8_t *p_data, int8_t power, uint8_t lqi)
|
||||
receivedFrame->mInfo.mRxInfo.mMsec = timestamp / US_PER_MS;
|
||||
receivedFrame->mInfo.mRxInfo.mUsec = timestamp - receivedFrame->mInfo.mRxInfo.mMsec * US_PER_MS;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
// Get the timestamp when the SFD was received.
|
||||
uint32_t offset =
|
||||
(int32_t)otPlatAlarmMicroGetNow() - (int32_t)nrf_802154_first_symbol_timestamp_get(time, p_data[0]);
|
||||
receivedFrame->mIeInfo->mTimestamp = otPlatTimeGet() - offset;
|
||||
#endif
|
||||
|
||||
PlatformEventSignalPending();
|
||||
}
|
||||
@@ -775,3 +801,27 @@ int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
|
||||
(void)aInstance;
|
||||
return NRF52840_RECEIVE_SENSITIVITY;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
void nrf_802154_tx_started(const uint8_t *aFrame)
|
||||
{
|
||||
assert(aFrame == sTransmitPsdu);
|
||||
|
||||
if (sTransmitFrame.mIeInfo->mTimeIeOffset != 0)
|
||||
{
|
||||
uint8_t *timeIe = sTransmitFrame.mPsdu + sTransmitFrame.mIeInfo->mTimeIeOffset;
|
||||
uint64_t time = otPlatTimeGet() + sTransmitFrame.mIeInfo->mNetworkTimeOffset;
|
||||
|
||||
*timeIe = sTransmitFrame.mIeInfo->mTimeSyncSeq;
|
||||
|
||||
*(++timeIe) = (uint8_t)(time & 0xff);
|
||||
for (uint8_t i = 1; i < sizeof(uint64_t); i++)
|
||||
{
|
||||
time = time >> 8;
|
||||
*(++timeIe) = (uint8_t)(time & 0xff);
|
||||
}
|
||||
|
||||
otPlatRadioFrameUpdated(sInstance, &sTransmitFrame);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -60,15 +60,19 @@ void platformAlarmInit(uint32_t aSpeedUpFactor)
|
||||
gettimeofday(&sStart, NULL);
|
||||
}
|
||||
|
||||
uint32_t otPlatAlarmMilliGetNow(void)
|
||||
uint64_t platformGetNow(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
timersub(&tv, &sStart, &tv);
|
||||
|
||||
return (uint32_t)(((uint64_t)tv.tv_sec * sSpeedUpFactor * MS_PER_S) +
|
||||
((uint64_t)tv.tv_usec * sSpeedUpFactor / US_PER_MS));
|
||||
return (uint64_t)tv.tv_sec * sSpeedUpFactor * US_PER_S + (uint64_t)tv.tv_usec * sSpeedUpFactor;
|
||||
}
|
||||
|
||||
uint32_t otPlatAlarmMilliGetNow(void)
|
||||
{
|
||||
return (uint32_t)(platformGetNow() / US_PER_MS);
|
||||
}
|
||||
|
||||
void otPlatAlarmMilliStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt)
|
||||
@@ -86,12 +90,7 @@ void otPlatAlarmMilliStop(otInstance *aInstance)
|
||||
|
||||
uint32_t otPlatAlarmMicroGetNow(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
timersub(&tv, &sStart, &tv);
|
||||
|
||||
return (uint32_t)(tv.tv_sec * US_PER_S + tv.tv_usec) * sSpeedUpFactor;
|
||||
return (uint32_t)platformGetNow();
|
||||
}
|
||||
|
||||
void otPlatAlarmMicroStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt)
|
||||
@@ -196,4 +195,16 @@ void platformAlarmProcess(otInstance *aInstance)
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
uint64_t otPlatTimeGet(void)
|
||||
{
|
||||
return platformGetNow();
|
||||
}
|
||||
|
||||
uint16_t otPlatTimeGetXtalAccuracy(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
#endif // OPENTHREAD_POSIX_VIRTUAL_TIME == 0
|
||||
|
||||
@@ -30,10 +30,12 @@
|
||||
|
||||
#if OPENTHREAD_POSIX_VIRTUAL_TIME == 0
|
||||
|
||||
#include <openthread/platform/alarm-micro.h>
|
||||
#include <openthread/platform/alarm-milli.h>
|
||||
#include <openthread/platform/diag.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
#include <openthread/platform/random.h>
|
||||
#include <openthread/platform/time.h>
|
||||
|
||||
#include "utils/code_utils.h"
|
||||
|
||||
@@ -109,6 +111,11 @@ static otRadioFrame sReceiveFrame;
|
||||
static otRadioFrame sTransmitFrame;
|
||||
static otRadioFrame sAckFrame;
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
static otRadioIeInfo sTransmitIeInfo;
|
||||
static otRadioIeInfo sReceivedIeInfo;
|
||||
#endif
|
||||
|
||||
static uint8_t sExtendedAddress[OT_EXT_ADDRESS_SIZE];
|
||||
static uint16_t sShortAddress;
|
||||
static uint16_t sPanid;
|
||||
@@ -423,6 +430,14 @@ void platformRadioInit(void)
|
||||
sReceiveFrame.mPsdu = sReceiveMessage.mPsdu;
|
||||
sTransmitFrame.mPsdu = sTransmitMessage.mPsdu;
|
||||
sAckFrame.mPsdu = sAckMessage.mPsdu;
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
sTransmitFrame.mIeInfo = &sTransmitIeInfo;
|
||||
sReceiveFrame.mIeInfo = &sReceivedIeInfo;
|
||||
#else
|
||||
sTransmitFrame.mIeInfo = NULL;
|
||||
sReceiveFrame.mIeInfo = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void platformRadioDeinit(void)
|
||||
@@ -560,6 +575,10 @@ void radioReceive(otInstance *aInstance)
|
||||
sReceiveFrame.mInfo.mRxInfo.mUsec = 0; // Don't support microsecond timer for now.
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
sReceiveFrame.mIeInfo->mTimestamp = otPlatTimeGet();
|
||||
#endif
|
||||
|
||||
sReceiveFrame.mLength = (uint8_t)(rval - 1);
|
||||
|
||||
if (sAckWait && sTransmitFrame.mChannel == sReceiveMessage.mChannel && isFrameTypeAck(sReceiveFrame.mPsdu) &&
|
||||
@@ -579,6 +598,25 @@ void radioReceive(otInstance *aInstance)
|
||||
|
||||
void radioSendMessage(otInstance *aInstance)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
if (sTransmitFrame.mIeInfo->mTimeIeOffset != 0)
|
||||
{
|
||||
uint8_t *timeIe = sTransmitFrame.mPsdu + sTransmitFrame.mIeInfo->mTimeIeOffset;
|
||||
uint64_t time = otPlatTimeGet() + sTransmitFrame.mIeInfo->mNetworkTimeOffset;
|
||||
|
||||
*timeIe = sTransmitFrame.mIeInfo->mTimeSyncSeq;
|
||||
|
||||
*(++timeIe) = (uint8_t)(time & 0xff);
|
||||
for (uint8_t i = 0; i < sizeof(uint64_t); i++)
|
||||
{
|
||||
time = time >> 8;
|
||||
*(++timeIe) = (uint8_t)(time & 0xff);
|
||||
}
|
||||
|
||||
otPlatRadioFrameUpdated(aInstance, &sTransmitFrame);
|
||||
}
|
||||
#endif
|
||||
|
||||
sTransmitMessage.mChannel = sTransmitFrame.mChannel;
|
||||
|
||||
otPlatRadioTxStarted(aInstance, &sTransmitFrame);
|
||||
|
||||
@@ -72,6 +72,7 @@ openthread_headers = \
|
||||
message.h \
|
||||
ncp.h \
|
||||
netdata.h \
|
||||
network_time.h \
|
||||
openthread.h \
|
||||
server.h \
|
||||
tasklet.h \
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2018, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
* This file defines the OpenThread Network Time Synchronization Service API.
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_NETWORK_TIME_H_
|
||||
#define OPENTHREAD_NETWORK_TIME_H_
|
||||
|
||||
#include <openthread/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup api-network-time
|
||||
*
|
||||
* @brief
|
||||
* This module includes functions that control network time synchronization service.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This enum represents OpenThread time synchronization status.
|
||||
*
|
||||
*/
|
||||
typedef enum otNetworkTimeStatus {
|
||||
OT_NETWORK_TIME_UNSYNCHRONIZED = -1, ///< The device hasn't attached to a network.
|
||||
OT_NETWORK_TIME_RESYNC_NEEDED = 0, ///< The device hasn’t received time sync for more than two periods time.
|
||||
OT_NETWORK_TIME_SYNCHRONIZED = 1, ///< The device network time is synchronized.
|
||||
} otNetworkTimeStatus;
|
||||
|
||||
/**
|
||||
* zero is considered as invalid time synchronization sequence.
|
||||
*
|
||||
*/
|
||||
#define OT_TIME_SYNC_INVALID_SEQ 0
|
||||
|
||||
/**
|
||||
* Get the Thread network time.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[inout] aNetworkTime The Thread network time in microseconds.
|
||||
*
|
||||
* @returns The time synchronization status.
|
||||
*
|
||||
*/
|
||||
otNetworkTimeStatus otNetworkTimeGet(otInstance *aInstance, uint64_t &aNetworkTime);
|
||||
|
||||
/**
|
||||
* Set the time synchronization period.
|
||||
*
|
||||
* This function can only be called while Thread protocols are disabled.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aTimeSyncPeriod The time synchronization period, in seconds.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the time sync period.
|
||||
* @retval OT_ERROR_INVALID_STATE Thread protocols are enabled.
|
||||
*
|
||||
*/
|
||||
otError otNetworkTimeSetSyncPeriod(otInstance *aInstance, uint16_t aTimeSyncPeriod);
|
||||
|
||||
/**
|
||||
* Get the time synchronization period.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
*
|
||||
* @returns The time synchronization period.
|
||||
*
|
||||
*/
|
||||
uint16_t otNetworkTimeGetSyncPeriod(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Set the time synchronization XTAL accuracy threshold for Router-Capable device.
|
||||
*
|
||||
* This function can only be called while Thread protocols are disabled.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aXTALThreshold The XTAL accuracy threshold for Router, in PPM.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the time sync period.
|
||||
* @retval OT_ERROR_INVALID_STATE Thread protocols are enabled.
|
||||
*
|
||||
*/
|
||||
otError otNetworkTimeSetXtalThreshold(otInstance *aInstance, uint16_t aXTALThreshold);
|
||||
|
||||
/**
|
||||
* Get the time synchronization XTAL accuracy threshold for Router.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
*
|
||||
* @returns The XTAL accuracy threshold for Router, in PPM.
|
||||
*
|
||||
*/
|
||||
uint16_t otNetworkTimeGetXtalThreshold(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_NETWORK_TIME_H_
|
||||
@@ -38,6 +38,7 @@ ot_platform_headers = \
|
||||
logging.h \
|
||||
radio.h \
|
||||
random.h \
|
||||
time.h \
|
||||
uart.h \
|
||||
spi-slave.h \
|
||||
settings.h \
|
||||
|
||||
@@ -92,15 +92,27 @@ typedef enum otRadioCaps {
|
||||
OT_RADIO_CAPS_CSMA_BACKOFF = 8, ///< Radio supports CSMA backoff for frame transmission (but no retry).
|
||||
} otRadioCaps;
|
||||
|
||||
/**
|
||||
* This structure represents the IEEE 802.15.4 Header IE (Information Element) related information of a radio frame.
|
||||
*/
|
||||
typedef struct otRadioIeInfo
|
||||
{
|
||||
uint8_t mTimeIeOffset; ///< The Time IE offset from the start of PSDU.
|
||||
uint8_t mTimeSyncSeq; ///< The Time sync sequence.
|
||||
uint64_t mTimestamp; ///< The time in microseconds when the SFD was received.
|
||||
int64_t mNetworkTimeOffset; ///< The time offset to the Thread network time.
|
||||
} otRadioIeInfo;
|
||||
|
||||
/**
|
||||
* This structure represents an IEEE 802.15.4 radio frame.
|
||||
*/
|
||||
typedef struct otRadioFrame
|
||||
{
|
||||
uint8_t *mPsdu; ///< The PSDU.
|
||||
uint8_t mLength; ///< Length of the PSDU.
|
||||
uint8_t mChannel; ///< Channel used to transmit/receive the frame.
|
||||
bool mDidTx : 1; ///< Set to true if this frame sent from the radio. Ignored by radio driver.
|
||||
uint8_t * mPsdu; ///< The PSDU.
|
||||
uint8_t mLength; ///< Length of the PSDU.
|
||||
uint8_t mChannel; ///< Channel used to transmit/receive the frame.
|
||||
bool mDidTx : 1; ///< Set to true if this frame sent from the radio. Ignored by radio driver.
|
||||
otRadioIeInfo *mIeInfo; ///< The pointer to the Header IE(s) related information.
|
||||
|
||||
/**
|
||||
* The union of transmit and receive information for a radio frame.
|
||||
@@ -564,6 +576,19 @@ extern void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanM
|
||||
*/
|
||||
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* The radio driver calls this method to notify OpenThread to process transmit security for the frame,
|
||||
* this happens when the frame includes Header IE(s) that were updated before transmission.
|
||||
*
|
||||
* @note This function will be called from interrupt context, it should only read/write data passed in
|
||||
* via @p aFrame, but should not read/write any state within OpenThread.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aFrame The radio frame which neeeds to process transmit security.
|
||||
*
|
||||
*/
|
||||
extern void otPlatRadioFrameUpdated(otInstance *aInstance, otRadioFrame *aFrame);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2018, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
* This file includes the platform abstraction for the time service.
|
||||
*/
|
||||
|
||||
#ifndef TIME_H_
|
||||
#define TIME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openthread/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup plat-time
|
||||
*
|
||||
* @brief
|
||||
* This module includes the platform abstraction for the time service.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the current time (64bits width).
|
||||
*
|
||||
* @returns The current time in microseconds.
|
||||
*
|
||||
*/
|
||||
uint64_t otPlatTimeGet(void);
|
||||
|
||||
/**
|
||||
* Get the device's XTAL accuracy.
|
||||
*
|
||||
* @returns The device's XTAL accuracy, in ppm.
|
||||
*
|
||||
*/
|
||||
uint16_t otPlatTimeGetXtalAccuracy(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // TIME_H_
|
||||
@@ -1160,6 +1160,10 @@ typedef struct otThreadLinkInfo
|
||||
int8_t mRss; ///< Received Signal Strength in dBm.
|
||||
uint8_t mLqi; ///< Link Quality Indicator for a received message.
|
||||
bool mLinkSecurity; ///< Indicates whether or not link security is enabled.
|
||||
|
||||
// Applicable/Required only when time sync feature (`OPENTHREAD_CONFIG_ENABLE_TIME_SYNC`) is enabled.
|
||||
uint8_t mTimeSyncSeq; ///< The time sync sequence.
|
||||
int64_t mNetworkTimeOffset; ///< The time offset to the Thread network time, in microseconds.
|
||||
} otThreadLinkInfo;
|
||||
|
||||
#ifdef OTDLL
|
||||
|
||||
@@ -47,6 +47,7 @@ OpenThread test scripts use the CLI to execute test cases.
|
||||
* [networkdiagnostic](#networkdiagnostic-get-addr-type-)
|
||||
* [networkidtimeout](#networkidtimeout)
|
||||
* [networkname](#networkname)
|
||||
* [networktime](#networktime)
|
||||
* [panid](#panid)
|
||||
* [parent](#parent)
|
||||
* [parentpriority](#parentpriority)
|
||||
@@ -605,6 +606,31 @@ Set network name.
|
||||
Done
|
||||
```
|
||||
|
||||
### networktime
|
||||
|
||||
Get the Thread network time and the time sync parameters.
|
||||
|
||||
```bash
|
||||
> networktime
|
||||
Network Time: 21084154us (synchronized)
|
||||
Time Sync Period: 100s
|
||||
XTAL Threshold: 300ppm
|
||||
Done
|
||||
```
|
||||
|
||||
### networktime \<timesyncperiod\> \<xtalthreshold\>
|
||||
|
||||
Set time sync parameters
|
||||
|
||||
* timesyncperiod: The time synchronization period, in seconds.
|
||||
* xtalthreshold: The XTAL accuracy threshold for a device to become Router-Capable device, in PPM.
|
||||
|
||||
```bash
|
||||
> networktime 100 300
|
||||
Done
|
||||
```
|
||||
|
||||
|
||||
### dataset panid \<panid\>
|
||||
|
||||
Set panid.
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
#include <openthread/icmp6.h>
|
||||
#include <openthread/joiner.h>
|
||||
#include <openthread/link.h>
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
#include <openthread/network_time.h>
|
||||
#endif
|
||||
#include <openthread/openthread.h>
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
@@ -177,6 +180,9 @@ const struct Command Interpreter::sCommands[] = {
|
||||
{"networkidtimeout", &Interpreter::ProcessNetworkIdTimeout},
|
||||
#endif
|
||||
{"networkname", &Interpreter::ProcessNetworkName},
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
{"networktime", &Interpreter::ProcessNetworkTime},
|
||||
#endif
|
||||
{"panid", &Interpreter::ProcessPanId},
|
||||
{"parent", &Interpreter::ProcessParent},
|
||||
#if OPENTHREAD_FTD
|
||||
@@ -1579,6 +1585,60 @@ exit:
|
||||
AppendResult(error);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
void Interpreter::ProcessNetworkTime(int argc, char *argv[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
long value;
|
||||
|
||||
if (argc == 0)
|
||||
{
|
||||
uint64_t time;
|
||||
otNetworkTimeStatus networkTimeStatus;
|
||||
|
||||
networkTimeStatus = otNetworkTimeGet(mInstance, time);
|
||||
|
||||
mServer->OutputFormat("Network Time: %dus", time);
|
||||
|
||||
switch (networkTimeStatus)
|
||||
{
|
||||
case OT_NETWORK_TIME_UNSYNCHRONIZED:
|
||||
mServer->OutputFormat(" (unsynchronized)\r\n");
|
||||
break;
|
||||
|
||||
case OT_NETWORK_TIME_RESYNC_NEEDED:
|
||||
mServer->OutputFormat(" (resync needed)\r\n");
|
||||
break;
|
||||
|
||||
case OT_NETWORK_TIME_SYNCHRONIZED:
|
||||
mServer->OutputFormat(" (synchronized)\r\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mServer->OutputFormat("Time Sync Period: %ds\r\n", otNetworkTimeGetSyncPeriod(mInstance));
|
||||
mServer->OutputFormat("XTAL Threshold: %dppm\r\n", otNetworkTimeGetXtalThreshold(mInstance));
|
||||
}
|
||||
else if (argc == 2)
|
||||
{
|
||||
SuccessOrExit(error = ParseLong(argv[0], value));
|
||||
SuccessOrExit(error = otNetworkTimeSetSyncPeriod(mInstance, static_cast<uint16_t>(value)));
|
||||
|
||||
SuccessOrExit(error = ParseLong(argv[1], value));
|
||||
SuccessOrExit(error = otNetworkTimeSetXtalThreshold(mInstance, static_cast<uint16_t>(value)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitNow(error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
exit:
|
||||
AppendResult(error);
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
void Interpreter::ProcessPanId(int argc, char *argv[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
@@ -266,6 +266,9 @@ private:
|
||||
void ProcessNetworkIdTimeout(int argc, char *argv[]);
|
||||
#endif
|
||||
void ProcessNetworkName(int argc, char *argv[]);
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
void ProcessNetworkTime(int argc, char *argv[]);
|
||||
#endif
|
||||
void ProcessPanId(int argc, char *argv[]);
|
||||
void ProcessParent(int argc, char *argv[]);
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
@@ -114,6 +114,7 @@ SOURCES_COMMON = \
|
||||
api/link_raw_api.cpp \
|
||||
api/message_api.cpp \
|
||||
api/netdata_api.cpp \
|
||||
api/network_time_api.cpp \
|
||||
api/server_api.cpp \
|
||||
api/tasklet_api.cpp \
|
||||
api/thread_api.cpp \
|
||||
@@ -195,6 +196,7 @@ SOURCES_COMMON = \
|
||||
thread/src_match_controller.cpp \
|
||||
thread/thread_netif.cpp \
|
||||
thread/tmf_proxy.cpp \
|
||||
thread/time_sync_service.cpp \
|
||||
thread/topology.cpp \
|
||||
utils/channel_manager.cpp \
|
||||
utils/channel_monitor.cpp \
|
||||
@@ -326,6 +328,7 @@ HEADERS_COMMON = \
|
||||
thread/thread_tlvs.hpp \
|
||||
thread/thread_uri_paths.hpp \
|
||||
thread/tmf_proxy.hpp \
|
||||
thread/time_sync_service.hpp \
|
||||
thread/topology.hpp \
|
||||
utils/channel_manager.hpp \
|
||||
utils/channel_monitor.hpp \
|
||||
|
||||
@@ -729,6 +729,15 @@ uint16_t otLinkGetShortAddress(otInstance *aInstance)
|
||||
return static_cast<Instance *>(aInstance)->GetLinkRaw().GetShortAddress();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
void otPlatRadioFrameUpdated(otInstance *aInstance, otRadioFrame *aFrame)
|
||||
{
|
||||
// Note: For now this functionality is not supported in Radio Only mode.
|
||||
(void)aInstance;
|
||||
(void)aFrame;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_RADIO
|
||||
|
||||
#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2018, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the OpenThread Network Time Synchronization Service API.
|
||||
*/
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
#include "openthread/network_time.h"
|
||||
|
||||
#include "common/instance.hpp"
|
||||
|
||||
using namespace ot;
|
||||
|
||||
otNetworkTimeStatus otNetworkTimeGet(otInstance *aInstance, uint64_t &aNetworkTime)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetThreadNetif().GetTimeSync().GetTime(aNetworkTime);
|
||||
}
|
||||
|
||||
otError otNetworkTimeSetSyncPeriod(otInstance *aInstance, uint16_t aTimeSyncPeriod)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
|
||||
error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
instance.GetThreadNetif().GetTimeSync().SetTimeSyncPeriod(aTimeSyncPeriod);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t otNetworkTimeGetSyncPeriod(otInstance *aInstance)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetThreadNetif().GetTimeSync().GetTimeSyncPeriod();
|
||||
}
|
||||
|
||||
otError otNetworkTimeSetXtalThreshold(otInstance *aInstance, uint16_t aXtalThreshold)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
|
||||
error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
instance.GetThreadNetif().GetTimeSync().SetXtalThreshold(aXtalThreshold);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t otNetworkTimeGetXtalThreshold(otInstance *aInstance)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetThreadNetif().GetTimeSync().GetXtalThreshold();
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
@@ -668,6 +668,9 @@ Message *Message::Clone(uint16_t aLength) const
|
||||
messageCopy->SetSubType(GetSubType());
|
||||
messageCopy->SetPriority(GetPriority());
|
||||
messageCopy->SetLinkSecurityEnabled(IsLinkSecurityEnabled());
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
messageCopy->SetTimeSync(IsTimeSync());
|
||||
#endif
|
||||
|
||||
exit:
|
||||
|
||||
|
||||
@@ -114,6 +114,11 @@ struct MessageInfo
|
||||
uint8_t mPriority : 2; ///< Identifies the message priority level (lower value is higher priority).
|
||||
bool mInPriorityQ : 1; ///< Indicates whether the message is queued in normal or priority queue.
|
||||
bool mTxSuccess : 1; ///< Indicates whether the direct tx of the message was successful.
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
bool mTimeSync : 1; ///< Indicates whether the message is also used for time sync purpose.
|
||||
uint8_t mTimeSyncSeq; ///< The time sync sequence.
|
||||
int64_t mNetworkTimeOffset; ///< The time offset to the Thread network time, in microseconds.
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -710,6 +715,60 @@ public:
|
||||
return (!mBuffer.mHead.mInfo.mInPriorityQ) ? mBuffer.mHead.mInfo.mQueue.mMessage : NULL;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
/**
|
||||
* This method indicates whether or not the message is also used for time sync purpose.
|
||||
*
|
||||
* @retval TRUE If the message is also used for time sync purpose.
|
||||
* @retval FALSE If the message is not used for time sync purpose.
|
||||
*
|
||||
*/
|
||||
bool IsTimeSync(void) const { return mBuffer.mHead.mInfo.mTimeSync; }
|
||||
|
||||
/**
|
||||
* This method sets whether or not the message is also used for time sync purpose.
|
||||
*
|
||||
* @param[in] aEnabled TRUE if the message is also used for time sync purpose, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
void SetTimeSync(bool aEnabled) { mBuffer.mHead.mInfo.mTimeSync = aEnabled; }
|
||||
|
||||
/**
|
||||
* This method sets the offset to network time.
|
||||
*
|
||||
* @param[in] aNetworkTimeOffset The offset to network time.
|
||||
*
|
||||
*/
|
||||
void SetNetworkTimeOffset(int64_t aNetworkTimeOffset)
|
||||
{
|
||||
mBuffer.mHead.mInfo.mNetworkTimeOffset = aNetworkTimeOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the offset to network time.
|
||||
*
|
||||
* @returns The offset to network time.
|
||||
*
|
||||
*/
|
||||
int64_t GetNetworkTimeOffset(void) const { return mBuffer.mHead.mInfo.mNetworkTimeOffset; }
|
||||
|
||||
/**
|
||||
* This method sets the time sync sequence.
|
||||
*
|
||||
* @param[in] aTimeSyncSeq The time sync sequence.
|
||||
*
|
||||
*/
|
||||
void SetTimeSyncSeq(uint8_t aTimeSyncSeq) { mBuffer.mHead.mInfo.mTimeSyncSeq = aTimeSyncSeq; }
|
||||
|
||||
/**
|
||||
* This method gets the time sync sequence.
|
||||
*
|
||||
* @returns The time sync sequence.
|
||||
*
|
||||
*/
|
||||
uint8_t GetTimeSyncSeq(void) const { return mBuffer.mHead.mInfo.mTimeSyncSeq; }
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
private:
|
||||
/**
|
||||
* This method returns a pointer to the message pool to which this message belongs
|
||||
|
||||
+81
-1
@@ -1104,7 +1104,11 @@ void Mac::BeginTransmit(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
bool applyTransmitSecurity = true;
|
||||
bool processTransmitAesCcm = true;
|
||||
Frame & sendFrame(*GetOperationFrame());
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
uint8_t timeIeOffset = 0;
|
||||
#endif
|
||||
|
||||
VerifyOrExit(mEnabled, error = OT_ERROR_ABORT);
|
||||
|
||||
@@ -1161,10 +1165,24 @@ void Mac::BeginTransmit(void)
|
||||
break;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
timeIeOffset = GetTimeIeOffset(sendFrame);
|
||||
sendFrame.SetTimeIeOffset(timeIeOffset);
|
||||
|
||||
if (timeIeOffset != 0)
|
||||
{
|
||||
// Transmit security will be processed after time IE content is updated.
|
||||
processTransmitAesCcm = false;
|
||||
sendFrame.SetTimeSyncSeq(GetNetif().GetTimeSync().GetTimeSyncSeq());
|
||||
sendFrame.SetNetworkTimeOffset(GetNetif().GetTimeSync().GetNetworkTimeOffset());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (applyTransmitSecurity)
|
||||
{
|
||||
// Security Processing
|
||||
ProcessTransmitSecurity(sendFrame, true);
|
||||
ProcessTransmitSecurity(sendFrame, processTransmitAesCcm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1923,6 +1941,15 @@ void Mac::HandleReceivedFrame(Frame *aFrame, otError aError)
|
||||
|
||||
netif.GetMeshForwarder().GetDataPollManager().CheckFramePending(*aFrame);
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
if (aFrame->GetVersion() == Frame::kFcfFrameVersion2015)
|
||||
{
|
||||
ProcessTimeIe(*aFrame);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (neighbor != NULL)
|
||||
{
|
||||
#if OPENTHREAD_ENABLE_MAC_FILTER
|
||||
@@ -2287,5 +2314,58 @@ void Mac::LogFrameTxFailure(const Frame &, otError) const
|
||||
|
||||
#endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
void Mac::ProcessTimeIe(Frame &aFrame)
|
||||
{
|
||||
TimeIe *timeIe = reinterpret_cast<TimeIe *>(aFrame.GetTimeIe());
|
||||
|
||||
VerifyOrExit(timeIe != NULL);
|
||||
|
||||
aFrame.SetNetworkTimeOffset(static_cast<int64_t>(timeIe->GetTime()) - static_cast<int64_t>(aFrame.GetTimestamp()));
|
||||
aFrame.SetTimeSyncSeq(timeIe->GetSequence());
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t Mac::GetTimeIeOffset(Frame &aFrame)
|
||||
{
|
||||
uint8_t offset = 0;
|
||||
uint8_t *base = aFrame.GetPsdu();
|
||||
uint8_t *cur = NULL;
|
||||
|
||||
cur = aFrame.GetTimeIe();
|
||||
VerifyOrExit(cur != NULL);
|
||||
|
||||
cur += sizeof(VendorIeHeader);
|
||||
offset = cur - base;
|
||||
|
||||
exit:
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will be called from interrupt context, it should only read/write data passed in
|
||||
* via @p aFrame, but should not read/write any state within OpenThread.
|
||||
*/
|
||||
extern "C" void otPlatRadioFrameUpdated(otInstance *aInstance, otRadioFrame *aFrame)
|
||||
{
|
||||
Instance * instance = static_cast<Instance *>(aInstance);
|
||||
Frame frame = *static_cast<Frame *>(aFrame);
|
||||
const ExtAddress *extAddress = NULL;
|
||||
|
||||
VerifyOrExit(instance->IsInitialized());
|
||||
|
||||
if (frame.GetSecurityEnabled() == true)
|
||||
{
|
||||
extAddress = &instance->GetThreadNetif().GetMac().GetExtAddress();
|
||||
instance->GetThreadNetif().GetMac().ProcessTransmitAesCcm(frame, extAddress);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
} // namespace Mac
|
||||
} // namespace ot
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <openthread/platform/radio.h>
|
||||
#include <openthread/platform/time.h>
|
||||
|
||||
#include "common/locator.hpp"
|
||||
#include "common/tasklet.hpp"
|
||||
@@ -986,6 +987,11 @@ private:
|
||||
void LogFrameTxFailure(const Frame &aFrame, otError aError) const;
|
||||
void LogBeacon(const char *aActionText, const BeaconPayload &aBeaconPayload) const;
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
void ProcessTimeIe(Frame &aFrame);
|
||||
uint8_t GetTimeIeOffset(Frame &aFrame);
|
||||
#endif
|
||||
|
||||
static const char *OperationToString(Operation aOperation);
|
||||
|
||||
Operation mOperation;
|
||||
|
||||
+187
-39
@@ -111,27 +111,23 @@ otError Frame::InitMacHeader(uint16_t aFcf, uint8_t aSecurityControl)
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// Source PAN + Address
|
||||
// Source PAN
|
||||
if (IsSrcPanIdPresent(aFcf))
|
||||
{
|
||||
length += sizeof(PanId);
|
||||
}
|
||||
|
||||
// Source Address
|
||||
switch (aFcf & kFcfSrcAddrMask)
|
||||
{
|
||||
case kFcfSrcAddrNone:
|
||||
break;
|
||||
|
||||
case kFcfSrcAddrShort:
|
||||
if ((aFcf & kFcfPanidCompression) == 0)
|
||||
{
|
||||
length += sizeof(PanId);
|
||||
}
|
||||
|
||||
length += sizeof(ShortAddress);
|
||||
break;
|
||||
|
||||
case kFcfSrcAddrExt:
|
||||
if ((aFcf & kFcfPanidCompression) == 0)
|
||||
{
|
||||
length += sizeof(PanId);
|
||||
}
|
||||
|
||||
length += sizeof(ExtAddress);
|
||||
break;
|
||||
|
||||
@@ -363,6 +359,30 @@ exit:
|
||||
return index;
|
||||
}
|
||||
|
||||
bool Frame::IsSrcPanIdPresent(uint16_t aFcf) const
|
||||
{
|
||||
bool srcPanIdPresent = false;
|
||||
|
||||
if ((aFcf & kFcfSrcAddrMask) != kFcfSrcAddrNone && (aFcf & kFcfPanidCompression) == 0)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
// Handle a special case in IEEE 802.15.4-2015, when Pan ID Compression is 0, but Src Pan ID is not present:
|
||||
// Dest Address: Extended
|
||||
// Source Address: Extended
|
||||
// Dest Pan ID: Present
|
||||
// Src Pan ID: Not Present
|
||||
// Pan ID Compression: 0
|
||||
if ((aFcf & kFcfFrameVersionMask) != kFcfFrameVersion2015 || (aFcf & kFcfDstAddrMask) != kFcfDstAddrExt ||
|
||||
(aFcf & kFcfSrcAddrMask) != kFcfSrcAddrExt)
|
||||
#endif
|
||||
{
|
||||
srcPanIdPresent = true;
|
||||
}
|
||||
}
|
||||
|
||||
return srcPanIdPresent;
|
||||
}
|
||||
|
||||
otError Frame::GetSrcPanId(PanId &aPanId) const
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
@@ -408,7 +428,7 @@ uint8_t Frame::FindSrcAddrIndex(void) const
|
||||
}
|
||||
|
||||
// Source PAN
|
||||
if ((fcf & kFcfPanidCompression) == 0)
|
||||
if (IsSrcPanIdPresent(fcf))
|
||||
{
|
||||
index += sizeof(PanId);
|
||||
}
|
||||
@@ -515,24 +535,20 @@ uint8_t Frame::FindSecurityHeaderIndex(void) const
|
||||
break;
|
||||
}
|
||||
|
||||
// Source PAN + Address
|
||||
// Source PAN
|
||||
if (IsSrcPanIdPresent(fcf))
|
||||
{
|
||||
index += sizeof(PanId);
|
||||
}
|
||||
|
||||
// Source Address
|
||||
switch (fcf & kFcfSrcAddrMask)
|
||||
{
|
||||
case kFcfSrcAddrShort:
|
||||
if ((fcf & kFcfPanidCompression) == 0)
|
||||
{
|
||||
index += sizeof(PanId);
|
||||
}
|
||||
|
||||
index += sizeof(ShortAddress);
|
||||
break;
|
||||
|
||||
case kFcfSrcAddrExt:
|
||||
if ((fcf & kFcfPanidCompression) == 0)
|
||||
{
|
||||
index += sizeof(PanId);
|
||||
}
|
||||
|
||||
index += sizeof(ExtAddress);
|
||||
break;
|
||||
}
|
||||
@@ -784,7 +800,7 @@ otError Frame::SetPayloadLength(uint8_t aLength)
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
uint8_t Frame::FindPayloadIndex(void) const
|
||||
uint8_t Frame::SkipSecurityHeaderIndex(void) const
|
||||
{
|
||||
uint8_t index = 0;
|
||||
uint16_t fcf;
|
||||
@@ -816,27 +832,23 @@ uint8_t Frame::FindPayloadIndex(void) const
|
||||
ExitNow(index = kInvalidIndex);
|
||||
}
|
||||
|
||||
// Source PAN + Address
|
||||
// Source PAN
|
||||
if (IsSrcPanIdPresent(fcf))
|
||||
{
|
||||
index += sizeof(PanId);
|
||||
}
|
||||
|
||||
// Source Address
|
||||
switch (fcf & kFcfSrcAddrMask)
|
||||
{
|
||||
case kFcfSrcAddrNone:
|
||||
break;
|
||||
|
||||
case kFcfSrcAddrShort:
|
||||
if ((fcf & kFcfPanidCompression) == 0)
|
||||
{
|
||||
index += sizeof(PanId);
|
||||
}
|
||||
|
||||
index += sizeof(ShortAddress);
|
||||
break;
|
||||
|
||||
case kFcfSrcAddrExt:
|
||||
if ((fcf & kFcfPanidCompression) == 0)
|
||||
{
|
||||
index += sizeof(PanId);
|
||||
}
|
||||
|
||||
index += sizeof(ExtAddress);
|
||||
break;
|
||||
|
||||
@@ -873,6 +885,49 @@ uint8_t Frame::FindPayloadIndex(void) const
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return index;
|
||||
}
|
||||
|
||||
uint8_t Frame::FindPayloadIndex(void) const
|
||||
{
|
||||
uint16_t fcf = GetFrameControlField();
|
||||
uint8_t index = SkipSecurityHeaderIndex();
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
uint8_t *cur = NULL;
|
||||
uint8_t *footer = GetFooter();
|
||||
#endif
|
||||
|
||||
VerifyOrExit(index != kInvalidIndex);
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
cur = GetPsdu() + index;
|
||||
|
||||
if (IsIePresent())
|
||||
{
|
||||
while (cur + sizeof(HeaderIe) <= footer)
|
||||
{
|
||||
HeaderIe *ie = reinterpret_cast<HeaderIe *>(cur);
|
||||
uint8_t len = static_cast<uint8_t>(ie->GetLength());
|
||||
|
||||
cur += sizeof(HeaderIe);
|
||||
index += sizeof(HeaderIe);
|
||||
|
||||
VerifyOrExit(cur + len <= footer, index = kInvalidIndex);
|
||||
|
||||
cur += len;
|
||||
index += len;
|
||||
|
||||
if (ie->GetId() == kHeaderIeTermination2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Assume no Payload IE in current implementation
|
||||
}
|
||||
#endif
|
||||
|
||||
// Command ID
|
||||
if ((fcf & kFcfFrameTypeMask) == kFcfFrameMacCmd)
|
||||
{
|
||||
@@ -894,10 +949,10 @@ exit:
|
||||
return payload;
|
||||
}
|
||||
|
||||
const uint8_t *Frame::GetPayload(void) const
|
||||
uint8_t *Frame::GetPayload(void) const
|
||||
{
|
||||
uint8_t index = FindPayloadIndex();
|
||||
const uint8_t *payload = GetPsdu() + index;
|
||||
uint8_t index = FindPayloadIndex();
|
||||
uint8_t *payload = GetPsdu() + index;
|
||||
|
||||
VerifyOrExit(index != kInvalidIndex, payload = NULL);
|
||||
|
||||
@@ -910,11 +965,104 @@ uint8_t *Frame::GetFooter(void)
|
||||
return GetPsdu() + GetPsduLength() - GetFooterLength();
|
||||
}
|
||||
|
||||
const uint8_t *Frame::GetFooter(void) const
|
||||
uint8_t *Frame::GetFooter(void) const
|
||||
{
|
||||
return GetPsdu() + GetPsduLength() - GetFooterLength();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
uint8_t Frame::FindHeaderIeIndex(void) const
|
||||
{
|
||||
uint8_t index;
|
||||
|
||||
VerifyOrExit(IsIePresent(), index = kInvalidIndex);
|
||||
|
||||
index = SkipSecurityHeaderIndex();
|
||||
|
||||
exit:
|
||||
return index;
|
||||
}
|
||||
|
||||
otError Frame::AppendHeaderIe(HeaderIe *aIeList, uint8_t aIeCount)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint8_t index = FindHeaderIeIndex();
|
||||
uint8_t *cur;
|
||||
uint8_t *base;
|
||||
|
||||
VerifyOrExit(index != kInvalidIndex, error = OT_ERROR_FAILED);
|
||||
cur = GetPsdu() + index;
|
||||
base = cur;
|
||||
|
||||
for (uint8_t i = 0; i < aIeCount; i++)
|
||||
{
|
||||
memcpy(cur, &aIeList[i], sizeof(HeaderIe));
|
||||
cur += sizeof(HeaderIe);
|
||||
cur += aIeList[i].GetLength();
|
||||
}
|
||||
|
||||
SetPsduLength(GetPsduLength() + cur - base);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t *Frame::GetHeaderIe(uint8_t aIeId) const
|
||||
{
|
||||
uint8_t index = FindHeaderIeIndex();
|
||||
uint8_t *cur = NULL;
|
||||
uint8_t *payload = GetPayload();
|
||||
|
||||
VerifyOrExit(index != kInvalidIndex);
|
||||
|
||||
cur = GetPsdu() + index;
|
||||
|
||||
while (cur + sizeof(HeaderIe) <= payload)
|
||||
{
|
||||
HeaderIe *ie = reinterpret_cast<HeaderIe *>(cur);
|
||||
uint8_t len = static_cast<uint8_t>(ie->GetLength());
|
||||
|
||||
if (ie->GetId() == aIeId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
cur += sizeof(HeaderIe);
|
||||
|
||||
VerifyOrExit(cur + len <= payload, cur = NULL);
|
||||
|
||||
cur += len;
|
||||
}
|
||||
|
||||
if (cur == payload)
|
||||
{
|
||||
cur = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
return cur;
|
||||
}
|
||||
|
||||
uint8_t *Frame::GetTimeIe(void) const
|
||||
{
|
||||
TimeIe * timeIe = NULL;
|
||||
uint8_t *cur = NULL;
|
||||
uint8_t oui[kVendorOuiSize] = {kVendorOuiNest & 0xff, (kVendorOuiNest >> 8) & 0xff, (kVendorOuiNest >> 16) & 0xff};
|
||||
|
||||
cur = GetHeaderIe(kHeaderIeVendor);
|
||||
VerifyOrExit(cur != NULL);
|
||||
|
||||
cur += sizeof(HeaderIe);
|
||||
|
||||
timeIe = reinterpret_cast<TimeIe *>(cur);
|
||||
VerifyOrExit(memcmp(oui, timeIe->GetVendorOui(), kVendorOuiSize) == 0, cur = NULL);
|
||||
VerifyOrExit(timeIe->GetSubType() == kVendorIeTime, cur = NULL);
|
||||
|
||||
exit:
|
||||
return cur;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
Frame::InfoString Frame::ToInfoString(void) const
|
||||
{
|
||||
InfoString string;
|
||||
|
||||
+297
-4
@@ -377,6 +377,76 @@ private:
|
||||
Type mType; ///< The address type (Short, Extended, or none).
|
||||
};
|
||||
|
||||
/**
|
||||
* This class implements IEEE 802.15.4 IE (Information Element) generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class HeaderIe
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kIdOffset = 7,
|
||||
kIdMask = 0xff << kIdOffset,
|
||||
kLengthOffset = 0,
|
||||
kLengthMask = 0x7f << kLengthOffset,
|
||||
};
|
||||
|
||||
/**
|
||||
* This method initializes the Header IE.
|
||||
*
|
||||
*/
|
||||
void Init(void) { mHeaderIe = 0; }
|
||||
|
||||
/**
|
||||
* This method returns the IE Element Id.
|
||||
*
|
||||
* @returns the IE Element Id.
|
||||
*
|
||||
*/
|
||||
uint16_t GetId(void) const { return (ot::Encoding::LittleEndian::HostSwap16(mHeaderIe) & kIdMask) >> kIdOffset; }
|
||||
|
||||
/**
|
||||
* This method sets the IE Element Id.
|
||||
*
|
||||
* @param[in] aID The IE Element Id.
|
||||
*
|
||||
*/
|
||||
void SetId(uint16_t aId)
|
||||
{
|
||||
mHeaderIe = ot::Encoding::LittleEndian::HostSwap16(
|
||||
(ot::Encoding::LittleEndian::HostSwap16(mHeaderIe) & ~kIdMask) | ((aId << kIdOffset) & kIdMask));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the IE content length.
|
||||
*
|
||||
* @returns the IE content length.
|
||||
*
|
||||
*/
|
||||
uint16_t GetLength(void) const
|
||||
{
|
||||
return (ot::Encoding::LittleEndian::HostSwap16(mHeaderIe) & kLengthMask) >> kLengthOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the IE content length.
|
||||
*
|
||||
* @param[in] aLength The IE content length.
|
||||
*
|
||||
*/
|
||||
void SetLength(uint16_t aLength)
|
||||
{
|
||||
mHeaderIe =
|
||||
ot::Encoding::LittleEndian::HostSwap16((ot::Encoding::LittleEndian::HostSwap16(mHeaderIe) & ~kLengthMask) |
|
||||
((aLength << kLengthOffset) & kLengthMask));
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t mHeaderIe;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements IEEE 802.15.4 MAC frame generation and parsing.
|
||||
*
|
||||
@@ -403,12 +473,14 @@ public:
|
||||
kFcfFramePending = 1 << 4,
|
||||
kFcfAckRequest = 1 << 5,
|
||||
kFcfPanidCompression = 1 << 6,
|
||||
kFcfIePresent = 1 << 9,
|
||||
kFcfDstAddrNone = 0 << 10,
|
||||
kFcfDstAddrShort = 2 << 10,
|
||||
kFcfDstAddrExt = 3 << 10,
|
||||
kFcfDstAddrMask = 3 << 10,
|
||||
kFcfFrameVersion2006 = 1 << 12,
|
||||
kFcfFrameVersionMask = 3 << 13,
|
||||
kFcfFrameVersion2015 = 2 << 12,
|
||||
kFcfFrameVersionMask = 3 << 12,
|
||||
kFcfSrcAddrNone = 0 << 14,
|
||||
kFcfSrcAddrShort = 2 << 14,
|
||||
kFcfSrcAddrExt = 3 << 14,
|
||||
@@ -453,6 +525,12 @@ public:
|
||||
kMacCmdCoordinatorRealignment = 8,
|
||||
kMacCmdGtsRequest = 9,
|
||||
|
||||
kHeaderIeVendor = 0x00,
|
||||
kHeaderIeTermination2 = 0x7f,
|
||||
kVendorOuiNest = 0x18b430,
|
||||
kVendorOuiSize = 3,
|
||||
kVendorIeTime = 0x01,
|
||||
|
||||
kInfoStringSize = 110, ///< Max chars needed for the info string representation (@sa ToInfoString()).
|
||||
};
|
||||
|
||||
@@ -491,6 +569,14 @@ public:
|
||||
*/
|
||||
uint8_t GetType(void) const { return GetPsdu()[0] & kFcfFrameTypeMask; }
|
||||
|
||||
/**
|
||||
* This method returns the IEEE 802.15.4 Frame Version.
|
||||
*
|
||||
* @returns The IEEE 802.15.4 Frame Version.
|
||||
*
|
||||
*/
|
||||
uint16_t GetVersion(void) const { return GetFrameControlField() & kFcfFrameVersionMask; };
|
||||
|
||||
/**
|
||||
* This method indicates whether or not security is enabled.
|
||||
*
|
||||
@@ -534,6 +620,15 @@ public:
|
||||
*/
|
||||
void SetAckRequest(bool aAckRequest);
|
||||
|
||||
/**
|
||||
* This method indicates whether or not IEs present.
|
||||
*
|
||||
* @retval TRUE If IEs present.
|
||||
* @retval FALSE If no IE present.
|
||||
*
|
||||
*/
|
||||
bool IsIePresent(void) const { return (GetFrameControlField() & kFcfIePresent) != 0; };
|
||||
|
||||
/**
|
||||
* This method returns the Sequence Number value.
|
||||
*
|
||||
@@ -610,6 +705,14 @@ public:
|
||||
*/
|
||||
otError SetDstAddr(const Address &aAddress);
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the Src PanId is present.
|
||||
*
|
||||
* @returns TRUE if the Src PanId is present, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsSrcPanIdPresent(uint16_t aFcf) const;
|
||||
|
||||
/**
|
||||
* This method gets the Source PAN Identifier.
|
||||
*
|
||||
@@ -980,7 +1083,7 @@ public:
|
||||
* @returns A pointer to the PSDU.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetPsdu(void) const { return mPsdu; }
|
||||
uint8_t *GetPsdu(void) const { return mPsdu; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the MAC Header.
|
||||
@@ -1012,7 +1115,7 @@ public:
|
||||
* @returns A pointer to the MAC Payload.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetPayload(void) const;
|
||||
uint8_t *GetPayload(void) const;
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the MAC Footer.
|
||||
@@ -1028,7 +1131,88 @@ public:
|
||||
* @returns A pointer to the MAC Footer.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetFooter(void) const;
|
||||
uint8_t *GetFooter(void) const;
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
/**
|
||||
* This method sets the Time IE offset.
|
||||
*
|
||||
* @param[in] aOffset The Time IE offset, 0 means no Time IE.
|
||||
*
|
||||
*/
|
||||
void SetTimeIeOffset(uint8_t aOffset) { mIeInfo->mTimeIeOffset = aOffset; }
|
||||
|
||||
/**
|
||||
* This method sets the offset to network time.
|
||||
*
|
||||
* @param[in] aNetworkTimeOffset The offset to network time.
|
||||
*
|
||||
*/
|
||||
void SetNetworkTimeOffset(int64_t aNetworkTimeOffset) { mIeInfo->mNetworkTimeOffset = aNetworkTimeOffset; }
|
||||
|
||||
/**
|
||||
* This method gets the offset to network time.
|
||||
*
|
||||
* @returns The offset to network time.
|
||||
*
|
||||
*/
|
||||
int64_t GetNetworkTimeOffset(void) const { return mIeInfo->mNetworkTimeOffset; }
|
||||
|
||||
/**
|
||||
* This method sets the time sync sequence.
|
||||
*
|
||||
* @param[in] aTimeSyncSeq The time sync sequence.
|
||||
*
|
||||
*/
|
||||
void SetTimeSyncSeq(uint8_t aTimeSyncSeq) { mIeInfo->mTimeSyncSeq = aTimeSyncSeq; }
|
||||
|
||||
/**
|
||||
* This method gets the time sync sequence.
|
||||
*
|
||||
* @returns The time sync sequence.
|
||||
*
|
||||
*/
|
||||
uint8_t GetTimeSyncSeq(void) const { return mIeInfo->mTimeSyncSeq; }
|
||||
|
||||
/**
|
||||
* This method returns the timestamp when the SFD was received.
|
||||
*
|
||||
* @returns The timestamp when the SFD was received, in microseconds.
|
||||
*
|
||||
*/
|
||||
uint64_t GetTimestamp(void) const { return mIeInfo->mTimestamp; }
|
||||
|
||||
/**
|
||||
* This method appends Header IEs to MAC header.
|
||||
*
|
||||
* @param[in] aIeList The pointer to the Header IEs array.
|
||||
* @param[in] aIeCount The number of Header IEs in the array.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully appended the Header IEs.
|
||||
* @retval OT_ERROR_FAILED If IE Present bit is not set.
|
||||
*
|
||||
*/
|
||||
otError AppendHeaderIe(HeaderIe *aIeList, uint8_t aIeCount);
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the Header IE.
|
||||
*
|
||||
* @param[in] aIeId The Element Id of the Header IE.
|
||||
*
|
||||
* @returns A pointer to the Header IE, NULL if not found.
|
||||
*
|
||||
*/
|
||||
uint8_t *GetHeaderIe(uint8_t aIeId) const;
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the vendor specific Time IE.
|
||||
*
|
||||
* @returns A pointer to the Time IE, NULL if not found.
|
||||
*
|
||||
*/
|
||||
uint8_t *GetTimeIe(void) const;
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
/**
|
||||
* This method returns information about the frame object as an `InfoString` object.
|
||||
@@ -1051,7 +1235,11 @@ private:
|
||||
uint8_t FindSrcPanIdIndex(void) const;
|
||||
uint8_t FindSrcAddrIndex(void) const;
|
||||
uint8_t FindSecurityHeaderIndex(void) const;
|
||||
uint8_t SkipSecurityHeaderIndex(void) const;
|
||||
uint8_t FindPayloadIndex(void) const;
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
uint8_t FindHeaderIeIndex(void) const;
|
||||
#endif
|
||||
|
||||
static uint8_t GetKeySourceLength(uint8_t aKeyIdMode);
|
||||
};
|
||||
@@ -1271,6 +1459,111 @@ private:
|
||||
uint8_t mExtendedPanId[kExtPanIdSize];
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
/**
|
||||
* This class implements vendor specific Header IE generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class VendorIeHeader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method returns the Vendor OUI.
|
||||
*
|
||||
* @returns the Vendor OUI.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetVendorOui(void) const { return mVendorOui; }
|
||||
|
||||
/**
|
||||
* This method sets the Vendor OUI.
|
||||
*
|
||||
* @param[in] aVendorOui A pointer to the Vendor OUI.
|
||||
*
|
||||
*/
|
||||
void SetVendorOui(uint8_t *aVendorOui) { memcpy(mVendorOui, aVendorOui, Frame::kVendorOuiSize); }
|
||||
|
||||
/**
|
||||
* This method returns the Vendor IE sub-type.
|
||||
*
|
||||
* @returns the Vendor IE sub-type.
|
||||
*
|
||||
*/
|
||||
uint8_t GetSubType(void) const { return mSubType; }
|
||||
|
||||
/**
|
||||
* This method sets the Vendor IE sub-type.
|
||||
*
|
||||
* @param[in] the Vendor IE sub-type.
|
||||
*
|
||||
*/
|
||||
void SetSubType(uint8_t aSubType) { mSubType = aSubType; }
|
||||
|
||||
private:
|
||||
uint8_t mVendorOui[Frame::kVendorOuiSize];
|
||||
uint8_t mSubType;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements Time Header IE generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class TimeIe : public VendorIeHeader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the time IE.
|
||||
*
|
||||
*/
|
||||
void Init(void)
|
||||
{
|
||||
uint8_t oui[3] = {Frame::kVendorOuiNest & 0xff, (Frame::kVendorOuiNest >> 8) & 0xff,
|
||||
(Frame::kVendorOuiNest >> 16) & 0xff};
|
||||
|
||||
SetVendorOui(oui);
|
||||
SetSubType(Frame::kVendorIeTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the time sync sequence.
|
||||
*
|
||||
* @returns the time sync sequence.
|
||||
*
|
||||
*/
|
||||
uint8_t GetSequence(void) const { return mSequence; }
|
||||
|
||||
/**
|
||||
* This method sets the tine sync sequence.
|
||||
*
|
||||
* @param[in] aSequence The time sync sequence.
|
||||
*
|
||||
*/
|
||||
void SetSequence(uint8_t aSequence) { mSequence = aSequence; }
|
||||
|
||||
/**
|
||||
* This method returns the network time.
|
||||
*
|
||||
* @returns the network time, in microseconds.
|
||||
*
|
||||
*/
|
||||
uint64_t GetTime(void) const { return ot::Encoding::LittleEndian::HostSwap64(mTime); }
|
||||
|
||||
/**
|
||||
* This method sets the network time.
|
||||
*
|
||||
* @param[in] aTime The network time.
|
||||
*
|
||||
*/
|
||||
void SetTime(uint64_t aTime) { mTime = ot::Encoding::LittleEndian::HostSwap64(aTime); }
|
||||
|
||||
private:
|
||||
uint8_t mSequence;
|
||||
uint64_t mTime;
|
||||
} OT_TOOL_PACKED_END;
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -1632,4 +1632,54 @@
|
||||
#define OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE 256
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
*
|
||||
* Define as 1 to enable the time synchronization service feature.
|
||||
*
|
||||
* @note If it's enabled, plaforms must support interrupt context and concurrent access AES.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
#define OPENTHREAD_CONFIG_ENABLE_TIME_SYNC 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
|
||||
*
|
||||
* Define as 1 to require time synchronization when attaching to a network. If the device is router capable
|
||||
* and cannot find a neighboring router supporting time synchronization, the device will form a new partition.
|
||||
* If the device is not router capable, the device will remain an orphan.
|
||||
*
|
||||
* Applicable only if time synchronization service feature is enabled (i.e., OPENTHREAD_CONFIG_ENABLE_TIME_SYNC is set)
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
|
||||
#define OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_TIME_SYNC_PERIOD
|
||||
*
|
||||
* Specifies the default period of time synchronization, in seconds.
|
||||
*
|
||||
* Applicable only if time synchronization service feature is enabled (i.e., OPENTHREAD_CONFIG_ENABLE_TIME_SYNC is set)
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_TIME_SYNC_PERIOD
|
||||
#define OPENTHREAD_CONFIG_TIME_SYNC_PERIOD 30
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_TIME_SYNC_XTAL_THRESHOLD
|
||||
*
|
||||
* Specifies the default XTAL threshold for a device to become Router in time synchronization enabled network, in PPM.
|
||||
*
|
||||
* Applicable only if time synchronization service feature is enabled (i.e., OPENTHREAD_CONFIG_ENABLE_TIME_SYNC is set)
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_TIME_SYNC_XTAL_THRESHOLD
|
||||
#define OPENTHREAD_CONFIG_TIME_SYNC_XTAL_THRESHOLD 300
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_CORE_DEFAULT_CONFIG_H_
|
||||
|
||||
@@ -622,6 +622,9 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
|
||||
uint16_t dstpan;
|
||||
uint8_t secCtl = Mac::Frame::kSecNone;
|
||||
otError error = OT_ERROR_NONE;
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
Mac::HeaderIe ieList[2];
|
||||
#endif
|
||||
|
||||
if (mAddMeshHeader)
|
||||
{
|
||||
@@ -635,7 +638,20 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
|
||||
}
|
||||
|
||||
// initialize MAC header
|
||||
fcf = Mac::Frame::kFcfFrameData | Mac::Frame::kFcfFrameVersion2006;
|
||||
fcf = Mac::Frame::kFcfFrameData;
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
if (aMessage.IsTimeSync())
|
||||
{
|
||||
fcf |= Mac::Frame::kFcfFrameVersion2015 | Mac::Frame::kFcfIePresent;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fcf |= Mac::Frame::kFcfFrameVersion2006;
|
||||
}
|
||||
|
||||
fcf |= (mMacDest.IsShort()) ? Mac::Frame::kFcfDstAddrShort : Mac::Frame::kFcfDstAddrExt;
|
||||
fcf |= (mMacSource.IsShort()) ? Mac::Frame::kFcfSrcAddrShort : Mac::Frame::kFcfSrcAddrExt;
|
||||
|
||||
@@ -687,7 +703,21 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
|
||||
|
||||
if (dstpan == netif.GetMac().GetPanId())
|
||||
{
|
||||
fcf |= Mac::Frame::kFcfPanidCompression;
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
// Handle a special case in IEEE 802.15.4-2015, when Pan ID Compression is 0, but Src Pan ID is not present:
|
||||
// Dest Address: Extended
|
||||
// Src Address: Extended
|
||||
// Dest Pan ID: Present
|
||||
// Src Pan ID: Not Present
|
||||
// Pan ID Compression: 0
|
||||
|
||||
if ((fcf & Mac::Frame::kFcfFrameVersionMask) != Mac::Frame::kFcfFrameVersion2015 ||
|
||||
(fcf & Mac::Frame::kFcfDstAddrMask) != Mac::Frame::kFcfDstAddrExt ||
|
||||
(fcf & Mac::Frame::kFcfSrcAddrMask) != Mac::Frame::kFcfSrcAddrExt)
|
||||
#endif
|
||||
{
|
||||
fcf |= Mac::Frame::kFcfPanidCompression;
|
||||
}
|
||||
}
|
||||
|
||||
aFrame.InitMacHeader(fcf, secCtl);
|
||||
@@ -696,6 +726,28 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
|
||||
aFrame.SetDstAddr(mMacDest);
|
||||
aFrame.SetSrcAddr(mMacSource);
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
if (aMessage.IsTimeSync())
|
||||
{
|
||||
Mac::TimeIe *ie;
|
||||
uint8_t * cur = NULL;
|
||||
|
||||
ieList[0].Init();
|
||||
ieList[0].SetId(Mac::Frame::kHeaderIeVendor);
|
||||
ieList[0].SetLength(sizeof(Mac::TimeIe));
|
||||
ieList[1].Init();
|
||||
ieList[1].SetId(Mac::Frame::kHeaderIeTermination2);
|
||||
ieList[1].SetLength(0);
|
||||
aFrame.AppendHeaderIe(ieList, 2);
|
||||
|
||||
cur = aFrame.GetHeaderIe(Mac::Frame::kHeaderIeVendor);
|
||||
ie = reinterpret_cast<Mac::TimeIe *>(cur + sizeof(Mac::HeaderIe));
|
||||
ie->Init();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
payload = aFrame.GetPayload();
|
||||
|
||||
headerLength = 0;
|
||||
@@ -833,6 +885,9 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
|
||||
if (mMessageNextOffset < aMessage.GetLength())
|
||||
{
|
||||
aFrame.SetFramePending(true);
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
aMessage.SetTimeSync(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -1110,6 +1165,10 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame)
|
||||
linkInfo.mRss = aFrame.GetRssi();
|
||||
linkInfo.mLqi = aFrame.GetLqi();
|
||||
linkInfo.mLinkSecurity = aFrame.GetSecurityEnabled();
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
linkInfo.mNetworkTimeOffset = aFrame.GetNetworkTimeOffset();
|
||||
linkInfo.mTimeSyncSeq = aFrame.GetTimeSyncSeq();
|
||||
#endif
|
||||
|
||||
payload = aFrame.GetPayload();
|
||||
payloadLength = aFrame.GetPayloadLength();
|
||||
@@ -1204,6 +1263,10 @@ void MeshForwarder::HandleFragment(uint8_t * aFrame,
|
||||
message->SetLinkSecurityEnabled(aLinkInfo.mLinkSecurity);
|
||||
message->SetPanId(aLinkInfo.mPanId);
|
||||
message->AddRss(aLinkInfo.mRss);
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
message->SetTimeSyncSeq(aLinkInfo.mTimeSyncSeq);
|
||||
message->SetNetworkTimeOffset(aLinkInfo.mNetworkTimeOffset);
|
||||
#endif
|
||||
headerLength = netif.GetLowpan().Decompress(*message, aMacSource, aMacDest, aFrame, aFrameLength,
|
||||
fragmentHeader.GetDatagramSize());
|
||||
VerifyOrExit(headerLength > 0, error = OT_ERROR_PARSE);
|
||||
@@ -1372,6 +1435,10 @@ void MeshForwarder::HandleLowpanHC(uint8_t * aFrame,
|
||||
message->SetLinkSecurityEnabled(aLinkInfo.mLinkSecurity);
|
||||
message->SetPanId(aLinkInfo.mPanId);
|
||||
message->AddRss(aLinkInfo.mRss);
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
message->SetTimeSyncSeq(aLinkInfo.mTimeSyncSeq);
|
||||
message->SetNetworkTimeOffset(aLinkInfo.mNetworkTimeOffset);
|
||||
#endif
|
||||
|
||||
headerLength = netif.GetLowpan().Decompress(*message, aMacSource, aMacDest, aFrame, aFrameLength, 0);
|
||||
VerifyOrExit(headerLength > 0, error = OT_ERROR_PARSE);
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "mle.hpp"
|
||||
|
||||
#include <openthread/platform/radio.h>
|
||||
#include <openthread/platform/time.h>
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
@@ -55,6 +56,7 @@
|
||||
#include "thread/key_manager.hpp"
|
||||
#include "thread/mle_router.hpp"
|
||||
#include "thread/thread_netif.hpp"
|
||||
#include "thread/time_sync_service.hpp"
|
||||
|
||||
using ot::Encoding::BigEndian::HostSwap16;
|
||||
|
||||
@@ -1349,6 +1351,38 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
otError Mle::AppendTimeRequest(Message &aMessage)
|
||||
{
|
||||
TimeRequestTlv tlv;
|
||||
|
||||
tlv.Init();
|
||||
|
||||
return aMessage.Append(&tlv, sizeof(tlv));
|
||||
}
|
||||
|
||||
otError Mle::AppendTimeParameter(Message &aMessage)
|
||||
{
|
||||
TimeParameterTlv tlv;
|
||||
|
||||
tlv.Init();
|
||||
tlv.SetTimeSyncPeriod(GetNetif().GetTimeSync().GetTimeSyncPeriod());
|
||||
tlv.SetXtalThreshold(GetNetif().GetTimeSync().GetXtalThreshold());
|
||||
|
||||
return aMessage.Append(&tlv, sizeof(tlv));
|
||||
}
|
||||
|
||||
otError Mle::AppendXtalAccuracy(Message &aMessage)
|
||||
{
|
||||
XtalAccuracyTlv tlv;
|
||||
|
||||
tlv.Init();
|
||||
tlv.SetXtalAccuracy(otPlatTimeGetXtalAccuracy());
|
||||
|
||||
return aMessage.Append(&tlv, sizeof(tlv));
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
otError Mle::AppendActiveTimestamp(Message &aMessage)
|
||||
{
|
||||
ThreadNetif & netif = GetNetif();
|
||||
@@ -1845,6 +1879,9 @@ otError Mle::SendParentRequest(ParentRequestType aType)
|
||||
SuccessOrExit(error = AppendChallenge(*message, mParentRequest.mChallenge, sizeof(mParentRequest.mChallenge)));
|
||||
SuccessOrExit(error = AppendScanMask(*message, scanMask));
|
||||
SuccessOrExit(error = AppendVersion(*message));
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
SuccessOrExit(error = AppendTimeRequest(*message));
|
||||
#endif
|
||||
|
||||
memset(&destination, 0, sizeof(destination));
|
||||
destination.mFields.m16[0] = HostSwap16(0xff02);
|
||||
@@ -2604,6 +2641,12 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
|
||||
case Header::kCommandAnnounce:
|
||||
HandleAnnounce(aMessage, aMessageInfo);
|
||||
break;
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
case Header::kCommandTimeSync:
|
||||
mle.HandleTimeSync(aMessage, aMessageInfo);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -2947,6 +2990,9 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf
|
||||
MleFrameCounterTlv mleFrameCounter;
|
||||
ChallengeTlv challenge;
|
||||
Mac::ExtAddress extAddress;
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
TimeParameterTlv timeParameter;
|
||||
#endif
|
||||
|
||||
// Source Address
|
||||
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kSourceAddress, sizeof(sourceAddress), sourceAddress));
|
||||
@@ -3050,6 +3096,27 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf
|
||||
mleFrameCounter.SetFrameCounter(linkFrameCounter.GetFrameCounter());
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
// Time Parameter
|
||||
if (Tlv::GetTlv(aMessage, Tlv::kTimeParameter, sizeof(timeParameter), timeParameter) == OT_ERROR_NONE)
|
||||
{
|
||||
VerifyOrExit(timeParameter.IsValid());
|
||||
|
||||
GetNetif().GetTimeSync().SetTimeSyncPeriod(timeParameter.GetTimeSyncPeriod());
|
||||
GetNetif().GetTimeSync().SetXtalThreshold(timeParameter.GetXtalThreshold());
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
|
||||
else
|
||||
{
|
||||
// If the time sync feature is required, don't choose the parent which doesn't support it.
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
// Challenge
|
||||
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kChallenge, sizeof(challenge), challenge));
|
||||
VerifyOrExit(challenge.IsValid(), error = OT_ERROR_PARSE);
|
||||
@@ -3158,6 +3225,14 @@ otError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::MessageIn
|
||||
netif.GetPendingDataset().ClearNetwork();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
// Sync to Thread network time
|
||||
if (aMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ)
|
||||
{
|
||||
GetNetif().GetTimeSync().HandleTimeSyncMessage(aMessage);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Parent Attach Success
|
||||
mAttachTimer.Stop();
|
||||
SetStateDetached();
|
||||
|
||||
@@ -301,6 +301,13 @@ public:
|
||||
kCommandAnnounce = 15, ///< Announce
|
||||
kCommandDiscoveryRequest = 16, ///< Discovery Request
|
||||
kCommandDiscoveryResponse = 17, ///< Discovery Response
|
||||
|
||||
/**
|
||||
* Applicable/Required only when time synchronization service
|
||||
* (`OPENTHREAD_CONFIG_ENABLE_TIME_SYNC`) is enabled.
|
||||
*
|
||||
*/
|
||||
kCommandTimeSync = 99, ///< Time Synchronization
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1248,6 +1255,41 @@ protected:
|
||||
*/
|
||||
otError AppendAddressRegistration(Message &aMessage);
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
/**
|
||||
* This method appends a Time Request TLV to a message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully appended the Time Request TLV.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to append the Time Request TLV.
|
||||
*
|
||||
*/
|
||||
otError AppendTimeRequest(Message &aMessage);
|
||||
|
||||
/**
|
||||
* This method appends a Time Parameter TLV to a message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully appended the Time Parameter TLV.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to append the Time Parameter TLV.
|
||||
*
|
||||
*/
|
||||
otError AppendTimeParameter(Message &aMessage);
|
||||
|
||||
/**
|
||||
* This method appends a XTAL Accuracy TLV to a message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully appended the XTAL Accuracy TLV.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to append the XTAl Accuracy TLV.
|
||||
*
|
||||
*/
|
||||
otError AppendXtalAccuracy(Message &aMessage);
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
/**
|
||||
* This method appends a Active Timestamp TLV to a message.
|
||||
*
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "thread/thread_netif.hpp"
|
||||
#include "thread/thread_tlvs.hpp"
|
||||
#include "thread/thread_uri_paths.hpp"
|
||||
#include "thread/time_sync_service.hpp"
|
||||
|
||||
using ot::Encoding::BigEndian::HostSwap16;
|
||||
|
||||
@@ -506,6 +507,10 @@ otError MleRouter::SendLinkRequest(Neighbor *aNeighbor)
|
||||
break;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
SuccessOrExit(error = AppendTimeRequest(*message));
|
||||
#endif
|
||||
|
||||
if (aNeighbor == NULL)
|
||||
{
|
||||
Random::FillBuffer(mChallenge, sizeof(mChallenge));
|
||||
@@ -561,6 +566,9 @@ otError MleRouter::HandleLinkRequest(const Message &aMessage, const Ip6::Message
|
||||
SourceAddressTlv sourceAddress;
|
||||
TlvRequestTlv tlvRequest;
|
||||
uint16_t rloc16;
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
TimeRequestTlv timeRequest;
|
||||
#endif
|
||||
|
||||
LogMleMessage("Receive Link Request", aMessageInfo.GetPeerAddr());
|
||||
|
||||
@@ -646,6 +654,17 @@ otError MleRouter::HandleLinkRequest(const Message &aMessage, const Ip6::Message
|
||||
tlvRequest.SetLength(0);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
if (Tlv::GetTlv(aMessage, Tlv::kTimeRequest, sizeof(timeRequest), timeRequest) == OT_ERROR_NONE)
|
||||
{
|
||||
neighbor->SetTimeSyncEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
neighbor->SetTimeSyncEnabled(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
SuccessOrExit(error = SendLinkAccept(aMessageInfo, neighbor, tlvRequest, challenge));
|
||||
|
||||
exit:
|
||||
@@ -717,6 +736,13 @@ otError MleRouter::SendLinkAccept(const Ip6::MessageInfo &aMessageInfo,
|
||||
aNeighbor->SetState(Neighbor::kStateLinkRequest);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
if (aNeighbor->IsTimeSyncEnabled())
|
||||
{
|
||||
message->SetTimeSync(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (aMessageInfo.GetSockAddr().IsMulticast())
|
||||
{
|
||||
SuccessOrExit(error = AddDelayedResponse(*message, aMessageInfo.GetPeerAddr(),
|
||||
@@ -900,6 +926,9 @@ otError MleRouter::HandleLinkAccept(const Message & aMessage,
|
||||
SendDataRequest(aMessageInfo.GetPeerAddr(), dataRequestTlvs, sizeof(dataRequestTlvs), 0);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
GetNetif().GetTimeSync().HandleTimeSyncMessage(aMessage);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case OT_DEVICE_ROLE_CHILD:
|
||||
@@ -1167,7 +1196,12 @@ otError MleRouter::HandleAdvertisement(const Message &aMessage, const Ip6::Messa
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
if (ComparePartitions(IsSingleton(route), leaderData, IsSingleton(), mLeaderData) > 0)
|
||||
if (ComparePartitions(IsSingleton(route), leaderData, IsSingleton(), mLeaderData) > 0
|
||||
#if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
|
||||
// if time sync is required, it will only migrate to a better network which also enables time sync.
|
||||
&& aMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ
|
||||
#endif
|
||||
)
|
||||
{
|
||||
BecomeChild(kAttachBetter);
|
||||
}
|
||||
@@ -1189,6 +1223,10 @@ otError MleRouter::HandleAdvertisement(const Message &aMessage, const Ip6::Messa
|
||||
VerifyOrExit(IsActiveRouter(sourceAddress.GetRloc16()) && route.IsValid());
|
||||
routerId = GetRouterId(sourceAddress.GetRloc16());
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
GetNetif().GetTimeSync().HandleTimeSyncMessage(aMessage);
|
||||
#endif
|
||||
|
||||
if (IsFullThreadDevice() &&
|
||||
((mRouterTable.GetActiveRouterCount() == 0) ||
|
||||
(static_cast<int8_t>(route.GetRouterIdSequence() - mRouterTable.GetRouterIdSequence()) > 0)))
|
||||
@@ -1507,6 +1545,9 @@ otError MleRouter::HandleParentRequest(const Message &aMessage, const Ip6::Messa
|
||||
ChallengeTlv challenge;
|
||||
Router * leader;
|
||||
Child * child;
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
TimeRequestTlv timeRequest;
|
||||
#endif
|
||||
|
||||
LogMleMessage("Receive Parent Request", aMessageInfo.GetPeerAddr());
|
||||
|
||||
@@ -1577,6 +1618,16 @@ otError MleRouter::HandleParentRequest(const Message &aMessage, const Ip6::Messa
|
||||
child->ResetLinkFailures();
|
||||
child->SetState(Neighbor::kStateParentRequest);
|
||||
child->SetDataRequestPending(false);
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
if (Tlv::GetTlv(aMessage, Tlv::kTimeRequest, sizeof(timeRequest), timeRequest) == OT_ERROR_NONE)
|
||||
{
|
||||
child->SetTimeSyncEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
child->SetTimeSyncEnabled(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!child->IsStateValidOrRestoring())
|
||||
@@ -1794,6 +1845,13 @@ void MleRouter::HandleStateUpdateTimer(void)
|
||||
|
||||
SynchronizeChildNetworkData();
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
if (mRole == OT_DEVICE_ROLE_LEADER || mRole == OT_DEVICE_ROLE_ROUTER)
|
||||
{
|
||||
GetNetif().GetTimeSync().ProcessTimeSync();
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
@@ -1814,6 +1872,12 @@ otError MleRouter::SendParentResponse(Child *aChild, const ChallengeTlv &aChalle
|
||||
SuccessOrExit(error = AppendLinkFrameCounter(*message));
|
||||
SuccessOrExit(error = AppendMleFrameCounter(*message));
|
||||
SuccessOrExit(error = AppendResponse(*message, aChallenge.GetChallenge(), aChallenge.GetLength()));
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
if (aChild->IsTimeSyncEnabled())
|
||||
{
|
||||
SuccessOrExit(error = AppendTimeParameter(*message));
|
||||
}
|
||||
#endif
|
||||
|
||||
aChild->GenerateChallenge();
|
||||
|
||||
@@ -2740,6 +2804,13 @@ otError MleRouter::SendChildIdResponse(Child &aChild)
|
||||
netif.GetMeshForwarder().GetSourceMatchController().SetSrcMatchAsShort(aChild, false);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
if (aChild.IsTimeSyncEnabled())
|
||||
{
|
||||
message->SetTimeSync(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&destination, 0, sizeof(destination));
|
||||
destination.mFields.m16[0] = HostSwap16(0xfe80);
|
||||
destination.SetIid(aChild.GetExtAddress());
|
||||
@@ -3695,6 +3766,10 @@ otError MleRouter::SendAddressSolicit(ThreadStatusTlv::Status aStatus)
|
||||
statusTlv.SetStatus(aStatus);
|
||||
SuccessOrExit(error = message->Append(&statusTlv, sizeof(statusTlv)));
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
SuccessOrExit(error = AppendXtalAccuracy(*message));
|
||||
#endif
|
||||
|
||||
SuccessOrExit(error = GetLeaderAddress(messageInfo.GetPeerAddr()));
|
||||
messageInfo.SetSockAddr(GetMeshLocal16());
|
||||
messageInfo.SetPeerPort(kCoapUdpPort);
|
||||
@@ -3889,6 +3964,9 @@ void MleRouter::HandleAddressSolicit(Coap::Header &aHeader, Message &aMessage, c
|
||||
ThreadRloc16Tlv rlocTlv;
|
||||
ThreadStatusTlv statusTlv;
|
||||
Router * router = NULL;
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
XtalAccuracyTlv xtalAccuracyTlv;
|
||||
#endif
|
||||
|
||||
VerifyOrExit(aHeader.GetType() == OT_COAP_TYPE_CONFIRMABLE && aHeader.GetCode() == OT_COAP_CODE_POST,
|
||||
error = OT_ERROR_PARSE);
|
||||
@@ -3901,6 +3979,15 @@ void MleRouter::HandleAddressSolicit(Coap::Header &aHeader, Message &aMessage, c
|
||||
SuccessOrExit(error = ThreadTlv::GetTlv(aMessage, ThreadTlv::kStatus, sizeof(statusTlv), statusTlv));
|
||||
VerifyOrExit(statusTlv.IsValid(), error = OT_ERROR_PARSE);
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
// In a time sync enabled network, all routers' xtal accuracy must be less than the threshold.
|
||||
if (Tlv::GetTlv(aMessage, Tlv::kXtalAccuracy, sizeof(xtalAccuracyTlv), xtalAccuracyTlv) != OT_ERROR_NONE ||
|
||||
xtalAccuracyTlv.GetXtalAccuracy() > GetNetif().GetTimeSync().GetXtalThreshold())
|
||||
{
|
||||
ExitNow(router = NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
// see if allocation already exists
|
||||
router = mRouterTable.GetRouter(macAddr64Tlv.GetMacAddr());
|
||||
|
||||
@@ -4554,6 +4641,45 @@ bool MleRouter::IsSleepyChildSubscribed(const Ip6::Address &aAddress, Child &aCh
|
||||
aChild.HasIp6Address(GetInstance(), aAddress);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
otError MleRouter::HandleTimeSync(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
LogMleMessage("Receive Time Sync", aMessageInfo.GetPeerAddr());
|
||||
|
||||
GetNetif().GetTimeSync().HandleTimeSyncMessage(aMessage);
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError MleRouter::SendTimeSync(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Ip6::Address destination;
|
||||
Message * message = NULL;
|
||||
|
||||
VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS);
|
||||
SuccessOrExit(error = AppendHeader(*message, Header::kCommandTimeSync));
|
||||
|
||||
message->SetTimeSync(true);
|
||||
|
||||
memset(&destination, 0, sizeof(destination));
|
||||
destination.mFields.m16[0] = HostSwap16(0xff02);
|
||||
destination.mFields.m16[7] = HostSwap16(0x0001);
|
||||
SuccessOrExit(error = SendMessage(*message, destination));
|
||||
|
||||
LogMleMessage("Send Time Sync", destination);
|
||||
|
||||
exit:
|
||||
|
||||
if (error != OT_ERROR_NONE && message != NULL)
|
||||
{
|
||||
message->Free();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
} // namespace Mle
|
||||
} // namespace ot
|
||||
|
||||
|
||||
@@ -669,6 +669,17 @@ public:
|
||||
*/
|
||||
static uint8_t LinkQualityToCost(uint8_t aLinkQuality);
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
/**
|
||||
* This method generates an MLE Time Synchronization message.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully sent an MLE Time Synchronization message.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Time Synchronization message.
|
||||
*
|
||||
*/
|
||||
otError SendTimeSync(void);
|
||||
#endif
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
@@ -707,6 +718,9 @@ private:
|
||||
otError HandleDataRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
otError HandleNetworkDataUpdateRouter(void);
|
||||
otError HandleDiscoveryRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
otError HandleTimeSync(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
#endif
|
||||
|
||||
otError ProcessRouteTlv(const RouteTlv &aRoute);
|
||||
void StopAdvertiseTimer(void);
|
||||
|
||||
@@ -147,6 +147,9 @@ private:
|
||||
void HandlePartitionChange(void) {}
|
||||
void StopAdvertiseTimer(void) {}
|
||||
otError ProcessRouteTlv(const RouteTlv &) { return OT_ERROR_NONE; }
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
otError HandleTimeSync(const Message &, const Ip6::MessageInfo &) { return OT_ERROR_DROP; }
|
||||
#endif
|
||||
|
||||
ChildTable mChildTable;
|
||||
RouterTable mRouterTable;
|
||||
|
||||
@@ -109,7 +109,17 @@ public:
|
||||
kActiveDataset = 24, ///< Active Operational Dataset TLV
|
||||
kPendingDataset = 25, ///< Pending Operational Dataset TLV
|
||||
kDiscovery = 26, ///< Thread Discovery TLV
|
||||
kInvalid = 255,
|
||||
|
||||
/**
|
||||
* Applicable/Required only when time synchronization service
|
||||
* (`OPENTHREAD_CONFIG_ENABLE_TIME_SYNC`) is enabled.
|
||||
*
|
||||
*/
|
||||
kTimeRequest = 252, ///< Time Request TLV
|
||||
kTimeParameter = 253, ///< Time Parameter TLV
|
||||
kXtalAccuracy = 254, ///< XTAL Accuracy TLV
|
||||
|
||||
kInvalid = 255,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1595,6 +1605,147 @@ private:
|
||||
uint16_t mPanId;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
/**
|
||||
* This class implements Time Request TLV generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class TimeRequestTlv : public Tlv
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the TLV.
|
||||
*
|
||||
*/
|
||||
void Init(void)
|
||||
{
|
||||
SetType(kTimeRequest);
|
||||
SetLength(sizeof(*this) - sizeof(Tlv));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the TLV appears to be well-formed.
|
||||
*
|
||||
* @retval TRUE If the TLV appears to be well-formed.
|
||||
* @retval FALSE If the TLV does not appear to be well-formed.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements Time Parameter TLV generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class TimeParameterTlv : public Tlv
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the TLV.
|
||||
*
|
||||
*/
|
||||
void Init(void)
|
||||
{
|
||||
SetType(kTimeParameter);
|
||||
SetLength(sizeof(*this) - sizeof(Tlv));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the TLV appears to be well-formed.
|
||||
*
|
||||
* @retval TRUE If the TLV appears to be well-formed.
|
||||
* @retval FALSE If the TLV does not appear to be well-formed.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
|
||||
|
||||
/**
|
||||
* This method returns the time sync period.
|
||||
*
|
||||
* @returns The time sync period.
|
||||
*
|
||||
*/
|
||||
uint16_t GetTimeSyncPeriod(void) const { return HostSwap16(mTimeSyncPeriod); }
|
||||
|
||||
/**
|
||||
* This method sets the time sync period.
|
||||
*
|
||||
* @param[in] aTimeSyncPeriod The time sync period.
|
||||
*
|
||||
*/
|
||||
void SetTimeSyncPeriod(uint16_t aTimeSyncPeriod) { mTimeSyncPeriod = HostSwap16(aTimeSyncPeriod); }
|
||||
|
||||
/**
|
||||
* This method returns the XTAL accuracy threshold.
|
||||
*
|
||||
* @returns The XTAL accuracy threshold.
|
||||
*
|
||||
*/
|
||||
uint16_t GetXtalThreshold(void) const { return HostSwap16(mXtalThreshold); }
|
||||
|
||||
/**
|
||||
* This method sets the XTAL accuracy threshold.
|
||||
*
|
||||
* @param[in] aXTALThreshold The XTAL accuracy threshold.
|
||||
*
|
||||
*/
|
||||
void SetXtalThreshold(uint16_t aXtalThreshold) { mXtalThreshold = HostSwap16(aXtalThreshold); }
|
||||
|
||||
private:
|
||||
uint16_t mTimeSyncPeriod;
|
||||
uint16_t mXtalThreshold;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements XTAL Accuracy TLV generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class XtalAccuracyTlv : public Tlv
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the TLV.
|
||||
*
|
||||
*/
|
||||
void Init(void)
|
||||
{
|
||||
SetType(kXtalAccuracy);
|
||||
SetLength(sizeof(*this) - sizeof(Tlv));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the TLV appears to be well-formed.
|
||||
*
|
||||
* @retval TRUE If the TLV appears to be well-formed.
|
||||
* @retval FALSE If the TLV does not appear to be well-formed.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
|
||||
|
||||
/**
|
||||
* This method returns the XTAL accuracy.
|
||||
*
|
||||
* @returns The XTAL accuracy.
|
||||
*
|
||||
*/
|
||||
uint16_t GetXtalAccuracy(void) const { return HostSwap16(mXtalAccuracy); }
|
||||
|
||||
/**
|
||||
* This method sets the XTAL accuracy.
|
||||
*
|
||||
* @param[in] aXTALAccuracy The XTAL accuracy.
|
||||
*
|
||||
*/
|
||||
void SetXtalAccuracy(uint16_t aXtalAccuracy) { mXtalAccuracy = HostSwap16(aXtalAccuracy); }
|
||||
|
||||
private:
|
||||
uint16_t mXtalAccuracy;
|
||||
} OT_TOOL_PACKED_END;
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
/**
|
||||
* This class implements Active Timestamp TLV generation and parsing.
|
||||
*
|
||||
|
||||
@@ -102,7 +102,9 @@ ThreadNetif::ThreadNetif(Instance &aInstance)
|
||||
, mAnnounceBegin(aInstance)
|
||||
, mPanIdQuery(aInstance)
|
||||
, mEnergyScan(aInstance)
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
, mTimeSync(aInstance)
|
||||
#endif
|
||||
{
|
||||
mCoap.SetInterceptor(&ThreadNetif::TmfFilter, this);
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
#include "thread/network_data_local.hpp"
|
||||
#include "thread/network_diagnostic.hpp"
|
||||
#include "thread/panid_query_server.hpp"
|
||||
#include "thread/time_sync_service.hpp"
|
||||
#include "utils/child_supervision.hpp"
|
||||
|
||||
#if OPENTHREAD_ENABLE_JAM_DETECTION
|
||||
@@ -412,6 +413,16 @@ public:
|
||||
*/
|
||||
PanIdQueryServer &GetPanIdQueryServer(void) { return mPanIdQuery; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
/**
|
||||
* This method returns a reference to the Time Synchronization Service object.
|
||||
*
|
||||
* @returns A reference to the Time Synchronization Service object.
|
||||
*
|
||||
*/
|
||||
TimeSync &GetTimeSync(void) { return mTimeSync; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method returns whether Thread Management Framework Addressing Rules are met.
|
||||
*
|
||||
@@ -483,6 +494,9 @@ private:
|
||||
AnnounceBeginServer mAnnounceBegin;
|
||||
PanIdQueryServer mPanIdQuery;
|
||||
EnergyScanServer mEnergyScan;
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
TimeSync mTimeSync;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (c) 2018, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements OpenThread Time Synchronization Service.
|
||||
*/
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
#include "time_sync_service.hpp"
|
||||
|
||||
#include <openthread/platform/alarm-micro.h>
|
||||
#include <openthread/platform/alarm-milli.h>
|
||||
#include <openthread/platform/time.h>
|
||||
|
||||
#include "common/instance.hpp"
|
||||
#include "common/logging.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
TimeSync::TimeSync(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mTimeSyncRequired(false)
|
||||
, mTimeSyncSeq(OT_TIME_SYNC_INVALID_SEQ)
|
||||
, mTimeSyncPeriod(OPENTHREAD_CONFIG_TIME_SYNC_PERIOD)
|
||||
, mXtalThreshold(OPENTHREAD_CONFIG_TIME_SYNC_XTAL_THRESHOLD)
|
||||
, mLastTimeSyncSent(0)
|
||||
, mLastTimeSyncReceived(0)
|
||||
, mNetworkTimeOffset(0)
|
||||
{
|
||||
}
|
||||
|
||||
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 hasn’t received time sync for more than two periods time.
|
||||
networkTimeStatus = OT_NETWORK_TIME_RESYNC_NEEDED;
|
||||
}
|
||||
break;
|
||||
|
||||
case OT_DEVICE_ROLE_LEADER:
|
||||
break;
|
||||
}
|
||||
|
||||
aNetworkTime = otPlatTimeGet() + mNetworkTimeOffset;
|
||||
|
||||
return networkTimeStatus;
|
||||
}
|
||||
|
||||
void TimeSync::HandleTimeSyncMessage(const Message &aMessage)
|
||||
{
|
||||
VerifyOrExit(aMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ);
|
||||
|
||||
if (mTimeSyncSeq != OT_TIME_SYNC_INVALID_SEQ && (int8_t)(aMessage.GetTimeSyncSeq() - mTimeSyncSeq) < 0)
|
||||
{
|
||||
// receive older time sync sequence.
|
||||
mTimeSyncRequired = true;
|
||||
}
|
||||
else if (GetInstance().GetThreadNetif().GetMle().GetRole() != OT_DEVICE_ROLE_LEADER)
|
||||
{
|
||||
// Update network time in following three cases:
|
||||
// 1. during first attach;
|
||||
// 2. already attached, receive newer time sync sequence;
|
||||
// 3. during reattach or migration process.
|
||||
if (mTimeSyncSeq == OT_TIME_SYNC_INVALID_SEQ || (int8_t)(aMessage.GetTimeSyncSeq() - mTimeSyncSeq) > 0 ||
|
||||
GetInstance().GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DETACHED)
|
||||
{
|
||||
// update network time and forward it.
|
||||
mLastTimeSyncReceived = TimerMilli::GetNow();
|
||||
mTimeSyncSeq = aMessage.GetTimeSyncSeq();
|
||||
mNetworkTimeOffset = aMessage.GetNetworkTimeOffset();
|
||||
mTimeSyncRequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void TimeSync::IncrementTimeSyncSeq(void)
|
||||
{
|
||||
if (++mTimeSyncSeq == OT_TIME_SYNC_INVALID_SEQ)
|
||||
{
|
||||
++mTimeSyncSeq;
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
void TimeSync::ProcessTimeSync(void)
|
||||
{
|
||||
if (GetInstance().GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_LEADER &&
|
||||
TimerMilli::GetNow() - mLastTimeSyncSent > TimerMilli::SecToMsec(mTimeSyncPeriod))
|
||||
{
|
||||
IncrementTimeSyncSeq();
|
||||
mTimeSyncRequired = true;
|
||||
}
|
||||
|
||||
if (mTimeSyncRequired)
|
||||
{
|
||||
VerifyOrExit(GetInstance().GetThreadNetif().GetMle().SendTimeSync() == OT_ERROR_NONE);
|
||||
|
||||
mLastTimeSyncSent = TimerMilli::GetNow();
|
||||
mTimeSyncRequired = false;
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2018, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for Thread network time synchronization service.
|
||||
*/
|
||||
|
||||
#ifndef TIME_SYNC_HPP_
|
||||
#define TIME_SYNC_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
#include <openthread/network_time.h>
|
||||
#include <openthread/types.h>
|
||||
|
||||
#include "common/locator.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "common/timer.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
/**
|
||||
* This class implements OpenThread Time Synchronization Service.
|
||||
*
|
||||
*/
|
||||
class TimeSync : public InstanceLocator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes the object.
|
||||
*
|
||||
*/
|
||||
TimeSync(Instance &aInstance);
|
||||
|
||||
/**
|
||||
* Get the Thread network time.
|
||||
*
|
||||
* @param[inout] aNetworkTime The Thread network time in microseconds.
|
||||
*
|
||||
* @returns The time synchronization status.
|
||||
*
|
||||
*/
|
||||
otNetworkTimeStatus GetTime(uint64_t &aNetworkTime) const;
|
||||
|
||||
/**
|
||||
* Handle the message which includes time synchronization information.
|
||||
*
|
||||
* @param[in] aMessage The message which includes time synchronization information.
|
||||
*
|
||||
*/
|
||||
void HandleTimeSyncMessage(const Message &aMessage);
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
/**
|
||||
* Send a time synchronization message when it is required.
|
||||
*
|
||||
* Note: A time synchronization message is required in following cases:
|
||||
* 1. Leader send time sync message periodically;
|
||||
* 2. Router(except Leader) received a time sync message with newer sequence;
|
||||
* 3. Router received a time sync message with older sequence.
|
||||
*
|
||||
*/
|
||||
void ProcessTimeSync(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method gets the time synchronization sequence.
|
||||
*
|
||||
* @returns The time synchronization sequence.
|
||||
*
|
||||
*/
|
||||
uint8_t GetTimeSyncSeq(void) const { return mTimeSyncSeq; };
|
||||
|
||||
/**
|
||||
* This method gets the time offset to the Thread network time.
|
||||
*
|
||||
* @returns The time offset to the Thread network time, in microseconds.
|
||||
*
|
||||
*/
|
||||
int64_t GetNetworkTimeOffset(void) const { return mNetworkTimeOffset; };
|
||||
|
||||
/**
|
||||
* Set the time synchronization period.
|
||||
*
|
||||
* @param[in] aTimeSyncPeriod The time synchronization period, in seconds.
|
||||
*
|
||||
*/
|
||||
void SetTimeSyncPeriod(uint16_t aTimeSyncPeriod) { mTimeSyncPeriod = aTimeSyncPeriod; }
|
||||
|
||||
/**
|
||||
* Get the time synchronization period.
|
||||
*
|
||||
* @returns The time synchronization period, in seconds.
|
||||
*
|
||||
*/
|
||||
uint16_t GetTimeSyncPeriod(void) const { return mTimeSyncPeriod; }
|
||||
|
||||
/**
|
||||
* Set the time synchronization XTAL accuracy threshold for Router.
|
||||
*
|
||||
* @param[in] aXtalThreshold The XTAL accuracy threshold for Router, in PPM.
|
||||
*
|
||||
*/
|
||||
void SetXtalThreshold(uint16_t aXtalThreshold) { mXtalThreshold = aXtalThreshold; }
|
||||
|
||||
/**
|
||||
* Get the time synchronization XTAL accuracy threshold for Router.
|
||||
*
|
||||
* @returns The XTAL accuracy threshold for Router, in PPM.
|
||||
*
|
||||
*/
|
||||
uint16_t GetXtalThreshold(void) const { return mXtalThreshold; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Increase the time synchronization sequence.
|
||||
*
|
||||
*/
|
||||
void IncrementTimeSyncSeq(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.
|
||||
uint16_t mXtalThreshold; ///< The XTAL accuracy threshold for a device to become a Router, in PPM.
|
||||
uint32_t mLastTimeSyncSent; ///< The time when the last time synchronization message was sent.
|
||||
uint32_t mLastTimeSyncReceived; ///< The time when the last time synchronization message was received.
|
||||
int64_t mNetworkTimeOffset; ///< The time offset to the Thread Network time
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
#endif // TIME_SYNC_HPP_
|
||||
@@ -336,6 +336,24 @@ public:
|
||||
*/
|
||||
uint8_t GetChallengeSize(void) const { return sizeof(mValidPending.mPending.mChallenge); }
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
/**
|
||||
* This method indicates whether or not time sync feature is enabled.
|
||||
*
|
||||
* @returns TRUE if time sync feature is enabled, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsTimeSyncEnabled(void) const { return mTimeSyncEnabled; }
|
||||
|
||||
/**
|
||||
* This method sets whether or not time sync feature is enabled.
|
||||
*
|
||||
* @param[in] aEnable TRUE if time sync feature is enabled, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
void SetTimeSyncEnabled(bool aEnabled) { mTimeSyncEnabled = aEnabled; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
Mac::ExtAddress mMacAddr; ///< The IEEE 802.15.4 Extended Address
|
||||
uint32_t mLastHeard; ///< Time when last heard.
|
||||
@@ -352,13 +370,18 @@ private:
|
||||
} mPending;
|
||||
} mValidPending;
|
||||
|
||||
uint32_t mKeySequence; ///< Current key sequence
|
||||
uint16_t mRloc16; ///< The RLOC16
|
||||
uint8_t mState : 3; ///< The link state
|
||||
uint8_t mMode : 4; ///< The MLE device mode
|
||||
bool mDataRequest : 1; ///< Indicates whether or not a Data Poll was received
|
||||
uint8_t mLinkFailures; ///< Consecutive link failure count
|
||||
LinkQualityInfo mLinkInfo; ///< Link quality info (contains average RSS, link margin and link quality)
|
||||
uint32_t mKeySequence; ///< Current key sequence
|
||||
uint16_t mRloc16; ///< The RLOC16
|
||||
uint8_t mState : 3; ///< The link state
|
||||
uint8_t mMode : 4; ///< The MLE device mode
|
||||
bool mDataRequest : 1; ///< Indicates whether or not a Data Poll was received
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
uint8_t mLinkFailures : 7; ///< Consecutive link failure count
|
||||
bool mTimeSyncEnabled : 1; ///< Indicates whether or not time sync feature is enabled.
|
||||
#else
|
||||
uint8_t mLinkFailures; ///< Consecutive link failure count
|
||||
#endif
|
||||
LinkQualityInfo mLinkInfo; ///< Link quality info (contains average RSS, link margin and link quality)
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -217,6 +217,9 @@ const NcpBase::PropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = {
|
||||
NCP_GET_PROP_HANDLER_ENTRY(CNTR_IP_RX_SUCCESS),
|
||||
NCP_GET_PROP_HANDLER_ENTRY(CNTR_IP_TX_FAILURE),
|
||||
NCP_GET_PROP_HANDLER_ENTRY(CNTR_IP_RX_FAILURE),
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
NCP_GET_PROP_HANDLER_ENTRY(THREAD_NETWORK_TIME),
|
||||
#endif
|
||||
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
@@ -253,6 +256,11 @@ const NcpBase::PropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = {
|
||||
NCP_GET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_AUTO_SELECT_ENABLED),
|
||||
NCP_GET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_AUTO_SELECT_INTERVAL),
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
NCP_GET_PROP_HANDLER_ENTRY(TIME_SYNC_PERIOD),
|
||||
NCP_GET_PROP_HANDLER_ENTRY(TIME_SYNC_XTAL_THRESHOLD),
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
|
||||
@@ -361,6 +369,10 @@ const NcpBase::PropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = {
|
||||
NCP_SET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_AUTO_SELECT_ENABLED),
|
||||
NCP_SET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_AUTO_SELECT_INTERVAL),
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
NCP_SET_PROP_HANDLER_ENTRY(TIME_SYNC_PERIOD),
|
||||
NCP_SET_PROP_HANDLER_ENTRY(TIME_SYNC_XTAL_THRESHOLD),
|
||||
#endif
|
||||
#endif // #if OPENTHREAD_FTD
|
||||
};
|
||||
|
||||
@@ -2026,6 +2038,10 @@ otError NcpBase::GetPropertyHandler_CAPS(void)
|
||||
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_CHANNEL_MANAGER));
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_TIME_SYNC));
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TX_ERROR_RATE_TRACKING
|
||||
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_ERROR_RATE_TRACKING));
|
||||
#endif
|
||||
|
||||
@@ -628,6 +628,10 @@ protected:
|
||||
NCP_GET_PROP_HANDLER(NEST_LEGACY_LAST_NODE_JOINED);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
NCP_GET_PROP_HANDLER(THREAD_NETWORK_TIME);
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
@@ -695,6 +699,12 @@ protected:
|
||||
NCP_GET_PROP_HANDLER(CHANNEL_MANAGER_AUTO_SELECT_INTERVAL);
|
||||
NCP_SET_PROP_HANDLER(CHANNEL_MANAGER_AUTO_SELECT_INTERVAL);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
NCP_GET_PROP_HANDLER(TIME_SYNC_PERIOD);
|
||||
NCP_SET_PROP_HANDLER(TIME_SYNC_PERIOD);
|
||||
NCP_GET_PROP_HANDLER(TIME_SYNC_XTAL_THRESHOLD);
|
||||
NCP_SET_PROP_HANDLER(TIME_SYNC_XTAL_THRESHOLD);
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
|
||||
@@ -998,6 +998,44 @@ exit:
|
||||
|
||||
#endif // OPENTHREAD_ENABLE_CHANNEL_MANAGER
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
otError NcpBase::GetPropertyHandler_TIME_SYNC_PERIOD(void)
|
||||
{
|
||||
return mEncoder.WriteUint16(otNetworkTimeGetSyncPeriod(mInstance));
|
||||
}
|
||||
|
||||
otError NcpBase::SetPropertyHandler_TIME_SYNC_PERIOD(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t timeSyncPeriod;
|
||||
|
||||
SuccessOrExit(error = mDecoder.ReadUint16(timeSyncPeriod));
|
||||
|
||||
SuccessOrExit(error = otNetworkTimeSetSyncPeriod(mInstance, timeSyncPeriod));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError NcpBase::GetPropertyHandler_TIME_SYNC_XTAL_THRESHOLD(void)
|
||||
{
|
||||
return mEncoder.WriteUint16(otNetworkTimeGetXtalThreshold(mInstance));
|
||||
}
|
||||
|
||||
otError NcpBase::SetPropertyHandler_TIME_SYNC_XTAL_THRESHOLD(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t xtalThreshold;
|
||||
|
||||
SuccessOrExit(error = mDecoder.ReadUint16(xtalThreshold));
|
||||
|
||||
SuccessOrExit(error = otNetworkTimeSetXtalThreshold(mInstance, xtalThreshold));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
} // namespace Ncp
|
||||
} // namespace ot
|
||||
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
#include <openthread/jam_detection.h>
|
||||
#endif
|
||||
#include <openthread/ncp.h>
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
#include <openthread/network_time.h>
|
||||
#endif
|
||||
#include <openthread/openthread.h>
|
||||
#include <openthread/platform/misc.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
@@ -2521,6 +2524,23 @@ void NcpBase::StopLegacy(void)
|
||||
|
||||
#endif // OPENTHREAD_ENABLE_LEGACY
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
otError NcpBase::GetPropertyHandler_THREAD_NETWORK_TIME(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
otNetworkTimeStatus networkTimeStatus;
|
||||
uint64_t time;
|
||||
|
||||
networkTimeStatus = otNetworkTimeGet(mInstance, time);
|
||||
|
||||
SuccessOrExit(error = mEncoder.WriteUint64(time));
|
||||
SuccessOrExit(error = mEncoder.WriteInt8((int8_t)networkTimeStatus));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
|
||||
|
||||
otError NcpBase::EncodeChannelMask(uint32_t aChannelMask)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
@@ -1641,6 +1641,18 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key)
|
||||
ret = "PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL";
|
||||
break;
|
||||
|
||||
case SPINEL_PROP_THREAD_NETWORK_TIME:
|
||||
ret = "PROP_THREAD_NETWORK_TIME";
|
||||
break;
|
||||
|
||||
case SPINEL_PROP_TIME_SYNC_PERIOD:
|
||||
ret = "PROP_TIME_SYNC_PERIOD";
|
||||
break;
|
||||
|
||||
case SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD:
|
||||
ret = "PROP_TIME_SYNC_XTAL_THRESHOLD";
|
||||
break;
|
||||
|
||||
case SPINEL_PROP_UART_BITRATE:
|
||||
ret = "PROP_UART_BITRATE";
|
||||
break;
|
||||
@@ -2226,6 +2238,10 @@ const char *spinel_capability_to_cstr(unsigned int capability)
|
||||
ret = "CAP_OPENTHREAD_LOG_METADATA";
|
||||
break;
|
||||
|
||||
case SPINEL_CAP_TIME_SYNC:
|
||||
ret = "CAP_TIME_SYNC";
|
||||
break;
|
||||
|
||||
case SPINEL_CAP_ERROR_RATE_TRACKING:
|
||||
ret = "CAP_ERROR_RATE_TRACKING";
|
||||
break;
|
||||
|
||||
@@ -452,6 +452,7 @@ enum
|
||||
SPINEL_CAP_ERROR_RATE_TRACKING = (SPINEL_CAP_OPENTHREAD__BEGIN + 4),
|
||||
SPINEL_CAP_CHANNEL_MANAGER = (SPINEL_CAP_OPENTHREAD__BEGIN + 5),
|
||||
SPINEL_CAP_OPENTHREAD_LOG_METADATA = (SPINEL_CAP_OPENTHREAD__BEGIN + 6),
|
||||
SPINEL_CAP_TIME_SYNC = (SPINEL_CAP_OPENTHREAD__BEGIN + 7),
|
||||
SPINEL_CAP_OPENTHREAD__END = 640,
|
||||
|
||||
SPINEL_CAP_THREAD__BEGIN = 1024,
|
||||
@@ -1567,6 +1568,37 @@ typedef enum {
|
||||
*/
|
||||
SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL = SPINEL_PROP_OPENTHREAD__BEGIN + 6,
|
||||
|
||||
/// Thread network time.
|
||||
/** Format: `Xc` - Read only
|
||||
*
|
||||
* Data per item is:
|
||||
*
|
||||
* `X`: The Thread network time, in microseconds.
|
||||
* `c`: Time synchronization status.
|
||||
*
|
||||
*/
|
||||
SPINEL_PROP_THREAD_NETWORK_TIME = SPINEL_PROP_OPENTHREAD__BEGIN + 7,
|
||||
|
||||
/// Thread time synchronization period
|
||||
/** Format: `S` - Read-Write
|
||||
*
|
||||
* Data per item is:
|
||||
*
|
||||
* `S`: Time synchronization period, in seconds.
|
||||
*
|
||||
*/
|
||||
SPINEL_PROP_TIME_SYNC_PERIOD = SPINEL_PROP_OPENTHREAD__BEGIN + 8,
|
||||
|
||||
/// Thread Time synchronization XTAL accuracy threshold for Router
|
||||
/** Format: `S` - Read-Write
|
||||
*
|
||||
* Data per item is:
|
||||
*
|
||||
* `S`: The XTAL accuracy threshold for Router, in PPM.
|
||||
*
|
||||
*/
|
||||
SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD = SPINEL_PROP_OPENTHREAD__BEGIN + 9,
|
||||
|
||||
SPINEL_PROP_OPENTHREAD__END = 0x2000,
|
||||
|
||||
/// UART Bitrate
|
||||
|
||||
@@ -46,26 +46,34 @@ void TestMacHeader(void)
|
||||
uint8_t secCtl;
|
||||
uint8_t headerLength;
|
||||
} tests[] = {
|
||||
{Mac::Frame::kFcfDstAddrNone | Mac::Frame::kFcfSrcAddrNone, 0, 3},
|
||||
{Mac::Frame::kFcfDstAddrNone | Mac::Frame::kFcfSrcAddrShort, 0, 7},
|
||||
{Mac::Frame::kFcfDstAddrNone | Mac::Frame::kFcfSrcAddrExt, 0, 13},
|
||||
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrNone, 0, 7},
|
||||
{Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrNone, 0, 13},
|
||||
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort, 0, 11},
|
||||
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrExt, 0, 17},
|
||||
{Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrShort, 0, 17},
|
||||
{Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrExt, 0, 23},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrNone | Mac::Frame::kFcfSrcAddrNone, 0, 3},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrNone | Mac::Frame::kFcfSrcAddrShort, 0, 7},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrNone | Mac::Frame::kFcfSrcAddrExt, 0, 13},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrNone, 0, 7},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrNone, 0, 13},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort, 0, 11},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrExt, 0, 17},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrShort, 0, 17},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrExt, 0, 23},
|
||||
|
||||
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort | Mac::Frame::kFcfPanidCompression, 0, 9},
|
||||
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrExt | Mac::Frame::kFcfPanidCompression, 0, 15},
|
||||
{Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrShort | Mac::Frame::kFcfPanidCompression, 0, 15},
|
||||
{Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrExt | Mac::Frame::kFcfPanidCompression, 0, 21},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort |
|
||||
Mac::Frame::kFcfPanidCompression,
|
||||
0, 9},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrExt |
|
||||
Mac::Frame::kFcfPanidCompression,
|
||||
0, 15},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrShort |
|
||||
Mac::Frame::kFcfPanidCompression,
|
||||
0, 15},
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrExt |
|
||||
Mac::Frame::kFcfPanidCompression,
|
||||
0, 21},
|
||||
|
||||
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort | Mac::Frame::kFcfPanidCompression |
|
||||
Mac::Frame::kFcfSecurityEnabled,
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort |
|
||||
Mac::Frame::kFcfPanidCompression | Mac::Frame::kFcfSecurityEnabled,
|
||||
Mac::Frame::kSecMic32 | Mac::Frame::kKeyIdMode1, 15},
|
||||
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort | Mac::Frame::kFcfPanidCompression |
|
||||
Mac::Frame::kFcfSecurityEnabled,
|
||||
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort |
|
||||
Mac::Frame::kFcfPanidCompression | Mac::Frame::kFcfSecurityEnabled,
|
||||
Mac::Frame::kSecMic32 | Mac::Frame::kKeyIdMode2, 19},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user