feat: move iperf to component registry

This commit is contained in:
Chen Yudong
2024-03-11 14:28:11 +08:00
parent 5e47ed70c2
commit c48eb1055b
28 changed files with 99 additions and 2668 deletions

View File

@@ -1,3 +1,2 @@
idf_component_register(SRCS "cmd_wifi.c"
"iperf_example_main.c"
idf_component_register(SRCS "iperf_example_main.c"
INCLUDE_DIRS ".")

View File

@@ -1,20 +0,0 @@
/* Iperf example — declarations of command registration functions.
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.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "cmd_system.h"
#include "cmd_wifi.h"
#ifdef __cplusplus
}
#endif

View File

@@ -1,616 +0,0 @@
/* Iperf Example - wifi commands
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 <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "esp_log.h"
#include "esp_console.h"
#include "argtable3/argtable3.h"
#include "cmd_decl.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_netif.h"
#include "esp_event.h"
#include "esp_mac.h"
#include "iperf.h"
#include "esp_coexist.h"
#include "wifi_cmd.h"
typedef struct {
struct arg_str *ip;
struct arg_lit *server;
struct arg_lit *udp;
struct arg_lit *version;
struct arg_int *port;
struct arg_int *length;
struct arg_int *interval;
struct arg_int *time;
struct arg_int *bw_limit;
struct arg_lit *abort;
struct arg_end *end;
} wifi_iperf_t;
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;
static wifi_iperf_t iperf_args;
static wifi_args_t sta_args;
static wifi_scan_arg_t scan_args;
static wifi_args_t ap_args;
static bool reconnect = true;
static const char *TAG = "cmd_wifi";
esp_netif_t *netif_ap = NULL;
esp_netif_t *netif_sta = NULL;
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);
if (!sta_number) {
ESP_LOGE(TAG, "No AP found");
return;
}
ap_list_buffer = malloc(sta_number * sizeof(wifi_ap_record_t));
if (ap_list_buffer == NULL) {
ESP_LOGE(TAG, "Failed to malloc buffer to print scan results");
esp_wifi_clear_ap_list();
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++) {
#if CONFIG_SOC_WIFI_HE_SUPPORT
char ssid_rssi[46] = { 0, };
sprintf(ssid_rssi, "[%s][rssi=%d]", ap_list_buffer[i].ssid, ap_list_buffer[i].rssi);
if (ap_list_buffer[i].phy_11ax) {
ESP_LOGW(TAG,
"[%2d]%45s authmode:0x%x, channel:%2d[%d], phymode:%4s, "MACSTR", bssid-index:%d, bss_color:%d, disabled:%d",
i, ssid_rssi, ap_list_buffer[i].authmode,
ap_list_buffer[i].primary, ap_list_buffer[i].second,
ap_list_buffer[i].phy_11ax ? "11ax" : (ap_list_buffer[i].phy_11n ? "11n" :
(ap_list_buffer[i].phy_11g ? "11g" : (ap_list_buffer[i].phy_11b ? "11b" : ""))),
MAC2STR(ap_list_buffer[i].bssid), ap_list_buffer[i].he_ap.bssid_index,
ap_list_buffer[i].he_ap.bss_color, ap_list_buffer[i].he_ap.bss_color_disabled);
} else {
ESP_LOGI(TAG,
"[%2d]%45s authmode:0x%x, channel:%2d[%d], phymode:%4s, "MACSTR"",
i, ssid_rssi, ap_list_buffer[i].authmode,
ap_list_buffer[i].primary, ap_list_buffer[i].second,
ap_list_buffer[i].phy_11ax ? "11ax" : (ap_list_buffer[i].phy_11n ? "11n" :
(ap_list_buffer[i].phy_11g ? "11g" : (ap_list_buffer[i].phy_11b ? "11b" : ""))),
MAC2STR(ap_list_buffer[i].bssid));
}
#else
ESP_LOGI(TAG, "[%s][rssi=%d]", ap_list_buffer[i].ssid, ap_list_buffer[i].rssi);
#endif
}
}
free(ap_list_buffer);
ESP_LOGI(TAG, "sta scan done");
}
static void got_ip_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
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 (reconnect) {
ESP_LOGI(TAG, "sta disconnect, reconnect...");
esp_wifi_connect();
} else {
ESP_LOGI(TAG, "sta disconnect");
}
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
xEventGroupSetBits(wifi_event_group, DISCONNECTED_BIT);
}
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() );
netif_ap = esp_netif_create_default_wifi_ap();
assert(netif_ap);
netif_sta = esp_netif_create_default_wifi_sta();
assert(netif_sta);
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_DISCONNECTED,
&disconnect_handler,
NULL,
NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&got_ip_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() );
#if CONFIG_EXTERNAL_COEX_ENABLE
esp_external_coex_gpio_set_t gpio_pin;
gpio_pin.request = 1;
gpio_pin.priority = 2;
gpio_pin.grant = 3;
#if SOC_EXTERNAL_COEX_LEADER_TX_LINE
gpio_pin.tx_line = 4;
#endif
esp_external_coex_set_work_mode(EXTERNAL_COEX_LEADER_ROLE);
#if SOC_EXTERNAL_COEX_LEADER_TX_LINE
ESP_ERROR_CHECK(esp_enable_extern_coex_gpio_pin(EXTERN_COEX_WIRE_4, gpio_pin));
#else
ESP_ERROR_CHECK(esp_enable_extern_coex_gpio_pin(EXTERN_COEX_WIRE_3, gpio_pin));
#endif /* SOC_EXTERNAL_COEX_LEADER_TX_LINE */
#endif /* CONFIG_EXTERNAL_COEX_ENABLE */
#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_MU_STATS
esp_wifi_enable_rx_statistics(true, true);
#else
esp_wifi_enable_rx_statistics(true, false);
#endif
#endif
#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
esp_wifi_enable_tx_statistics(ESP_WIFI_ACI_BE, true);
#endif
initialized = true;
}
static bool wifi_cmd_sta_join(const char *ssid, const char *pass, bool enable_he_mcs9)
{
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 (enable_he_mcs9 == true) {
wifi_config.sta.he_mcs9_enabled = 1;
}
if (bits & CONNECTED_BIT) {
reconnect = false;
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
ESP_ERROR_CHECK( esp_wifi_disconnect() );
xEventGroupWaitBits(wifi_event_group, DISCONNECTED_BIT, 0, 1, portTICK_PERIOD_MS);
}
reconnect = true;
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
esp_wifi_connect();
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 5000 / portTICK_PERIOD_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 connecting to '%s'", sta_args.ssid->sval[0]);
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
wifi_cmd_sta_join(sta_args.ssid->sval[0], sta_args.password->sval[0], false);
return 0;
}
static int wifi_cmd_sta40(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_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_protocol(0, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N));
ESP_ERROR_CHECK(esp_wifi_set_bandwidth(0, WIFI_BW_HT40));
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
ESP_LOGI(TAG, "sta connecting to '%s'", sta_args.ssid->sval[0]);
wifi_cmd_sta_join(sta_args.ssid->sval[0], sta_args.password->sval[0], false);
return 0;
}
static int wifi_cmd_sta_mcs89(int argc, char **argv)
{
#if CONFIG_SOC_WIFI_HE_SUPPORT
int nerrors = arg_parse(argc, argv, (void **) &sta_args);
if (nerrors != 0) {
arg_print_errors(stderr, sta_args.end, argv[0]);
return 1;
}
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_protocol(0, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N | WIFI_PROTOCOL_11AX));
ESP_ERROR_CHECK(esp_wifi_set_bandwidth(0, WIFI_BW_HT20));
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
ESP_LOGI(TAG, "sta connecting to '%s'", sta_args.ssid->sval[0]);
wifi_cmd_sta_join(sta_args.ssid->sval[0], sta_args.password->sval[0], true);
#else
ESP_LOGW(TAG, "HE-MCS[0, 9] is not supported");
#endif
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_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 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_WPA_WPA2_PSK
},
};
reconnect = false;
strlcpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid));
if (pass) {
if (strlen(pass) != 0 && strlen(pass) < 8) {
reconnect = true;
ESP_LOGE(TAG, "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(WIFI_IF_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 mode, %s %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 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 mode, connected %s", cfg.ap.ssid);
} else {
ESP_LOGI(TAG, "sta mode, disconnected");
}
} else {
ESP_LOGI(TAG, "NULL mode");
return 0;
}
return 0;
}
static uint32_t wifi_get_local_ip(void)
{
int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 0);
esp_netif_t *netif = netif_ap;
esp_netif_ip_info_t ip_info;
wifi_mode_t mode;
esp_wifi_get_mode(&mode);
if (WIFI_MODE_STA == mode) {
bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 0);
if (bits & CONNECTED_BIT) {
netif = netif_sta;
} else {
ESP_LOGE(TAG, "sta has no IP");
return 0;
}
}
esp_netif_get_ip_info(netif, &ip_info);
return ip_info.ip.addr;
}
static int wifi_cmd_iperf(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **) &iperf_args);
iperf_cfg_t cfg;
if (nerrors != 0) {
arg_print_errors(stderr, iperf_args.end, argv[0]);
return 0;
}
memset(&cfg, 0, sizeof(cfg));
// now wifi iperf only support IPV4 address
cfg.type = IPERF_IP_TYPE_IPV4;
if ( iperf_args.abort->count != 0) {
iperf_stop();
return 0;
}
if ( ((iperf_args.ip->count == 0) && (iperf_args.server->count == 0)) ||
((iperf_args.ip->count != 0) && (iperf_args.server->count != 0)) ) {
ESP_LOGE(TAG, "should specific client/server mode");
return 0;
}
if (iperf_args.ip->count == 0) {
cfg.flag |= IPERF_FLAG_SERVER;
} else {
cfg.destination_ip4 = esp_ip4addr_aton(iperf_args.ip->sval[0]);
cfg.flag |= IPERF_FLAG_CLIENT;
}
cfg.source_ip4 = wifi_get_local_ip();
if (cfg.source_ip4 == 0) {
return 0;
}
if (iperf_args.udp->count == 0) {
cfg.flag |= IPERF_FLAG_TCP;
} else {
cfg.flag |= IPERF_FLAG_UDP;
}
if (iperf_args.length->count == 0) {
cfg.len_send_buf = 0;
} else {
cfg.len_send_buf = iperf_args.length->ival[0];
}
if (iperf_args.port->count == 0) {
cfg.sport = IPERF_DEFAULT_PORT;
cfg.dport = IPERF_DEFAULT_PORT;
} else {
if (cfg.flag & IPERF_FLAG_SERVER) {
cfg.sport = iperf_args.port->ival[0];
cfg.dport = IPERF_DEFAULT_PORT;
} else {
cfg.sport = IPERF_DEFAULT_PORT;
cfg.dport = iperf_args.port->ival[0];
}
}
if (iperf_args.interval->count == 0) {
cfg.interval = IPERF_DEFAULT_INTERVAL;
} else {
cfg.interval = iperf_args.interval->ival[0];
if (cfg.interval <= 0) {
cfg.interval = IPERF_DEFAULT_INTERVAL;
}
}
if (iperf_args.time->count == 0) {
cfg.time = IPERF_DEFAULT_TIME;
} else {
cfg.time = iperf_args.time->ival[0];
if (cfg.time <= cfg.interval) {
cfg.time = cfg.interval;
}
}
/* iperf -b */
if (iperf_args.bw_limit->count == 0) {
cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
} else {
cfg.bw_lim = iperf_args.bw_limit->ival[0];
if (cfg.bw_lim <= 0) {
cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
}
}
ESP_LOGI(TAG, "mode=%s-%s sip=%" PRId32 ".%" PRId32 ".%" PRId32 ".%" PRId32 ":%d,\
dip=%" PRId32 ".%" PRId32 ".%" PRId32 ".%" PRId32 ":%d,\
interval=%" PRId32 ", time=%" PRId32 "",
cfg.flag & IPERF_FLAG_TCP ? "tcp" : "udp",
cfg.flag & IPERF_FLAG_SERVER ? "server" : "client",
cfg.source_ip4 & 0xFF, (cfg.source_ip4 >> 8) & 0xFF, (cfg.source_ip4 >> 16) & 0xFF,
(cfg.source_ip4 >> 24) & 0xFF, cfg.sport,
cfg.destination_ip4 & 0xFF, (cfg.destination_ip4 >> 8) & 0xFF,
(cfg.destination_ip4 >> 16) & 0xFF, (cfg.destination_ip4 >> 24) & 0xFF, cfg.dport,
cfg.interval, cfg.time);
iperf_start(&cfg);
return 0;
}
void register_wifi(void)
{
sta_args.ssid = arg_str1(NULL, NULL, "<ssid>", "SSID of AP");
sta_args.password = arg_str0(NULL, NULL, "<pass>", "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) );
const esp_console_cmd_t sta40_cmd = {
.command = "sta40",
.help = "WiFi is station mode, set protocol to bgn and cbw to 40MHz, join a specified AP",
.hint = NULL,
.func = &wifi_cmd_sta40,
.argtable = &sta_args
};
ESP_ERROR_CHECK( esp_console_cmd_register(&sta40_cmd) );
const esp_console_cmd_t stamcs89_cmd = {
.command = "stamcs89",
.help = "WiFi is station mode, set protocol to ax and mcs set to HE-MCS[0,9], join a specified AP",
.hint = NULL,
.func = &wifi_cmd_sta_mcs89,
.argtable = &sta_args
};
ESP_ERROR_CHECK( esp_console_cmd_register(&stamcs89_cmd) );
scan_args.ssid = arg_str0(NULL, NULL, "<ssid>", "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
};
ap_args.ssid = arg_str1(NULL, NULL, "<ssid>", "SSID of AP");
ap_args.password = arg_str0(NULL, NULL, "<pass>", "password of AP");
ap_args.end = arg_end(2);
ESP_ERROR_CHECK( esp_console_cmd_register(&scan_cmd) );
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) );
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) );
iperf_args.ip = arg_str0("c", "client", "<ip>", "run in client mode, connecting to <host>");
iperf_args.server = arg_lit0("s", "server", "run in server mode");
iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP");
iperf_args.version = arg_lit0("V", "ipv6_domain", "use IPV6 address rather than IPV4");
iperf_args.port = arg_int0("p", "port", "<port>", "server port to listen on/connect to");
iperf_args.length = arg_int0("l", "len", "<length>", "Set read/write buffer size");
iperf_args.interval = arg_int0("i", "interval", "<interval>", "seconds between periodic bandwidth reports");
iperf_args.time = arg_int0("t", "time", "<time>", "time in seconds to transmit for (default 10 secs)");
iperf_args.bw_limit = arg_int0("b", "bandwidth", "<bandwidth>", "bandwidth to send at in Mbits/sec");
iperf_args.abort = arg_lit0("a", "abort", "abort running iperf");
iperf_args.end = arg_end(1);
const esp_console_cmd_t iperf_cmd = {
.command = "iperf",
.help = "iperf command",
.hint = NULL,
.func = &wifi_cmd_iperf,
.argtable = &iperf_args
};
ESP_ERROR_CHECK( esp_console_cmd_register(&iperf_cmd) );
register_wifi_cmd();
register_wifi_stats();
}

View File

@@ -1,13 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// Register WiFi functions
void register_wifi(void);
void initialise_wifi(void);
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,9 @@
dependencies:
cmd_system:
path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system
iperf:
path: ${IDF_PATH}/examples/common_components/iperf
espressif/iperf-cmd:
version: "~0.1.1"
esp-qa/wifi-cmd:
version: "~0.0.2"
esp-qa/ping-cmd:
version: "~0.0.1"

View File

@@ -14,7 +14,58 @@
#include "esp_err.h"
#include "nvs_flash.h"
#include "esp_console.h"
#include "cmd_decl.h"
#include "cmd_system.h"
/* component manager */
#include "iperf.h"
#include "wifi_cmd.h"
#include "iperf_cmd.h"
#include "ping_cmd.h"
#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS || CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
#include "esp_wifi_he.h"
#endif
#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
extern int wifi_cmd_get_tx_statistics(int argc, char **argv);
extern int wifi_cmd_clr_tx_statistics(int argc, char **argv);
#endif
#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
extern int wifi_cmd_get_rx_statistics(int argc, char **argv);
extern int wifi_cmd_clr_rx_statistics(int argc, char **argv);
#endif
void iperf_hook_show_wifi_stats(iperf_traffic_type_t type, iperf_status_t status)
{
if (status == IPERF_STARTED) {
#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
if (type != IPERF_UDP_SERVER) {
wifi_cmd_clr_tx_statistics(0, NULL);
}
#endif
#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
if (type != IPERF_UDP_CLIENT) {
wifi_cmd_clr_rx_statistics(0, NULL);
}
#endif
}
if (status == IPERF_STOPPED) {
#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
if (type != IPERF_UDP_SERVER) {
wifi_cmd_get_tx_statistics(0, NULL);
}
#endif
#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
if (type != IPERF_UDP_SERVER) {
wifi_cmd_get_rx_statistics(0, NULL);
}
#endif
}
}
void app_main(void)
{
@@ -25,7 +76,22 @@ void app_main(void)
}
ESP_ERROR_CHECK( ret );
initialise_wifi();
/* initialise wifi */
app_wifi_initialise_config_t config = APP_WIFI_CONFIG_DEFAULT();
config.storage = WIFI_STORAGE_RAM;
config.ps_type = WIFI_PS_NONE;
app_initialise_wifi(&config);
#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_MU_STATS
esp_wifi_enable_rx_statistics(true, true);
#else
esp_wifi_enable_rx_statistics(true, false);
#endif
#endif
#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
esp_wifi_enable_tx_statistics(ESP_WIFI_ACI_BE, true);
#endif
esp_console_repl_t *repl = NULL;
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
@@ -45,7 +111,11 @@ void app_main(void)
/* Register commands */
register_system();
register_wifi();
app_register_all_wifi_commands();
app_register_iperf_commands();
app_register_ping_commands();
app_register_iperf_hook_func(iperf_hook_show_wifi_stats);
printf("\n ==================================================\n");
printf(" | Steps to test WiFi throughput |\n");

