diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index 308af32145..202e68bfb2 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -1292,6 +1292,26 @@ esp_err_t esp_wifi_ftm_end_session(void); */ esp_err_t esp_wifi_ftm_resp_set_offset(int16_t offset_cm); +/** + * @brief Get FTM measurements report copied into a user provided buffer. + * + * @attention 1. To get the FTM report, user first needs to allocate a buffer of size + * (sizeof(wifi_ftm_report_entry_t) * num_entries) where the API will fill up to num_entries + * valid FTM measurements in the buffer. Total number of entries can be found in the event + * WIFI_EVENT_FTM_REPORT as ftm_report_num_entries + * @attention 2. The internal FTM report is freed upon use of this API which means the API can only be used + * once afer every FTM session initiated + * @attention 3. Passing the buffer as NULL merely frees the FTM report + * + * @param report Pointer to the buffer for receiving the FTM report + * @param num_entries Number of FTM report entries to be filled in the report + * + * @return + * - ESP_OK: succeed + * - others: failed + */ +esp_err_t esp_wifi_ftm_get_report(wifi_ftm_report_entry_t *report, uint8_t num_entries); + /** * @brief Enable or disable 11b rate of specified interface * diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index 1b949f2109..1709952456 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -656,7 +656,9 @@ typedef struct { uint8_t resp_mac[6]; /**< MAC address of the FTM Responder */ uint8_t channel; /**< Primary channel of the FTM Responder */ uint8_t frm_count; /**< No. of FTM frames requested in terms of 4 or 8 bursts (allowed values - 0(No pref), 16, 24, 32, 64) */ - uint16_t burst_period; /**< Requested time period between consecutive FTM bursts in 100's of milliseconds (0 - No pref) */ + uint16_t burst_period; /**< Requested period between FTM bursts in 100's of milliseconds (allowed values 0(No pref) - 100) */ + bool use_get_report_api; /**< True - Using esp_wifi_ftm_get_report to get FTM report, False - Using ftm_report_data from + WIFI_EVENT_FTM_REPORT to get FTM report */ } wifi_ftm_initiator_cfg_t; /** @@ -1001,6 +1003,8 @@ typedef enum { FTM_STATUS_CONF_REJECTED, /**< Peer rejected FTM configuration in FTM Request */ FTM_STATUS_NO_RESPONSE, /**< Peer did not respond to FTM Requests */ FTM_STATUS_FAIL, /**< Unknown error during FTM exchange */ + FTM_STATUS_NO_VALID_MSMT, /**< FTM session did not result in any valid measurements */ + FTM_STATUS_USER_TERM, /**< User triggered termination */ } wifi_ftm_status_t; /** Argument structure for */ @@ -1021,7 +1025,8 @@ typedef struct { uint32_t rtt_raw; /**< Raw average Round-Trip-Time with peer in Nano-Seconds */ uint32_t rtt_est; /**< Estimated Round-Trip-Time with peer in Nano-Seconds */ uint32_t dist_est; /**< Estimated one-way distance in Centi-Meters */ - wifi_ftm_report_entry_t *ftm_report_data; /**< Pointer to FTM Report with multiple entries, should be freed after use */ + wifi_ftm_report_entry_t *ftm_report_data; /**< Pointer to FTM Report, should be freed after use. Note: Highly recommended + to use API esp_wifi_ftm_get_report to get the report instead of using this */ uint8_t ftm_report_num_entries; /**< Number of entries in the FTM Report data */ } wifi_event_ftm_report_t; diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 775025e7d3..c50813bc75 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 775025e7d30632253f5ad81ad3cbf7ab16dc2d2a +Subproject commit c50813bc755d7a8724707c07fee4e9bb7f4cf66f diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index fd96f51093..34045759d8 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,6 +25,9 @@ #ifdef CONFIG_ESP_WIFI_NAN_ENABLE #include "apps_private/wifi_apps_private.h" #endif +#ifdef CONFIG_ESP_WIFI_FTM_ENABLE +#include "esp_chip_info.h" +#endif static bool s_wifi_inited = false; @@ -318,6 +321,13 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config) #endif esp_wifi_set_log_level(); esp_wifi_power_domain_on(); +#ifdef CONFIG_ESP_WIFI_FTM_ENABLE + esp_chip_info_t info = {0}; + esp_chip_info(&info); + if (info.model == CHIP_ESP32C6 && info.revision <= 1) { + ((wifi_init_config_t *)config)->feature_caps &= ~(CONFIG_FEATURE_FTM_INITIATOR_BIT); + } +#endif result = esp_wifi_init_internal(config); if (result == ESP_OK) { #if CONFIG_MAC_BB_PD @@ -398,9 +408,10 @@ void wifi_apb80m_release(void) #endif //CONFIG_PM_ENABLE #ifndef CONFIG_ESP_WIFI_FTM_ENABLE -void ieee80211_ftm_attach(void) +esp_err_t ieee80211_ftm_attach(void) { /* Do not remove, stub to overwrite weak link in Wi-Fi Lib */ + return ESP_OK; } #endif diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 75cb9a0d2f..bd125d1f6f 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1229,7 +1229,7 @@ config SOC_WIFI_HW_TSF config SOC_WIFI_FTM_SUPPORT bool - default n + default y config SOC_WIFI_GCMP_SUPPORT bool diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 2ad4866ff1..56ef2fdafa 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -511,7 +511,7 @@ /*------------------------------------ WI-FI CAPS ------------------------------------*/ #define SOC_WIFI_HW_TSF (1) /*!< Support hardware TSF */ -#define SOC_WIFI_FTM_SUPPORT (0) /*!< Support FTM */ +#define SOC_WIFI_FTM_SUPPORT (1) /*!< Support FTM */ #define SOC_WIFI_GCMP_SUPPORT (1) /*!< Support GCMP(GCMP128 and GCMP256) */ #define SOC_WIFI_WAPI_SUPPORT (1) /*!< Support WAPI */ #define SOC_WIFI_CSI_SUPPORT (1) /*!< Support CSI */ diff --git a/docs/en/api-guides/wifi.rst b/docs/en/api-guides/wifi.rst index 84f0e5c1e3..f135a31f95 100644 --- a/docs/en/api-guides/wifi.rst +++ b/docs/en/api-guides/wifi.rst @@ -1735,7 +1735,13 @@ A config option :ref:`CONFIG_ESP_WIFI_11R_SUPPORT` and configuration parameter : - {IDF_TARGET_NAME} as FTM Initiator in station mode. - {IDF_TARGET_NAME} as FTM Responder in AP mode. - Distance measurement using RTT is not accurate, and factors such as RF interference, multi-path travel, antenna orientation, and lack of calibration increase these inaccuracies. For better results, it is suggested to perform FTM between two ESP32 chip series devices (except ESP32-C2) as station and AP. +.. only:: esp32c6 + + {IDF_TARGET_NAME} ECO1 and older versions do not support FTM Initiator mode. + +.. attention:: + + Distance measurement using RTT is not accurate, and factors such as RF interference, multi-path travel, antenna orientation, and lack of calibration increase these inaccuracies. For better results, it is suggested to perform FTM between two ESP32 chip series devices as station and AP. Refer to ESP-IDF example :idf_file:`examples/wifi/ftm/README.md` for steps on how to set up and perform FTM. diff --git a/examples/wifi/ftm/README.md b/examples/wifi/ftm/README.md index d585ee76a1..1928681dfc 100644 --- a/examples/wifi/ftm/README.md +++ b/examples/wifi/ftm/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | -------- | # FTM Example diff --git a/examples/wifi/ftm/main/ftm_main.c b/examples/wifi/ftm/main/ftm_main.c index bc8e27fada..29f783e66c 100644 --- a/examples/wifi/ftm/main/ftm_main.c +++ b/examples/wifi/ftm/main/ftm_main.c @@ -70,6 +70,8 @@ wifi_config_t g_ap_config = { #define ETH_ALEN 6 #define MAX_CONNECT_RETRY_ATTEMPTS 5 +#define DEFAULT_WAIT_TIME_MS (10 * 1000) +#define MAX_FTM_BURSTS 8 #define DEFAULT_AP_CHANNEL 1 #define DEFAULT_AP_BANDWIDTH 20 @@ -85,7 +87,6 @@ static const int DISCONNECTED_BIT = BIT1; static EventGroupHandle_t s_ftm_event_group; static const int FTM_REPORT_BIT = BIT0; static const int FTM_FAILURE_BIT = BIT1; -static wifi_ftm_report_entry_t *s_ftm_report; static uint8_t s_ftm_report_num_entries; static uint32_t s_rtt_est, s_dist_est; static bool s_ap_started; @@ -137,10 +138,12 @@ static void event_handler(void *arg, esp_event_base_t event_base, s_rtt_est = event->rtt_est; s_dist_est = event->dist_est; - s_ftm_report = event->ftm_report_data; s_ftm_report_num_entries = event->ftm_report_num_entries; if (event->status == FTM_STATUS_SUCCESS) { xEventGroupSetBits(s_ftm_event_group, FTM_REPORT_BIT); + } else if (event->status == FTM_STATUS_USER_TERM) { + /* Do Nothing */ + ESP_LOGI(TAG_STA, "User terminated FTM procedure"); } else { ESP_LOGI(TAG_STA, "FTM procedure with Peer("MACSTR") failed! (Status - %d)", MAC2STR(event->peer_mac), event->status); @@ -153,21 +156,38 @@ static void event_handler(void *arg, esp_event_base_t event_base, } } -static void ftm_process_report(void) +static void ftm_print_report(void) { int i; char *log = NULL; + wifi_ftm_report_entry_t *ftm_report = NULL; - if (s_ftm_report_num_entries == 0) + if (s_ftm_report_num_entries == 0) { + /* FTM Failure case */ return; + } - if (!g_report_lvl) - return; + if (!g_report_lvl) { + /* No need to print, just free the internal FTM report */ + esp_wifi_ftm_get_report(NULL, 0); + goto exit; + } + + ftm_report = malloc(sizeof(wifi_ftm_report_entry_t) * s_ftm_report_num_entries); + if (!ftm_report) { + ESP_LOGE(TAG_STA, "Failed to alloc buffer for FTM report"); + goto exit; + } + bzero(ftm_report, sizeof(wifi_ftm_report_entry_t) * s_ftm_report_num_entries); + if (ESP_OK != esp_wifi_ftm_get_report(ftm_report, s_ftm_report_num_entries)) { + ESP_LOGE(TAG_STA, "Could not get FTM report"); + goto exit; + } log = malloc(200); if (!log) { ESP_LOGE(TAG_STA, "Failed to alloc buffer for FTM report"); - return; + goto exit; } bzero(log, 200); @@ -181,24 +201,32 @@ static void ftm_process_report(void) bzero(log, 200); if (g_report_lvl & BIT0) { - log_ptr += sprintf(log_ptr, "%6d|", s_ftm_report[i].dlog_token); + log_ptr += sprintf(log_ptr, "%6d|", ftm_report[i].dlog_token); } if (g_report_lvl & BIT1) { - if (s_ftm_report[i].rtt != UINT32_MAX) - log_ptr += sprintf(log_ptr, "%7" PRIi32 " |", s_ftm_report[i].rtt); + if (ftm_report[i].rtt != UINT32_MAX) + log_ptr += sprintf(log_ptr, "%7" PRIi32 " |", ftm_report[i].rtt); else log_ptr += sprintf(log_ptr, " INVALID |"); } if (g_report_lvl & BIT2) { - log_ptr += sprintf(log_ptr, "%14llu |%14llu |%14llu |%14llu |", s_ftm_report[i].t1, - s_ftm_report[i].t2, s_ftm_report[i].t3, s_ftm_report[i].t4); + log_ptr += sprintf(log_ptr, "%14llu |%14llu |%14llu |%14llu |", ftm_report[i].t1, + ftm_report[i].t2, ftm_report[i].t3, ftm_report[i].t4); } if (g_report_lvl & BIT3) { - log_ptr += sprintf(log_ptr, "%6d |", s_ftm_report[i].rssi); + log_ptr += sprintf(log_ptr, "%6d |", ftm_report[i].rssi); } ESP_LOGI(TAG_STA, "|%s", log); } - free(log); + +exit: + if (log) { + free(log); + } + if (ftm_report) { + free(ftm_report); + } + s_ftm_report_num_entries = 0; } void initialise_wifi(void) @@ -245,7 +273,7 @@ static bool wifi_cmd_sta_join(const char *ssid, const char *pass) s_reconnect = false; xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT); ESP_ERROR_CHECK( esp_wifi_disconnect() ); - xEventGroupWaitBits(s_wifi_event_group, DISCONNECTED_BIT, 0, 1, portTICK_PERIOD_MS); + xEventGroupWaitBits(s_wifi_event_group, DISCONNECTED_BIT, 0, 1, portMAX_DELAY); } s_reconnect = true; @@ -271,7 +299,7 @@ static int wifi_cmd_sta(int argc, char **argv) s_reconnect = false; xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT); esp_wifi_disconnect(); - xEventGroupWaitBits(s_wifi_event_group, DISCONNECTED_BIT, 0, 1, portTICK_PERIOD_MS); + xEventGroupWaitBits(s_wifi_event_group, DISCONNECTED_BIT, 0, 1, portMAX_DELAY); return 0; } @@ -461,11 +489,13 @@ static int wifi_cmd_ftm(int argc, char **argv) { int nerrors = arg_parse(argc, argv, (void **) &ftm_args); wifi_ap_record_t *ap_record; + uint32_t wait_time_ms = DEFAULT_WAIT_TIME_MS; EventBits_t bits; wifi_ftm_initiator_cfg_t ftmi_cfg = { .frm_count = 32, .burst_period = 2, + .use_get_report_api = true, }; if (nerrors != 0) { @@ -509,11 +539,11 @@ static int wifi_cmd_ftm(int argc, char **argv) } if (ftm_args.burst_period->count != 0) { - if (ftm_args.burst_period->ival[0] >= 2 && - ftm_args.burst_period->ival[0] < 256) { + if (ftm_args.burst_period->ival[0] >= 0 && + ftm_args.burst_period->ival[0] <= 100) { ftmi_cfg.burst_period = ftm_args.burst_period->ival[0]; } else { - ESP_LOGE(TAG_STA, "Invalid Burst Period! Valid range is 2-255"); + ESP_LOGE(TAG_STA, "Invalid Burst Period! Valid range is 0-100"); return 0; } } @@ -526,18 +556,24 @@ static int wifi_cmd_ftm(int argc, char **argv) return 0; } + if (ftmi_cfg.burst_period) { + /* Wait at least double the duration of maximum FTM bursts */ + wait_time_ms = (ftmi_cfg.burst_period * 100) * (MAX_FTM_BURSTS * 2); + } bits = xEventGroupWaitBits(s_ftm_event_group, FTM_REPORT_BIT | FTM_FAILURE_BIT, - pdTRUE, pdFALSE, portMAX_DELAY); - /* Processing data from FTM session */ - ftm_process_report(); - free(s_ftm_report); - s_ftm_report = NULL; - s_ftm_report_num_entries = 0; + pdTRUE, pdFALSE, wait_time_ms / portTICK_PERIOD_MS); if (bits & FTM_REPORT_BIT) { + /* Print detailed data from FTM session */ + ftm_print_report(); ESP_LOGI(TAG_STA, "Estimated RTT - %" PRId32 " nSec, Estimated Distance - %" PRId32 ".%02" PRId32 " meters", s_rtt_est, s_dist_est / 100, s_dist_est % 100); + } else if (bits & FTM_FAILURE_BIT) { + /* FTM Failure case */ + ESP_LOGE(TAG_STA, "FTM procedure failed!"); } else { - /* Failure case */ + /* Timeout, end session gracefully */ + ESP_LOGE(TAG_STA, "FTM procedure timed out!"); + esp_wifi_ftm_end_session(); } return 0; @@ -632,7 +668,7 @@ void register_wifi(void) ftm_args.initiator = arg_lit0("I", "ftm_initiator", "FTM Initiator mode"); ftm_args.ssid = arg_str0("s", "ssid", "SSID", "SSID of AP"); ftm_args.frm_count = arg_int0("c", "frm_count", "<0/8/16/24/32/64>", "FTM frames to be exchanged (0: No preference)"); - ftm_args.burst_period = arg_int0("p", "burst_period", "<2-255 (x 100 mSec)>", "Periodicity of FTM bursts in 100's of miliseconds (0: No preference)"); + ftm_args.burst_period = arg_int0("p", "burst_period", "<0-100 (x 100 mSec)>", "Periodicity of FTM bursts in 100's of miliseconds (0: No preference)"); /* FTM Responder commands */ ftm_args.responder = arg_lit0("R", "ftm_responder", "FTM Responder mode"); ftm_args.enable = arg_lit0("e", "enable", "Restart SoftAP with FTM enabled");