From acb1143409ae0ad80d21f9af8a23fe01728e3d1f Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Thu, 21 Jan 2021 19:55:39 +0530 Subject: [PATCH 1/3] Add support for FTM operation Add FTM support for below configuration - 1. Station(connected) as Initiator with AP as responder 2. SoftAP as responder with the connected Station Added Station example with runtime FTM configurations. --- components/esp_event/event_send.c | 3 + components/esp_event/event_send_compat.inc | 5 + .../esp_event/include/esp_event_legacy.h | 5 + components/esp_wifi/Kconfig | 37 ++ .../esp_wifi/include/esp_private/wifi.h | 23 + components/esp_wifi/include/esp_wifi.h | 14 + components/esp_wifi/include/esp_wifi_types.h | 34 +- components/esp_wifi/src/wifi_init.c | 25 + docs/en/api-guides/wifi.rst | 22 +- examples/wifi/README.md | 6 + examples/wifi/ftm/CMakeLists.txt | 8 + examples/wifi/ftm/README.md | 119 +++++ examples/wifi/ftm/main/CMakeLists.txt | 2 + examples/wifi/ftm/main/ftm_station_main.c | 442 ++++++++++++++++++ 14 files changed, 743 insertions(+), 2 deletions(-) create mode 100644 examples/wifi/ftm/CMakeLists.txt create mode 100644 examples/wifi/ftm/README.md create mode 100644 examples/wifi/ftm/main/CMakeLists.txt create mode 100644 examples/wifi/ftm/main/ftm_station_main.c diff --git a/components/esp_event/event_send.c b/components/esp_event/event_send.c index 334be196a3..62c0513952 100644 --- a/components/esp_event/event_send.c +++ b/components/esp_event/event_send.c @@ -91,6 +91,9 @@ static system_event_id_t esp_event_legacy_wifi_event_id(int32_t event_id) case WIFI_EVENT_ROC_DONE: return SYSTEM_EVENT_ROC_DONE; + case WIFI_EVENT_FTM_REPORT: + return SYSTEM_EVENT_FTM_REPORT; + default: ESP_LOGE(TAG, "invalid wifi event id %d", event_id); return SYSTEM_EVENT_MAX; diff --git a/components/esp_event/event_send_compat.inc b/components/esp_event/event_send_compat.inc index 78fbb14b65..d8381f36c1 100644 --- a/components/esp_event/event_send_compat.inc +++ b/components/esp_event/event_send_compat.inc @@ -70,6 +70,7 @@ esp_err_t esp_event_send_to_default_loop(system_event_t *event) HANDLE_SYS_EVENT_ARG(WIFI, SCAN_DONE, scan_done); HANDLE_SYS_EVENT(WIFI, STA_START); HANDLE_SYS_EVENT(WIFI, STA_STOP); + HANDLE_SYS_EVENT_ARG(WIFI, FTM_REPORT, ftm_report); /* STA events */ HANDLE_SYS_EVENT_ARG(WIFI, STA_CONNECTED, connected); @@ -207,6 +208,10 @@ static void esp_system_event_debug(const system_event_t* event) ESP_LOGD(TAG, "SYSTEM_EVENT_STA_AUTHMODE_CHNAGE, old_mode:%d, new_mode:%d", auth_change->old_mode, auth_change->new_mode); break; } + case SYSTEM_EVENT_FTM_REPORT: { + ESP_LOGD(TAG, "SYSTEM_EVENT_FTM_REPORT"); + break; + } case SYSTEM_EVENT_STA_GOT_IP: { const system_event_sta_got_ip_t *got_ip = &event->event_info.got_ip; ESP_LOGD(TAG, "SYSTEM_EVENT_STA_GOT_IP, ip:" IPSTR ", mask:" IPSTR ", gw:" IPSTR, diff --git a/components/esp_event/include/esp_event_legacy.h b/components/esp_event/include/esp_event_legacy.h index e307d8e60e..ddcb194a6b 100644 --- a/components/esp_event/include/esp_event_legacy.h +++ b/components/esp_event/include/esp_event_legacy.h @@ -50,6 +50,7 @@ typedef enum { SYSTEM_EVENT_AP_PROBEREQRECVED, /*!< Receive probe request packet in soft-AP interface */ SYSTEM_EVENT_ACTION_TX_STATUS, /*!< Receive status of Action frame transmitted */ SYSTEM_EVENT_ROC_DONE, /*!< Indicates the completion of Remain-on-Channel operation status */ + SYSTEM_EVENT_FTM_REPORT, /*!< Receive report of FTM procedure */ SYSTEM_EVENT_GOT_IP6, /*!< ESP32 station or ap or ethernet interface v6IP addr is preferred */ SYSTEM_EVENT_ETH_START, /*!< ESP32 ethernet start */ SYSTEM_EVENT_ETH_STOP, /*!< ESP32 ethernet stop */ @@ -95,6 +96,9 @@ typedef wifi_event_ap_stadisconnected_t system_event_ap_stadisconnected_t; /** Argument structure of event */ typedef wifi_event_ap_probe_req_rx_t system_event_ap_probe_req_rx_t; +/** Argument structure of SYSTEM_EVENT_FTM_REPORT event */ +typedef wifi_event_ftm_report_t system_event_ftm_report_t; + /** Argument structure of event */ typedef ip_event_ap_staipassigned_t system_event_ap_staipassigned_t; @@ -117,6 +121,7 @@ typedef union { system_event_ap_staconnected_t sta_connected; /*!< a station connected to ESP32 soft-AP */ system_event_ap_stadisconnected_t sta_disconnected; /*!< a station disconnected to ESP32 soft-AP */ system_event_ap_probe_req_rx_t ap_probereqrecved; /*!< ESP32 soft-AP receive probe request packet */ + system_event_ftm_report_t ftm_report; /*!< Report of FTM procedure */ system_event_ap_staipassigned_t ap_staipassigned; /**< ESP32 soft-AP assign an IP to the station*/ system_event_got_ip6_t got_ip6; /*!< ESP32 station or ap or ethernet ipv6 addr state change to preferred */ } system_event_info_t; diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index e72afb2e09..8cfe901fec 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -331,6 +331,43 @@ menu "Wi-Fi" If neither of them are enabled, the other 7.4KB IRAM memory would be taken by this option. Wi-Fi power-save mode average current would be reduced if this option is enabled. + config ESP32S2_WIFI_FTM_INITIATOR_SUPPORT + bool "FTM Initiator support" + default y + depends on IDF_TARGET_ESP32S2 + + config ESP32S2_WIFI_FTM_REPORT_LOG_ENABLE + bool "FTM Report logging" + default n + depends on ESP32S2_WIFI_FTM_INITIATOR_SUPPORT + help + Select this option to get a detailed report of FTM Procedure with raw values + + config ESP32S2_WIFI_FTM_REPORT_SHOW_RTT + depends on ESP32S2_WIFI_FTM_REPORT_LOG_ENABLE + bool "Show RTT values" + default y + + config ESP32S2_WIFI_FTM_REPORT_SHOW_DIAG + depends on ESP32S2_WIFI_FTM_REPORT_LOG_ENABLE + bool "Show dialog tokens" + default y + + config ESP32S2_WIFI_FTM_REPORT_SHOW_T1T2T3T4 + depends on ESP32S2_WIFI_FTM_REPORT_LOG_ENABLE + bool "Show T1 to T4" + default y + + config ESP32S2_WIFI_FTM_REPORT_SHOW_RSSI + depends on ESP32S2_WIFI_FTM_REPORT_LOG_ENABLE + bool "Show RSSI levels" + default y + + config ESP32S2_WIFI_FTM_RESPONDER_SUPPORT + bool "FTM Responder support" + default y + depends on IDF_TARGET_ESP32S2 + endmenu # Wi-Fi menu "PHY" diff --git a/components/esp_wifi/include/esp_private/wifi.h b/components/esp_wifi/include/esp_private/wifi.h index 5f10f9b765..c0df0d2749 100644 --- a/components/esp_wifi/include/esp_private/wifi.h +++ b/components/esp_wifi/include/esp_private/wifi.h @@ -72,6 +72,17 @@ typedef enum { WIFI_LOG_MODULE_MESH, /*logs related to Mesh*/ } wifi_log_module_t; +/** + * @brief FTM Report log levels configuration + * + */ +typedef struct { + uint8_t show_rtt:1; /**< Display all valid Round-Trip-Time readings for FTM frames */ + uint8_t show_diag:1; /**< Display dialogue tokens for all FTM frames with valid readings */ + uint8_t show_t1t2t3t4:1;/**< Display all valid T1, T2, T3, T4 readings considered while calculating RTT */ + uint8_t show_rxrssi:1; /**< Display RSSI for each FTM frame with valid readings */ +} ftm_report_log_level_t; + /** * @brief WiFi log submodule definition * @@ -558,6 +569,18 @@ esp_err_t esp_wifi_internal_set_spp_amsdu(wifi_interface_t ifidx, bool spp_cap, * */ void esp_wifi_internal_optimize_wake_ahead_time(void); + +/** + * @brief Set FTM Report log level + * + * @param log_lvl Log levels configuration + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_NOT_SUPPORTED: No FTM support + */ +esp_err_t esp_wifi_set_ftm_report_log_level(ftm_report_log_level_t *log_lvl); + #ifdef __cplusplus } #endif diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index a893ce0453..2df46515a0 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -203,6 +203,8 @@ extern uint64_t g_wifi_feature_caps; #define CONFIG_FEATURE_WPA3_SAE_BIT (1<<0) #define CONFIG_FEATURE_CACHE_TX_BUF_BIT (1<<1) +#define CONFIG_FEATURE_FTM_INITIATOR_BIT (1<<2) +#define CONFIG_FEATURE_FTM_RESPONDER_BIT (1<<3) #define WIFI_INIT_CONFIG_DEFAULT() { \ .event_handler = &esp_event_send_internal, \ @@ -1153,6 +1155,18 @@ esp_err_t esp_wifi_statis_dump(uint32_t modules); */ esp_err_t esp_wifi_set_rssi_threshold(int32_t rssi); +/** + * @brief Start FTM Initiator session + * If successful, event WIFI_EVENT_FTM_REPORT is generated with the result of the FTM procedure + * + * @param cfg FTM Initiator configurations + * + * @return + * - ESP_OK: succeed + * - others: failed + */ +esp_err_t esp_wifi_ftm_start_initiator(wifi_ftm_initiator_cfg_t *cfg); + #ifdef __cplusplus } #endif diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index 238e90a8aa..4155409555 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -178,7 +178,9 @@ typedef struct { uint32_t phy_11n:1; /**< bit: 2 flag to identify if 11n mode is enabled or not */ uint32_t phy_lr:1; /**< bit: 3 flag to identify if low rate is enabled or not */ uint32_t wps:1; /**< bit: 4 flag to identify if WPS is supported or not */ - uint32_t reserved:27; /**< bit: 5..31 reserved */ + uint32_t ftm_responder:1; /**< bit: 5 flag to identify if FTM is supported in responder mode */ + uint32_t ftm_initiator:1; /**< bit: 6 flag to identify if FTM is supported in initiator mode */ + uint32_t reserved:25; /**< bit: 7..31 reserved */ wifi_country_t country; /**< country information of AP */ } wifi_ap_record_t; @@ -515,6 +517,15 @@ typedef struct { uint8_t data[0]; /**< Appended Data payload */ } wifi_action_tx_req_t; +/** + * @brief FTM Initiator configuration + * + */ +typedef struct { + 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) */ +} wifi_ftm_initiator_cfg_t; + /** * @brief WiFi PHY rate encodings * @@ -672,6 +683,27 @@ typedef struct { int32_t rssi; /**< RSSI value of bss */ } wifi_event_bss_rssi_low_t; +/** + * @brief FTM operation status types + * + */ +typedef enum { + FTM_STATUS_SUCCESS = 0, /**< FTM exchange is successful */ + FTM_STATUS_UNSUPPORTED, /**< Peer does not support FTM */ + 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 */ +} wifi_ftm_status_t; + +/** Argument structure for WIFI_EVENT_FTM_REPORT event */ +typedef struct { + uint8_t peer_mac[6]; /**< MAC address of the FTM Peer */ + wifi_ftm_status_t status; /**< Status of the FTM operation */ + 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_event_ftm_report_t; + #define WIFI_STATIS_BUFFER (1<<0) #define WIFI_STATIS_RXTX (1<<1) #define WIFI_STATIS_HW (1<<2) diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index 5a5a5ffcdb..353345d406 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -56,6 +56,12 @@ uint64_t g_wifi_feature_caps = #if (CONFIG_ESP32_SPIRAM_SUPPORT | CONFIG_ESP32S2_SPIRAM_SUPPORT) CONFIG_FEATURE_CACHE_TX_BUF_BIT | #endif +#if CONFIG_ESP32S2_WIFI_FTM_INITIATOR_SUPPORT + CONFIG_FEATURE_FTM_INITIATOR_BIT | +#endif +#if CONFIG_ESP32S2_WIFI_FTM_RESPONDER_SUPPORT + CONFIG_FEATURE_FTM_RESPONDER_BIT | +#endif 0; static bool s_wifi_adc_xpd_flag; @@ -248,6 +254,25 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config) } } adc2_cal_include(); //This enables the ADC2 calibration constructor at start up. + +#if CONFIG_IDF_TARGET_ESP32S2 +#ifdef CONFIG_ESP32S2_WIFI_FTM_REPORT_LOG_ENABLE + ftm_report_log_level_t log_lvl = {0}; +#ifdef CONFIG_ESP32S2_WIFI_FTM_REPORT_SHOW_RTT + log_lvl.show_rtt = 1; +#endif +#ifdef CONFIG_ESP32S2_WIFI_FTM_REPORT_SHOW_DIAG + log_lvl.show_diag = 1; +#endif +#ifdef CONFIG_ESP32S2_WIFI_FTM_REPORT_SHOW_T1T2T3T4 + log_lvl.show_t1t2t3t4 = 1; +#endif +#ifdef CONFIG_ESP32S2_WIFI_FTM_REPORT_SHOW_RSSI + log_lvl.show_rxrssi = 1; +#endif + esp_wifi_set_ftm_report_log_level(&log_lvl); +#endif +#endif esp_wifi_config_info(); return result; } diff --git a/docs/en/api-guides/wifi.rst b/docs/en/api-guides/wifi.rst index 3a23ea7735..23a2954650 100644 --- a/docs/en/api-guides/wifi.rst +++ b/docs/en/api-guides/wifi.rst @@ -1459,6 +1459,26 @@ For establishing a secure connection, AP and Station negotiate and agree on the Detailed information on creating certificates and how to run wpa2_enterprise example on {IDF_TARGET_NAME} can be found in :example:`wifi/wpa2_enterprise`. +.. only:: esp32s2 + +Wi-Fi Location +------------------------------- + +Wi-Fi Location will improve the accuracy of a device's location data beyond the Access Point, which will enable creation of new, feature-rich applications and services such as geo-fencing, network management, navigation and others. One of the protocols used to determine the device location with respect to the Access Point is Fine Timing Measurement which calculates Time-of-Flight of a WiFi frame. + +Fine Timing Measurement (FTM) ++++++++++++++++++++++++++++++ + +FTM is used to measure Wi-Fi Round Trip Time (Wi-Fi RTT) which is the time a WiFi signal takes to travel from a device to another device and back again. Using WiFi RTT the distance between the devices can be calculated with a simple formula of `RTT * c / 2`, where c is the speed of light. +FTM uses timestamps given by WiFi interface hardware at the time of arrival or departure of frames exchanged between a pair of devices. One entity called FTM Initiator (mostly a Station device) discovers the FTM Responder (can be a Station or an Access Point) and negotiates to start an FTM procedure. The procedure uses multiple Action frames sent in bursts and its ACK's to gather the timestamps data. FTM Initiator gathers the data in the end to calculate an average Round-Trip-Time. +{IDF_TARGET_NAME} supports FTM in below configuration: + + - {IDF_TARGET_NAME} as FTM Initiator in Station mode with the associated AP acting as FTM Responder. + - {IDF_TARGET_NAME} as FTM Responder in SoftAP mode with an associated Station acting as FTM Initiator. + +Distance measurement using RTT is not accurate, 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 {IDF_TARGET_NAME} devices as Station and SoftAP. +Refer to IDF example :idf_file:`examples/wifi/ftm/README.md` for steps on how to setup and perform FTM. + {IDF_TARGET_NAME} Wi-Fi Power-saving Mode ----------------------------------------- @@ -2318,4 +2338,4 @@ Please refer to a separate document with :doc:`wireshark-user-guide`. .. toctree:: :hidden: - wireshark-user-guide \ No newline at end of file + wireshark-user-guide diff --git a/examples/wifi/README.md b/examples/wifi/README.md index 0aab2e2dc2..9879ea3efc 100644 --- a/examples/wifi/README.md +++ b/examples/wifi/README.md @@ -38,6 +38,12 @@ Show how to scan for all the available APs. See the [README.md](./scan/README.md) file in the project [scan](./scan/). +## FTM(Fine Timing Measurement) + +Shows how to use FTM(Fine Timing Measurement). + +See the [README.md](./ftm/README.md) file in the project [ftm](./ftm/). + # More See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. diff --git a/examples/wifi/ftm/CMakeLists.txt b/examples/wifi/ftm/CMakeLists.txt new file mode 100644 index 0000000000..acb3c076d2 --- /dev/null +++ b/examples/wifi/ftm/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/components) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ftm) diff --git a/examples/wifi/ftm/README.md b/examples/wifi/ftm/README.md new file mode 100644 index 0000000000..c1cae5c79d --- /dev/null +++ b/examples/wifi/ftm/README.md @@ -0,0 +1,119 @@ +| Supported Targets | ESP32-S2 | +| ----------------- | -------- | + +# FTM Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +## Introduction +One of the ways in which WiFi enabled devices can measure their distance to the Access Point is by measuring Wi-Fi Round Trip Time (Wi-Fi RTT). Wi-Fi RTT is the time a WiFi signal takes to travel from Station to an AP. This time is proportional to the actual distance between them. Given the RTT, the distance can be calculated with below simple formula - + +> distance = RTT * c / 2 +> (Where c is the speed of light) + +Wi-Fi RTT is calculated using a procedure called Fine Timing Measurement(FTM). During FTM procedure, a burst of Action frames is transmitted by one device(FTM Responder) to another(FTM Initiator) and each of them is ACK'ed. Hardware in both the devices mark time-of-arrival (TOA) and time-of-departure (TOD) of both Action frame and its ACK. In the end, the FTM Initiator collects the data for all pairs of Action frame and ACK and calculates RTT for each pair with below formula - + +> RTT[i] = (T4[i] - T1[i]) - (T3[i] - T2[i]) Where +> T1[i] : TOD of i'th Action frame from Responder +> T2[i] : TOA of i'th Action frame at Initiator +> T3[i] : TOD of i'th ACK from Initiator +> T4[i] : TOA of i'th ACK at Responder + +Average RTT is calculated over all such pairs to get a more accurate result. +In this example, FTM procedure is supported only between a Station(ESP32S2) and an AP it is connected to. The AP can be a SoftAP(ESP32S2) or an External AP that supports FTM Responder mode. + +## How to use example + +With this example, users can scan for AP's that support FTM Responder role, connect with them and perform FTM procedure with different configurations. Below steps show how to do this using 2 ESP32-S2's in Station and SoftAP mode. +First make sure that FTM Initiator support on Station and FTM Responder support on SoftAP is enabled in the example configuration menu. For this, open project configuration menu (`idf.py menuconfig`), navigate to `Component config -> Wi-Fi` and check `FTM Initiator support` on Station build and `FTM Responder support` on SoftAP build. Furthermore for getting a per frame detailed report of the FTM procedure, enable `FTM Report logging` option. +Build and flash the example on respective ESP32-S2's to see below output - + +```bash + ========================================================== + | Steps to test FTM | + | | + | 1. Print 'help' to gain overview of commands | + | 2. Use 'scan' command for AP that support FTM | + | OR | + | 2. Start SoftAP on another ESP32S2 with 'ap' command | + | 3. Setup connection with the AP using 'sta' command | + | 4. Initiate FTM from Station using 'ftm -I' command | + | | + ========================================================== + +ftm> +``` + +Use `help` to get a list of available commands and options. Use `scan` command to scan for AP's that support FTM Responder mode. +Before testing FTM with an external AP, make sure that `FTM Responder` is visible in the respective scan result entry. + +```bash +ftm> scan +I (476765) ftm_station: sta start to scan +ftm> I (478805) ftm_station: [Abeeys Palace][rssi=84] +I (478805) ftm_station: [privateproperty][rssi=76] +I (478805) ftm_station: [C904][rssi=69] +I (478815) ftm_station: [FTM][rssi=-94][FTM Responder] +I (478815) ftm_station: [Velop][rssi=-115] +I (478825) ftm_station: sta scan done +``` + +AP's that support FTM Responder mode can be seen in the scan results. Or setup a SoftAP using another ESP32-S2 device using the `ap` command - + +```bash +ftm> ap FTM password +I (91271) ftm_ap: Starting SoftAP with FTM Responder support, SSID - FTM, Password - password +ftm> +``` + +Use command `sta []` to connect with an eligible AP. Then simply issue `ftm -I` to initiate a session with default configuration of 32 FTM frames. For more configurations below options are available - +`ftm [-I] [-c <0/16/24/32/64>] [-p <0-255 (x 100 mSec)>]` +Where - +* `-I` OR `--ftm_initiator`: FTM Initiator mode +* `-c` OR `--frm_count`: FTM frames to be exchanged (Valid values: 0=No preference, 16, 24, 32, 64, default: 32) +* `-p` OR `--burst_period`: Periodicity of FTM bursts in 100's of miliseconds (0: No preference, default: 2) + +Currently FTM is only supported in below configuration - + 1. Station(ESP32-S2) as Initiator in connected mode with SoftAP(ESP32-S2) as Responder + 2. Station(ESP32-S2) as Initiator in connected mode with external AP as Responder +The first option should be preferred since ESP32-S2 is self calibrated for high resolution measurement. Support for more configurations like STA to STA with ASAP mode will follow in future updates. + +## Example Output +Example output of an FTM Procedure - + +```bash +ftm> ftm -I +I (13796) ftm_station: Starting FTM Initiator with Frm Count 32, Burst Period - 200mSec +ftm> W (23696) wifi:FTM report: +W (23696) wifi:| Diag | RTT | RSSI | T1 | T2 | T3 | T4 | +W (23706) wifi:| 3| 24850 | -18 |13598650592600 | 3973101843750 | 3973205662500 |13598754436200 | +W (23716) wifi:| 5| 32662 | -18 |13600546592600 | 3974997826562 | 3975101662500 |13600650461200 | +W (23726) wifi:| 7| 31100 | -18 |14498977692600 | 4873420043750 | 4873523662500 |14499081342450 | +W (23736) wifi:| 9| 29412 | -18 |14500856692600 | 4875299026562 | 4875402662500 |14500960357950 | +W (23746) wifi:| 11| 24850 | -18 |15399235817600 | 5773669262500 | 5773785662500 |15399352242450 | +W (23756) wifi:| 12| 27975 | -18 |15400258817600 | 5774692253125 | 5774796662500 |15400363254950 | +W (23766) wifi:| 13| 26287 | -18 |15401215817600 | 5775649242187 | 5775753662500 |15401320264200 | +W (23776) wifi:| 14| 24725 | -18 |15402158817600 | 5776592234375 | 5776696662500 |15402263270450 | +W (23786) wifi:| 15| 24850 | -18 |16298632917600 | 6673057456250 | 6673173662500 |16298749148700 | +W (23796) wifi:| 16| 29412 | -18 |16299698917600 | 6674123445312 | 6674227662500 |16299803164200 | +W (23796) wifi:| 17| 26287 | -18 |16300637917600 | 6675062435937 | 6675166662500 |16300742170450 | +W (23816) wifi:| 18| 27975 | -18 |16301580917600 | 6676005428125 | 6676109662500 |16301685179950 | +W (23826) wifi:| 19| 27850 | -18 |17198977042600 | 862506262500 | 862622262500 |17199093070450 | +W (23836) wifi:| 20| 23162 | -18 |17200051042600 | 863580251562 | 863684262500 |17200155076700 | +W (23846) wifi:| 21| 31100 | -18 |17200991042600 | 864520243750 | 864624262500 |17201095092450 | +W (23846) wifi:| 22| 26412 | -18 |17201930042600 | 865459232812 | 865563262500 |17202034098700 | +W (23856) wifi:| 23| 31100 | -18 |18099333142600 | 1762853443750 | 1762969262500 |18099448992450 | +W (23876) wifi:| 24| 23162 | -18 |18100397142600 | 1763917432812 | 1764021262500 |18100500995450 | +W (23886) wifi:| 25| 26287 | -18 |18101336142600 | 1764856423437 | 1764960262500 |18101440007950 | +W (23896) wifi:| 26| 24850 | -18 |18102343142600 | 1765863412500 | 1765967262500 |18102447017450 | +W (23896) wifi:| 27| 31100 | -18 |19000187242600 | 2663698618750 | 2663814262500 |19000302917450 | +W (23906) wifi:| 28| 24725 | -18 |19001274242600 | 2664785609375 | 2664889262500 |19001377920450 | +W (23916) wifi:| 29| 31100 | -18 |19002225242600 | 2665736600000 | 2665840262500 |19002328936200 | +W (23936) wifi:| 31| 23287 | -19 |19004133242600 | 2667644579687 | 2667748262500 |19004236948700 | +W (23936) wifi:| 32| 26287 | -18 |19899976367600 | 3563478835937 | 3563595262500 |19900092820450 | +W (23946) wifi:FTM session ends with 25 valid readings out of 31, Avg raw RTT: 27.232 nSec, Avg RSSI: -18 +I (23956) ftm_station: Estimated RTT - 13 nSec, Estimated Distance - 1.95 meters +``` + +The final statement gives the average calculated RTT along with an estimated distance between the Station and the AP. This distance is measured by first adjusting the RTT with any physical analog delays and a calibration delta. Distances measured using RTT are not perfectly accurate, and are subjected to various errors like RF interference, multi-path, path loss, orientations etc. +The design requires line-of-sight with straightforward propagation path with no less than -70dBm RSSI for better results. diff --git a/examples/wifi/ftm/main/CMakeLists.txt b/examples/wifi/ftm/main/CMakeLists.txt new file mode 100644 index 0000000000..9713164e27 --- /dev/null +++ b/examples/wifi/ftm/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "ftm_station_main.c" + INCLUDE_DIRS ".") diff --git a/examples/wifi/ftm/main/ftm_station_main.c b/examples/wifi/ftm/main/ftm_station_main.c new file mode 100644 index 0000000000..69f7127538 --- /dev/null +++ b/examples/wifi/ftm/main/ftm_station_main.c @@ -0,0 +1,442 @@ +/* Wi-Fi FTM Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include "nvs_flash.h" +#include "cmd_system.h" +#include "argtable3/argtable3.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_err.h" +#include "esp_wifi.h" +#include "esp_console.h" + +typedef struct { + struct arg_str *ssid; + struct arg_str *password; + struct arg_end *end; +} wifi_args_t; + +typedef struct { + struct arg_str *ssid; + struct arg_end *end; +} wifi_scan_arg_t; + +typedef struct { + struct arg_lit *mode; + struct arg_int *frm_count; + struct arg_int *burst_period; + struct arg_end *end; +} wifi_ftm_args_t; + +static wifi_args_t sta_args; +static wifi_args_t ap_args; +static wifi_scan_arg_t scan_args; +static wifi_ftm_args_t ftm_args; + +static bool s_reconnect = true; +static const char *TAG_STA = "ftm_station"; +static const char *TAG_AP = "ftm_ap"; + +static EventGroupHandle_t wifi_event_group; +const int CONNECTED_BIT = BIT0; +const int DISCONNECTED_BIT = BIT1; + +static void scan_done_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + uint16_t sta_number = 0; + uint8_t i; + wifi_ap_record_t *ap_list_buffer; + + esp_wifi_scan_get_ap_num(&sta_number); + ap_list_buffer = malloc(sta_number * sizeof(wifi_ap_record_t)); + if (ap_list_buffer == NULL) { + ESP_LOGE(TAG_STA, "Failed to malloc buffer to print scan results"); + return; + } + + if (esp_wifi_scan_get_ap_records(&sta_number, (wifi_ap_record_t *)ap_list_buffer) == ESP_OK) { + for (i = 0; i < sta_number; i++) { + ESP_LOGI(TAG_STA, "[%s][rssi=%d]""%s", ap_list_buffer[i].ssid, ap_list_buffer[i].rssi, + ap_list_buffer[i].ftm_responder ? "[FTM Responder]" : ""); + } + } + free(ap_list_buffer); + ESP_LOGI(TAG_STA, "sta scan done"); +} + +static void wifi_connected_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + wifi_event_sta_connected_t *event = (wifi_event_sta_connected_t *)event_data; + + ESP_LOGI(TAG_STA, "Connected to %s (BSSID: "MACSTR", Channel: %d)", event->ssid, + MAC2STR(event->bssid), event->channel); + + xEventGroupClearBits(wifi_event_group, DISCONNECTED_BIT); + xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); +} + +static void disconnect_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + if (s_reconnect) { + ESP_LOGI(TAG_STA, "sta disconnect, s_reconnect..."); + esp_wifi_connect(); + } else { + ESP_LOGI(TAG_STA, "sta disconnect"); + } + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + xEventGroupSetBits(wifi_event_group, DISCONNECTED_BIT); +} + +static void ftm_report_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + wifi_event_ftm_report_t *event = (wifi_event_ftm_report_t *) event_data; + + ESP_LOGI(TAG_STA, "Estimated RTT - %d nSec, Estimated Distance - %d.%02d meters", event->rtt_est, + event->dist_est / 100, event->dist_est % 100); +} + +void initialise_wifi(void) +{ + esp_log_level_set("wifi", ESP_LOG_WARN); + static bool initialized = false; + + if (initialized) { + return; + } + + ESP_ERROR_CHECK(esp_netif_init()); + wifi_event_group = xEventGroupCreate(); + ESP_ERROR_CHECK( esp_event_loop_create_default() ); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_SCAN_DONE, + &scan_done_handler, + NULL, + NULL)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_STA_CONNECTED, + &wifi_connected_handler, + NULL, + NULL)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_STA_DISCONNECTED, + &disconnect_handler, + NULL, + NULL)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_FTM_REPORT, + &ftm_report_handler, + NULL, + NULL)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL) ); + ESP_ERROR_CHECK(esp_wifi_start() ); + initialized = true; +} + +static bool wifi_cmd_sta_join(const char *ssid, const char *pass) +{ + int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 0); + + wifi_config_t wifi_config = { 0 }; + + strlcpy((char *) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid)); + if (pass) { + strlcpy((char *) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password)); + } + + if (bits & CONNECTED_BIT) { + s_reconnect = false; + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + ESP_ERROR_CHECK( esp_wifi_disconnect() ); + xEventGroupWaitBits(wifi_event_group, DISCONNECTED_BIT, 0, 1, portTICK_RATE_MS); + } + + s_reconnect = true; + ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); + ESP_ERROR_CHECK( esp_wifi_connect() ); + + xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 5000 / portTICK_RATE_MS); + + return true; +} + +static int wifi_cmd_sta(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &sta_args); + + if (nerrors != 0) { + arg_print_errors(stderr, sta_args.end, argv[0]); + return 1; + } + + ESP_LOGI(TAG_STA, "sta connecting to '%s'", sta_args.ssid->sval[0]); + wifi_cmd_sta_join(sta_args.ssid->sval[0], sta_args.password->sval[0]); + return 0; +} + +static bool wifi_cmd_sta_scan(const char *ssid) +{ + wifi_scan_config_t scan_config = { 0 }; + scan_config.ssid = (uint8_t *) ssid; + + ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK( esp_wifi_scan_start(&scan_config, false) ); + + return true; +} + +static int wifi_cmd_scan(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &scan_args); + + if (nerrors != 0) { + arg_print_errors(stderr, scan_args.end, argv[0]); + return 1; + } + + ESP_LOGI(TAG_STA, "sta start to scan"); + if ( scan_args.ssid->count == 1 ) { + wifi_cmd_sta_scan(scan_args.ssid->sval[0]); + } else { + wifi_cmd_sta_scan(NULL); + } + return 0; +} + +static bool wifi_cmd_ap_set(const char* ssid, const char* pass) +{ + wifi_config_t wifi_config = { + .ap = { + .ssid = "", + .ssid_len = 0, + .max_connection = 4, + .password = "", + .authmode = WIFI_AUTH_WPA2_PSK + }, + }; + + s_reconnect = false; + strlcpy((char*) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); + if (pass) { + if (strlen(pass) != 0 && strlen(pass) < 8) { + s_reconnect = true; + ESP_LOGE(TAG_AP, "password less than 8"); + return false; + } + strlcpy((char*) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password)); + } + + if (strlen(pass) == 0) { + wifi_config.ap.authmode = WIFI_AUTH_OPEN; + } + + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); + ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config)); + return true; +} + +static int wifi_cmd_ap(int argc, char** argv) +{ + int nerrors = arg_parse(argc, argv, (void**) &ap_args); + + if (nerrors != 0) { + arg_print_errors(stderr, ap_args.end, argv[0]); + return 1; + } + + wifi_cmd_ap_set(ap_args.ssid->sval[0], ap_args.password->sval[0]); + ESP_LOGI(TAG_AP, "Starting SoftAP with FTM Responder support, SSID - %s, Password - %s", ap_args.ssid->sval[0], ap_args.password->sval[0]); + return 0; +} + +static int wifi_cmd_query(int argc, char **argv) +{ + wifi_config_t cfg; + wifi_mode_t mode; + + esp_wifi_get_mode(&mode); + if (WIFI_MODE_AP == mode) { + esp_wifi_get_config(WIFI_IF_AP, &cfg); + ESP_LOGI(TAG_AP, "AP mode, %s %s", cfg.ap.ssid, cfg.ap.password); + } else if (WIFI_MODE_STA == mode) { + int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 0); + if (bits & CONNECTED_BIT) { + esp_wifi_get_config(WIFI_IF_STA, &cfg); + ESP_LOGI(TAG_STA, "sta mode, connected %s", cfg.ap.ssid); + } else { + ESP_LOGI(TAG_STA, "sta mode, disconnected"); + } + } else { + ESP_LOGI(TAG_STA, "NULL mode"); + return 0; + } + + return 0; +} + +static int wifi_cmd_ftm(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &ftm_args); + + wifi_ftm_initiator_cfg_t ftmi_cfg = { + .frm_count = 32, + .burst_period = 2, + }; + + if (nerrors != 0) { + arg_print_errors(stderr, ftm_args.end, argv[0]); + return 0; + } + + if (ftm_args.mode->count == 0) { + goto ftm_start; + } + + if (ftm_args.frm_count->count != 0) { + uint8_t count = ftm_args.frm_count->ival[0]; + if (count != 0 && count != 16 && count != 24 && + count != 32 && count != 64) { + count = 0; + } + ftmi_cfg.frm_count = count; + } + + if (ftm_args.burst_period->count != 0) { + if (ftm_args.burst_period->ival[0] > 0 && + ftm_args.burst_period->ival[0] < 256) { + ftmi_cfg.burst_period = ftm_args.burst_period->ival[0]; + } else { + ftmi_cfg.burst_period = 0; + } + } + +ftm_start: + ESP_LOGI(TAG_STA, "Starting FTM Initiator with Frm Count %d, Burst Period - %dmSec", + ftmi_cfg.frm_count, ftmi_cfg.burst_period * 100); + esp_wifi_ftm_start_initiator(&ftmi_cfg); + + return 0; +} + +void register_wifi(void) +{ + sta_args.ssid = arg_str1(NULL, NULL, "", "SSID of AP"); + sta_args.password = arg_str0(NULL, NULL, "", "password of AP"); + sta_args.end = arg_end(2); + + const esp_console_cmd_t sta_cmd = { + .command = "sta", + .help = "WiFi is station mode, join specified soft-AP", + .hint = NULL, + .func = &wifi_cmd_sta, + .argtable = &sta_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&sta_cmd) ); + + ap_args.ssid = arg_str1(NULL, NULL, "", "SSID of AP"); + ap_args.password = arg_str0(NULL, NULL, "", "password of AP"); + ap_args.end = arg_end(2); + + const esp_console_cmd_t ap_cmd = { + .command = "ap", + .help = "AP mode, configure ssid and password", + .hint = NULL, + .func = &wifi_cmd_ap, + .argtable = &ap_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&ap_cmd) ); + + scan_args.ssid = arg_str0(NULL, NULL, "", "SSID of AP want to be scanned"); + scan_args.end = arg_end(1); + + const esp_console_cmd_t scan_cmd = { + .command = "scan", + .help = "WiFi is station mode, start scan ap", + .hint = NULL, + .func = &wifi_cmd_scan, + .argtable = &scan_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&scan_cmd) ); + + const esp_console_cmd_t query_cmd = { + .command = "query", + .help = "query WiFi info", + .hint = NULL, + .func = &wifi_cmd_query, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&query_cmd) ); + + ftm_args.mode = arg_lit1("I", "ftm_initiator", "FTM Initiator mode"); + ftm_args.frm_count = arg_int0("c", "frm_count", "<0/16/24/32/64>", "FTM frames to be exchanged (0: No preference)"); + ftm_args.burst_period = arg_int0("p", "burst_period", "<0-255 (x 100 mSec)>", "Periodicity of FTM bursts in 100's of miliseconds (0: No preference)"); + ftm_args.end = arg_end(1); + + const esp_console_cmd_t ftm_cmd = { + .command = "ftm", + .help = "FTM command", + .hint = NULL, + .func = &wifi_cmd_ftm, + .argtable = &ftm_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&ftm_cmd) ); +} + +void app_main(void) +{ + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK( ret ); + + initialise_wifi(); + + esp_console_repl_t *repl = NULL; + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + repl_config.prompt = "ftm>"; + // init console REPL environment + ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl)); + /* Register commands */ + register_system(); + register_wifi(); + + printf("\n ==========================================================\n"); + printf(" | Steps to test FTM |\n"); + printf(" | |\n"); + printf(" | 1. Print 'help' to gain overview of commands |\n"); + printf(" | 2. Use 'scan' command for AP that support FTM |\n"); + printf(" | OR |\n"); + printf(" | 2. Start SoftAP on another ESP32S2 with 'ap' command |\n"); + printf(" | 3. Setup connection with the AP using 'sta' command |\n"); + printf(" | 4. Initiate FTM from Station using 'ftm -I' command |\n"); + printf(" | |\n"); + printf(" ==========================================================\n\n"); + + // start console REPL + ESP_ERROR_CHECK(esp_console_start_repl(repl)); +} From a71976ab5411d5cfd8b254acdcff899b7a2e5182 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Thu, 7 Jan 2021 19:02:57 +0530 Subject: [PATCH 2/3] wifi/ftm: Stability fixes, raw FTM data in event Update wifi lib with below additions - 1. Add FTM frame formation, IEEE definitions, event and IOCTL. 2. Implementation of FTM bursts, Measurements and RTT calculations 3. Fix Watchdog timeout, crashes with better cleanup of timers 4. Included FTM Report raw data in FTM event Closes https://github.com/espressif/esp-idf/issues/5059 --- components/esp_wifi/include/esp_wifi_types.h | 23 ++++++-- components/esp_wifi/lib | 2 +- examples/wifi/ftm/main/ftm_station_main.c | 57 +++++++++++++++++--- 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index 4155409555..db15125ce2 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -695,13 +695,26 @@ typedef enum { FTM_STATUS_FAIL, /**< Unknown error during FTM exchange */ } wifi_ftm_status_t; +/** Argument structure for */ +typedef struct { + uint8_t dlog_token; /**< Dialog Token of the FTM frame */ + int8_t rssi; /**< RSSI of the FTM frame received */ + uint32_t rtt; /**< Round Trip Time in pSec with a peer */ + uint64_t t1; /**< Time of departure of FTM frame from FTM Responder in pSec */ + uint64_t t2; /**< Time of arrival of FTM frame at FTM Initiator in pSec */ + uint64_t t3; /**< Time of departure of ACK from FTM Initiator in pSec */ + uint64_t t4; /**< Time of arrival of ACK at FTM Responder in pSec */ +} wifi_ftm_report_entry_t; + /** Argument structure for WIFI_EVENT_FTM_REPORT event */ typedef struct { - uint8_t peer_mac[6]; /**< MAC address of the FTM Peer */ - wifi_ftm_status_t status; /**< Status of the FTM operation */ - 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 */ + uint8_t peer_mac[6]; /**< MAC address of the FTM Peer */ + wifi_ftm_status_t status; /**< Status of the FTM operation */ + 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 */ + uint8_t ftm_report_num_entries; /**< Number of entries in the FTM Report data */ } wifi_event_ftm_report_t; #define WIFI_STATIS_BUFFER (1<<0) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index bad7d9df47..2e4ba2b423 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit bad7d9df47543691d8be80b449f416bf5d581746 +Subproject commit 2e4ba2b423d350a53698660274bb65ead89f22e4 diff --git a/examples/wifi/ftm/main/ftm_station_main.c b/examples/wifi/ftm/main/ftm_station_main.c index 69f7127538..d8e288d580 100644 --- a/examples/wifi/ftm/main/ftm_station_main.c +++ b/examples/wifi/ftm/main/ftm_station_main.c @@ -53,6 +53,12 @@ static EventGroupHandle_t wifi_event_group; const int CONNECTED_BIT = BIT0; const int DISCONNECTED_BIT = BIT1; +static EventGroupHandle_t ftm_event_group; +const int FTM_REPORT_BIT = BIT0; +const int FTM_FAILURE_BIT = BIT1; +wifi_ftm_report_entry_t *g_ftm_report; +uint8_t g_ftm_report_num_entries; + static void scan_done_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { @@ -107,8 +113,17 @@ static void ftm_report_handler(void *arg, esp_event_base_t event_base, { wifi_event_ftm_report_t *event = (wifi_event_ftm_report_t *) event_data; - ESP_LOGI(TAG_STA, "Estimated RTT - %d nSec, Estimated Distance - %d.%02d meters", event->rtt_est, - event->dist_est / 100, event->dist_est % 100); + if (event->status == FTM_STATUS_SUCCESS) { + ESP_LOGI(TAG_STA, "Estimated RTT - %d nSec, Estimated Distance - %d.%02d meters", event->rtt_est, + event->dist_est / 100, event->dist_est % 100); + xEventGroupSetBits(ftm_event_group, FTM_REPORT_BIT); + g_ftm_report = event->ftm_report_data; + g_ftm_report_num_entries = event->ftm_report_num_entries; + } else { + ESP_LOGI(TAG_STA, "FTM procedure with Peer("MACSTR") failed! (Status - %d)", + MAC2STR(event->peer_mac), event->status); + xEventGroupSetBits(ftm_event_group, FTM_FAILURE_BIT); + } } void initialise_wifi(void) @@ -122,6 +137,7 @@ void initialise_wifi(void) ESP_ERROR_CHECK(esp_netif_init()); wifi_event_group = xEventGroupCreate(); + ftm_event_group = xEventGroupCreate(); ESP_ERROR_CHECK( esp_event_loop_create_default() ); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); @@ -321,7 +337,7 @@ static int wifi_cmd_ftm(int argc, char **argv) } if (ftm_args.burst_period->count != 0) { - if (ftm_args.burst_period->ival[0] > 0 && + if (ftm_args.burst_period->ival[0] >= 2 && ftm_args.burst_period->ival[0] < 256) { ftmi_cfg.burst_period = ftm_args.burst_period->ival[0]; } else { @@ -330,9 +346,34 @@ static int wifi_cmd_ftm(int argc, char **argv) } ftm_start: - ESP_LOGI(TAG_STA, "Starting FTM Initiator with Frm Count %d, Burst Period - %dmSec", - ftmi_cfg.frm_count, ftmi_cfg.burst_period * 100); - esp_wifi_ftm_start_initiator(&ftmi_cfg); + if (ftmi_cfg.burst_period == 0) { + ESP_LOGI(TAG_STA, "Starting FTM Initiator with Frm Count %d, Burst Period - No Preference", + ftmi_cfg.frm_count); + } else { + ESP_LOGI(TAG_STA, "Starting FTM Initiator with Frm Count %d, Burst Period - %dmSec", + ftmi_cfg.frm_count, ftmi_cfg.burst_period * 100); + } + + if (ESP_OK != esp_wifi_ftm_start_initiator(&ftmi_cfg)) { + ESP_LOGE(TAG_STA, "Failed to start FTM session"); + return 0; + } + + EventBits_t bits = xEventGroupWaitBits(ftm_event_group, FTM_REPORT_BIT | FTM_FAILURE_BIT, + pdFALSE, pdFALSE, portMAX_DELAY); + /* Processing data from FTM session */ + if (bits & FTM_REPORT_BIT) { + int i; + for (i = 0; i < g_ftm_report_num_entries; i++) { + /* NOTE: Process FTM report elements here, e.g. g_ftm_report[i].rtt etc */ + } + free(g_ftm_report); + g_ftm_report = NULL; + g_ftm_report_num_entries = 0; + xEventGroupClearBits(ftm_event_group, FTM_REPORT_BIT); + } else { + /* Failure case */ + } return 0; } @@ -390,7 +431,7 @@ void register_wifi(void) ftm_args.mode = arg_lit1("I", "ftm_initiator", "FTM Initiator mode"); ftm_args.frm_count = arg_int0("c", "frm_count", "<0/16/24/32/64>", "FTM frames to be exchanged (0: No preference)"); - ftm_args.burst_period = arg_int0("p", "burst_period", "<0-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", "<2-255 (x 100 mSec)>", "Periodicity of FTM bursts in 100's of miliseconds (0: No preference)"); ftm_args.end = arg_end(1); const esp_console_cmd_t ftm_cmd = { @@ -431,7 +472,7 @@ void app_main(void) printf(" | 1. Print 'help' to gain overview of commands |\n"); printf(" | 2. Use 'scan' command for AP that support FTM |\n"); printf(" | OR |\n"); - printf(" | 2. Start SoftAP on another ESP32S2 with 'ap' command |\n"); + printf(" | 2. Start SoftAP on another device with 'ap' command |\n"); printf(" | 3. Setup connection with the AP using 'sta' command |\n"); printf(" | 4. Initiate FTM from Station using 'ftm -I' command |\n"); printf(" | |\n"); From 8de3b31d2d82c4740aca87a30f58bccf00631ca9 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Tue, 26 Jan 2021 12:49:18 +0530 Subject: [PATCH 3/3] FTM support for ESP32-C3 and connectionless mode 1. Support for FTM to work without any connection 1. Support for ESP32-C3 chip 3. Fix error case handling if FTM fails 4. Fix asynchronization, re-transmission related issues --- components/esp_wifi/Kconfig | 28 ++-- components/esp_wifi/include/esp_wifi.h | 10 +- components/esp_wifi/include/esp_wifi_types.h | 2 + components/esp_wifi/lib | 2 +- components/esp_wifi/src/wifi_init.c | 16 +-- docs/en/api-guides/wifi.rst | 6 +- examples/wifi/ftm/README.md | 79 ++++------- examples/wifi/ftm/main/CMakeLists.txt | 2 +- .../main/{ftm_station_main.c => ftm_main.c} | 126 ++++++++++++------ 9 files changed, 151 insertions(+), 120 deletions(-) rename examples/wifi/ftm/main/{ftm_station_main.c => ftm_main.c} (84%) diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index 8cfe901fec..1fc15fc180 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -331,42 +331,42 @@ menu "Wi-Fi" If neither of them are enabled, the other 7.4KB IRAM memory would be taken by this option. Wi-Fi power-save mode average current would be reduced if this option is enabled. - config ESP32S2_WIFI_FTM_INITIATOR_SUPPORT + config ESP_WIFI_FTM_INITIATOR_SUPPORT bool "FTM Initiator support" default y - depends on IDF_TARGET_ESP32S2 + depends on (IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3) - config ESP32S2_WIFI_FTM_REPORT_LOG_ENABLE + config ESP_WIFI_FTM_REPORT_LOG_ENABLE bool "FTM Report logging" default n - depends on ESP32S2_WIFI_FTM_INITIATOR_SUPPORT + depends on ESP_WIFI_FTM_INITIATOR_SUPPORT help Select this option to get a detailed report of FTM Procedure with raw values - config ESP32S2_WIFI_FTM_REPORT_SHOW_RTT - depends on ESP32S2_WIFI_FTM_REPORT_LOG_ENABLE + config ESP_WIFI_FTM_REPORT_SHOW_RTT + depends on ESP_WIFI_FTM_REPORT_LOG_ENABLE bool "Show RTT values" default y - config ESP32S2_WIFI_FTM_REPORT_SHOW_DIAG - depends on ESP32S2_WIFI_FTM_REPORT_LOG_ENABLE + config ESP_WIFI_FTM_REPORT_SHOW_DIAG + depends on ESP_WIFI_FTM_REPORT_LOG_ENABLE bool "Show dialog tokens" default y - config ESP32S2_WIFI_FTM_REPORT_SHOW_T1T2T3T4 - depends on ESP32S2_WIFI_FTM_REPORT_LOG_ENABLE + config ESP_WIFI_FTM_REPORT_SHOW_T1T2T3T4 + depends on ESP_WIFI_FTM_REPORT_LOG_ENABLE bool "Show T1 to T4" default y - config ESP32S2_WIFI_FTM_REPORT_SHOW_RSSI - depends on ESP32S2_WIFI_FTM_REPORT_LOG_ENABLE + config ESP_WIFI_FTM_REPORT_SHOW_RSSI + depends on ESP_WIFI_FTM_REPORT_LOG_ENABLE bool "Show RSSI levels" default y - config ESP32S2_WIFI_FTM_RESPONDER_SUPPORT + config ESP_WIFI_FTM_RESPONDER_SUPPORT bool "FTM Responder support" default y - depends on IDF_TARGET_ESP32S2 + depends on (IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3) endmenu # Wi-Fi diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index 2df46515a0..22b38ed142 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -1156,16 +1156,18 @@ esp_err_t esp_wifi_statis_dump(uint32_t modules); esp_err_t esp_wifi_set_rssi_threshold(int32_t rssi); /** - * @brief Start FTM Initiator session - * If successful, event WIFI_EVENT_FTM_REPORT is generated with the result of the FTM procedure + * @brief Start an FTM Initiator session by sending FTM request + * If successful, event WIFI_EVENT_FTM_REPORT is generated with the result of the FTM procedure * - * @param cfg FTM Initiator configurations + * @attention Use this API only in Station mode + * + * @param cfg FTM Initiator session configuration * * @return * - ESP_OK: succeed * - others: failed */ -esp_err_t esp_wifi_ftm_start_initiator(wifi_ftm_initiator_cfg_t *cfg); +esp_err_t esp_wifi_ftm_initiate_session(wifi_ftm_initiator_cfg_t *cfg); #ifdef __cplusplus } diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index db15125ce2..d01fc91ae9 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -522,6 +522,8 @@ typedef struct { * */ 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) */ } wifi_ftm_initiator_cfg_t; diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 2e4ba2b423..56d0911c8a 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 2e4ba2b423d350a53698660274bb65ead89f22e4 +Subproject commit 56d0911c8a27bd97e7939057bf82c61e82a689e6 diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index 353345d406..f01336665b 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -56,10 +56,10 @@ uint64_t g_wifi_feature_caps = #if (CONFIG_ESP32_SPIRAM_SUPPORT | CONFIG_ESP32S2_SPIRAM_SUPPORT) CONFIG_FEATURE_CACHE_TX_BUF_BIT | #endif -#if CONFIG_ESP32S2_WIFI_FTM_INITIATOR_SUPPORT +#if CONFIG_ESP_WIFI_FTM_INITIATOR_SUPPORT CONFIG_FEATURE_FTM_INITIATOR_BIT | #endif -#if CONFIG_ESP32S2_WIFI_FTM_RESPONDER_SUPPORT +#if CONFIG_ESP_WIFI_FTM_RESPONDER_SUPPORT CONFIG_FEATURE_FTM_RESPONDER_BIT | #endif 0; @@ -255,23 +255,21 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config) } adc2_cal_include(); //This enables the ADC2 calibration constructor at start up. -#if CONFIG_IDF_TARGET_ESP32S2 -#ifdef CONFIG_ESP32S2_WIFI_FTM_REPORT_LOG_ENABLE +#ifdef CONFIG_ESP_WIFI_FTM_REPORT_LOG_ENABLE ftm_report_log_level_t log_lvl = {0}; -#ifdef CONFIG_ESP32S2_WIFI_FTM_REPORT_SHOW_RTT +#ifdef CONFIG_ESP_WIFI_FTM_REPORT_SHOW_RTT log_lvl.show_rtt = 1; #endif -#ifdef CONFIG_ESP32S2_WIFI_FTM_REPORT_SHOW_DIAG +#ifdef CONFIG_ESP_WIFI_FTM_REPORT_SHOW_DIAG log_lvl.show_diag = 1; #endif -#ifdef CONFIG_ESP32S2_WIFI_FTM_REPORT_SHOW_T1T2T3T4 +#ifdef CONFIG_ESP_WIFI_FTM_REPORT_SHOW_T1T2T3T4 log_lvl.show_t1t2t3t4 = 1; #endif -#ifdef CONFIG_ESP32S2_WIFI_FTM_REPORT_SHOW_RSSI +#ifdef CONFIG_ESP_WIFI_FTM_REPORT_SHOW_RSSI log_lvl.show_rxrssi = 1; #endif esp_wifi_set_ftm_report_log_level(&log_lvl); -#endif #endif esp_wifi_config_info(); return result; diff --git a/docs/en/api-guides/wifi.rst b/docs/en/api-guides/wifi.rst index 23a2954650..71383396f7 100644 --- a/docs/en/api-guides/wifi.rst +++ b/docs/en/api-guides/wifi.rst @@ -1459,7 +1459,7 @@ For establishing a secure connection, AP and Station negotiate and agree on the Detailed information on creating certificates and how to run wpa2_enterprise example on {IDF_TARGET_NAME} can be found in :example:`wifi/wpa2_enterprise`. -.. only:: esp32s2 +.. only:: esp32s2 or esp32c3 Wi-Fi Location ------------------------------- @@ -1473,8 +1473,8 @@ FTM is used to measure Wi-Fi Round Trip Time (Wi-Fi RTT) which is the time a WiF FTM uses timestamps given by WiFi interface hardware at the time of arrival or departure of frames exchanged between a pair of devices. One entity called FTM Initiator (mostly a Station device) discovers the FTM Responder (can be a Station or an Access Point) and negotiates to start an FTM procedure. The procedure uses multiple Action frames sent in bursts and its ACK's to gather the timestamps data. FTM Initiator gathers the data in the end to calculate an average Round-Trip-Time. {IDF_TARGET_NAME} supports FTM in below configuration: - - {IDF_TARGET_NAME} as FTM Initiator in Station mode with the associated AP acting as FTM Responder. - - {IDF_TARGET_NAME} as FTM Responder in SoftAP mode with an associated Station acting as FTM Initiator. + - {IDF_TARGET_NAME} as FTM Initiator in Station mode. + - {IDF_TARGET_NAME} as FTM Responder in SoftAP mode. Distance measurement using RTT is not accurate, 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 {IDF_TARGET_NAME} devices as Station and SoftAP. Refer to IDF example :idf_file:`examples/wifi/ftm/README.md` for steps on how to setup and perform FTM. diff --git a/examples/wifi/ftm/README.md b/examples/wifi/ftm/README.md index c1cae5c79d..ae00bb9267 100644 --- a/examples/wifi/ftm/README.md +++ b/examples/wifi/ftm/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-S2 | -| ----------------- | -------- | +| Supported Targets | ESP32-S2 | ESP32-C3 | +| ----------------- | -------- | -------- | # FTM Example @@ -20,32 +20,30 @@ Wi-Fi RTT is calculated using a procedure called Fine Timing Measurement(FTM). D > T4[i] : TOA of i'th ACK at Responder Average RTT is calculated over all such pairs to get a more accurate result. -In this example, FTM procedure is supported only between a Station(ESP32S2) and an AP it is connected to. The AP can be a SoftAP(ESP32S2) or an External AP that supports FTM Responder mode. +Use this example to perform FTM between a Station and a SoftAP or en external AP that supports FTM Responder mode. Both Station and SoftAP need to be run on the supported ESP targets that support FTM and have it enabled. ## How to use example -With this example, users can scan for AP's that support FTM Responder role, connect with them and perform FTM procedure with different configurations. Below steps show how to do this using 2 ESP32-S2's in Station and SoftAP mode. -First make sure that FTM Initiator support on Station and FTM Responder support on SoftAP is enabled in the example configuration menu. For this, open project configuration menu (`idf.py menuconfig`), navigate to `Component config -> Wi-Fi` and check `FTM Initiator support` on Station build and `FTM Responder support` on SoftAP build. Furthermore for getting a per frame detailed report of the FTM procedure, enable `FTM Report logging` option. -Build and flash the example on respective ESP32-S2's to see below output - +With this example, users can scan for AP's that support FTM Responder role and perform FTM procedure with different configurations. Below steps show how to do this using 2 devices in Station and SoftAP mode. +First make sure that `FTM Initiator support` on Station and `FTM Responder support` on SoftAP is enabled in the project configuration menu (`idf.py menuconfig`). These options are located in `Component config -> Wi-Fi`. Furthermore for getting a per frame detailed report of the FTM procedure on the console, enable `FTM Report logging` option. Users can also access this report data in the example code. +Build and flash the example on a supported device to see below output - ```bash ========================================================== | Steps to test FTM | | | - | 1. Print 'help' to gain overview of commands | - | 2. Use 'scan' command for AP that support FTM | + | 1. Use 'help' to gain overview of commands | + | 2. Use 'scan' command to search for external AP's | | OR | - | 2. Start SoftAP on another ESP32S2 with 'ap' command | - | 3. Setup connection with the AP using 'sta' command | - | 4. Initiate FTM from Station using 'ftm -I' command | + | 2. Start SoftAP on another device using 'ap' command | + | 3. Start FTM with command 'ftm -I -s ' | | | ========================================================== - ftm> ``` Use `help` to get a list of available commands and options. Use `scan` command to scan for AP's that support FTM Responder mode. -Before testing FTM with an external AP, make sure that `FTM Responder` is visible in the respective scan result entry. +Before initiating FTM with an external AP, make sure that `FTM Responder` is visible in the respective scan result entry. ```bash ftm> scan @@ -58,7 +56,7 @@ I (478815) ftm_station: [Velop][rssi=-115] I (478825) ftm_station: sta scan done ``` -AP's that support FTM Responder mode can be seen in the scan results. Or setup a SoftAP using another ESP32-S2 device using the `ap` command - +AP's that support FTM Responder mode can be seen in the scan results. Or setup a SoftAP on another device using the `ap` command - ```bash ftm> ap FTM password @@ -66,53 +64,34 @@ I (91271) ftm_ap: Starting SoftAP with FTM Responder support, SSID - FTM, Passwo ftm> ``` -Use command `sta []` to connect with an eligible AP. Then simply issue `ftm -I` to initiate a session with default configuration of 32 FTM frames. For more configurations below options are available - -`ftm [-I] [-c <0/16/24/32/64>] [-p <0-255 (x 100 mSec)>]` +Issue `ftm -I` to initiate a session with default configuration of 32 FTM frames. For more configurations below options are available - +`ftm [-I] [-c <0/16/24/32/64>] [-p <2-255 (x 100 mSec)>] [-s SSID]` Where - * `-I` OR `--ftm_initiator`: FTM Initiator mode * `-c` OR `--frm_count`: FTM frames to be exchanged (Valid values: 0=No preference, 16, 24, 32, 64, default: 32) * `-p` OR `--burst_period`: Periodicity of FTM bursts in 100's of miliseconds (0: No preference, default: 2) +* `-s` OR `--ssid=SSID`: SSID of AP that supports FTM Responder mode Currently FTM is only supported in below configuration - - 1. Station(ESP32-S2) as Initiator in connected mode with SoftAP(ESP32-S2) as Responder - 2. Station(ESP32-S2) as Initiator in connected mode with external AP as Responder -The first option should be preferred since ESP32-S2 is self calibrated for high resolution measurement. Support for more configurations like STA to STA with ASAP mode will follow in future updates. +1. Station as Initiator and SoftAP as Responder on supported ESP devices +2. Station as Initiator and an external AP that supports FTM in Responder mode +The first option should be preferred since ESP devices are self calibrated for high resolution measurement. FTM Responder support for external Stations and ASAP mode will follow in future updates. ## Example Output Example output of an FTM Procedure - ```bash -ftm> ftm -I -I (13796) ftm_station: Starting FTM Initiator with Frm Count 32, Burst Period - 200mSec -ftm> W (23696) wifi:FTM report: -W (23696) wifi:| Diag | RTT | RSSI | T1 | T2 | T3 | T4 | -W (23706) wifi:| 3| 24850 | -18 |13598650592600 | 3973101843750 | 3973205662500 |13598754436200 | -W (23716) wifi:| 5| 32662 | -18 |13600546592600 | 3974997826562 | 3975101662500 |13600650461200 | -W (23726) wifi:| 7| 31100 | -18 |14498977692600 | 4873420043750 | 4873523662500 |14499081342450 | -W (23736) wifi:| 9| 29412 | -18 |14500856692600 | 4875299026562 | 4875402662500 |14500960357950 | -W (23746) wifi:| 11| 24850 | -18 |15399235817600 | 5773669262500 | 5773785662500 |15399352242450 | -W (23756) wifi:| 12| 27975 | -18 |15400258817600 | 5774692253125 | 5774796662500 |15400363254950 | -W (23766) wifi:| 13| 26287 | -18 |15401215817600 | 5775649242187 | 5775753662500 |15401320264200 | -W (23776) wifi:| 14| 24725 | -18 |15402158817600 | 5776592234375 | 5776696662500 |15402263270450 | -W (23786) wifi:| 15| 24850 | -18 |16298632917600 | 6673057456250 | 6673173662500 |16298749148700 | -W (23796) wifi:| 16| 29412 | -18 |16299698917600 | 6674123445312 | 6674227662500 |16299803164200 | -W (23796) wifi:| 17| 26287 | -18 |16300637917600 | 6675062435937 | 6675166662500 |16300742170450 | -W (23816) wifi:| 18| 27975 | -18 |16301580917600 | 6676005428125 | 6676109662500 |16301685179950 | -W (23826) wifi:| 19| 27850 | -18 |17198977042600 | 862506262500 | 862622262500 |17199093070450 | -W (23836) wifi:| 20| 23162 | -18 |17200051042600 | 863580251562 | 863684262500 |17200155076700 | -W (23846) wifi:| 21| 31100 | -18 |17200991042600 | 864520243750 | 864624262500 |17201095092450 | -W (23846) wifi:| 22| 26412 | -18 |17201930042600 | 865459232812 | 865563262500 |17202034098700 | -W (23856) wifi:| 23| 31100 | -18 |18099333142600 | 1762853443750 | 1762969262500 |18099448992450 | -W (23876) wifi:| 24| 23162 | -18 |18100397142600 | 1763917432812 | 1764021262500 |18100500995450 | -W (23886) wifi:| 25| 26287 | -18 |18101336142600 | 1764856423437 | 1764960262500 |18101440007950 | -W (23896) wifi:| 26| 24850 | -18 |18102343142600 | 1765863412500 | 1765967262500 |18102447017450 | -W (23896) wifi:| 27| 31100 | -18 |19000187242600 | 2663698618750 | 2663814262500 |19000302917450 | -W (23906) wifi:| 28| 24725 | -18 |19001274242600 | 2664785609375 | 2664889262500 |19001377920450 | -W (23916) wifi:| 29| 31100 | -18 |19002225242600 | 2665736600000 | 2665840262500 |19002328936200 | -W (23936) wifi:| 31| 23287 | -19 |19004133242600 | 2667644579687 | 2667748262500 |19004236948700 | -W (23936) wifi:| 32| 26287 | -18 |19899976367600 | 3563478835937 | 3563595262500 |19900092820450 | -W (23946) wifi:FTM session ends with 25 valid readings out of 31, Avg raw RTT: 27.232 nSec, Avg RSSI: -18 -I (23956) ftm_station: Estimated RTT - 13 nSec, Estimated Distance - 1.95 meters +ftm> scan +I (356414) ftm_station: sta start to scan +I (358514) ftm_station: [DigitalFortress][rssi=114] +I (358524) ftm_station: [TEST][rssi=-96][FTM Responder] +I (358524) ftm_station: sta scan done +ftm> ftm -I -s TEST +Starting FTM with 18:fe:34:72:50:c9 on channel 1 +I (391824) ftm_station: Starting FTM Initiator with Frm Count 32, Burst Period - 200mSec +W (391834) wifi:Starting FTM session in 0.200 Sec +W (393564) wifi:FTM session ends with 26 valid readings out of 31, Avg raw RTT: 49.218 nSec, Avg RSSI: -1 +I (393564) ftm_station: Estimated RTT - 33 nSec, Estimated Distance - 5.07 meters ``` The final statement gives the average calculated RTT along with an estimated distance between the Station and the AP. This distance is measured by first adjusting the RTT with any physical analog delays and a calibration delta. Distances measured using RTT are not perfectly accurate, and are subjected to various errors like RF interference, multi-path, path loss, orientations etc. diff --git a/examples/wifi/ftm/main/CMakeLists.txt b/examples/wifi/ftm/main/CMakeLists.txt index 9713164e27..3fa327c699 100644 --- a/examples/wifi/ftm/main/CMakeLists.txt +++ b/examples/wifi/ftm/main/CMakeLists.txt @@ -1,2 +1,2 @@ -idf_component_register(SRCS "ftm_station_main.c" +idf_component_register(SRCS "ftm_main.c" INCLUDE_DIRS ".") diff --git a/examples/wifi/ftm/main/ftm_station_main.c b/examples/wifi/ftm/main/ftm_main.c similarity index 84% rename from examples/wifi/ftm/main/ftm_station_main.c rename to examples/wifi/ftm/main/ftm_main.c index d8e288d580..8934d2075c 100644 --- a/examples/wifi/ftm/main/ftm_station_main.c +++ b/examples/wifi/ftm/main/ftm_main.c @@ -37,6 +37,7 @@ typedef struct { struct arg_lit *mode; struct arg_int *frm_count; struct arg_int *burst_period; + struct arg_str *ssid; struct arg_end *end; } wifi_ftm_args_t; @@ -59,29 +60,8 @@ const int FTM_FAILURE_BIT = BIT1; wifi_ftm_report_entry_t *g_ftm_report; uint8_t g_ftm_report_num_entries; -static void scan_done_handler(void *arg, esp_event_base_t event_base, - int32_t event_id, void *event_data) -{ - uint16_t sta_number = 0; - uint8_t i; - wifi_ap_record_t *ap_list_buffer; - - esp_wifi_scan_get_ap_num(&sta_number); - ap_list_buffer = malloc(sta_number * sizeof(wifi_ap_record_t)); - if (ap_list_buffer == NULL) { - ESP_LOGE(TAG_STA, "Failed to malloc buffer to print scan results"); - return; - } - - if (esp_wifi_scan_get_ap_records(&sta_number, (wifi_ap_record_t *)ap_list_buffer) == ESP_OK) { - for (i = 0; i < sta_number; i++) { - ESP_LOGI(TAG_STA, "[%s][rssi=%d]""%s", ap_list_buffer[i].ssid, ap_list_buffer[i].rssi, - ap_list_buffer[i].ftm_responder ? "[FTM Responder]" : ""); - } - } - free(ap_list_buffer); - ESP_LOGI(TAG_STA, "sta scan done"); -} +uint16_t g_scan_ap_num; +wifi_ap_record_t *g_ap_list_buffer; static void wifi_connected_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) @@ -141,11 +121,6 @@ void initialise_wifi(void) ESP_ERROR_CHECK( esp_event_loop_create_default() ); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, - WIFI_EVENT_SCAN_DONE, - &scan_done_handler, - NULL, - NULL)); ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &wifi_connected_handler, @@ -209,13 +184,40 @@ static int wifi_cmd_sta(int argc, char **argv) return 0; } -static bool wifi_cmd_sta_scan(const char *ssid) +static bool wifi_perform_scan(const char *ssid, bool internal) { wifi_scan_config_t scan_config = { 0 }; scan_config.ssid = (uint8_t *) ssid; + uint8_t i; ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); - ESP_ERROR_CHECK( esp_wifi_scan_start(&scan_config, false) ); + ESP_ERROR_CHECK( esp_wifi_scan_start(&scan_config, true) ); + + esp_wifi_scan_get_ap_num(&g_scan_ap_num); + if (g_scan_ap_num == 0) { + ESP_LOGI(TAG_STA, "No matching AP found"); + return false; + } + + if (g_ap_list_buffer) { + free(g_ap_list_buffer); + } + g_ap_list_buffer = malloc(g_scan_ap_num * sizeof(wifi_ap_record_t)); + if (g_ap_list_buffer == NULL) { + ESP_LOGE(TAG_STA, "Failed to malloc buffer to print scan results"); + return false; + } + + if (esp_wifi_scan_get_ap_records(&g_scan_ap_num, (wifi_ap_record_t *)g_ap_list_buffer) == ESP_OK) { + if (!internal) { + for (i = 0; i < g_scan_ap_num; i++) { + ESP_LOGI(TAG_STA, "[%s][rssi=%d]""%s", g_ap_list_buffer[i].ssid, g_ap_list_buffer[i].rssi, + g_ap_list_buffer[i].ftm_responder ? "[FTM Responder]" : ""); + } + } + } + + ESP_LOGI(TAG_STA, "sta scan done"); return true; } @@ -231,9 +233,9 @@ static int wifi_cmd_scan(int argc, char **argv) ESP_LOGI(TAG_STA, "sta start to scan"); if ( scan_args.ssid->count == 1 ) { - wifi_cmd_sta_scan(scan_args.ssid->sval[0]); + wifi_perform_scan(scan_args.ssid->sval[0], false); } else { - wifi_cmd_sta_scan(NULL); + wifi_perform_scan(NULL, false); } return 0; } @@ -309,9 +311,45 @@ static int wifi_cmd_query(int argc, char **argv) return 0; } +wifi_ap_record_t *find_ftm_responder_ap(const char *ssid) +{ + bool retry_scan = false; + uint8_t i; + + if (!ssid) + return NULL; + +retry: + if (!g_ap_list_buffer || (g_scan_ap_num == 0)) { + ESP_LOGI(TAG_STA, "Scanning for %s", ssid); + if (false == wifi_perform_scan(ssid, true)) { + return NULL; + } + } + + for (i = 0; i < g_scan_ap_num; i++) { + if (strcmp((const char *)g_ap_list_buffer[i].ssid, ssid) == 0) + return &g_ap_list_buffer[i]; + } + + if (!retry_scan) { + retry_scan = true; + if (g_ap_list_buffer) { + free(g_ap_list_buffer); + g_ap_list_buffer = NULL; + } + goto retry; + } + + ESP_LOGI(TAG_STA, "No matching AP found"); + + return NULL; +} + static int wifi_cmd_ftm(int argc, char **argv) { int nerrors = arg_parse(argc, argv, (void **) &ftm_args); + wifi_ap_record_t *ap_record; wifi_ftm_initiator_cfg_t ftmi_cfg = { .frm_count = 32, @@ -327,6 +365,18 @@ static int wifi_cmd_ftm(int argc, char **argv) goto ftm_start; } + if (ftm_args.ssid->count == 1) { + ap_record = find_ftm_responder_ap(ftm_args.ssid->sval[0]); + if (ap_record) { + printf("Starting FTM with " MACSTR " on channel %d\n", MAC2STR(ap_record->bssid), + ap_record->primary); + memcpy(ftmi_cfg.resp_mac, ap_record->bssid, 6); + ftmi_cfg.channel = ap_record->primary; + } else { + return 0; + } + } + if (ftm_args.frm_count->count != 0) { uint8_t count = ftm_args.frm_count->ival[0]; if (count != 0 && count != 16 && count != 24 && @@ -354,7 +404,7 @@ ftm_start: ftmi_cfg.frm_count, ftmi_cfg.burst_period * 100); } - if (ESP_OK != esp_wifi_ftm_start_initiator(&ftmi_cfg)) { + if (ESP_OK != esp_wifi_ftm_initiate_session(&ftmi_cfg)) { ESP_LOGE(TAG_STA, "Failed to start FTM session"); return 0; } @@ -430,6 +480,7 @@ void register_wifi(void) ESP_ERROR_CHECK( esp_console_cmd_register(&query_cmd) ); ftm_args.mode = arg_lit1("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/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.end = arg_end(1); @@ -469,12 +520,11 @@ void app_main(void) printf("\n ==========================================================\n"); printf(" | Steps to test FTM |\n"); printf(" | |\n"); - printf(" | 1. Print 'help' to gain overview of commands |\n"); - printf(" | 2. Use 'scan' command for AP that support FTM |\n"); + printf(" | 1. Use 'help' to gain overview of commands |\n"); + printf(" | 2. Use 'scan' command to search for external AP's |\n"); printf(" | OR |\n"); - printf(" | 2. Start SoftAP on another device with 'ap' command |\n"); - printf(" | 3. Setup connection with the AP using 'sta' command |\n"); - printf(" | 4. Initiate FTM from Station using 'ftm -I' command |\n"); + printf(" | 2. Start SoftAP on another device using 'ap' command |\n"); + printf(" | 3. Start FTM with command 'ftm -I -s ' |\n"); printf(" | |\n"); printf(" ==========================================================\n\n");