Explorar o código

Merge branch 'support/esp32c6_csl_feature_merge' into 'master'

openthread_port: support CSL on esp32c6

Closes TZ-41

See merge request espressif/esp-idf!22259
Jiang Jiang Jian %!s(int64=2) %!d(string=hai) anos
pai
achega
bb9200acec

+ 70 - 1
components/ieee802154/include/esp_ieee802154.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -474,6 +474,75 @@ extern void esp_ieee802154_timer0_done(void);
  */
 extern void esp_ieee802154_timer1_done(void);
 
+/**
+ * @brief  Set the IEEE 802.15.4 Radio to receive state at a specific time.
+ *
+ *
+ * @param[in]  time  A specific timestamp for starting receiving.
+ * @return
+ *      - ESP_OK on success
+ *      - ESP_FAIL on failure due to invalid state.
+ *
+ * Note: Radio will start receiving after the timestamp, and continue receiving until it receives a valid frame.
+ *       Ref to esp_ieee802154_receive_done().
+ *
+ */
+esp_err_t esp_ieee802154_receive_at(uint32_t time);
+
+/**
+ * @brief  Transmit the given frame at a specific time.
+ *
+ * @param[in]  frame  The pointer to the frame. Refer to `esp_ieee802154_transmit()`.
+ * @param[in]  cca    Perform CCA before transmission if it's true, otherwise transmit the frame directly.
+ * @param[in]  time  A specific timestamp for starting transmission.
+ *
+ * @return
+ *      - ESP_OK on success.
+ *      - ESP_FAIL on failure due to invalid state.
+ *
+ * Note: The transmit result will be reported via esp_ieee802154_transmit_done()
+ *       or esp_ieee802154_transmit_failed().
+ *
+ */
+esp_err_t esp_ieee802154_transmit_at(const uint8_t *frame, bool cca, uint32_t time);
+
+/**
+ * @brief  Get the RSSI of the most recent received frame.
+ *
+ * @return The value of RSSI.
+ *
+ */
+int8_t esp_ieee802154_get_recent_rssi(void);
+
+/**
+ * @brief  Get the LQI of the most recent received frame.
+ *
+ * @return The value of LQI.
+ *
+ */
+uint8_t esp_ieee802154_get_recent_lqi(void);
+
+/**
+ * @brief  Set the key and addr for a frame needs to be encrypted by HW.
+ *
+ * @param[in]  frame  A frame needs to be encrypted. Refer to `esp_ieee802154_transmit()`.
+ * @param[in]  key    A 16-bytes key for encryption.
+ * @param[in]  addr   An 8-bytes addr for HW to generate nonce, in general, is the device extended address.
+ *
+ */
+void esp_ieee802154_set_transmit_security(uint8_t *frame, uint8_t *key, uint8_t *addr);
+
+/**
+ * @brief  This function will be called when a received frame needs to be acked with Enh-Ack, the upper
+ *         layer should generate the Enh-Ack frame in this callback function.
+ *
+ * @param[in]  frame          The received frame.
+ * @param[in]  frame_info     The frame information. Refer to `esp_ieee802154_frame_info_t`.
+ * @param[out] enhack_frame   The Enh-ack frame need to be generated via this function, HW will send it back after AIFS.
+ *
+ */
+void esp_ieee802154_enh_ack_generator(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info, uint8_t* enhack_frame);
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 1
components/ieee802154/lib

@@ -1 +1 @@
-Subproject commit ecb84fc262cfb8d0f262c22f7f8792bf069dfdd9
+Subproject commit 54ceb75476f7bdbb8a2557d2a8a012a9342e7a37

+ 1 - 0
components/openthread/CMakeLists.txt

@@ -167,6 +167,7 @@ idf_component_register(SRC_DIRS "${src_dirs}"
                        INCLUDE_DIRS "${public_include_dirs}"
                        PRIV_INCLUDE_DIRS "${private_include_dirs}"
                        REQUIRES esp_netif lwip
+                       LDFRAGMENTS linker.lf
                        PRIV_REQUIRES console driver esp_event esp_partition esp_timer
                                      ieee802154 mbedtls spi_flash)
 

