diff --git a/examples/platforms/nrf52840/alarm.c b/examples/platforms/nrf52840/alarm.c index c12300455..4484f783a 100644 --- a/examples/platforms/nrf52840/alarm.c +++ b/examples/platforms/nrf52840/alarm.c @@ -39,6 +39,7 @@ #include #include +#include #include "platform-config.h" #include "cmsis/cmsis_gcc.h" @@ -57,51 +58,83 @@ #define MS_PER_S 1000UL #define MS_PER_OVERFLOW (512UL * MS_PER_S) ///< Time that has passed between overflow events. On full RTC speed, it occurs every 512 s. +typedef enum +{ + kMsTimer, + kUsTimer, + kNumTimers +} AlarmIndex; + typedef struct { - uint32_t ms; - uint16_t us; -} AlarmTime; + volatile bool mFireAlarm; ///< Information for processing function, that alarm should fire. + otPlatUsecAlarmTime mT0; ///< Alarm start time, for tracking overflows. + otPlatUsecAlarmTime mTargetTime; ///< Alarm fire time. +} AlarmData; -static volatile bool sFireAlarm = false; ///< Information for processing function, that alarm should fire. -static volatile AlarmTime sTimeOffset = { 0 }; ///< Time offset to keep track of current time. -static AlarmTime sT0Time = { 0 }; ///< Alarm start time, for tracking overflows. -static AlarmTime sTargetTime = { 0 }; ///< Alarm fire time. +typedef struct +{ + uint32_t mChannelNumber; + uint32_t mCompareEventMask; + nrf_rtc_event_t mCompareEvent; + nrf_rtc_int_t mCompareInt; +} AlarmChannelData; + +static volatile otPlatUsecAlarmTime sTimeOffset = { 0 }; ///< Time offset to keep track of current time. +static AlarmData sTimerData[kNumTimers]; ///< Data of the timers. +static const AlarmChannelData sChannelData[kNumTimers] = +{ + [kMsTimer] = { + .mChannelNumber = 0, + .mCompareEventMask = RTC_EVTEN_COMPARE0_Msk, + .mCompareEvent = NRF_RTC_EVENT_COMPARE_0, + .mCompareInt = NRF_RTC_INT_COMPARE0_MASK, + }, + [kUsTimer] = { + .mChannelNumber = 1, + .mCompareEventMask = RTC_EVTEN_COMPARE1_Msk, + .mCompareEvent = NRF_RTC_EVENT_COMPARE_1, + .mCompareInt = NRF_RTC_INT_COMPARE1_MASK, + } +}; + +static otPlatUsecAlarmHandler sUsecHandler = NULL; ///< Handler called when usec alarm fires. +static void *sUsecContext = NULL; ///< The context information passed to the usec handler callback. static void HandleOverflow(void); -static inline uint32_t TimeToTicks(AlarmTime aTime) +static inline uint32_t TimeToTicks(otPlatUsecAlarmTime aTime) { - uint64_t microseconds = US_PER_MS * (uint64_t)aTime.ms + (uint64_t)aTime.us; + uint64_t microseconds = US_PER_MS * (uint64_t)aTime.mMs + (uint64_t)aTime.mUs; return (uint32_t)((microseconds * RTC_FREQUENCY) / US_PER_S) & RTC_CC_COMPARE_Msk; } -static inline AlarmTime TicksToTime(uint32_t aTicks) +static inline otPlatUsecAlarmTime TicksToTime(uint32_t aTicks) { uint64_t microseconds = (US_PER_S * (uint64_t)aTicks) / RTC_FREQUENCY; - return (AlarmTime) {microseconds / US_PER_MS, microseconds % US_PER_MS}; + return (otPlatUsecAlarmTime) {microseconds / US_PER_MS, microseconds % US_PER_MS}; } -static inline AlarmTime TimeAdd(AlarmTime aTime1, AlarmTime aTime2) +static inline otPlatUsecAlarmTime TimeAdd(otPlatUsecAlarmTime aTime1, otPlatUsecAlarmTime aTime2) { - AlarmTime result = { aTime1.ms + aTime2.ms, aTime1.us + aTime2.us }; + otPlatUsecAlarmTime result = { aTime1.mMs + aTime2.mMs, aTime1.mUs + aTime2.mUs }; - assert(result.us < 2 * US_PER_MS); + assert(result.mUs < 2 * US_PER_MS); - if (result.us >= US_PER_MS) + if (result.mUs >= US_PER_MS) { - result.ms++; - result.us -= US_PER_MS; + result.mMs++; + result.mUs -= US_PER_MS; } return result; } -static inline AlarmTime AlarmGetCurrentTime(void) +static inline otPlatUsecAlarmTime AlarmGetCurrentTime(void) { uint32_t rtcValue1; uint32_t rtcValue2; - AlarmTime offset; + otPlatUsecAlarmTime offset; rtcValue1 = nrf_rtc_counter_get(RTC_INSTANCE); @@ -139,30 +172,30 @@ static inline AlarmTime AlarmGetCurrentTime(void) return TimeAdd(offset, TicksToTime(rtcValue2)); } -static inline AlarmTime AlarmGetCurrentTimeRtcProtected(void) +static inline otPlatUsecAlarmTime AlarmGetCurrentTimeRtcProtected(void) { - return TimeAdd(AlarmGetCurrentTime(), (AlarmTime) {0, 2 * US_PER_TICK}); + return TimeAdd(AlarmGetCurrentTime(), (otPlatUsecAlarmTime) {0, 2 * US_PER_TICK}); } -static inline bool TimeIsLower(AlarmTime aTime1, AlarmTime aTime2) +static inline bool TimeIsLower(otPlatUsecAlarmTime aTime1, otPlatUsecAlarmTime aTime2) { - return ((aTime1.ms < aTime2.ms) || - ((aTime1.ms == aTime2.ms) && (aTime1.us < aTime2.us))); + return ((aTime1.mMs < aTime2.mMs) || + ((aTime1.mMs == aTime2.mMs) && (aTime1.mUs < aTime2.mUs))); } -static inline bool AlarmShallStrike(AlarmTime aNow) +static inline bool AlarmShallStrike(otPlatUsecAlarmTime aNow, AlarmIndex aIndex) { - if (TimeIsLower(sTargetTime, sT0Time)) + if (TimeIsLower(sTimerData[aIndex].mTargetTime, sTimerData[aIndex].mT0)) { // Handle situation when timespan included timer overflow. - if (TimeIsLower(aNow, sT0Time) && !TimeIsLower(aNow, sTargetTime)) + if (TimeIsLower(aNow, sTimerData[aIndex].mT0) && !TimeIsLower(aNow, sTimerData[aIndex].mTargetTime)) { return true; } } else { - if (TimeIsLower(aNow, sT0Time) || !TimeIsLower(aNow, sTargetTime)) + if (TimeIsLower(aNow, sTimerData[aIndex].mT0) || !TimeIsLower(aNow, sTimerData[aIndex].mTargetTime)) { return true; } @@ -171,20 +204,20 @@ static inline bool AlarmShallStrike(AlarmTime aNow) return false; } -static void HandleCompare0Match(void) +static void HandleCompareMatch(AlarmIndex aIndex) { - nrf_rtc_event_clear(RTC_INSTANCE, NRF_RTC_EVENT_COMPARE_0); + nrf_rtc_event_clear(RTC_INSTANCE, sChannelData[aIndex].mCompareEvent); - AlarmTime now = AlarmGetCurrentTimeRtcProtected(); + otPlatUsecAlarmTime now = AlarmGetCurrentTimeRtcProtected(); // In case the target time was larger than single overflow, // we should only strike the timer on final compare event. - if (AlarmShallStrike(now)) + if (AlarmShallStrike(now, aIndex)) { - nrf_rtc_event_disable(RTC_INSTANCE, RTC_EVTEN_COMPARE0_Msk); - nrf_rtc_int_disable(RTC_INSTANCE, NRF_RTC_INT_COMPARE0_MASK); + nrf_rtc_event_disable(RTC_INSTANCE, sChannelData[aIndex].mCompareEventMask); + nrf_rtc_int_disable(RTC_INSTANCE, sChannelData[aIndex].mCompareInt); - sFireAlarm = true; + sTimerData[aIndex].mFireAlarm = true; } } @@ -193,15 +226,51 @@ static void HandleOverflow(void) nrf_rtc_event_clear(RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW); // Increment counter on overflow. - sTimeOffset = TimeAdd(sTimeOffset, (AlarmTime) {MS_PER_OVERFLOW, 0}); + sTimeOffset = TimeAdd(sTimeOffset, (otPlatUsecAlarmTime) {MS_PER_OVERFLOW, 0}); } +static void AlarmStartAt(const otPlatUsecAlarmTime *aT0, const otPlatUsecAlarmTime *aTargetTime, AlarmIndex aIndex) +{ + uint32_t targetCounter; + otPlatUsecAlarmTime now; + + nrf_rtc_int_disable(RTC_INSTANCE, sChannelData[aIndex].mCompareInt); + nrf_rtc_event_enable(RTC_INSTANCE, sChannelData[aIndex].mCompareEventMask); + + sTimerData[aIndex].mT0 = *aT0; + sTimerData[aIndex].mTargetTime = *aTargetTime; + + targetCounter = TimeToTicks(sTimerData[aIndex].mTargetTime); + + nrf_rtc_cc_set(RTC_INSTANCE, sChannelData[aIndex].mChannelNumber, targetCounter); + + now = AlarmGetCurrentTimeRtcProtected(); + + if (AlarmShallStrike(now, aIndex)) + { + HandleCompareMatch(aIndex); + } + else + { + nrf_rtc_int_enable(RTC_INSTANCE, sChannelData[aIndex].mCompareInt); + } +} + +static void AlarmStop(AlarmIndex aIndex) +{ + nrf_rtc_event_disable(RTC_INSTANCE, sChannelData[aIndex].mCompareEventMask); + nrf_rtc_int_disable(RTC_INSTANCE, sChannelData[aIndex].mCompareInt); + nrf_rtc_event_clear(RTC_INSTANCE, sChannelData[aIndex].mCompareEvent); + + sTimerData[aIndex].mFireAlarm = false; +} + + void nrf5AlarmInit(void) { - sFireAlarm = false; - memset((void *)&sTimeOffset, 0, sizeof(sTimeOffset)); - memset((void *)&sTargetTime, 0, sizeof(sTargetTime)); - memset((void *)&sT0Time, 0, sizeof(sT0Time)); + sTimeOffset.mMs = 0; + sTimeOffset.mUs = 0; + memset(sTimerData, 0, sizeof(sTimerData)); // Setup low frequency clock. nrf_drv_clock_lfclk_request(NULL); @@ -219,18 +288,21 @@ void nrf5AlarmInit(void) nrf_rtc_event_enable(RTC_INSTANCE, RTC_EVTEN_OVRFLW_Msk); nrf_rtc_int_enable(RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK); - nrf_rtc_event_clear(RTC_INSTANCE, NRF_RTC_EVENT_COMPARE_0); - nrf_rtc_event_disable(RTC_INSTANCE, RTC_EVTEN_COMPARE0_Msk); - nrf_rtc_int_disable(RTC_INSTANCE, NRF_RTC_INT_COMPARE0_MASK); + for (uint32_t i = 0; i < kNumTimers; i++) + { + nrf_rtc_event_clear(RTC_INSTANCE, sChannelData[i].mCompareEvent); + nrf_rtc_event_disable(RTC_INSTANCE, sChannelData[i].mCompareEventMask); + nrf_rtc_int_disable(RTC_INSTANCE, sChannelData[i].mCompareInt); + } nrf_rtc_task_trigger(RTC_INSTANCE, NRF_RTC_TASK_START); } void nrf5AlarmProcess(otInstance *aInstance) { - if (sFireAlarm) + if (sTimerData[kMsTimer].mFireAlarm) { - sFireAlarm = false; + sTimerData[kMsTimer].mFireAlarm = false; #if OPENTHREAD_ENABLE_DIAG @@ -244,55 +316,68 @@ void nrf5AlarmProcess(otInstance *aInstance) otPlatAlarmFired(aInstance); } } + + if (sTimerData[kUsTimer].mFireAlarm) + { + sTimerData[kUsTimer].mFireAlarm = false; + + sUsecHandler(sUsecContext); + } } uint32_t otPlatAlarmGetNow(void) { - AlarmTime now = AlarmGetCurrentTime(); + otPlatUsecAlarmTime now = AlarmGetCurrentTime(); - return now.ms; + return now.mMs; } void otPlatAlarmStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt) { (void)aInstance; - uint32_t targetCounter; - AlarmTime now; + otPlatUsecAlarmTime T0 = (otPlatUsecAlarmTime) {aT0, 0}; + otPlatUsecAlarmTime TargetTime = (otPlatUsecAlarmTime) {aT0 + aDt, 0}; - nrf_rtc_int_disable(RTC_INSTANCE, NRF_RTC_INT_COMPARE0_MASK); - nrf_rtc_event_enable(RTC_INSTANCE, RTC_EVTEN_COMPARE0_Msk); - - sT0Time = (AlarmTime) {aT0, 0}; - sTargetTime = (AlarmTime) {aT0 + aDt, 0}; - - targetCounter = TimeToTicks(sTargetTime); - - nrf_rtc_cc_set(RTC_INSTANCE, 0, targetCounter); - - now = AlarmGetCurrentTimeRtcProtected(); - - if (AlarmShallStrike(now)) - { - HandleCompare0Match(); - } - else - { - nrf_rtc_int_enable(RTC_INSTANCE, NRF_RTC_INT_COMPARE0_MASK); - } + AlarmStartAt(&T0, &TargetTime, kMsTimer); } void otPlatAlarmStop(otInstance *aInstance) { (void)aInstance; - nrf_rtc_event_disable(RTC_INSTANCE, RTC_EVTEN_COMPARE0_Msk); - nrf_rtc_int_disable(RTC_INSTANCE, NRF_RTC_INT_COMPARE0_MASK); - nrf_rtc_event_clear(RTC_INSTANCE, NRF_RTC_EVENT_COMPARE_0); - - sFireAlarm = false; + AlarmStop(kMsTimer); } -void RTC0_IRQHandler(void) +void otPlatUsecAlarmGetNow(otPlatUsecAlarmTime *aNow) +{ + otPlatUsecAlarmTime now = AlarmGetCurrentTime(); + + memcpy(aNow, &now, sizeof(*aNow)); +} + +void otPlatUsecAlarmStartAt(otInstance *aInstance, + const otPlatUsecAlarmTime *aT0, + const otPlatUsecAlarmTime *aDt, + otPlatUsecAlarmHandler aHandler, + void *aContext) +{ + (void)aInstance; + otPlatUsecAlarmTime TargetTime = TimeAdd(*aT0, *aDt); + + AlarmStartAt(aT0, &TargetTime, kUsTimer); + + sUsecHandler = aHandler; + sUsecContext = aContext; +} + +void otPlatUsecAlarmStop(otInstance *aInstance) +{ + (void)aInstance; + + AlarmStop(kUsTimer); +} + +void RTC_IRQ_HANDLER(void) { // Handle overflow. if (nrf_rtc_event_pending(RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW)) @@ -301,9 +386,12 @@ void RTC0_IRQHandler(void) } // Handle compare match. - if (nrf_rtc_int_is_enabled(RTC_INSTANCE, NRF_RTC_INT_COMPARE0_MASK) && - nrf_rtc_event_pending(RTC_INSTANCE, NRF_RTC_EVENT_COMPARE_0)) + for (uint32_t i = 0; i < kNumTimers; i++) { - HandleCompare0Match(); + if (nrf_rtc_int_is_enabled(RTC_INSTANCE, sChannelData[i].mCompareInt) && + nrf_rtc_event_pending(RTC_INSTANCE, sChannelData[i].mCompareEvent)) + { + HandleCompareMatch(i); + } } } diff --git a/examples/platforms/nrf52840/openthread-core-nrf52840-config.h b/examples/platforms/nrf52840/openthread-core-nrf52840-config.h index 8986ac122..04058517d 100644 --- a/examples/platforms/nrf52840/openthread-core-nrf52840-config.h +++ b/examples/platforms/nrf52840/openthread-core-nrf52840-config.h @@ -83,6 +83,14 @@ */ #define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT 1 +/** + * @def OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER + * + * Define to 1 if you want to enable microsecond backoff timer implemented in platform. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER 1 + /** * @def SETTINGS_CONFIG_BASE_ADDRESS * diff --git a/examples/platforms/nrf52840/platform-config.h b/examples/platforms/nrf52840/platform-config.h index 1ba5c8945..6761222a7 100644 --- a/examples/platforms/nrf52840/platform-config.h +++ b/examples/platforms/nrf52840/platform-config.h @@ -170,7 +170,15 @@ * RTC Instance. * */ -#define RTC_INSTANCE NRF_RTC0 +#define RTC_INSTANCE NRF_RTC2 + +/** + * @def RTC_IRQ_HANDLER + * + * RTC interrupt handler name + * + */ +#define RTC_IRQ_HANDLER RTC2_IRQHandler /** * @def RTC_IRQN @@ -178,7 +186,7 @@ * RTC Interrupt number. * */ -#define RTC_IRQN RTC0_IRQn +#define RTC_IRQN RTC2_IRQn /** * @def RTC_IRQ_PRIORITY diff --git a/include/platform/Makefile.am b/include/platform/Makefile.am index db9c1d3d8..0921d4e44 100644 --- a/include/platform/Makefile.am +++ b/include/platform/Makefile.am @@ -42,6 +42,7 @@ ot_platform_headers =\ settings.h \ messagepool.h \ toolchain.h \ + usec-alarm.h \ $(NULL) ot_platformdir = $(includedir)/platform diff --git a/include/platform/usec-alarm.h b/include/platform/usec-alarm.h new file mode 100644 index 000000000..438b83cca --- /dev/null +++ b/include/platform/usec-alarm.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016, 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 microsecond alarm service. + */ + +#ifndef USEC_ALARM_H_ +#define USEC_ALARM_H_ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup usec-alarm Microsecond alarm + * @ingroup alarm + * + * @brief + * This module includes the platform abstraction for the microsecond alarm service. + * + * @{ + * + */ + +typedef struct +{ + uint32_t mMs; ///< Time in milliseconds. + uint16_t mUs; ///< Time fraction in microseconds. +} otPlatUsecAlarmTime; + +typedef void (*otPlatUsecAlarmHandler)(void *aContext); + +/** + * Set the alarm to fire at @p aDt milliseconds and microseconds after @p aT0. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aT0 The reference time. + * @param[in] aDt The time delay in milliseconds and microseconds from @p aT0. + * @param[in] aHandler A pointer to a function that is called when the timer expires. + * @param[in] aContext A pointer to arbitrary context information. + */ +void otPlatUsecAlarmStartAt(otInstance *aInstance, + const otPlatUsecAlarmTime *aT0, + const otPlatUsecAlarmTime *aDt, + otPlatUsecAlarmHandler aHandler, + void *aContext); + +/** + * Stop the alarm. + * + * @param[in] aInstance The OpenThread instance structure. + */ +void otPlatUsecAlarmStop(otInstance *aInstance); + +/** + * Get the current time. + * + * @param[out] aNow The current time in milliseconds and microseconds. + */ +void otPlatUsecAlarmGetNow(otPlatUsecAlarmTime *aNow); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // USEC_ALARM_H_ diff --git a/src/core/api/link_raw_api.cpp b/src/core/api/link_raw_api.cpp index 8b87b81fd..0a8c214f8 100644 --- a/src/core/api/link_raw_api.cpp +++ b/src/core/api/link_raw_api.cpp @@ -33,6 +33,7 @@ #include #include +#include #include "openthread-instance.h" #ifdef __cplusplus @@ -524,11 +525,24 @@ void LinkRaw::StartCsmaBackoff(void) backoffExponent = Mac::kMaxBE; } - backoff = Mac::kMinBackoff + (Mac::kUnitBackoffPeriod * kPhyUsPerSymbol * (1 << backoffExponent)) / 1000; - backoff = (otPlatRandomGet() % backoff); + backoff = (otPlatRandomGet() % (1UL << backoffExponent)); + backoff *= (Mac::kUnitBackoffPeriod * kPhyUsPerSymbol); + +#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER + otPlatUsecAlarmTime now; + otPlatUsecAlarmTime delay; + + otPlatUsecAlarmGetNow(&now); + delay.mMs = backoff / 1000UL; + delay.mUs = backoff - (delay.mMs * 1000UL); mTimerReason = kTimerReasonRetransmitTimeout; - mTimer.Start(backoff); + otPlatUsecAlarmStartAt(&mInstance, &now, &delay, &HandleTimer, this); +#else // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER + mTimerReason = kTimerReasonRetransmitTimeout; + mTimer.Start(backoff / 1000UL); +#endif // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER + } #endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index b78cdd952..0bb58518e 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -84,7 +85,7 @@ void Mac::StartCsmaBackoff(void) { // If the radio supports the retry and back off logic, immediately schedule the send, // and the radio will take care of everything. - mBackoffTimer.Start(0); + HandleBeginTransmit(); } else { @@ -96,16 +97,29 @@ void Mac::StartCsmaBackoff(void) backoffExponent = kMaxBE; } - backoff = kMinBackoff + (kUnitBackoffPeriod * kPhyUsPerSymbol * (1 << backoffExponent)) / 1000; - backoff = (otPlatRandomGet() % backoff); + backoff = (otPlatRandomGet() % (1UL << backoffExponent)); + backoff *= (kUnitBackoffPeriod * kPhyUsPerSymbol); - mBackoffTimer.Start(backoff); +#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER + otPlatUsecAlarmTime now; + otPlatUsecAlarmTime delay; + + otPlatUsecAlarmGetNow(&now); + delay.mMs = backoff / 1000UL; + delay.mUs = backoff - (delay.mMs * 1000UL); + + otPlatUsecAlarmStartAt(mNetif.GetInstance(), &now, &delay, &Mac::HandleBeginTransmit, this); +#else // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER + mBackoffTimer.Start(backoff / 1000UL); +#endif // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER } } Mac::Mac(ThreadNetif &aThreadNetif): mMacTimer(aThreadNetif.GetIp6().mTimerScheduler, &Mac::HandleMacTimer, this), +#if !OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER mBackoffTimer(aThreadNetif.GetIp6().mTimerScheduler, &Mac::HandleBeginTransmit, this), +#endif mReceiveTimer(aThreadNetif.GetIp6().mTimerScheduler, &Mac::HandleReceiveTimer, this), mNetif(aThreadNetif), mEnergyScanSampleRssiTask(aThreadNetif.GetIp6().mTaskletScheduler, &Mac::HandleEnergyScanSampleRssi, this), @@ -1630,5 +1644,6 @@ void Mac::ClearSrcMatchEntries() otLogDebgMac("Clearing source match table"); } + } // namespace Mac } // namespace Thread diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index c1d2eb3b2..42d2e8df7 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -606,7 +606,9 @@ private: ThreadError Scan(ScanType aType, uint32_t aScanChannels, uint16_t aScanDuration, void *aContext); Timer mMacTimer; +#if !OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER Timer mBackoffTimer; +#endif Timer mReceiveTimer; ThreadNetif &mNetif; diff --git a/src/core/openthread-core-default-config.h b/src/core/openthread-core-default-config.h index 68ec7c388..69c4fd323 100644 --- a/src/core/openthread-core-default-config.h +++ b/src/core/openthread-core-default-config.h @@ -579,6 +579,16 @@ #define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT 0 #endif +/** + * @def OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER + * + * Define to 1 if you want to enable microsecond backoff timer implemented in platform. + * + */ +#ifndef OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER +#define OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER 0 +#endif + /** * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN *