diff --git a/examples/platforms/nrf528xx/nrf52811/openthread-core-nrf52811-config.h b/examples/platforms/nrf528xx/nrf52811/openthread-core-nrf52811-config.h index c4cfa9a24..c3fc13a73 100644 --- a/examples/platforms/nrf528xx/nrf52811/openthread-core-nrf52811-config.h +++ b/examples/platforms/nrf528xx/nrf52811/openthread-core-nrf52811-config.h @@ -160,6 +160,16 @@ #define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) #endif +/** + * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE + * + * Define to 1 to enable software reception target time logic. + * + */ +#ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE +#define OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +#endif + /** * @def OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE * @@ -226,6 +236,27 @@ #define RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM 0 #endif +/** + * @def OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD + * + * Reception scheduling and ramp up time needed for the CSL receiver to be ready, in units of microseconds. + * + */ +#ifndef OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD +#define OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD 2000 +#endif + +/** + * @def OPENTHREAD_CONFIG_CSL_MIN_RECEIVE_ON + * + * The minimum CSL receive window (in microseconds) required to receive an IEEE 802.15.4 frame. + * - Frame preamble: 6*2 symbols + margin + * + */ +#ifndef OPENTHREAD_CONFIG_CSL_MIN_RECEIVE_ON +#define OPENTHREAD_CONFIG_CSL_MIN_RECEIVE_ON 12 * 16 +#endif + /* * Suppress the ARMCC warning on unreachable statement, * e.g. break after assert(false) or ExitNow() macro. diff --git a/examples/platforms/nrf528xx/nrf52833/openthread-core-nrf52833-config.h b/examples/platforms/nrf528xx/nrf52833/openthread-core-nrf52833-config.h index 14e6991ed..759432c16 100644 --- a/examples/platforms/nrf528xx/nrf52833/openthread-core-nrf52833-config.h +++ b/examples/platforms/nrf528xx/nrf52833/openthread-core-nrf52833-config.h @@ -182,6 +182,16 @@ #define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) #endif +/** + * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE + * + * Define to 1 to enable software reception target time logic. + * + */ +#ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE +#define OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +#endif + /** * @def OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE * @@ -278,6 +288,27 @@ #define RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM 0 #endif +/** + * @def OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD + * + * Reception scheduling and ramp up time needed for the CSL receiver to be ready, in units of microseconds. + * + */ +#ifndef OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD +#define OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD 2000 +#endif + +/** + * @def OPENTHREAD_CONFIG_CSL_MIN_RECEIVE_ON + * + * The minimum CSL receive window (in microseconds) required to receive an IEEE 802.15.4 frame. + * - Frame preamble: 6*2 symbols + margin + * + */ +#ifndef OPENTHREAD_CONFIG_CSL_MIN_RECEIVE_ON +#define OPENTHREAD_CONFIG_CSL_MIN_RECEIVE_ON 12 * 16 +#endif + /* * Suppress the ARMCC warning on unreachable statement, * e.g. break after assert(false) or ExitNow() macro. diff --git a/examples/platforms/nrf528xx/nrf52840/openthread-core-nrf52840-config.h b/examples/platforms/nrf528xx/nrf52840/openthread-core-nrf52840-config.h index a89af6e20..d2a47086c 100644 --- a/examples/platforms/nrf528xx/nrf52840/openthread-core-nrf52840-config.h +++ b/examples/platforms/nrf528xx/nrf52840/openthread-core-nrf52840-config.h @@ -182,6 +182,16 @@ #define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) #endif +/** + * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE + * + * Define to 1 to enable software reception target time logic. + * + */ +#ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE +#define OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +#endif + /** * @def OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE * @@ -285,14 +295,13 @@ * */ #ifndef OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD -#define OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD 800 +#define OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD 2000 #endif /** * @def OPENTHREAD_CONFIG_CSL_MIN_RECEIVE_ON * - * The total duration, in units of microseconds, required for the CSL receiver to fully receive and acknowledge a frame - * of maximum possible length. + * The minimum CSL receive window (in microseconds) required to receive an IEEE 802.15.4 frame. * - Frame preamble: 6*2 symbols + margin * */ diff --git a/examples/platforms/nrf528xx/src/radio.c b/examples/platforms/nrf528xx/src/radio.c index 91272b41b..1aefd2128 100644 --- a/examples/platforms/nrf528xx/src/radio.c +++ b/examples/platforms/nrf528xx/src/radio.c @@ -79,6 +79,7 @@ #define SECURITY_ENABLED_BIT (1 << 3) ///< Security enabled bit. #define RSSI_SETTLE_TIME_US 40 ///< RSSI settle time in microseconds. +#define SAFE_DELTA 1000 ///< A safe value for the `dt` parameter of delayed operations. #if defined(__ICCARM__) _Pragma("diag_suppress=Pe167") @@ -488,13 +489,27 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel) } nrf_802154_tx_power_set(GetTransmitPowerForChannel(aChannel)); - result = nrf_802154_receive(); clearPendingEvents(); return result ? OT_ERROR_NONE : OT_ERROR_INVALID_STATE; } +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 +otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart, uint32_t aDuration) +{ + OT_UNUSED_VARIABLE(aInstance); + + bool result; + + nrf_802154_tx_power_set(GetTransmitPowerForChannel(aChannel)); + result = nrf_802154_receive_at(aStart - SAFE_DELTA, SAFE_DELTA, aDuration, aChannel); + clearPendingEvents(); + + return result ? OT_ERROR_NONE : OT_ERROR_FAILED; +} +#endif + otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) { bool result = true; @@ -575,7 +590,7 @@ otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) return (otRadioCaps)(OT_RADIO_CAPS_ENERGY_SCAN | OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF | #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 - OT_RADIO_CAPS_TRANSMIT_SEC | OT_RADIO_CAPS_TRANSMIT_TIMING | + OT_RADIO_CAPS_TRANSMIT_SEC | OT_RADIO_CAPS_TRANSMIT_TIMING | OT_RADIO_CAPS_RECEIVE_TIMING | #endif OT_RADIO_CAPS_SLEEP_TO_TX); } @@ -1053,6 +1068,7 @@ void nrf_802154_receive_failed(nrf_802154_rx_error_t error) case NRF_802154_RX_ERROR_ABORTED: case NRF_802154_RX_ERROR_DELAYED_TIMESLOT_DENIED: case NRF_802154_RX_ERROR_INVALID_LENGTH: + case NRF_802154_RX_ERROR_DELAYED_ABORTED: sReceiveError = OT_ERROR_FAILED; break; @@ -1065,7 +1081,17 @@ void nrf_802154_receive_failed(nrf_802154_rx_error_t error) sAckedWithSecEnhAck = false; #endif - setPendingEvent(kPendingEventReceiveFailed); +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + if ((error == NRF_802154_RX_ERROR_DELAYED_TIMEOUT) || (error == NRF_802154_RX_ERROR_TIMESLOT_ENDED)) + { + sReceiveError = OT_ERROR_NONE; + setPendingEvent(kPendingEventSleep); + } + else +#endif + { + setPendingEvent(kPendingEventReceiveFailed); + } } #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE diff --git a/include/openthread/crypto.h b/include/openthread/crypto.h index a1353991f..ecde22e7a 100644 --- a/include/openthread/crypto.h +++ b/include/openthread/crypto.h @@ -129,7 +129,7 @@ void otCryptoAesCcm(const uint8_t *aKey, * @param[out] aOutput An output buffer where ECDSA sign should be stored. * @param[inout] aOutputLength The length of the @p aOutput buffer. * @param[in] aInputHash An input hash. - * @param[in] aInputHashLength The length of the @p aClaims buffer. + * @param[in] aInputHashLength The length of the @p aInputHash buffer. * @param[in] aPrivateKey A private key in PEM format. * @param[in] aPrivateKeyLength The length of the @p aPrivateKey buffer. * diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 793afc76b..34ea6828b 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (104) +#define OPENTHREAD_API_VERSION (105) /** * @addtogroup api-instance diff --git a/include/openthread/platform/radio.h b/include/openthread/platform/radio.h index 80cd79972..5ec08182e 100644 --- a/include/openthread/platform/radio.h +++ b/include/openthread/platform/radio.h @@ -127,6 +127,7 @@ enum OT_RADIO_CAPS_SLEEP_TO_TX = 1 << 4, ///< Radio supports direct transition from sleep to TX with CSMA. OT_RADIO_CAPS_TRANSMIT_SEC = 1 << 5, ///< Radio supports tx security. OT_RADIO_CAPS_TRANSMIT_TIMING = 1 << 6, ///< Radio supports tx at specific time. + OT_RADIO_CAPS_RECEIVE_TIMING = 1 << 7, ///< Radio supports rx at specific time. }; #define OT_PANID_BROADCAST 0xffff ///< IEEE 802.15.4 Broadcast PAN ID @@ -680,6 +681,18 @@ otError otPlatRadioSleep(otInstance *aInstance); */ 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 + * + * @retval OT_ERROR_NONE Successfully scheduled receive window. + * @retval OT_ERROR_FAILED The receive window could not be scheduled. + */ +otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart, uint32_t aDuration); + /** * The radio driver calls this method to notify OpenThread of a received frame. * diff --git a/src/core/config/mac.h b/src/core/config/mac.h index dc93e9402..86598ebd5 100644 --- a/src/core/config/mac.h +++ b/src/core/config/mac.h @@ -315,6 +315,16 @@ #define OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_TIMING_ENABLE 0 #endif +/** + * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE + * + * Define to 1 to enable software reception target time logic. + * + */ +#ifndef OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE +#define OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE 0 +#endif + /** * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_ENERGY_SCAN_ENABLE * @@ -399,8 +409,7 @@ /** * @def OPENTHREAD_CONFIG_CSL_MIN_RECEIVE_ON * - * The total duration, in units of microseconds, required for the CSL receiver to fully receive and acknowledge a frame - * of maximum possible length. + * The minimum CSL receive window (in microseconds) required to receive an IEEE 802.15.4 frame. * - Maximum frame size with preamble: 6*2+127*2 symbols * - AIFS: 12 symbols * - Maximum ACK size with preamble: 6*2+33*2 symbols diff --git a/src/core/mac/sub_mac.cpp b/src/core/mac/sub_mac.cpp index ce71c8a17..5b4f67e16 100644 --- a/src/core/mac/sub_mac.cpp +++ b/src/core/mac/sub_mac.cpp @@ -113,9 +113,14 @@ otRadioCaps SubMac::GetCaps(void) const caps |= OT_RADIO_CAPS_TRANSMIT_TIMING; #endif +#if OPENTHREAD_CONFIG_MAC_SOFTWARE_RX_TIMING_ENABLE + caps |= OT_RADIO_CAPS_RECEIVE_TIMING; +#endif + #else caps = OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_TRANSMIT_RETRIES | - OT_RADIO_CAPS_ENERGY_SCAN | OT_RADIO_CAPS_TRANSMIT_SEC | OT_RADIO_CAPS_TRANSMIT_TIMING; + OT_RADIO_CAPS_ENERGY_SCAN | OT_RADIO_CAPS_TRANSMIT_SEC | OT_RADIO_CAPS_TRANSMIT_TIMING | + OT_RADIO_CAPS_RECEIVE_TIMING; #endif return caps; @@ -949,9 +954,7 @@ void SubMac::SetCslPeriod(uint16_t aPeriod) if (mCslPeriod > 0) { mCslSampleTime = TimeMicro(static_cast(otPlatRadioGetNow(&GetInstance()))); - Get().UpdateCslSampleTime(mCslSampleTime.GetValue()); - - mCslState = kCslSleep; + mCslState = kCslSleep; HandleCslTimer(); } else @@ -984,11 +987,12 @@ void SubMac::HandleCslTimer(void) * | | | * |<--Ahead-->|<--UnCert-->|<--Drift-->|<--Drift-->|<--UnCert-->|<--MinWin-->| | * | | | | | | | | - * ---|-----------|------------|-----------|-----------|------------|------------|----------//------------|-- - * -Ahead CslPhase +After -Ahead + * ---|-----------|------------|-----------|-----------|------------|------------|----------//------------|--- + * -timeAhead CslPhase +timeAfter -timeAhead */ - uint32_t timeAhead; - uint32_t timeAfter; + uint32_t periodUs = mCslPeriod * kUsPerTenSymbols; + uint32_t timeAhead, timeAfter; + GetCslWindowEdges(timeAhead, timeAfter); switch (mCslState) @@ -1007,16 +1011,32 @@ void SubMac::HandleCslTimer(void) break; case kCslSleep: - mCslState = kCslSample; + mCslSampleTime += periodUs; - mCslTimer.FireAt(mCslSampleTime + timeAfter); - mCslSampleTime += mCslPeriod * kUsPerTenSymbols; + if (RadioSupportsReceiveTiming()) + { + mCslTimer.FireAt(mCslSampleTime - timeAhead); + timeAhead -= kCslReceiveTimeAhead; + } + else + { + mCslTimer.FireAt(mCslSampleTime + timeAfter); + mCslState = kCslSample; + } Get().UpdateCslSampleTime(mCslSampleTime.GetValue()); if (mState == kStateCslSample) { - IgnoreError(Get().Receive(mCslChannel)); - otLogDebgMac("CSL sample %u, duration %u", mCslTimer.GetNow().GetValue(), timeAhead + timeAfter); + if (RadioSupportsReceiveTiming()) + { + IgnoreError(Get().ReceiveAt(mCslChannel, mCslSampleTime.GetValue() - periodUs - timeAhead, + timeAhead + timeAfter)); + } + else + { + IgnoreError(Get().Receive(mCslChannel)); + otLogDebgMac("CSL sample %u, duration %u", mCslTimer.GetNow().GetValue(), timeAhead + timeAfter); + } } break; diff --git a/src/core/mac/sub_mac.hpp b/src/core/mac/sub_mac.hpp index dabbe87a5..b6926a7fd 100644 --- a/src/core/mac/sub_mac.hpp +++ b/src/core/mac/sub_mac.hpp @@ -572,6 +572,7 @@ private: bool RadioSupportsAckTimeout(void) const { return ((mRadioCaps & OT_RADIO_CAPS_ACK_TIMEOUT) != 0); } bool RadioSupportsEnergyScan(void) const { return ((mRadioCaps & OT_RADIO_CAPS_ENERGY_SCAN) != 0); } bool RadioSupportsTransmitTiming(void) const { return ((mRadioCaps & OT_RADIO_CAPS_TRANSMIT_TIMING) != 0); } + bool RadioSupportsReceiveTiming(void) const { return ((mRadioCaps & OT_RADIO_CAPS_RECEIVE_TIMING) != 0); } bool ShouldHandleTransmitSecurity(void) const; bool ShouldHandleCsmaBackOff(void) const; diff --git a/src/core/radio/radio.hpp b/src/core/radio/radio.hpp index 0f25d98a7..de4de4fd0 100644 --- a/src/core/radio/radio.hpp +++ b/src/core/radio/radio.hpp @@ -413,6 +413,19 @@ public: */ void UpdateCslSampleTime(uint32_t aCslSampleTime); + /** + * This method schedules 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. + * + * @retval kErrorNone Successfully scheduled receive window. + * @retval kErrorFailed The receive window could not be scheduled. + * + */ + Error ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDuration); + /** This method enables CSL sampling in radio. * * @param[in] aCslPeriod CSL period, 0 for disabling CSL. @@ -741,6 +754,11 @@ inline void Radio::UpdateCslSampleTime(uint32_t aCslSampleTime) otPlatRadioUpdateCslSampleTime(GetInstancePtr(), aCslSampleTime); } +inline Error Radio::ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDuration) +{ + return otPlatRadioReceiveAt(GetInstancePtr(), aChannel, aStart, aDuration); +} + inline Error Radio::EnableCsl(uint32_t aCslPeriod, const otExtAddress *aExtAddr) { return otPlatRadioEnableCsl(GetInstancePtr(), aCslPeriod, aExtAddr); @@ -894,6 +912,11 @@ inline void Radio::UpdateCslSampleTime(uint32_t) { } +inline Error Radio::ReceiveAt(uint8_t, uint32_t, uint32_t) +{ + return kErrorNone; +} + inline Error Radio::EnableCsl(uint32_t, const otExtAddress *) { return kErrorNotImplemented; diff --git a/src/core/radio/radio_platform.cpp b/src/core/radio/radio_platform.cpp index 526e83a28..f80c3041c 100644 --- a/src/core/radio/radio_platform.cpp +++ b/src/core/radio/radio_platform.cpp @@ -289,3 +289,13 @@ OT_TOOL_WEAK Error otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegion return kErrorNotImplemented; } + +OT_TOOL_WEAK Error otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart, uint32_t aDuration) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aChannel); + OT_UNUSED_VARIABLE(aStart); + OT_UNUSED_VARIABLE(aDuration); + + return kErrorNotImplemented; +} diff --git a/src/posix/platform/radio.cpp b/src/posix/platform/radio.cpp index 32de15063..4ae06446d 100644 --- a/src/posix/platform/radio.cpp +++ b/src/posix/platform/radio.cpp @@ -579,3 +579,12 @@ otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode) OT_UNUSED_VARIABLE(aInstance); return sRadioSpinel.GetRadioRegion(aRegionCode); } + +otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart, uint32_t aDuration) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aChannel); + OT_UNUSED_VARIABLE(aStart); + OT_UNUSED_VARIABLE(aDuration); + return OT_ERROR_NOT_IMPLEMENTED; +}