+ 20 - 0
components/openthread/Kconfig

@@ -165,4 +165,24 @@ menu "OpenThread"
         help
             Set the OpenThread UART buffer size.
 
+    config OPENTHREAD_LINK_METRICS
+        bool "Enable link metrics feature"
+        depends on OPENTHREAD_ENABLED
+        default n
+        help
+            Select this option to enable link metrics feature
+
+    config OPENTHREAD_CSL_ENABLE
+        bool "Enable CSL feature"
+        depends on OPENTHREAD_ENABLED
+        default n
+        help
+            Select this option to enable CSL feature
+
+    config OPENTHREAD_CSL_DEBUG_ENABLE
+        bool "Enable CSL debug"
+        depends on OPENTHREAD_CSL_ENABLE
+        default n
+        help
+            Select this option to set rx on when sleep in CSL feature, only for debug
 endmenu

+ 10 - 0
components/openthread/linker.lf

@@ -0,0 +1,10 @@
+[mapping:openthread]
+archive: libopenthread.a
+entries:
+  if OPENTHREAD_CSL_ENABLE = y || OPENTHREAD_LINK_METRICS = y:
+    mesh_forwarder (noflash_text)
+    mac_frame (noflash_text)
+    csl_tx_scheduler (noflash_text)
+    link_metrics (noflash_text)
+    mac (noflash_text)
+    sub_mac (noflash_text)

+ 275 - 14
components/openthread/port/esp_openthread_radio.c

@@ -22,10 +22,16 @@
 #include "rom/ets_sys.h"
 
 #include "openthread-core-config.h"
+#include "openthread/link.h"
 #include "openthread/platform/diag.h"
 #include "openthread/platform/radio.h"
+#include "utils/link_metrics.h"
+#include "utils/mac_frame.h"
 
 #define ESP_RECEIVE_SENSITIVITY -120
+#define ESP_OPENTHREAD_XTAL_ACCURACY 130
+#define ESP_OPENTHREAD_CSL_ACCURACY 1
+#define ESP_OPENTHREAD_CSL_UNCERTAIN 1
 
 #define EVENT_TX_DONE (1 << 0)
 #define EVENT_TX_FAILED (1 << 1)