View File

@@ -16,19 +16,12 @@ The test env wifi_iperf do need the following config::
"""
import os
import time
from typing import Any
from typing import Callable
from typing import Tuple
import pexpect
import pytest
from common_test_methods import get_env_config_variable
from common_test_methods import get_host_ip_by_interface
from idf_iperf_test_util import IperfUtility
from idf_iperf_test_util.IperfUtility import SCAN_RETRY_COUNT
from idf_iperf_test_util.IperfUtility import SCAN_TIMEOUT
from idf_iperf_test_util.IperfUtility import TEST_TIME
from pytest_embedded import Dut
# configurations
@@ -39,105 +32,6 @@ NO_BANDWIDTH_LIMIT = -1 # iperf send bandwith is not limited
BEST_PERFORMANCE_CONFIG = '99'
class IperfTestUtilitySoftap(IperfUtility.IperfTestUtility):
""" iperf test implementation """
def __init__(self, dut: Dut, softap_dut: Dut, config_name:str, test_result:Any=None) -> None:
IperfUtility.IperfTestUtility.__init__(self, dut, config_name, 'softap', '1234567890', None, None, test_result)
self.softap_dut = softap_dut
self.softap_ip = '192.168.4.1'
def setup(self) -> Tuple[str,int]:
"""
setup iperf test:
1. kill current iperf process
2. reboot DUT (currently iperf is not very robust, need to reboot DUT)
3. scan to get AP RSSI
4. connect to AP
"""
self.softap_dut.write('restart')
self.softap_dut.expect_exact("Type 'help' to get the list of commands.")
self.softap_dut.expect('iperf>', timeout=30)
self.softap_dut.write('ap {} {}'.format(self.ap_ssid, self.ap_password))
self.dut.write('restart')
self.dut.expect_exact("Type 'help' to get the list of commands.")
self.dut.expect('iperf>', timeout=30)
self.dut.write('scan {}'.format(self.ap_ssid))
for _ in range(SCAN_RETRY_COUNT):
try:
rssi = int(self.dut.expect(r'\[{}]\[rssi=(-\d+)]'.format(self.ap_ssid),
timeout=SCAN_TIMEOUT).group(1))
break
except pexpect.TIMEOUT:
continue
else:
raise AssertionError('Failed to scan AP')
self.dut.write('sta {} {}'.format(self.ap_ssid, self.ap_password))
dut_ip = self.dut.expect(r'sta ip: ([\d.]+), mask: ([\d.]+), gw: ([\d.]+)').group(1).decode('utf-8')
return dut_ip, rssi
def _test_once(self, proto:str, direction:str, bw_limit:int) -> Tuple[str, int, int]:
""" do measure once for one type """
# connect and scan to get RSSI
dut_ip, rssi = self.setup()
assert direction in ['rx', 'tx']
assert proto in ['tcp', 'udp']
# run iperf test
if direction == 'tx':
if proto == 'tcp':
self.softap_dut.write('iperf -s -i 1 -t {}'.format(TEST_TIME))
# wait until DUT TCP server created
try:
self.softap_dut.expect('iperf tcp server create successfully', timeout=1)
except pexpect.TIMEOUT:
# compatible with old iperf example binary
pass
if bw_limit > 0:
self.dut.write('iperf -c {} -i 1 -t {} -b {}'.format(self.softap_ip, TEST_TIME, bw_limit))
else:
self.dut.write('iperf -c {} -i 1 -t {}'.format(self.softap_ip, TEST_TIME))
else:
self.softap_dut.write('iperf -s -u -i 1 -t {}'.format(TEST_TIME))
if bw_limit > 0:
self.dut.write('iperf -c {} -u -i 1 -t {} -b {}'.format(self.softap_ip, TEST_TIME, bw_limit))
else:
self.dut.write('iperf -c {} -u -i 1 -t {}'.format(self.softap_ip, TEST_TIME))
else:
if proto == 'tcp':
self.dut.write('iperf -s -i 1 -t {}'.format(TEST_TIME))
# wait until DUT TCP server created
try:
self.dut.expect('iperf tcp server create successfully', timeout=1)
except pexpect.TIMEOUT:
# compatible with old iperf example binary
pass
if bw_limit > 0:
self.softap_dut.write('iperf -c {} -i 1 -t {} -b {}'.format(dut_ip, TEST_TIME, bw_limit))
else:
self.softap_dut.write('iperf -c {} -i 1 -t {}'.format(dut_ip, TEST_TIME))
else:
self.dut.write('iperf -s -u -i 1 -t {}'.format(TEST_TIME))
if bw_limit > 0:
self.softap_dut.write('iperf -c {} -u -i 1 -t {} -b {}'.format(dut_ip, TEST_TIME, bw_limit))
else:
self.softap_dut.write('iperf -c {} -u -i 1 -t {}'.format(dut_ip, TEST_TIME))
time.sleep(TEST_TIME + 5)
if direction == 'tx':
server_raw_data = self.dut.expect(pexpect.TIMEOUT, timeout=0).decode('utf-8')
else:
server_raw_data = self.dut.expect(pexpect.TIMEOUT, timeout=0).decode('utf-8')
self.dut.write('iperf -a')
self.softap_dut.write('iperf -a')
self.dut.write('heap')
heap_size = self.dut.expect(r'min heap size: (\d+)\D').group(1)
# return server raw data (for parsing test results) and RSSI
return server_raw_data, rssi, heap_size
@pytest.mark.esp32
@pytest.mark.temp_skip_ci(targets=['esp32s2', 'esp32c3', 'esp32s3'], reason='lack of runners (run only for ESP32)')
@pytest.mark.timeout(1200)

View File

@@ -1,2 +1,4 @@
idf_component_register(SRCS "itwt.c"
idf_component_register(SRCS "itwt_main.c"
"wifi_stats_cmd.c"
"wifi_itwt_cmd.c"
INCLUDE_DIRS ".")

View File

@@ -3,7 +3,3 @@ dependencies:
path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system
cmd_nvs:
path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_nvs
cmd_wifi:
path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_wifi
iperf:
path: ${IDF_PATH}/examples/common_components/iperf

View File

@@ -26,11 +26,12 @@
#include "nvs_flash.h"
#include "esp_console.h"
#include "cmd_system.h"
#include "wifi_cmd.h"
#include "esp_wifi_he.h"
#include "esp_pm.h"
#include "esp_timer.h"
#include "wifi_cmd.h"
/*******************************************************
* Constants
*******************************************************/

View File

@@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void register_wifi_itwt(void);
void register_wifi_stats(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,227 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#if CONFIG_SOC_WIFI_HE_SUPPORT
#include "esp_console.h"
#include "argtable3/argtable3.h"
#include "esp_netif.h"
#include "esp_event.h"
#include "esp_wifi.h"
#include "esp_wifi_he.h"
/*******************************************************
* Constants
*******************************************************/
static const char *TAG = "twt";
/*******************************************************
* Structures
*******************************************************/
typedef struct {
struct arg_int *setup;
struct arg_int *teardown;
struct arg_int *suspend;
struct arg_int *trigger; //1-trigger-enabled, 0-non-trigger-enabled, setup
struct arg_int *flowtype; //1-unannounced, 0-announced, setup
struct arg_int *negtype;
struct arg_int *wakeinvlexp; //setup
struct arg_int *wakeduraunit; //1-TU, 0-256us
struct arg_int *wakeinvlman; //setup
struct arg_int *minwakedur; //setup
struct arg_int *flowid;
struct arg_int *twtid;
struct arg_int *setup_timeout_time_ms;
struct arg_int *suspend_time_ms;
struct arg_int *all_twt;
struct arg_end *end;
} wifi_itwt_args_t;
typedef struct {
struct arg_int *timeout;
struct arg_end *end;
} wifi_itwt_send_probereq_t;
/*******************************************************
* Variable Definitions
*******************************************************/
static wifi_itwt_args_t itwt_args;
static wifi_itwt_send_probereq_t itwt_probe_args;
/*******************************************************
* Function Declarations
*******************************************************/
/*******************************************************
* Function Definitions
*******************************************************/
static int wifi_cmd_itwt(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **) &itwt_args);
if (nerrors != 0) {
arg_print_errors(stderr, itwt_args.end, argv[0]);
return 1;
}
esp_err_t err = ESP_OK;
if (itwt_args.setup->count) {
if (itwt_args.wakeinvlman->count) {
if (itwt_args.wakeinvlman->ival[0] < 0 || itwt_args.wakeinvlman->ival[0] > 65535) {
ESP_LOGE(TAG, "(itwt)expect [0, 65535], wake_invl_mant: %d", itwt_args.wakeinvlman->ival[0]);
return 1;
}
}
if (itwt_args.wakeinvlexp->count) {
if (itwt_args.wakeinvlexp->ival[0] < 0 || itwt_args.wakeinvlexp->ival[0] > 31) {
ESP_LOGE(TAG, "(itwt)expect [0, 31], wake_invl_expn: %d", itwt_args.wakeinvlexp->ival[0]);
return 1;
}
}
if (itwt_args.minwakedur->count) {
if (itwt_args.minwakedur->ival[0] < 0 || itwt_args.minwakedur->ival[0] > 255) {
ESP_LOGE(TAG, "(itwt)expect [0, 255], min_wake_dura: %d", itwt_args.minwakedur->ival[0]);
return 1;
}
}
if (itwt_args.wakeduraunit->count) {
if (itwt_args.wakeduraunit->ival[0] < 0 || itwt_args.wakeduraunit->ival[0] > 1) {
ESP_LOGE(TAG, "(itwt)expect [0, 1], wake duration unit: %d", itwt_args.wakeduraunit->ival[0]);
return 1;
}
}
if (itwt_args.twtid->count) {
if (itwt_args.twtid->ival[0] < 0 || itwt_args.twtid->ival[0] > 32767) {
ESP_LOGE(TAG, "(itwt)expect [0, 32767], twt id: %d", itwt_args.twtid->ival[0]);
return 1;
}
}
if (itwt_args.setup_timeout_time_ms->count) {
if (itwt_args.setup_timeout_time_ms->ival[0] < 0 || itwt_args.setup_timeout_time_ms->ival[0] > 65535) {
ESP_LOGE(TAG, "(itwt)expect [0, 65535], setup timeout time: %d", itwt_args.setup_timeout_time_ms->ival[0]);
return 1;
}
}
wifi_twt_setup_config_t setup_config = {
.setup_cmd = (itwt_args.setup->ival[0] <= TWT_DEMAND) ? itwt_args.setup->ival[0] : TWT_REQUEST,
.flow_id = 0,
.twt_id = itwt_args.twtid->count ? itwt_args.twtid->ival[0] : 0,
.flow_type = itwt_args.flowtype->count ? ((itwt_args.flowtype->ival[0] == 0) ? 0 : 1) : 0,
.min_wake_dura = itwt_args.minwakedur->count ? itwt_args.minwakedur->ival[0] : 255,
.wake_duration_unit = itwt_args.wakeduraunit->count ? itwt_args.wakeduraunit->ival[0] : 0,
.wake_invl_expn = itwt_args.wakeinvlexp->count ? itwt_args.wakeinvlexp->ival[0] : 10,
.wake_invl_mant = itwt_args.wakeinvlman->count ? itwt_args.wakeinvlman->ival[0] : 512,
.trigger = itwt_args.trigger->count ? (itwt_args.trigger->ival[0] ? 1 : 0) : 1,
.timeout_time_ms = itwt_args.setup_timeout_time_ms->count ? itwt_args.setup_timeout_time_ms->ival[0] : 5000,
};
err = esp_wifi_sta_itwt_setup(&setup_config);
ESP_LOGI(TAG, "(itwt)setup, trigger:%d, %s, flow_id:%d, err:0x%x",
setup_config.trigger, setup_config.flow_type ? "unannounce" : "announced", setup_config.flow_id, err);
}
if (itwt_args.teardown->count) {
// teardown a given flow id, all_twt has a high priority
int flow_id = itwt_args.flowid->count ? itwt_args.flowid->ival[0] : (-1);
bool all_twt = itwt_args.all_twt->count ? ((itwt_args.all_twt->ival[0] == 1) ? true : false) : false;
flow_id = (all_twt == true) ? FLOW_ID_ALL : flow_id;
if (flow_id >= 0) {
err = esp_wifi_sta_itwt_teardown(flow_id);
ESP_LOGI(TAG, "(itwt)teardown, flow_id:%d, all_twt:%d, err:0x%x", flow_id, all_twt, err);
} else {
ESP_LOGE(TAG, "(itwt)teardown, should specify an existing flow id");
}
}
if (itwt_args.suspend->count) {
// suspend a given flow id
int flow_id = itwt_args.flowid->count ? itwt_args.flowid->ival[0] : (-1);
bool all_twt = itwt_args.all_twt->count ? (itwt_args.all_twt->ival[0] ? true : false) : false;
flow_id = (all_twt == true) ? FLOW_ID_ALL : flow_id;
int suspend_time_ms = itwt_args.suspend_time_ms->count ? itwt_args.suspend_time_ms->ival[0] : 0;
if (flow_id > 0) {
err = esp_wifi_sta_itwt_suspend(flow_id, suspend_time_ms);
ESP_LOGI(TAG, "(itwt)suspend, flow_id:%d, all_twt:%d, suspend:%d ms, err:0x%x", flow_id, all_twt, suspend_time_ms, err);
} else {
ESP_LOGE(TAG, "(itwt)suspend, should specify an existing flow id");
}
}
return 0;
}
static int wifi_cmd_itwt_probe(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **) &itwt_probe_args);
if (nerrors != 0) {
arg_print_errors(stderr, itwt_probe_args.end, argv[0]);
return 1;
}
esp_err_t err = ESP_OK;
if (itwt_probe_args.timeout->count) {
if (itwt_probe_args.timeout->ival[0] > 0) {
ESP_LOGI(TAG, "(itwt)send probe req, timeout:%d ms", itwt_probe_args.timeout->ival[0]);
err = esp_wifi_sta_itwt_send_probe_req(itwt_probe_args.timeout->ival[0]);
} else {
ESP_LOGE(TAG, "(itwt)invalid input, timeout:%d ms", itwt_probe_args.timeout->ival[0]);
}
}
ESP_LOGI(TAG, "err:0x%x", err);
return err;
}
void register_wifi_itwt(void)
{
/* itwt setup/teardown */
itwt_args.setup = arg_int0(NULL, "setup", "<setup>", "twt setup/teardown an individual flow id");
itwt_args.teardown = arg_int0(NULL, "teardown", "<setup>", "twt setup/teardown an individual flow id");
itwt_args.suspend = arg_int0(NULL, "suspend", "<setup>", "twt setup/teardown an individual flow id");
itwt_args.trigger = arg_int0("t", NULL, "<trigger>", "trigger");
itwt_args.flowtype = arg_int0("f", NULL, "<flow_type>", "flow type: 0-announced, 1-unannounced");
itwt_args.negtype = arg_int0("n", NULL, "<neg_type>", "negotiate type");
itwt_args.minwakedur = arg_int0("d", NULL, "<minwakedur>", "Norminal Min. Wake Duration");
itwt_args.wakeduraunit = arg_int0("u", NULL, "<wakeduraunit>", "wake duration unit 0-256us, 1-TU (TU = 1024us)");
itwt_args.wakeinvlexp = arg_int0("e", NULL, "<wakeinvlexp>", "Wake Interval Exponent");
itwt_args.wakeinvlman = arg_int0("m", NULL, "<wakeinvlman>", "Wake Interval Mantissa");
itwt_args.flowid = arg_int0("i", NULL, "<flow_id>", "Flow ID");
itwt_args.suspend_time_ms = arg_int0("s", NULL, "<suspend_time_ms>", "time of suspending iTWT agreements, unit ms");
itwt_args.twtid = arg_int0("w", NULL, "<twt_id>", "TWT ID");
itwt_args.setup_timeout_time_ms = arg_int0("u", NULL, "<setup_timeout_time_ms>", "iTWT setup timeout time, unit ms");
itwt_args.all_twt = arg_int0("a", NULL, "<all_twt>", "All TWT");
itwt_args.end = arg_end(1);
const esp_console_cmd_t itwt_cmd = {
.command = "itwt",
.help = "itwt setup, teardown or suspend",
.hint = NULL,
.func = &wifi_cmd_itwt,
.argtable = &itwt_args
};
ESP_ERROR_CHECK(esp_console_cmd_register(&itwt_cmd));
/* itwt probe */
itwt_probe_args.timeout = arg_int0("t", NULL, "[timeout]", "time of sending a probe request frame and receiving a probe response frame from ap, unit ms");
itwt_probe_args.end = arg_end(1);
const esp_console_cmd_t itwt_probe_cmd = {
.command = "probe",
.help = "send probe request for TSF update when at lease one itwt agreement setup",
.hint = NULL,
.func = &wifi_cmd_itwt_probe,
.argtable = &itwt_probe_args
};
ESP_ERROR_CHECK(esp_console_cmd_register(&itwt_probe_cmd));
}
#else
void register_wifi_itwt(void)
{
;
}
#endif /* CONFIG_SOC_WIFI_HE_SUPPORT */

View File

@@ -0,0 +1,585 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS || CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
#include "esp_console.h"
#include "argtable3/argtable3.h"
#include "esp_event.h"
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#include "wifi_stats.h"
#include "esp_private/esp_wifi_he_private.h"
/*******************************************************
* Macros
*******************************************************/
/*
* enable/disable rx/tx statistics after Wi-Fi started:
* (1) esp_wifi_enable_rx_statistics(true, true); //rx_stats=true, rx_mu_stats=true
* (2) esp_wifi_enable_tx_statistics(ESP_WIFI_ACI_BE, true); //aci=ESP_WIFI_ACI_BE, tx_stats=true
*/
/*******************************************************
* Constants
*******************************************************/
static const char *TAG = "stats";
/*******************************************************
* Structures
*******************************************************/
/*******************************************************
* Variable Definitions
*******************************************************/
#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_MU_STATS
esp_test_rx_mu_statistics_t rx_mu_stats = { 0, }; //10932 bytes
#endif
/*******************************************************
* Function Declarations
*******************************************************/
/*******************************************************
* Function Definitions
*******************************************************/
const char *tx_fail_error2str(esp_test_tx_fail_error_t error)
{
switch (error) {
case TEST_TX_FAIL_ERROR_H00:
return "0x00";
case TEST_TX_FAIL_ERROR_H53:
return "0x53";
case TEST_TX_FAIL_ERROR_H63:
return "0x63";
case TEST_TX_FAIL_ERROR_H75:
return "0x75";
case TEST_TX_FAIL_ERROR_H41:
return "0x41";
case TEST_TX_FAIL_ERROR_H42:
return "0x42";
case TEST_TX_FAIL_ERROR_H47:
return "0x47";
case TEST_TX_FAIL_ERROR_H80:
return "0x80";
case TEST_TX_FAIL_ERROR_H5A:
return "0x5A";
case TEST_TX_FAIL_ERROR_HXX:
return "Others";
case TEST_TX_FAIL_ERROR_MAX:
return "Undefined";
}
return "Undefined";
}
const char *tx_fail_match2str(esp_test_tx_fail_match_t match)
{
switch (match) {
case TEST_TX_WAIT_MATCH:
return "MATCH";
case TEST_TX_WAIT_NOT2SELF:
return "NOT2SELF";
case TEST_TX_MISMATCH:
return "MISMATCH";
case TEST_TX_WAIT_TIMEOUT:
return "TIMEOUT";
case TEST_TX_WAIT_MAX:
return "Undefined";
}
return "Undefined";
}
const char *tx_fail_state2str(esp_test_tx_fail_state_t state)
{
switch (state) {
case TEST_TX_SUCCESS:
return "TX Success";
case TEST_TX_FAIL_RTS:
return "TX RTS";
case TEST_TX_WAIT_CTS: //RX
return "Wait CTS";
case TEST_TX_FAIL_CTS:
return "TX RTS";
case TEST_TX_FAIL_DATA:
return "TX DATA";
case TEST_TX_WAIT_ACK: //RX
return "Wait ACK/BA";
case TEST_TX_FAIL_MAX:
return "Undefined";
}
return "Undefined";
}
int wifi_cmd_clr_tx_statistics(int argc, char **argv)
{
ESP_LOGW(TAG, "Clear tx statistics");
int i;
for (i = 0; i < 3; i++) {
esp_wifi_clr_tx_statistics(i); //BE
esp_wifi_clr_tx_tb_statistics(i);
}
esp_test_clr_hw_statistics();
return 0;
}
void print_hw_tb_statistics(void)
{
esp_test_hw_tb_statistics_t hw_tb_stats = { 0, };
esp_test_get_hw_tb_statistics(&hw_tb_stats);
printf("(test)rx_trig:%d, tx_bfrpt:%d, tb_times:%d, tb_qos_null:%d, tb_qos_data:%d, tb_cca_cancel:%d, tb_sifs_abort:%d, tb_pwr_outof_range:%d\n",
hw_tb_stats.rx_trig,
hw_tb_stats.tx_bfrpt, //including TB and Non-TB
hw_tb_stats.tb_times,
hw_tb_stats.tb_qos_null,
hw_tb_stats.tb_times - hw_tb_stats.tb_qos_null,
hw_tb_stats.tb_cca_cancel,
hw_tb_stats.tb_sifs_abort,
hw_tb_stats.tb_pwr_outof_range);
}
int wifi_cmd_get_tx_statistics(int argc, char **argv)
{
uint8_t i, h, j, k;
ESP_LOGW(TAG, "Get tx statistics");
esp_test_tx_tb_statistics_t tb_stats = { 0, }; //32 bytes
esp_test_tx_statistics_t tx_stats = { 0, }; //136 bytes
esp_test_tx_fail_statistics_t tx_fail[TEST_TX_FAIL_MAX] = { 0, }; //TEST_TX_FAIL_MAX * 164 bytes
print_hw_tb_statistics();
//only check BE
for (i = 2; i < 3; i++) {
esp_wifi_get_tx_tb_statistics(i, &tb_stats);
/* TB */
printf("(test)aci:%" PRIu8 ", tb(suc:%" PRIu32 ", ack:%" PRIu32 ", err:%" PRIu32 "), "
"count(suc:%" PRIu32 ", ack:%" PRIu32 ", err:%" PRIu32 ", tot:%" PRIu32 ", max_sent:%" PRIu32 ")\n",
i,
tb_stats.complete_suc_tb,
tb_stats.complete_ack_tb,
tb_stats.complete_err_tb,
tb_stats.complete_tb_suc_count,
tb_stats.complete_tb_ack_count,
tb_stats.complete_tb_err_count,
tb_stats.complete_tb_tot_count,
tb_stats.complete_tb_pack_sent);
esp_wifi_get_tx_statistics(i, &tx_stats, (esp_test_tx_fail_statistics_t *) &tx_fail);
int tot_tx_times = tx_stats.tb_times + (tx_stats.tx_enable - tx_stats.tb_last); //TB + EDCA
int tot_fail = tx_fail[1].count + tx_fail[2].count + tx_fail[3].count + tx_fail[4].count + tx_fail[5].count;
printf("(test)aci:%" PRIu8 ", enable:%" PRIu32 ", complete:%" PRIu32 ", tb_times:%" PRIu32 ", tb_last:%" PRIu32 ", edca:%" PRIu32 ", "
"succ:%" PRIu32 ", fail(%" PRIu32 ",%" PRIu32 ",%" PRIu32 ", cts:%" PRIu32 "/%2.2f%%, ack:%" PRIu32 "/%2.2f%%, tot:%d, %.2f%%), "
"edca(ack:%" PRIu32 ", ba:%" PRIu32 "), tb(hw-ba:%" PRIu32 ", sw-ba:%" PRIu32 ")\n",
i, tx_stats.tx_enable,
tx_stats.tx_complete,
tx_stats.tb_times,
tx_stats.tb_last,
tx_stats.tx_enable - tx_stats.tb_last,
tx_fail[0].count,
tx_fail[1].count,
tx_fail[3].count,
tx_fail[4].count,
tx_fail[2].count,
(float) ((float) tx_fail[2].count / (float) tot_tx_times) * 100, //rx cts
tx_fail[5].count, (float) ((float) tx_fail[5].count / (float) tot_tx_times) * 100, //rx ack
tot_fail,
(float) ((float) tot_fail / (float) tot_tx_times) * 100,
tx_stats.rx_ack,
tx_stats.rx_ba,
tx_stats.tb_rx_ba, //including ACKs
tx_stats.rx_dump_ba);
printf("(test)aci:%" PRIu8 ", txFrames:%" PRIu32 ", s-mpdu:%" PRIu32 "(%.2f%%), "
"bitmap(max:%d, min:%d, tot:%" PRIu32 ", avg:%.2f), "
"retry(edca:%" PRIu32 ", tb:%" PRIu32 ", %.2f%%), collision:%" PRIu32 ", timeout:%" PRIu32 "\n",
i,
tx_stats.tx_succ,
tx_stats.rx_ack,
((float) (tx_stats.rx_ack) / (float) tot_tx_times) * 100,
tx_stats.rx_max_bitmap,
tx_stats.rx_min_bitmap,
tx_stats.rx_tot_bitmap,
(float) tx_stats.rx_tot_bitmap / (float) (tx_stats.tb_rx_ba + tx_stats.rx_ba),
tx_stats.retry_edca, tx_stats.retry_tb, (float) (tx_stats.retry_edca + tx_stats.retry_tb) / (float) tx_stats.tx_succ * 100,
tx_stats.collision, tx_stats.timeout);
float tot_rtt_ms = (float) tx_stats.tx_tot_rtt / (float) 1000;
printf("(test)aci:%" PRIu8 ", seqno_rtt[%" PRIu32 ",%" PRIu32 "], hw_rtt[%" PRIu32 ", %" PRIu32 "], muedca[enable:%" PRIu32 ", times:%" PRIu32 ", %.2f, %.2f, tot:%.2f], avg:%.3f ms, tot:%.3f secs\n",
i,
tx_stats.tx_seq_min_rtt,
tx_stats.tx_seq_max_rtt,
tx_stats.tx_min_rtt,
tx_stats.tx_max_rtt,
tx_stats.tx_muedca_enable,
tx_stats.muedca_times,
(float) tx_stats.tx_min_muedca_time / (float) 1000,
(float) tx_stats.tx_max_muedca_time / (float) 1000,
(float) tx_stats.tx_tot_muedca_time / (float) 1000, //ms
(float) tot_rtt_ms / (float) tot_tx_times, //ms
(float) tot_rtt_ms / (float) 1000); //seconds
/* fail state */
for (h = 1; h < TEST_TX_FAIL_MAX; h++) { //state
for (j = 0; j < TEST_TX_WAIT_MAX; j++) { //match
for (k = 0; k < TEST_TX_FAIL_ERROR_MAX; k++) { //error
if (tx_fail[h].match[j][k]) {
printf("(test)[%d][%d][%d](%16s + %16s + %16s)%3" PRIu32 "/%3" PRIu32 "(%.2f%%)\n", h, j, k, tx_fail_state2str(h),
tx_fail_match2str(j), tx_fail_error2str(k),
tx_fail[h].match[j][k], tx_fail[h].count,
((float) tx_fail[h].match[j][k] / (float) tx_fail[h].count) * 100);
}
}
}
}
printf("\n");
}
wifi_cmd_clr_tx_statistics(0, 0);
return 0;
}
void print_rx_statistics_nonmimo(const esp_test_rx_mu_statistics_t *mu_stats)
{
if (!mu_stats->nonmimo_rx) {
return;
}
int i, j;
int tot_rx_nonmimo = 0;
ESP_LOGW(TAG, "(nonmimo)dut rx:%" PRIu32, mu_stats->nonmimo_rx);
ESP_LOGW(TAG, "(nonmimo)ru_alloc_96_num_2046:%" PRIu32 ", ru_alloc_112_num_2046:%" PRIu32, mu_stats->ru_alloc_96_num_2046, mu_stats->ru_alloc_112_num_2046);
ESP_LOGW(TAG, "(nonmimo)sigb, mcs0:%" PRIu32 "(%2.2f%%), mcs1:%" PRIu32 "(%2.2f%%), mcs2:%" PRIu32 "(%2.2f%%), mcs3:%" PRIu32 "(%2.2f%%), mcs4:%" PRIu32 "(%2.2f%%), mcs5:%" PRIu32 "(%2.2f%%)",
mu_stats->nonmimo_sigb_mcs[0], ((float) mu_stats->nonmimo_sigb_mcs[0] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_sigb_mcs[1], ((float) mu_stats->nonmimo_sigb_mcs[1] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_sigb_mcs[2], ((float) mu_stats->nonmimo_sigb_mcs[2] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_sigb_mcs[3], ((float) mu_stats->nonmimo_sigb_mcs[3] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_sigb_mcs[4], ((float) mu_stats->nonmimo_sigb_mcs[4] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_sigb_mcs[5], ((float) mu_stats->nonmimo_sigb_mcs[5] / (float) mu_stats->nonmimo_rx) * 100);
ESP_LOGW(TAG, "(nonmimo)users, num1:%" PRIu32 "(%2.2f%%), num2:%" PRIu32 "(%2.2f%%), num3:%" PRIu32 "(%2.2f%%), num4:%" PRIu32 "(%2.2f%%), num5:%" PRIu32 "(%2.2f%%), num6:%" PRIu32 "(%2.2f%%), num7:%" PRIu32 "(%2.2f%%), num8:%" PRIu32 "(%2.2f%%), num9:%" PRIu32 "(%2.2f%%)",
mu_stats->nonmimo_user_num_occu[0], ((float) mu_stats->nonmimo_user_num_occu[0] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_user_num_occu[1], ((float) mu_stats->nonmimo_user_num_occu[1] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_user_num_occu[2], ((float) mu_stats->nonmimo_user_num_occu[2] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_user_num_occu[3], ((float) mu_stats->nonmimo_user_num_occu[3] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_user_num_occu[4], ((float) mu_stats->nonmimo_user_num_occu[4] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_user_num_occu[5], ((float) mu_stats->nonmimo_user_num_occu[5] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_user_num_occu[6], ((float) mu_stats->nonmimo_user_num_occu[6] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_user_num_occu[7], ((float) mu_stats->nonmimo_user_num_occu[7] / (float) mu_stats->nonmimo_rx) * 100,
mu_stats->nonmimo_user_num_occu[8], ((float) mu_stats->nonmimo_user_num_occu[8] / (float) mu_stats->nonmimo_rx) * 100);
for (i = 0; i < 256; i++) {
for (j = 0; j < 9; j++) {
if (!mu_stats->nonmimo_ru_alloc[i][j]) {
continue;
}
ESP_LOGI(TAG, "(nonmimo)ru_allocation:0x%2x(%3" PRIu8 "), position:%" PRIu8 ", %5" PRIu32 "(%2.2f%%)", i, i, j + 1, mu_stats->nonmimo_ru_alloc[i][j],
((float) mu_stats->nonmimo_ru_alloc[i][j] / (float) mu_stats->nonmimo_rx) * 100);
}
}
for (i = 0; i < ESP_TEST_RX_MU_USER_NUM; i++) {
if (!mu_stats->nonmimo[i].aid) {
continue;
}
if (mu_stats->aid != mu_stats->nonmimo[i].aid) {
continue;
}
tot_rx_nonmimo = mu_stats->nonmimo[i].occu_nsts[0] + mu_stats->nonmimo[i].occu_nsts[1] + mu_stats->nonmimo[i].occu_nsts[2] + mu_stats->nonmimo[i].occu_nsts[3];
printf("[%" PRIu8 "]%said:0x%x, txbf:%" PRIu32 ", dcm:%" PRIu32 "\n", i, (mu_stats->aid == mu_stats->nonmimo[i].aid) ? "#" : " ", mu_stats->nonmimo[i].aid,
mu_stats->nonmimo[i].txbf, mu_stats->nonmimo[i].dcm);
printf("[%d]%said:0x%x, "
"mcs0:%" PRIu32 "(%2.2f%%), mcs1:%" PRIu32 "(%2.2f%%), mcs2:%" PRIu32 "(%2.2f%%), mcs3:%" PRIu32 "(%2.2f%%), mcs4:%" PRIu32 "(%2.2f%%), "
"mcs5:%" PRIu32 "(%2.2f%%), mcs6:%" PRIu32 "(%2.2f%%), mcs7:%" PRIu32 "(%2.2f%%), mcs8:%" PRIu32 "(%2.2f%%), mcs9:%" PRIu32 "(%2.2f%%), "
"mcs10:%" PRIu32 "(%2.2f%%), mcs11:%" PRIu32 "(%2.2f%%)\n",
i, (mu_stats->aid == mu_stats->nonmimo[i].aid) ? "#" : " ", mu_stats->nonmimo[i].aid,
mu_stats->nonmimo[i].occu_mcs[0], ((float) mu_stats->nonmimo[i].occu_mcs[0] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_mcs[1], ((float) mu_stats->nonmimo[i].occu_mcs[1] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_mcs[2], ((float) mu_stats->nonmimo[i].occu_mcs[2] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_mcs[3], ((float) mu_stats->nonmimo[i].occu_mcs[3] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_mcs[4], ((float) mu_stats->nonmimo[i].occu_mcs[4] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_mcs[5], ((float) mu_stats->nonmimo[i].occu_mcs[5] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_mcs[6], ((float) mu_stats->nonmimo[i].occu_mcs[6] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_mcs[7], ((float) mu_stats->nonmimo[i].occu_mcs[7] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_mcs[8], ((float) mu_stats->nonmimo[i].occu_mcs[8] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_mcs[9], ((float) mu_stats->nonmimo[i].occu_mcs[9] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_mcs[10], ((float) mu_stats->nonmimo[i].occu_mcs[10] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_mcs[11], ((float) mu_stats->nonmimo[i].occu_mcs[11] / (float) tot_rx_nonmimo) * 100);
printf("[%" PRIu8 "]%said:0x%x, "
"nsts0:%" PRIu32 "(%2.2f%%), nsts1:%" PRIu32 "(%2.2f%%), nsts2:%" PRIu32 "(%2.2f%%), nsts3:%" PRIu32 "(%2.2f%%)\n",
i, (mu_stats->aid == mu_stats->nonmimo[i].aid) ? "#" : " ", mu_stats->nonmimo[i].aid,
mu_stats->nonmimo[i].occu_nsts[0], ((float) mu_stats->nonmimo[i].occu_nsts[0] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_nsts[1], ((float) mu_stats->nonmimo[i].occu_nsts[1] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_nsts[2], ((float) mu_stats->nonmimo[i].occu_nsts[2] / (float) tot_rx_nonmimo) * 100,
mu_stats->nonmimo[i].occu_nsts[3], ((float) mu_stats->nonmimo[i].occu_nsts[3] / (float) tot_rx_nonmimo) * 100);
printf("[%" PRIu8 "]%said:0x%x, "
"tot_rx_nonmimo:%8d, sta/dut:%2.2f%%\n",
i, (mu_stats->aid == mu_stats->nonmimo[i].aid) ? "#" : " ", mu_stats->nonmimo[i].aid,
tot_rx_nonmimo, ((float) tot_rx_nonmimo / (float) mu_stats->nonmimo_rx) * 100);
}
}
void print_rx_statistics_mimo(const esp_test_rx_mu_statistics_t *mu_stats)
{
if (!mu_stats->mimo_rx) {
return;
}
int i;
int tot_rx_mimo = 0;
ESP_LOGW(TAG, "(mimo)dut rx:%" PRIu32 "", mu_stats->mimo_rx);
ESP_LOGW(TAG, "(mimo)sigb, mcs0:%" PRIu32 "(%2.2f%%), mcs1:%" PRIu32 "(%2.2f%%), mcs2:%" PRIu32 "(%2.2f%%), mcs3:%" PRIu32 "(%2.2f%%), mcs4:%" PRIu32 "(%2.2f%%), mcs5:%" PRIu32 "(%2.2f%%)",
mu_stats->mimo_sigb_mcs[0], ((float) mu_stats->mimo_sigb_mcs[0] / (float) mu_stats->mimo_rx) * 100,
mu_stats->mimo_sigb_mcs[1], ((float) mu_stats->mimo_sigb_mcs[1] / (float) mu_stats->mimo_rx) * 100,
mu_stats->mimo_sigb_mcs[2], ((float) mu_stats->mimo_sigb_mcs[2] / (float) mu_stats->mimo_rx) * 100,
mu_stats->mimo_sigb_mcs[3], ((float) mu_stats->mimo_sigb_mcs[3] / (float) mu_stats->mimo_rx) * 100,
mu_stats->mimo_sigb_mcs[4], ((float) mu_stats->mimo_sigb_mcs[4] / (float) mu_stats->mimo_rx) * 100,
mu_stats->mimo_sigb_mcs[5], ((float) mu_stats->mimo_sigb_mcs[5] / (float) mu_stats->mimo_rx) * 100);
ESP_LOGW(TAG, "(mimo)users num2:%" PRIu32 "(%2.2f%%), num3:%" PRIu32 "(%2.2f%%), num4:%" PRIu32 "(%2.2f%%), num5:%" PRIu32 "(%2.2f%%), num6:%" PRIu32 "(%2.2f%%), num7:%" PRIu32 "(%2.2f%%), num8:%" PRIu32 "(%2.2f%%)",
mu_stats->mimo_user_num_occu[0], ((float) mu_stats->mimo_user_num_occu[0] / (float) mu_stats->mimo_rx) * 100,
mu_stats->mimo_user_num_occu[1], ((float) mu_stats->mimo_user_num_occu[1] / (float) mu_stats->mimo_rx) * 100,
mu_stats->mimo_user_num_occu[2], ((float) mu_stats->mimo_user_num_occu[2] / (float) mu_stats->mimo_rx) * 100,
mu_stats->mimo_user_num_occu[3], ((float) mu_stats->mimo_user_num_occu[3] / (float) mu_stats->mimo_rx) * 100,
mu_stats->mimo_user_num_occu[4], ((float) mu_stats->mimo_user_num_occu[4] / (float) mu_stats->mimo_rx) * 100,
mu_stats->mimo_user_num_occu[5], ((float) mu_stats->mimo_user_num_occu[5] / (float) mu_stats->mimo_rx) * 100,
mu_stats->mimo_user_num_occu[6], ((float) mu_stats->mimo_user_num_occu[6] / (float) mu_stats->mimo_rx) * 100);
for (i = 0; i < ESP_TEST_RX_MU_USER_NUM; i++) {
if (!mu_stats->mimo[i].aid) {
continue;
}
tot_rx_mimo = mu_stats->mimo[i].occu_ss[0] + mu_stats->mimo[i].occu_ss[1] + mu_stats->mimo[i].occu_ss[2] + mu_stats->mimo[i].occu_ss[3];
printf("[%" PRIu8 "]%said:0x%x, "
"mcs0:%" PRIu32 "(%2.2f%%), mcs1:%" PRIu32 "(%2.2f%%), mcs2:%" PRIu32 "(%2.2f%%), mcs3:%" PRIu32 "(%2.2f%%), mcs4:%" PRIu32 "(%2.2f%%), "
"mcs5:%" PRIu32 "(%2.2f%%), mcs6:%" PRIu32 "(%2.2f%%), mcs7:%" PRIu32 "(%2.2f%%), mcs8:%" PRIu32 "(%2.2f%%), mcs9:%" PRIu32 "(%2.2f%%), "
"mcs10:%" PRIu32 "(%2.2f%%), mcs11:%" PRIu32 "(%2.2f%%)\n",
i, (mu_stats->aid == mu_stats->mimo[i].aid) ? "#" : " ", mu_stats->mimo[i].aid,
mu_stats->mimo[i].occu_mcs[0], ((float) mu_stats->mimo[i].occu_mcs[0] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_mcs[1], ((float) mu_stats->mimo[i].occu_mcs[1] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_mcs[2], ((float) mu_stats->mimo[i].occu_mcs[2] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_mcs[3], ((float) mu_stats->mimo[i].occu_mcs[3] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_mcs[4], ((float) mu_stats->mimo[i].occu_mcs[4] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_mcs[5], ((float) mu_stats->mimo[i].occu_mcs[5] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_mcs[6], ((float) mu_stats->mimo[i].occu_mcs[6] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_mcs[7], ((float) mu_stats->mimo[i].occu_mcs[7] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_mcs[8], ((float) mu_stats->mimo[i].occu_mcs[8] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_mcs[9], ((float) mu_stats->mimo[i].occu_mcs[9] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_mcs[10], ((float) mu_stats->mimo[i].occu_mcs[10] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_mcs[11], ((float) mu_stats->mimo[i].occu_mcs[11] / (float) tot_rx_mimo) * 100);
printf("[%" PRIu8 "]%said:0x%x, "
"ss0:%" PRIu32 "(%2.2f%%), ss1:%" PRIu32 "(%2.2f%%), ss2:%" PRIu32 "(%2.2f%%), ss3:%" PRIu32 "(%2.2f%%)\n",
i, (mu_stats->aid == mu_stats->mimo[i].aid) ? "#" : " ", mu_stats->mimo[i].aid,
mu_stats->mimo[i].occu_ss[0], ((float) mu_stats->mimo[i].occu_ss[0] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_ss[1], ((float) mu_stats->mimo[i].occu_ss[1] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_ss[2], ((float) mu_stats->mimo[i].occu_ss[2] / (float) tot_rx_mimo) * 100,
mu_stats->mimo[i].occu_ss[3], ((float) mu_stats->mimo[i].occu_ss[3] / (float) tot_rx_mimo) * 100);
printf("[%" PRIu8 "]%said:0x%x, "
"tot_rx_mimo:%8d, sta/dut:%2.2f%%\n",
i, (mu_stats->aid == mu_stats->mimo[i].aid) ? "#" : " ", mu_stats->mimo[i].aid,
tot_rx_mimo, ((float) tot_rx_mimo / (float) mu_stats->mimo_rx) * 100);
}
}
void print_hw_rx_statistics(void)
{
esp_test_hw_rx_statistics_t hw_rx_stats = { 0, };
esp_test_get_hw_rx_statistics(&hw_rx_stats);
printf(
"WDEVRX_FCS_ERR :%d\n"
"WDEVRX_ABORT :%d\n"
"WDEVRX_ABORT_FCS_PASS :%d\n"
"NRX_ERR_PWRDROP :%d\n"
"NRX_HESIGB_ERR :%d\n"
"WDEVRX_SAMEBM_ERRCNT :%d\n"
"WDEVRX_MPDU :%d\n"
"WDEVRX_END_CNT :%d\n"
"WDEVRX_DATASUC :%d\n"
"WDEVRX_LASTUNMATCH_ERR :%d\n"
"RXHUNG_STATIS :%d\n"
"TXHUNG_STATIS :%d\n"
"RXTXHUNG :%" PRIu32 "\n"
"WDEVRX_CFO :%d\n"
"WDEVRX_SF :%d\n"
"WDEVRX_OTHER_UCAST :%d\n"
"WDEVRX_BUF_FULLCNT :%d\n"
"WDEVRX_FIFO_OVFCNT :%d\n"
"WDEVRX_TKIP_ERRCNT :%d\n"
"WDEVRX_BTBLOCK_ERR :%d\n"
"WDEVRX_FREQHOP_ERR :%d\n"
"WDEVRX_ACK_INT_CNT :%d\n"
"WDEVRX_RTS_INT_CNT :%d\n"
"BRX_ERR_AGC :%d\n"
"BRX_ERR :%d\n"
"NRX_ERR :%d\n"
"NRX_ERR_ABORT :%d\n"
"NRX_ERR_AGCEXIT :%d\n"
"NRX_ERR_BBOFF :%d\n"
"NRX_ERR_FDM_WDG :%d\n"
"NRX_ERR_RESTART :%d\n"
"NRX_ERR_SERV :%d\n"
"NRX_ERR_TXOVER :%d\n"
"NRX_HE_UNSUPPORT :%d\n"
"NRX_HTSIG_ERR :%d\n"
"NRX_HEUNSUPPORT :%d\n"
"NRX_HESIGA_CRC :%d\n",
hw_rx_stats.rx_fcs_err,
hw_rx_stats.rx_abort,
hw_rx_stats.rx_abort_fcs_pass,
hw_rx_stats.nrx_err_pwrdrop,
hw_rx_stats.nrx_hesigb_err,
hw_rx_stats.rx_samebm_errcnt,
hw_rx_stats.rx_mpdu,
hw_rx_stats.rx_end_cnt,
hw_rx_stats.rx_datasuc,
hw_rx_stats.rx_lastunmatch_err,
hw_rx_stats.rxhung_statis,
hw_rx_stats.txhung_statis,
hw_rx_stats.rxtxhung,
hw_rx_stats.rx_cfo_hz,
hw_rx_stats.rx_sf,
hw_rx_stats.rx_other_ucast,
hw_rx_stats.rx_buf_fullcnt,
hw_rx_stats.rx_fifo_ovfcnt,
hw_rx_stats.rx_tkip_errcnt,
hw_rx_stats.rx_btblock_err,
hw_rx_stats.rx_freqhop_err,
hw_rx_stats.rx_ack_int_cnt,
hw_rx_stats.rx_rts_int_cnt,
hw_rx_stats.brx_err_agc,
hw_rx_stats.brx_err,
hw_rx_stats.nrx_err,
hw_rx_stats.nrx_err_abort,
hw_rx_stats.nrx_err_agcexit,
hw_rx_stats.nrx_err_bboff,
hw_rx_stats.nrx_err_fdm_wdg,
hw_rx_stats.nrx_err_restart,
hw_rx_stats.nrx_err_serv,
hw_rx_stats.nrx_err_txover,
hw_rx_stats.nrx_err_unsupport,
hw_rx_stats.nrx_htsig_err,
hw_rx_stats.nrx_heunsupport,
hw_rx_stats.nrx_hesiga_crc
);
}
int wifi_cmd_clr_rx_statistics(int argc, char **argv)
{
ESP_LOGW(TAG, "Clear rx statistics");
esp_wifi_clr_rx_statistics(0);
esp_wifi_clr_rx_statistics(7);
#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_MU_STATS
esp_test_clr_rx_error_occurs();
esp_wifi_clr_rx_mu_statistics();
#endif
esp_test_clr_hw_statistics();
return 0;
}
void print_rx_mu_statistics(void)
{
/* mu */
esp_wifi_get_rx_mu_statistics(&rx_mu_stats);
/* MIMO */
print_rx_statistics_mimo(&rx_mu_stats);
/* non-MIMO */
print_rx_statistics_nonmimo(&rx_mu_stats);
}
int wifi_cmd_get_rx_statistics(int argc, char **argv)
{
ESP_LOGW(TAG, "Get rx statistics");
esp_test_rx_statistics_t rx_stats = { 0, };
esp_test_rx_error_occurs_t rx_error_occurs = { 0, };
esp_wifi_get_rx_statistics(0, &rx_stats); //tid=0
print_hw_tb_statistics();
ESP_LOGW(TAG, "(0)legacy:%" PRIu32 ", ht(ht:%" PRIu32 ", ht_retry:%" PRIu32 "/%2.2f%%, ht_noeb:%" PRIu32 "/%2.2f%%)",
rx_stats.legacy,
rx_stats.ht, rx_stats.ht_retry,
rx_stats.ht_retry ? ((float) ((float) rx_stats.ht_retry / (float) rx_stats.ht) * 100) : 0,
rx_stats.ht_noeb, rx_stats.ht_noeb ? ((float) ((float) rx_stats.ht_noeb / (float) rx_stats.ht) * 100) : 0);
ESP_LOGW(TAG, "(0)su(su:%" PRIu32 ", su_txbf:%" PRIu32 ", su_stbc:%" PRIu32 ", su_retry:%" PRIu32 "/%2.2f%%, ersu:%" PRIu32 ", ersu_dcm:%" PRIu32 ", su_noeb:%" PRIu32 "/%2.2f%%)",
rx_stats.su,
rx_stats.su_txbf, rx_stats.su_stbc,
rx_stats.su_retry,
rx_stats.su_retry ? ((float) ((float) rx_stats.su_retry / (float) rx_stats.su) * 100) : 0,
rx_stats.ersu,
rx_stats.ersu_dcm,
rx_stats.su_noeb, rx_stats.su_noeb ? ((float) ((float) rx_stats.su_noeb / (float) rx_stats.su) * 100) : 0);
ESP_LOGW(TAG, "(0)mu(mu:%" PRIu32 ", mimo:%" PRIu32 ", non-mimo:%" PRIu32 ", txbf:%" PRIu32 ", stbc:%" PRIu32 ", mu_retry:%" PRIu32 "/%2.2f%%, mu_noeb:%" PRIu32 "/%2.2f%%)",
rx_stats.mu,
rx_stats.mu_mimo,
rx_stats.mu_ofdma, rx_stats.mu_txbf, rx_stats.mu_stbc,
rx_stats.mu_retry,
rx_stats.mu_retry ? ((float) ((float) rx_stats.mu_retry / (float) rx_stats.mu) * 100) : 0,
rx_stats.mu_noeb, rx_stats.mu_noeb ? ((float) ((float) rx_stats.mu_noeb / (float) rx_stats.mu) * 100) : 0);
memset(&rx_stats, 0, sizeof(rx_stats));
esp_wifi_get_rx_statistics(7, &rx_stats); //tid=7
ESP_LOGW(TAG, "(7)legacy:%" PRIu32 ", ht:%" PRIu32 ", su:%" PRIu32 ", su_txbf:%" PRIu32 ", ersu:%" PRIu32 ", mu:%" PRIu32, rx_stats.legacy,
rx_stats.ht, rx_stats.su, rx_stats.su_txbf, rx_stats.ersu, rx_stats.mu);
ESP_LOGW(TAG, "(hw)isr:%" PRIu32 ", nblks:%" PRIu32, rx_stats.rx_isr, rx_stats.rx_nblks);
/* hw rx statistics */
print_hw_rx_statistics();
#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_MU_STATS
print_rx_mu_statistics();
#endif
esp_test_get_rx_error_occurs(&rx_error_occurs);
ESP_LOGW(TAG, "(rx)tot_errors:%" PRIu32, rx_error_occurs.tot);
int known_errors = 0; //rx error: 0x40-0xff
int i;
for (i = 0; i < 2; i++) {
if (rx_error_occurs.occurs[i]) {
known_errors += rx_error_occurs.occurs[i];
printf("[%3d] 0x%x, %8" PRIu32 ", %2.2f%%\n", i, (i ? 0xf5 : 0xc6), rx_error_occurs.occurs[i], ((float) rx_error_occurs.occurs[i] / (float) rx_error_occurs.tot) * 100);
}
}
if (rx_error_occurs.tot - known_errors) {
printf("[%3d]others, %8" PRIu32 ", %2.2f%%\n\n", i, rx_error_occurs.tot - known_errors, ((float) known_errors / (float) rx_error_occurs.tot) * 100);
}
wifi_cmd_clr_rx_statistics(0, 0);
return 0;
}
#endif /* CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS || CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS */
void register_wifi_stats(void)
{
#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
/* get tx statistics */
const esp_console_cmd_t tx_stats_cmd = {
.command = "tx",
.help = "get tx statistics",
.hint = NULL,
.func = &wifi_cmd_get_tx_statistics,
};
ESP_ERROR_CHECK(esp_console_cmd_register(&tx_stats_cmd));
/* clear tx statistics */
const esp_console_cmd_t clr_cmd = {
.command = "clrtx",
.help = "clear tx statistics",
.hint = NULL,
.func = &wifi_cmd_clr_tx_statistics,
};
ESP_ERROR_CHECK(esp_console_cmd_register(&clr_cmd));
#endif
#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
/* get rx statistics */
const esp_console_cmd_t rx_stats_cmd = {
.command = "rx",
.help = "get rx statistics",
.hint = NULL,
.func = &wifi_cmd_get_rx_statistics,
};
ESP_ERROR_CHECK(esp_console_cmd_register(&rx_stats_cmd));
/* clear rx statistics */
const esp_console_cmd_t clr_rx_cmd = {
.command = "clrrx",
.help = "clear rx statistics",
.hint = NULL,
.func = &wifi_cmd_clr_rx_statistics,
};
ESP_ERROR_CHECK(esp_console_cmd_register(&clr_rx_cmd));
#endif
}