Procházet zdrojové kódy

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
Nachiket Kukade před 4 roky
rodič
revize
c1d5eafd16

+ 25 - 0
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
   *

+ 1 - 1
components/esp_wifi/lib

@@ -1 +1 @@
-Subproject commit 012747d3cf1901b9600d45aee69e17546bc47b61
+Subproject commit 8dc3acb6a620b01b9fa69cc8f11e276af8e61580

+ 9 - 10
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 <SSID> <password>'   |
  |                          OR                            |
- |  2. Start SoftAP on another device using 'ap' command  |
- |  3. Start FTM with command 'ftm -I -s <SSID>'          |
- |                                                        |
+ |  2. Use 'scan' command to search for external AP's     |
+ |  3. On second device initiate FTM with an AP using     |
+ |     command 'ftm -I -s <SSID>'                         |
  ==========================================================
 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 <cm0>` 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 -

+ 114 - 81
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)
-{
-    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)
+static void event_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_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);
+
+        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;
+
+        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 <SSID> <password>'   |\n");
     printf(" |                          OR                            |\n");
-    printf(" |  2. Start SoftAP on another device using 'ap' command  |\n");
-    printf(" |  3. Start FTM with command 'ftm -I -s <SSID>'          |\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 <SSID>'                         |\n");
     printf(" ==========================================================\n\n");
 
     // start console REPL