@@ -46,16 +52,38 @@ typedef struct {
 static otRadioFrame s_transmit_frame;
 
 static esp_openthread_radio_tx_psdu s_transmit_psdu;
+static uint8_t *s_enhack;
 static otRadioFrame s_receive_frame[CONFIG_IEEE802154_RX_BUFFER_SIZE];
 static otRadioFrame s_ack_frame;
 static int s_ed_power;
-static int s_rssi = 127;
 static esp_ieee802154_tx_error_t s_tx_error;
 static int s_radio_event_fd = -1;
 static bool s_diag_mode = false;
 static const char *s_radio_workflow = "radio";
 static uint8_t s_txrx_events;
 
+#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
+static otRadioIeInfo s_transmit_ie_info;
+#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
+
+#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
+static uint32_t s_csl_period;
+static uint32_t s_csl_sample_time;
+#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
+
+#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
+static uint32_t s_mac_frame_counter;
+static uint8_t s_key_id;
+static struct otMacKeyMaterial s_pervious_key;
+static struct otMacKeyMaterial s_current_key;
+static struct otMacKeyMaterial s_next_key;
+static bool s_with_security_enh_ack = false;
+static uint32_t s_ack_frame_counter;
+static uint8_t s_ack_key_id;
+static uint8_t s_security_key[16];
+static uint8_t s_security_addr[8];
+#endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
+
 static esp_openthread_circular_queue_info_t s_recv_queue = {.head = 0, .tail = 0, .used = 0};
 
 static void set_event(uint8_t event)
@@ -92,6 +120,10 @@ esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *conf
     s_ack_frame.mPsdu = NULL;
     memset(&s_recv_queue, 0, sizeof(esp_openthread_circular_queue_info_t));
 
+#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
+    s_transmit_frame.mInfo.mTxInfo.mIeInfo = &s_transmit_ie_info;
+#endif
+
     esp_ieee802154_enable();
     esp_ieee802154_set_promiscuous(false);
     esp_ieee802154_set_rx_when_idle(true);
@@ -266,7 +298,31 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
 
     aFrame->mPsdu[-1] = aFrame->mLength; // lenth locates one byte before the psdu (esp_openthread_radio_tx_psdu);
 
-    esp_ieee802154_transmit(&aFrame->mPsdu[-1], aFrame->mInfo.mTxInfo.mCsmaCaEnabled);
+// TODO: remove this macro check when esp32h4 unsupported.
+#if !CONFIG_IDF_TARGET_ESP32H4
+    // esp32h4 do not support tx security
+    if (otMacFrameIsSecurityEnabled(aFrame) && !aFrame->mInfo.mTxInfo.mIsSecurityProcessed) {
+        otMacFrameSetFrameCounter(aFrame, s_mac_frame_counter++);
+        if (otMacFrameIsKeyIdMode1(aFrame)) {
+            s_transmit_frame.mInfo.mTxInfo.mAesKey = &s_current_key;
+            if (!s_transmit_frame.mInfo.mTxInfo.mIsARetx) {
+                otMacFrameSetKeyId(aFrame, s_key_id);
+            }
+            esp_ieee802154_get_extended_address(s_security_addr);
+        }
+        memcpy(s_security_key, s_current_key.mKeyMaterial.mKey.m8, sizeof(s_current_key.mKeyMaterial.mKey.m8));
+        esp_ieee802154_set_transmit_security(&aFrame->mPsdu[-1], s_security_key, s_security_addr);
+    }
+
+    // esp32h4 do not support transmit at
+    if (aFrame->mInfo.mTxInfo.mTxDelay != 0) {
+        esp_ieee802154_transmit_at(&aFrame->mPsdu[-1], aFrame->mInfo.mTxInfo.mCsmaCaEnabled,
+                                   (aFrame->mInfo.mTxInfo.mTxDelayBaseTime + aFrame->mInfo.mTxInfo.mTxDelay));
+    } else
+#endif
+    {
+        esp_ieee802154_transmit(&aFrame->mPsdu[-1], aFrame->mInfo.mTxInfo.mCsmaCaEnabled);
+    }
 
     otPlatRadioTxStarted(aInstance, aFrame);
 
@@ -280,14 +336,29 @@ otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
 
 int8_t otPlatRadioGetRssi(otInstance *aInstance)
 {
-    return s_rssi;
+    return esp_ieee802154_get_recent_rssi();
 }
 
 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
 {
-    return (otRadioCaps)(OT_RADIO_CAPS_ENERGY_SCAN | OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_SLEEP_TO_TX);
+    return (otRadioCaps)(OT_RADIO_CAPS_ENERGY_SCAN |
+// TODO: remove this macro check when esp32h4 unsupported.
+#if !CONFIG_IDF_TARGET_ESP32H4
+                        OT_RADIO_CAPS_TRANSMIT_SEC | OT_RADIO_CAPS_RECEIVE_TIMING | OT_RADIO_CAPS_TRANSMIT_TIMING |
+#endif
+                        OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_SLEEP_TO_TX);
 }
 
+// TODO: remove this macro check when esp32h4 unsupported.
+#if !CONFIG_IDF_TARGET_ESP32H4
+// esp32h4 do not support receive at
+otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart, uint32_t aDuration)
+{
+    esp_ieee802154_receive_at((aStart + aDuration));
+    return OT_ERROR_NONE;
+}
+#endif
+
 bool otPlatRadioGetPromiscuous(otInstance *aInstance)
 {
     return esp_ieee802154_get_promiscuous();
@@ -295,7 +366,11 @@ bool otPlatRadioGetPromiscuous(otInstance *aInstance)
 
 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
 {
+#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
+    esp_ieee802154_set_pending_mode(ESP_IEEE802154_AUTO_PENDING_ENHANCED);
+#else
     esp_ieee802154_set_pending_mode(ESP_IEEE802154_AUTO_PENDING_ENABLE);
+#endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
 }
 
 otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
@@ -404,36 +479,212 @@ void otPlatDiagAlarmCallback(otInstance *aInstance)
     OT_UNUSED_VARIABLE(aInstance);
 }
 
