mirror of
https://github.com/espressif/openthread.git
synced 2026-09-05 08:40:06 +00:00
[mac] document and adjust to standards based timing concepts (#9322)
Adds a precise specification for the local radio clock that is at the core of all timing-sensitive aspects of the IEEE 802.15.4 protocol (currently mostly CSL) and refers to this definition for fields that reference the radio clock. Specifies the reference planes and message timestamp points for RX timestamps, RX windows and timed TX. Documents the Thread-specific interpretation of the CSL Phase and derives the formula for CSL TX timestamps from it. Based on the standard based definitions given, the TX timestamp used for timed TX now refers to the start of PHR. This change needs to be synchronized with the platform radio driver implementations. An appropriate change set has been prepared for Zephyr.
This commit is contained in:
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (356)
|
||||
#define OPENTHREAD_API_VERSION (357)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -270,10 +270,26 @@ typedef struct otRadioFrame
|
||||
*/
|
||||
struct
|
||||
{
|
||||
const otMacKeyMaterial *mAesKey; ///< The key material used for AES-CCM frame security.
|
||||
otRadioIeInfo *mIeInfo; ///< The pointer to the Header IE(s) related information.
|
||||
uint32_t mTxDelay; ///< The delay time for this transmission (based on `mTxDelayBaseTime`).
|
||||
uint32_t mTxDelayBaseTime; ///< The base time for the transmission delay.
|
||||
const otMacKeyMaterial *mAesKey; ///< The key material used for AES-CCM frame security.
|
||||
otRadioIeInfo *mIeInfo; ///< The pointer to the Header IE(s) related information.
|
||||
|
||||
/**
|
||||
* The base time in microseconds for scheduled transmissions
|
||||
* relative to the local radio clock, see `otPlatRadioGetNow` and
|
||||
* `mTxDelay`.
|
||||
*/
|
||||
uint32_t mTxDelayBaseTime;
|
||||
|
||||
/**
|
||||
* The delay time in microseconds for this transmission referenced
|
||||
* to `mTxDelayBaseTime`.
|
||||
*
|
||||
* Note: `mTxDelayBaseTime` + `mTxDelay` SHALL point to the point in
|
||||
* time when the end of the SFD will be present at the local
|
||||
* antenna, relative to the local radio clock.
|
||||
*/
|
||||
uint32_t mTxDelay;
|
||||
|
||||
uint8_t mMaxCsmaBackoffs; ///< Maximum number of backoffs attempts before declaring CCA failure.
|
||||
uint8_t mMaxFrameRetries; ///< Maximum number of retries allowed after a transmission failure.
|
||||
|
||||
@@ -332,10 +348,8 @@ typedef struct otRadioFrame
|
||||
struct
|
||||
{
|
||||
/**
|
||||
* The timestamp when the frame was received in microseconds.
|
||||
*
|
||||
* The value SHALL be the time when the SFD was received.
|
||||
*
|
||||
* The time of the local radio clock in microseconds when the end of
|
||||
* the SFD was present at the local antenna.
|
||||
*/
|
||||
uint64_t mTimestamp;
|
||||
|
||||
@@ -652,14 +666,25 @@ void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCoun
|
||||
void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacFrameCounter);
|
||||
|
||||
/**
|
||||
* Get the current estimated time (in microseconds) of the radio chip.
|
||||
* Get the current time in microseconds referenced to a continuous monotonic
|
||||
* local radio clock (64 bits width).
|
||||
*
|
||||
* This microsecond timer must be a free-running timer. The timer must continue to advance with microsecond precision
|
||||
* even when the radio is in the sleep state.
|
||||
* The radio clock SHALL NOT wrap during the device's uptime. Implementations
|
||||
* SHALL therefore identify and compensate for internal counter overflows. The
|
||||
* clock does not have a defined epoch and it SHALL NOT introduce any continuous
|
||||
* or discontinuous adjustments (e.g. leap seconds). Implementations SHALL
|
||||
* compensate for any sleep times of the device.
|
||||
*
|
||||
* Implementations MAY choose to discipline the radio clock and compensate for
|
||||
* sleep times by any means (e.g. by combining a high precision/low power RTC
|
||||
* with a high resolution counter) as long as the exposed combined clock
|
||||
* provides continuous monotonic microsecond resolution ticks within the
|
||||
* accuracy limits announced by @ref otPlatRadioGetCslAccuracy.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
* @returns The current time in microseconds. UINT64_MAX when platform does not support or radio time is not ready.
|
||||
* @returns The current time in microseconds. UINT64_MAX when platform does not
|
||||
* support or radio time is not ready.
|
||||
*
|
||||
*/
|
||||
uint64_t otPlatRadioGetNow(otInstance *aInstance);
|
||||
@@ -764,8 +789,17 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel);
|
||||
* Schedule a radio reception window at a specific time and duration.
|
||||
*
|
||||
* @param[in] aChannel The radio channel on which to receive.
|
||||
* @param[in] aStart The receive window start time, in microseconds.
|
||||
* @param[in] aDuration The receive window duration, in microseconds
|
||||
* @param[in] aStart The receive window start time relative to the local
|
||||
* radio clock, see `otPlatRadioGetNow`. The radio
|
||||
* receiver SHALL be on and ready to receive the first
|
||||
* symbol of a frame's SHR at the window start time.
|
||||
* @param[in] aDuration The receive window duration, in microseconds, as
|
||||
* measured by the local radio clock. The radio SHOULD be
|
||||
* turned off (or switched to TX mode if an ACK frame
|
||||
* needs to be sent) after that duration unless it is
|
||||
* still actively receiving a frame. In the latter case
|
||||
* the radio SHALL be kept in reception mode until frame
|
||||
* reception has either succeeded or failed.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully scheduled receive window.
|
||||
* @retval OT_ERROR_FAILED The receive window could not be scheduled.
|
||||
@@ -1078,28 +1112,50 @@ otError otPlatRadioEnableCsl(otInstance *aInstance,
|
||||
/**
|
||||
* Update CSL sample time in radio driver.
|
||||
*
|
||||
* Sample time is stored in radio driver as a copy to calculate phase when sending ACK with CSL IE.
|
||||
* Sample time is stored in radio driver as a copy to calculate phase when
|
||||
* sending ACK with CSL IE. The CSL sample (window) of the CSL receiver extends
|
||||
* before and after the sample time. The CSL sample time marks a timestamp in
|
||||
* the CSL sample window when a frame should be received in "ideal conditions"
|
||||
* if there would be no inaccuracy/clock-drift.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aCslSampleTime The latest sample time.
|
||||
*
|
||||
* @param[in] aCslSampleTime The next sample time, in microseconds. It is
|
||||
* the time when the first symbol of the MHR of
|
||||
* the frame is expected.
|
||||
*/
|
||||
void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime);
|
||||
|
||||
/**
|
||||
* Get the current accuracy, in units of ± ppm, of the clock used for scheduling CSL operations.
|
||||
* Get the current estimated worst case accuracy (maximum ± deviation from the
|
||||
* nominal frequency) of the local radio clock in units of PPM. This is the
|
||||
* clock used to schedule CSL operations.
|
||||
*
|
||||
* @note Platforms may optimize this value based on operational conditions (i.e.: temperature).
|
||||
* @note Implementations MAY estimate this value based on current operating
|
||||
* conditions (e.g. temperature).
|
||||
*
|
||||
* In case the implementation does not estimate the current value but returns a
|
||||
* fixed value, this value MUST be the worst-case accuracy over all possible
|
||||
* foreseen operating conditions (temperature, pressure, etc) of the
|
||||
* implementation.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
* @returns The current CSL rx/tx scheduling drift, in units of ± ppm.
|
||||
* @returns The current CSL rx/tx scheduling drift, in PPM.
|
||||
*
|
||||
*/
|
||||
uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* The fixed uncertainty of the Device for scheduling CSL Transmissions in units of 10 microseconds.
|
||||
* The fixed uncertainty (i.e. random jitter) of the arrival time of CSL
|
||||
* transmissions received by this device in units of 10 microseconds.
|
||||
*
|
||||
* This designates the worst case constant positive or negative deviation of
|
||||
* the actual arrival time of a transmission from the transmission time
|
||||
* calculated relative to the local radio clock independent of elapsed time. In
|
||||
* addition to uncertainty accumulated over elapsed time, the CSL channel sample
|
||||
* ("RX window") must be extended by twice this deviation such that an actual
|
||||
* transmission is guaranteed to be detected by the local receiver in the
|
||||
* presence of random arrival time jitter.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
|
||||
@@ -52,7 +52,20 @@ extern "C" {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the current time (64bits width).
|
||||
* Get the current platform time in microseconds referenced to a continuous
|
||||
* monotonic local clock (64 bits width).
|
||||
*
|
||||
* The clock SHALL NOT wrap during the device's uptime. Implementations SHALL
|
||||
* therefore identify and compensate for internal counter overflows. The clock
|
||||
* does not have a defined epoch and it SHALL NOT introduce any continuous or
|
||||
* discontinuous adjustments (e.g. leap seconds). Implementations SHALL
|
||||
* compensate for any sleep times of the device.
|
||||
*
|
||||
* Implementations MAY choose to discipline the platform clock and compensate
|
||||
* for sleep times by any means (e.g. by combining a high precision/low power
|
||||
* RTC with a high resolution counter) as long as the exposed combined clock
|
||||
* provides continuous monotonic microsecond resolution ticks within the
|
||||
* accuracy limits announced by @ref otPlatTimeGetXtalAccuracy.
|
||||
*
|
||||
* @returns The current time in microseconds.
|
||||
*
|
||||
@@ -60,9 +73,18 @@ extern "C" {
|
||||
uint64_t otPlatTimeGet(void);
|
||||
|
||||
/**
|
||||
* Get the device's XTAL accuracy.
|
||||
* Get the current estimated worst case accuracy (maximum ± deviation from the
|
||||
* nominal frequency) of the local platform clock in units of PPM.
|
||||
*
|
||||
* @returns The device's XTAL accuracy, in ppm.
|
||||
* @note Implementations MAY estimate this value based on current operating
|
||||
* conditions (e.g. temperature).
|
||||
*
|
||||
* In case the implementation does not estimate the current value but returns a
|
||||
* fixed value, this value MUST be the worst-case accuracy over all possible
|
||||
* foreseen operating conditions (temperature, pressure, etc) of the
|
||||
* implementation.
|
||||
*
|
||||
* @returns The current platform clock accuracy, in PPM.
|
||||
*
|
||||
*/
|
||||
uint16_t otPlatTimeGetXtalAccuracy(void);
|
||||
|
||||
@@ -1211,10 +1211,18 @@ public:
|
||||
|
||||
/**
|
||||
* Returns the timestamp when the frame was received.
|
||||
* The timestamp marks the frame detection time: the end of the last symbol of SFD.
|
||||
*
|
||||
* @returns The timestamp when the frame SFD was received, in microseconds.
|
||||
* The value SHALL be the time of the local radio clock in
|
||||
* microseconds when the end of the SFD (or equivalently: the start
|
||||
* of the first symbol of the PHR) was present at the local antenna,
|
||||
* see the definition of a "symbol boundary" in IEEE 802.15.4-2020,
|
||||
* section 6.5.2 or equivalently the RMARKER definition in section
|
||||
* 6.9.1 (albeit both unrelated to OT).
|
||||
*
|
||||
* The time is relative to the local radio clock as defined by
|
||||
* `otPlatRadioGetNow`.
|
||||
*
|
||||
* @returns The timestamp in microseconds.
|
||||
*/
|
||||
const uint64_t &GetTimestamp(void) const { return mInfo.mRxInfo.mTimestamp; }
|
||||
|
||||
|
||||
@@ -316,7 +316,7 @@ void SubMac::LogReceived(RxFrame *aFrame)
|
||||
// Treat as a warning when the deviation is not within the margins. Neither kCslReceiveTimeAhead
|
||||
// or kMinReceiveOnAhead/kMinReceiveOnAfter are considered for the margin since they have no
|
||||
// impact on understanding possible deviation errors between transmitter and receiver. So in this
|
||||
// case ahead equals after.
|
||||
// case only `ahead` is used, as an allowable max deviation in both +/- directions.
|
||||
if ((deviation + ahead > 0) && (deviation < static_cast<int32_t>(ahead)))
|
||||
{
|
||||
LogDebg("%s", logString.AsCString());
|
||||
@@ -468,10 +468,10 @@ void SubMac::StartCsmaBackoff(void)
|
||||
{
|
||||
if (Time(static_cast<uint32_t>(otPlatRadioGetNow(&GetInstance()))) <
|
||||
Time(mTransmitFrame.mInfo.mTxInfo.mTxDelayBaseTime) + mTransmitFrame.mInfo.mTxInfo.mTxDelay -
|
||||
kCcaSampleInterval - kCslTransmitTimeAhead)
|
||||
kCcaSampleInterval - kCslTransmitTimeAhead - kRadioHeaderShrDuration)
|
||||
{
|
||||
mTimer.StartAt(Time(mTransmitFrame.mInfo.mTxInfo.mTxDelayBaseTime) - kCcaSampleInterval -
|
||||
kCslTransmitTimeAhead,
|
||||
kCslTransmitTimeAhead - kRadioHeaderShrDuration,
|
||||
mTransmitFrame.mInfo.mTxInfo.mTxDelay);
|
||||
}
|
||||
else // Transmit without delay
|
||||
|
||||
@@ -667,7 +667,7 @@ private:
|
||||
bool mIsCslSampling : 1; // Indicates that the radio is receiving in CSL state for platforms not supporting delayed
|
||||
// reception.
|
||||
uint16_t mCslPeerShort; // The CSL peer short address.
|
||||
TimeMicro mCslSampleTime; // The CSL sample time of the current period.
|
||||
TimeMicro mCslSampleTime; // The CSL sample time of the current period relative to the local radio clock.
|
||||
TimeMicro mCslLastSync; // The timestamp of the last successful CSL synchronization.
|
||||
CslAccuracy mCslParentAccuracy; // The parent's CSL accuracy (clock accuracy and uncertainty).
|
||||
TimerMicro mCslTimer;
|
||||
|
||||
@@ -158,9 +158,10 @@ uint32_t CslTxScheduler::GetNextCslTransmissionDelay(const Child &aChild,
|
||||
{
|
||||
uint64_t radioNow = otPlatRadioGetNow(&GetInstance());
|
||||
uint32_t periodInUs = aChild.GetCslPeriod() * kUsPerTenSymbols;
|
||||
uint64_t firstTxWindow =
|
||||
aChild.GetLastRxTimestamp() - kRadioHeaderShrDuration + aChild.GetCslPhase() * kUsPerTenSymbols;
|
||||
uint64_t nextTxWindow = radioNow - (radioNow % periodInUs) + (firstTxWindow % periodInUs);
|
||||
|
||||
/* see CslTxScheduler::ChildInfo::mCslPhase */
|
||||
uint64_t firstTxWindow = aChild.GetLastRxTimestamp() + aChild.GetCslPhase() * kUsPerTenSymbols;
|
||||
uint64_t nextTxWindow = radioNow - (radioNow % periodInUs) + (firstTxWindow % periodInUs);
|
||||
|
||||
while (nextTxWindow < radioNow + aAheadUs)
|
||||
{
|
||||
|
||||
@@ -101,14 +101,59 @@ public:
|
||||
void SetLastRxTimestamp(uint64_t aLastRxTimestamp) { mLastRxTimestamp = aLastRxTimestamp; }
|
||||
|
||||
private:
|
||||
uint8_t mCslTxAttempts : 7; ///< Number of CSL triggered tx attempts.
|
||||
bool mCslSynchronized : 1; ///< Indicates whether or not the child is CSL synchronized.
|
||||
uint8_t mCslChannel; ///< The channel the device will listen on.
|
||||
uint32_t mCslTimeout; ///< The sync timeout, in seconds.
|
||||
uint16_t mCslPeriod; ///< CSL sampled listening period in units of 10 symbols (160 microseconds).
|
||||
uint16_t mCslPhase; ///< The time when the next CSL sample will start.
|
||||
TimeMilli mCslLastHeard; ///< Time when last frame containing CSL IE was heard.
|
||||
uint64_t mLastRxTimestamp; ///< Time when last frame containing CSL IE was received, in microseconds.
|
||||
uint8_t mCslTxAttempts : 7; ///< Number of CSL triggered tx attempts.
|
||||
bool mCslSynchronized : 1; ///< Indicates whether or not the child is CSL synchronized.
|
||||
uint8_t mCslChannel; ///< The channel the device will listen on.
|
||||
uint32_t mCslTimeout; ///< The sync timeout, in seconds.
|
||||
uint16_t mCslPeriod; ///< CSL sampled listening period between consecutive channel samples in units of 10
|
||||
///< symbols (160 microseconds).
|
||||
|
||||
/**
|
||||
* The time in units of 10 symbols from the first symbol of the frame
|
||||
* containing the CSL IE was transmitted until the next channel sample,
|
||||
* see IEEE 802.15.4-2015, section 6.12.2.
|
||||
*
|
||||
* The Thread standard further defines the CSL phase (see Thread 1.3.1,
|
||||
* section 3.2.6.3.4, also conforming to IEEE 802.15.4-2020, section
|
||||
* 6.12.2.1):
|
||||
* * The "first symbol" from the definition SHALL be interpreted as the
|
||||
* first symbol of the MAC Header.
|
||||
* * "until the next channel sample":
|
||||
* * The CSL Receiver SHALL be ready to receive when the preamble
|
||||
* time T_pa as specified below is reached.
|
||||
* * The CSL Receiver SHOULD be ready to receive earlier than T_pa
|
||||
* and SHOULD stay ready to receive until after the time specified
|
||||
* in CSL Phase, according to the implementation and accuracy
|
||||
* expectations.
|
||||
* * The CSL Transmitter SHALL start transmitting the first symbol
|
||||
* of the preamble of the frame to transmit at the preamble time
|
||||
* T_pa = (CSL-Phase-Time – 192 us) (that is, CCA must be
|
||||
* performed before time T_pa). Here, CSL-Phase-Time is the time
|
||||
* duration specified by the CslPhase field value (in units of 10
|
||||
* symbol periods).
|
||||
* * This implies that the CSL Transmitter SHALL start transmitting
|
||||
* the first symbol of the MAC Header at the time T_mh =
|
||||
* CSL-Phase-Time.
|
||||
*
|
||||
* Derivation of the next TX timestamp based on this definition and the
|
||||
* RX timestamp of the packet containing the CSL IE:
|
||||
*
|
||||
* Note that RX and TX timestamps are defined to point to the end of the
|
||||
* synchronization header (SHR).
|
||||
*
|
||||
* lastTmh = lastRxTimestamp + phrDuration
|
||||
*
|
||||
* nextTmh = lastTmh + symbolPeriod * 10 * (n * cslPeriod + cslPhase)
|
||||
* = lastTmh + 160us * (n * cslPeriod + cslPhase)
|
||||
*
|
||||
* nextTxTimestamp
|
||||
* = nextTmh - phrDuration
|
||||
* = lastRxTimestamp + 160us * (n * cslPeriod + cslPhase)
|
||||
*/
|
||||
uint16_t mCslPhase;
|
||||
TimeMilli mCslLastHeard; ///< Radio clock time when last frame containing CSL IE was heard.
|
||||
uint64_t
|
||||
mLastRxTimestamp; ///< Radio clock time when last frame containing CSL IE was received, in microseconds.
|
||||
|
||||
static_assert(kMaxCslTriggeredTxAttempts < (1 << 7), "mCslTxAttempts cannot fit max!");
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user