From 5f725faa7d9d8af788e260687250e5556b2500cf Mon Sep 17 00:00:00 2001 From: zwx Date: Wed, 15 Jul 2026 20:16:35 +0800 Subject: [PATCH] fix(ieee802154): skip receive_at when rx window already expired --- .../ieee802154/driver/esp_ieee802154_dev.c | 8 +++++++ .../ieee802154/driver/esp_ieee802154_timer.c | 7 +----- .../ieee802154/include/esp_ieee802154.h | 2 ++ .../private_include/esp_ieee802154_timer.h | 24 ++++++++++++++++++- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index 1594a660a64..681289419fa 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -1076,6 +1076,14 @@ IEEE802154_NOINLINE static void ieee802154_start_receive_at(void* ctx) esp_err_t ieee802154_receive_at(uint32_t time, uint32_t duration) { + // If a receive window is specified but it has already elapsed (time + duration is earlier + // than the current time), this is an expired rx window, so skip it and return directly. + if (duration) { + uint32_t current_time = (uint32_t)esp_timer_get_time(); + if (is_target_time_expired(time + duration, current_time)) { + return ESP_OK; + } + } // TODO: Light sleep current optimization, TZ-1613. IEEE802154_RF_ENABLE(); ieee802154_enter_critical(); diff --git a/components/ieee802154/driver/esp_ieee802154_timer.c b/components/ieee802154/driver/esp_ieee802154_timer.c index f4c6eb2b79c..cd64ea365d7 100644 --- a/components/ieee802154/driver/esp_ieee802154_timer.c +++ b/components/ieee802154/driver/esp_ieee802154_timer.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -62,11 +62,6 @@ uint32_t ieee802154_timer1_get_value(void) return ieee802154_ll_timer1_get_value(); } -FORCE_INLINE_ATTR bool is_target_time_expired(uint32_t target, uint32_t now) -{ - return (((now - target) & (1 << 31)) == 0); -} - void ieee802154_timer0_fire_at(uint32_t fire_time) { uint32_t current_time = (uint32_t)esp_timer_get_time(); diff --git a/components/ieee802154/include/esp_ieee802154.h b/components/ieee802154/include/esp_ieee802154.h index 19f5e247be1..680df8da3a2 100644 --- a/components/ieee802154/include/esp_ieee802154.h +++ b/components/ieee802154/include/esp_ieee802154.h @@ -607,6 +607,8 @@ extern void esp_ieee802154_receive_at_done(void); * @brief Set the IEEE 802.15.4 Radio to receive state at a specific time, for a specific duration. * * @note Radio will start receiving after the timestamp, and continue receiving for the specific duration. + * @note If a duration is specified and the target end time (time + duration) is earlier than the current + * time, the receive window has already expired and no operation will be performed. * * @param[in] time A specific timestamp for starting receiving. * @param[in] duration A specific duration after which to stop receiving. Set duration = 0 to rx indefinitely. diff --git a/components/ieee802154/private_include/esp_ieee802154_timer.h b/components/ieee802154/private_include/esp_ieee802154_timer.h index f445a281ec6..422d3f04839 100644 --- a/components/ieee802154/private_include/esp_ieee802154_timer.h +++ b/components/ieee802154/private_include/esp_ieee802154_timer.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,28 @@ extern "C" { #include "esp_log.h" #include "esp_err.h" +#include "esp_attr.h" +#include +#include + +/** + * @brief Check whether a target time has expired relative to a reference time. + * + * @note This is wrap-around safe for 32-bit timestamps: it returns true when + * @p target is at or before @p now within the first half of the counter range. + * + * @param[in] target The target time to check. + * @param[in] now The current/reference time. + * + * @return + * true if @p target has expired (is at or before @p now). + * false otherwise. + * + */ +FORCE_INLINE_ATTR bool is_target_time_expired(uint32_t target, uint32_t now) +{ + return (((now - target) & (1 << 31)) == 0); +} /** * @brief Start the IEEE802154 MAC internal timer0.