+#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
+void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKeyId, const otMacKeyMaterial *aPrevKey,
+                          const otMacKeyMaterial *aCurrKey, const otMacKeyMaterial *aNextKey, otRadioKeyType aKeyType)
+{
+    OT_UNUSED_VARIABLE(aInstance);
+    OT_UNUSED_VARIABLE(aKeyIdMode);
+    assert(aKeyType == OT_KEY_TYPE_LITERAL_KEY);
+    assert(aPrevKey != NULL && aCurrKey != NULL && aNextKey != NULL);
+
+    s_key_id = aKeyId;
+    s_pervious_key = *aPrevKey;
+    s_current_key = *aCurrKey;
+    s_next_key = *aNextKey;
+}
+
+void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
+{
+    OT_UNUSED_VARIABLE(aInstance);
+
+    s_mac_frame_counter = aMacFrameCounter;
+}
+#endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
+
+uint64_t otPlatRadioGetNow(otInstance *aInstance)
+{
+    OT_UNUSED_VARIABLE(aInstance);
+    return esp_timer_get_time();
+}
+
+#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
+void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime)
+{
+    OT_UNUSED_VARIABLE(aInstance);
+    s_csl_sample_time = aCslSampleTime;
+}
+
+static IRAM_ATTR uint16_t get_csl_phase()
+{
+    uint32_t cur_time = esp_timer_get_time();
+    uint32_t csl_period_us = s_csl_period * OT_US_PER_TEN_SYMBOLS;
+    uint32_t diff = (csl_period_us - (cur_time % csl_period_us) + (s_csl_sample_time % csl_period_us)) % csl_period_us;
+
+    return (uint16_t)(diff / OT_US_PER_TEN_SYMBOLS + 1);
+}
+#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
+
+uint16_t otPlatTimeGetXtalAccuracy(void)
+{
+    return ESP_OPENTHREAD_XTAL_ACCURACY;
+}
+
+#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
+otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, otLinkMetrics aLinkMetrics,
+                                          const otShortAddress aShortAddress, const otExtAddress *aExtAddress)
+{
+    otError error = otLinkMetricsConfigureEnhAckProbing(aShortAddress, aExtAddress, aLinkMetrics);
+    return error;
+}
+#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
+
+#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
+otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, otShortAddress aShortAddr,
+                             const otExtAddress *aExtAddr)
+{
+    OT_UNUSED_VARIABLE(aInstance);
+    OT_UNUSED_VARIABLE(aShortAddr);
+    OT_UNUSED_VARIABLE(aExtAddr);
+    s_csl_period = aCslPeriod;
+
+    return OT_ERROR_NONE;
+}
+
+uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
+{
+    return ESP_OPENTHREAD_CSL_ACCURACY;
+}
+
+uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance)
+{
+    return ESP_OPENTHREAD_CSL_UNCERTAIN;
+}
+
+#endif
+
 // events
 void IRAM_ATTR esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack,
-                                            esp_ieee802154_frame_info_t *s_ack_frame_info)
+                                            esp_ieee802154_frame_info_t *ack_frame_info)
 {
     ETS_ASSERT(frame == (uint8_t *)&s_transmit_psdu);
 
     if (ack != NULL) {
         s_ack_frame.mLength = (uint16_t)(*ack);
         s_ack_frame.mPsdu = (uint8_t *)(ack + 1);
+        s_ack_frame.mChannel = ack_frame_info->channel;
+        s_ack_frame.mInfo.mRxInfo.mRssi = ack_frame_info->rssi;
+        s_ack_frame.mInfo.mRxInfo.mTimestamp = ack_frame_info->timestamp;
     }
 
     set_event(EVENT_TX_DONE);
 }
 
