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
This commit is contained in:
Nachiket Kukade 2021-04-01 18:52:17 +05:30
parent 919e3ef9fb
commit eb49ee75b8
4 changed files with 146 additions and 89 deletions

View File

@ -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 @@
Subproject commit 9ac2374dd55c633dbedf8cfbafb329becfd66f09
Subproject commit f522a17117a0d64fce697d2b26c6e4a8c1781b1b

View File

@ -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 -

View File

@ -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 <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