From c1d5eafd16dada633580dc80587d7edc83a9f6df Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Fri, 25 Jun 2021 14:53:48 +0530 Subject: [PATCH] wifi/ftm: Additional FTM features implementation Update wifi lib with below features - 1. ASAP mode for both Initiator and Responder 2. Offchannel FTM while connected to AP (ASAP only) 3. Support up to 3 Initiators simultaneously 4. Session termination, failure support etc 5. Mem-zero AP scan buffer in get_records API --- components/esp_wifi/include/esp_wifi.h | 25 ++++ components/esp_wifi/lib | 2 +- examples/wifi/ftm/README.md | 19 ++- examples/wifi/ftm/main/ftm_main.c | 189 +++++++++++++++---------- 4 files changed, 146 insertions(+), 89 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index 86dcf637e4..150d3123e7 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -1177,6 +1177,31 @@ esp_err_t esp_wifi_set_rssi_threshold(int32_t rssi); */ esp_err_t esp_wifi_ftm_initiate_session(wifi_ftm_initiator_cfg_t *cfg); +/** + * @brief End the ongoing FTM Initiator session + * + * @attention This API works only on FTM Initiator + * + * @return + * - ESP_OK: succeed + * - others: failed + */ +esp_err_t esp_wifi_ftm_end_session(void); + +/** + * @brief Set offset in cm for FTM Responder. An equivalent offset is calculated in picoseconds + * and added in TOD of FTM Measurement frame (T1). + * + * @attention Use this API only in AP mode before performing FTM as responder + * + * @param offset_cm T1 Offset to be added in centimeters + * + * @return + * - ESP_OK: succeed + * - others: failed + */ +esp_err_t esp_wifi_ftm_resp_set_offset(int16_t offset_cm); + /** * @brief Enable or disable 11b rate of specified interface * diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 012747d3cf..8dc3acb6a6 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 012747d3cf1901b9600d45aee69e17546bc47b61 +Subproject commit 8dc3acb6a620b01b9fa69cc8f11e276af8e61580 diff --git a/examples/wifi/ftm/README.md b/examples/wifi/ftm/README.md index 20b6bdf410..49203bde9a 100644 --- a/examples/wifi/ftm/README.md +++ b/examples/wifi/ftm/README.md @@ -32,18 +32,17 @@ Build and flash the example on a supported device to see below output - ========================================================== | Steps to test FTM | | | - | 1. Use 'help' to gain overview of commands | - | 2. Use 'scan' command to search for external AP's | + | 1. Use 'help' for detailed information on parameters | + | 2. Start SoftAP with command 'ap ' | | OR | - | 2. Start SoftAP on another device using 'ap' command | - | 3. Start FTM with command 'ftm -I -s ' | - | | + | 2. Use 'scan' command to search for external AP's | + | 3. On second device initiate FTM with an AP using | + | 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 initiating FTM with an external AP, make sure that `FTM Responder` is visible in the respective scan result entry. +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 initiating FTM with an external AP, make sure that `FTM Responder` tag is visible in the respective scan result entry. Alternatively, start SoftAP on another device using `ap` command, it supports FTM Responder by default. If external FTM Initiators get a large error in distance readings with the SoftAP, note down the reading at zero distance in centimeters, say `cm0`. This distance can be offset using command `ftm -R -o ` to give accurate readings with the Initiator. ```bash ftm> scan @@ -65,17 +64,17 @@ ftm> ``` 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]` +`ftm [-I] [-c <0/8/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) +* `-c` OR `--frm_count`: FTM frames to be exchanged (Valid values: 0=No preference, 8, 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 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. +The first option should be preferred since ESP devices are self calibrated for high resolution measurement. ## Example Output Example output of an FTM Procedure - diff --git a/examples/wifi/ftm/main/ftm_main.c b/examples/wifi/ftm/main/ftm_main.c index 4698e1a969..971ebbf619 100644 --- a/examples/wifi/ftm/main/ftm_main.c +++ b/examples/wifi/ftm/main/ftm_main.c @@ -34,10 +34,16 @@ typedef struct { } wifi_scan_arg_t; typedef struct { - struct arg_lit *mode; + /* FTM Initiator */ + struct arg_lit *initiator; struct arg_int *frm_count; struct arg_int *burst_period; struct arg_str *ssid; + /* FTM Responder */ + struct arg_lit *responder; + struct arg_lit *enable; + struct arg_lit *disable; + struct arg_int *offset; struct arg_end *end; } wifi_ftm_args_t; @@ -46,6 +52,12 @@ static wifi_args_t ap_args; static wifi_scan_arg_t scan_args; static wifi_ftm_args_t ftm_args; +wifi_config_t g_ap_config = { + .ap.max_connection = 4, + .ap.authmode = WIFI_AUTH_WPA2_PSK, + .ap.ftm_responder = true +}; + static bool s_reconnect = true; static const char *TAG_STA = "ftm_station"; static const char *TAG_AP = "ftm_ap"; @@ -60,6 +72,7 @@ const int FTM_FAILURE_BIT = BIT1; wifi_ftm_report_entry_t *g_ftm_report; uint8_t g_ftm_report_num_entries; static uint32_t g_rtt_est, g_dist_est; +bool g_ap_started; const int g_report_lvl = #ifdef CONFIG_ESP_FTM_REPORT_SHOW_DIAG @@ -79,46 +92,44 @@ const int g_report_lvl = 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) +static void event_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; + if (event_id == WIFI_EVENT_STA_CONNECTED) { + 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); + 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); -} + xEventGroupClearBits(wifi_event_group, DISCONNECTED_BIT); + xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); + } else if (event_id == WIFI_EVENT_STA_DISCONNECTED) { + 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); + } else if (event_id == WIFI_EVENT_FTM_REPORT) { + wifi_event_ftm_report_t *event = (wifi_event_ftm_report_t *) event_data; -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; - - if (event->status == FTM_STATUS_SUCCESS) { - g_rtt_est = event->rtt_est; - g_dist_est = event->dist_est; - g_ftm_report = event->ftm_report_data; - g_ftm_report_num_entries = event->ftm_report_num_entries; - xEventGroupSetBits(ftm_event_group, FTM_REPORT_BIT); - } 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); + if (event->status == FTM_STATUS_SUCCESS) { + g_rtt_est = event->rtt_est; + g_dist_est = event->dist_est; + g_ftm_report = event->ftm_report_data; + g_ftm_report_num_entries = event->ftm_report_num_entries; + xEventGroupSetBits(ftm_event_group, FTM_REPORT_BIT); + } 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); + } + } else if (event_id == WIFI_EVENT_AP_START) { + g_ap_started = true; + } else if (event_id == WIFI_EVENT_AP_STOP) { + g_ap_started = false; } } @@ -178,21 +189,14 @@ 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_event_handler_instance_t instance_any_id; 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_EVENT_ANY_ID, + &event_handler, + NULL, + &instance_any_id)); + 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() ); @@ -299,34 +303,23 @@ static int wifi_cmd_scan(int argc, char **argv) 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, - .ftm_responder = true - }, - }; - s_reconnect = false; - strlcpy((char*) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); + strlcpy((char*) g_ap_config.ap.ssid, ssid, MAX_SSID_LEN); 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)); + strlcpy((char*) g_ap_config.ap.password, pass, MAX_PASSPHRASE_LEN); } if (strlen(pass) == 0) { - wifi_config.ap.authmode = WIFI_AUTH_OPEN; + g_ap_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)); + ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &g_ap_config)); return true; } @@ -419,10 +412,14 @@ static int wifi_cmd_ftm(int argc, char **argv) return 0; } - if (ftm_args.mode->count == 0) { - goto ftm_start; + if (ftm_args.initiator->count != 0 && ftm_args.responder->count != 0) { + ESP_LOGE(TAG_STA, "Invalid FTM cmd argument"); + return 0; } + if (ftm_args.responder->count != 0) + goto ftm_responder; + if (ftm_args.ssid->count == 1) { ap_record = find_ftm_responder_ap(ftm_args.ssid->sval[0]); if (ap_record) { @@ -435,9 +432,9 @@ static int wifi_cmd_ftm(int argc, char **argv) if (ftm_args.frm_count->count != 0) { uint8_t count = ftm_args.frm_count->ival[0]; - if (count != 0 && count != 16 && + if (count != 0 && count != 8 && count != 16 && count != 24 && count != 32 && count != 64) { - ESP_LOGE(TAG_STA, "Invalid Frame Count! Valid options are 0/16/24/32/64"); + ESP_LOGE(TAG_STA, "Invalid Frame Count! Valid options are 0/8/16/24/32/64"); return 0; } ftmi_cfg.frm_count = count; @@ -453,7 +450,6 @@ static int wifi_cmd_ftm(int argc, char **argv) } } -ftm_start: ESP_LOGI(TAG_STA, "Requesting FTM session with Frm Count - %d, Burst Period - %dmSec (0: No Preference)", ftmi_cfg.frm_count, ftmi_cfg.burst_period*100); @@ -477,6 +473,37 @@ ftm_start: /* Failure case */ } + return 0; + +ftm_responder: + if (ftm_args.offset->count != 0) { + int16_t offset_cm = ftm_args.offset->ival[0]; + + esp_wifi_ftm_resp_set_offset(offset_cm); + } + + if (ftm_args.enable->count != 0) { + if (!g_ap_started) { + ESP_LOGE(TAG_AP, "Start the SoftAP first with 'ap' command"); + return 0; + } + g_ap_config.ap.ftm_responder = true; + ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &g_ap_config)); + ESP_LOGI(TAG_AP, "Re-starting SoftAP with FTM Responder enabled"); + + return 0; + } + + if (ftm_args.disable->count != 0) { + if (!g_ap_started) { + ESP_LOGE(TAG_AP, "Start the SoftAP first with 'ap' command"); + return 0; + } + g_ap_config.ap.ftm_responder = false; + ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &g_ap_config)); + ESP_LOGI(TAG_AP, "Re-starting SoftAP with FTM Responder disabled"); + } + return 0; } @@ -531,10 +558,16 @@ 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 Initiator commands */ + 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/16/24/32/64>", "FTM frames to be exchanged (0: No preference)"); + 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 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"); + ftm_args.disable = arg_lit0("d", "disable", "Restart SoftAP with FTM disabled"); + ftm_args.offset = arg_int0("o", "offset", "Offset in cm", "T1 offset in cm for FTM Responder"); ftm_args.end = arg_end(1); const esp_console_cmd_t ftm_cmd = { @@ -572,12 +605,12 @@ void app_main(void) printf("\n ==========================================================\n"); printf(" | Steps to test FTM |\n"); printf(" | |\n"); - printf(" | 1. Use 'help' to gain overview of commands |\n"); - printf(" | 2. Use 'scan' command to search for external AP's |\n"); + printf(" | 1. Use 'help' for detailed information on parameters |\n"); + printf(" | 2. Start SoftAP with command 'ap ' |\n"); printf(" | OR |\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(" | 2. Use 'scan' command to search for external AP's |\n"); + printf(" | 3. On second device initiate FTM with an AP using |\n"); + printf(" | command 'ftm -I -s ' |\n"); printf(" ==========================================================\n\n"); // start console REPL