+static void IRAM_ATTR convert_to_ot_frame(uint8_t *data, esp_ieee802154_frame_info_t *frame_info,
+                                          otRadioFrame *radio_frame)
+{
+    radio_frame->mPsdu = data + 1;
+    radio_frame->mLength = *data;
+    radio_frame->mChannel = frame_info->channel;
+    radio_frame->mInfo.mRxInfo.mRssi = frame_info->rssi;
+    radio_frame->mInfo.mRxInfo.mAckedWithFramePending = frame_info->pending;
+    radio_frame->mInfo.mRxInfo.mTimestamp = esp_timer_get_time();
+
+#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
+    radio_frame->mInfo.mRxInfo.mTimestamp = frame_info->timestamp;
+#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
+}
+
+static void IRAM_ATTR enh_ack_set_security_addr_and_key(otRadioFrame *ack_frame)
+{
+    struct otMacKeyMaterial *key = NULL;
+    uint8_t key_id;
+
+    ETS_ASSERT(otMacFrameIsSecurityEnabled(ack_frame));
+    key_id = otMacFrameGetKeyId(ack_frame);
+    ETS_ASSERT(otMacFrameIsKeyIdMode1(ack_frame) && key_id != 0);
+
+    if (key_id == s_key_id) {
+        key = &s_current_key;
+    } else if (key_id == s_key_id - 1) {
+        key = &s_pervious_key;
+    } else if (key_id == s_key_id + 1) {
+        key = &s_next_key;
+    } else {
+        ETS_ASSERT(false);
+    }
+    s_ack_frame_counter = s_mac_frame_counter;
+    s_ack_key_id = key_id;
+    s_with_security_enh_ack = true;
+    if (otMacFrameIsKeyIdMode1(ack_frame)) {
+        esp_ieee802154_get_extended_address(s_security_addr);
+        memcpy(s_security_key, (*key).mKeyMaterial.mKey.m8, OT_MAC_KEY_SIZE);
+    }
+
+    esp_ieee802154_set_transmit_security(&ack_frame->mPsdu[-1], s_security_key, s_security_addr);
+}
+
+void IRAM_ATTR esp_ieee802154_enh_ack_generator(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info,
+                                                uint8_t *enhack_frame)
+{
+    otRadioFrame ack_frame;
+    otRadioFrame ot_frame;
+    uint8_t ack_ie_data[OT_ACK_IE_MAX_SIZE];
+    uint8_t offset = 0;
+#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
+    uint8_t link_metrics_data_len = 0;
+    uint8_t link_metrics_data[OT_ENH_PROBING_IE_DATA_MAX_SIZE];
+    otMacAddress mac_addr;
+#endif
+    ack_frame.mPsdu = enhack_frame + 1;
+    convert_to_ot_frame(frame, frame_info, &ot_frame);
+
+#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
+    if (s_csl_period > 0) {
+        offset += otMacFrameGenerateCslIeTemplate(ack_ie_data);
+    }
+#endif
+
+#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
+    otMacFrameGetSrcAddr(&ot_frame, &mac_addr);
+    link_metrics_data_len = otLinkMetricsEnhAckGenData(&mac_addr, esp_ieee802154_get_recent_lqi(),
+                                        esp_ieee802154_get_recent_rssi(), link_metrics_data);
+    if (link_metrics_data_len > 0) {
+        offset += otMacFrameGenerateEnhAckProbingIe(ack_ie_data, link_metrics_data, link_metrics_data_len);
+    }
+#endif
+
+    ETS_ASSERT(otMacFrameGenerateEnhAck(&ot_frame, frame_info->pending, ack_ie_data, offset, &ack_frame) == OT_ERROR_NONE);
+    enhack_frame[0] = ack_frame.mLength;
+
+    s_enhack = enhack_frame;
+
+    if (otMacFrameIsSecurityEnabled(&ack_frame) && !ack_frame.mInfo.mTxInfo.mIsSecurityProcessed) {
+        otMacFrameSetFrameCounter(&ack_frame, s_mac_frame_counter++);
+        enh_ack_set_security_addr_and_key(&ack_frame);
+    }
+}
+
 void IRAM_ATTR esp_ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info)
 {
+    otRadioFrame ot_frame;
+    ot_frame.mPsdu = data + 1;
+
     if (s_recv_queue.used == CONFIG_IEEE802154_RX_BUFFER_SIZE) {
         ESP_EARLY_LOGE(OT_PLAT_LOG_TAG, "radio receive buffer full!");
         return;
     }
 
-    s_rssi = frame_info->rssi;
-
-    s_receive_frame[s_recv_queue.tail].mPsdu = data + 1;
-    s_receive_frame[s_recv_queue.tail].mLength = *data;
-    s_receive_frame[s_recv_queue.tail].mChannel = frame_info->channel;
-    s_receive_frame[s_recv_queue.tail].mInfo.mRxInfo.mRssi = frame_info->rssi;
-    s_receive_frame[s_recv_queue.tail].mInfo.mRxInfo.mAckedWithFramePending = frame_info->pending;
-    s_receive_frame[s_recv_queue.tail].mInfo.mRxInfo.mTimestamp = esp_timer_get_time();
-
+    convert_to_ot_frame(data, frame_info, &(s_receive_frame[s_recv_queue.tail]));
+#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
+    // Inform if this frame was acknowledged with secured Enh-ACK.
+    if (otMacFrameIsAckRequested(&ot_frame) && otMacFrameIsVersion2015(&ot_frame)) {
+        s_receive_frame[s_recv_queue.tail].mInfo.mRxInfo.mAckedWithSecEnhAck = s_with_security_enh_ack;
+        s_receive_frame[s_recv_queue.tail].mInfo.mRxInfo.mAckFrameCounter = s_ack_frame_counter;
+        s_receive_frame[s_recv_queue.tail].mInfo.mRxInfo.mAckKeyId = s_ack_key_id;
+    }
+    s_with_security_enh_ack = false;
+#endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
     s_recv_queue.tail = (s_recv_queue.tail + 1) % CONFIG_IEEE802154_RX_BUFFER_SIZE;
     s_recv_queue.used++;
     set_event(EVENT_RX_DONE);
@@ -454,6 +705,16 @@ void IRAM_ATTR esp_ieee802154_receive_sfd_done(void)
 
 void IRAM_ATTR esp_ieee802154_transmit_sfd_done(uint8_t *frame)
 {
+    assert(frame == (uint8_t *)&s_transmit_psdu || frame == s_enhack);
+#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
+    otRadioFrame ot_frame;
+    ot_frame.mPsdu = frame + 1;
+    ot_frame.mLength = frame[0];
+
+    if (s_csl_period > 0) {
+        otMacFrameSetCslIe(&ot_frame, s_csl_period, get_csl_phase());
+    }
+#endif
 }
 
 void IRAM_ATTR esp_ieee802154_energy_detect_done(int8_t power)

+ 57 - 0
components/openthread/private_include/openthread-core-esp32x-ftd-config.h

@@ -434,4 +434,61 @@
  */
 #define OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE CONFIG_OPENTHREAD_DNS_CLIENT
 
+#if CONFIG_OPENTHREAD_CSL_ENABLE
+
+/**
+ * @def OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
+ *
+ * Define as 1 to support Thread 1.2 CSL feature.
+ *
+ */
+#ifndef OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
+#define OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE 1
+#endif
+
+/**
+ * @def OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
+ *
+ * Define as 1 to set the ahead time for CSL transmit timing.
+ *
+ */
+#ifndef OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US
+#define OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US 20000
+#endif
+
+/**
+ * @def OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE
+ *
+ * Define as 1 to enable support Thread 1.2 CSL debug.
+ *
+ */
+#ifndef OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE
+#define OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE CONFIG_OPENTHREAD_CSL_DEBUG_ENABLE
+#endif
+
+#endif // CONFIG_OPENTHREAD_CSL_ENABLE
+
+#if CONFIG_OPENTHREAD_LINK_METRICS
+
+/**
+ * @def OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
+ *
+ * Define as 1 to support Thread 1.2 Link Metrics Subject feature.
+ *
+ */
+#ifndef OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
+#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 1
+#endif
+
+/**
+ * @def OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
+ *
+ * Define as 1 to support Thread 1.2 Link Metrics feature.
+ *
+ */
+#ifndef OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
+#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 1
+#endif
+#endif //CONFIG_OPENTHREAD_LINK_METRICS
+
 #define OPENTHREAD_FTD 1