Skip to content

Commit d548b86

Browse files
finger563Copilot
andauthored
feat(iperf_menu): Add iperf_menu component (#467)
* feat(iperf): Add iperf menu component for use with CLI * update readme * readme: update * wip * Update components/iperf_menu/include/iperf_menu.hpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * minor update * flesh out docs and clean up menu / APIs * Update components/iperf_menu/include/iperf_menu.hpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update components/iperf_menu/include/iperf_menu.hpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix minor bug * fix sp * update readme and make various methods const * overload with tcp command for reference * properly display client destination address * remove unnecessary yaml * fix bug in refactor and turn on perf. optimizations for demo --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent e104ddb commit d548b86

18 files changed

+897
-3
lines changed

.github/workflows/build.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ jobs:
107107
target: esp32s3
108108
- path: 'components/interrupt/example'
109109
target: esp32s3
110+
- path: 'components/iperf_menu/example'
111+
target: esp32s3
112+
# NOTE: we must use custom command here because this component depends
113+
# on espressif/iperf, so we can't disable the component manager
114+
command: idf.py build
110115
- path: 'components/joystick/example'
111116
target: esp32
112117
- path: 'components/kts1622/example'

.github/workflows/upload_components.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ jobs:
7171
components/icm42607
7272
components/input_drivers
7373
components/interrupt
74+
components/iperf_menu
7475
components/joystick
7576
components/kts1622
7677
components/led

components/iperf_menu/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
idf_component_register(
2+
INCLUDE_DIRS "include"
3+
PRIV_REQUIRES format cli iperf)

components/iperf_menu/README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Iperf Menu Component
2+
[![Badge](https://components.espressif.com/components/espp/wifi/badge.svg)](https://components.espressif.com/components/espp/iperf_menu)
3+
4+
The `iperf_menu` component simply provides a menu for the `espressif/iperf`
5+
component, enabling you to easily use the `iperf` network performance testing
6+
tool on your ESP device using the `cli` component.
7+
8+
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
9+
**Table of Contents**
10+
11+
- [Iperf Menu Component](#iperf-menu-component)
12+
- [Menu Functions:](#menu-functions)
13+
- [Example](#example)
14+
15+
<!-- markdown-toc end -->
16+
17+
## Menu Functions:
18+
19+
The `iperf_menu` component provides a simple command-line interface (CLI) for
20+
interacting with the `iperf` tool. The available commands are:
21+
22+
```console
23+
iperf> help
24+
Commands available:
25+
- help
26+
This help message
27+
- exit
28+
Quit the session
29+
- udp
30+
Get the current UDP mode setting.
31+
- udp <udp>
32+
Set the UDP mode for iperf tests.
33+
- tcp
34+
Get the current TCP mode setting.
35+
- tcp <tcp>
36+
Set the TCP mode for iperf tests.
37+
- ipv6
38+
Get the current IPv6 setting.
39+
- ipv6 <ipv6>
40+
Set the IPv6 mode for iperf tests.
41+
- interval
42+
Get the current reporting interval setting.
43+
- interval <interval>
44+
Set the reporting interval for iperf tests.
45+
- time
46+
Get the current time (duration) setting.
47+
- time <time>
48+
Set the time for iperf tests.
49+
- format
50+
Get the current formatting setting (kibits/sec or mbits/sec).
51+
- format <format>
52+
Set the output format for iperf tests.
53+
- length
54+
Get the current buffer length setting.
55+
- length <length>
56+
Set the buffer length for iperf tests.
57+
- abort
58+
Abort the current iperf test if running. This will stop the test and print a message.
59+
- client <host>
60+
Run an iperf client, connecting to the specified host, using the default port.
61+
- client <host> <port>
62+
Run an iperf client, connecting to the specified host and port.
63+
- client <host> <port> <bandwidth>
64+
Run an iperf client, connecting to the specified host and port. Uses the passed length as the buffer length for data transmission.
65+
- server
66+
Run an iperf server, listening on the default port.
67+
- server <port>
68+
Run an iperf server, listening on the specified port.
69+
- example
70+
(menu)
71+
```
72+
73+
![CleanShot 2025-07-07 at 15 29 33](https://github.com/user-attachments/assets/da0f1b47-3db5-4ec4-8673-f8a61fa736e3)
74+
75+
## Example
76+
77+
The [example](./example) shows the use of the `espp::IperfMenu` (using WiFi station).
78+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# The following lines of boilerplate have to be in your project's CMakeLists
2+
# in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.20)
4+
5+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6+
7+
# add the component directories that we want to use
8+
set(EXTRA_COMPONENT_DIRS
9+
"../../../components/"
10+
)
11+
12+
set(
13+
COMPONENTS
14+
"main esptool_py wifi iperf_menu task format"
15+
CACHE STRING
16+
"List of components to include"
17+
)
18+
19+
project(iperf_menu_example)
20+
21+
set(CMAKE_CXX_STANDARD 20)
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Iperf Menu Example
2+
3+
This example shows the use of the `espp::IperfMenu` component to measure the
4+
throughput of a network (WiFi / ethernet) connection between an ESP chip and
5+
another device running iperf.
6+
7+
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
8+
**Table of Contents**
9+
10+
- [Iperf Menu Example](#iperf-menu-example)
11+
- [How to use example](#how-to-use-example)
12+
- [Build and Flash](#build-and-flash)
13+
- [Configuration](#configuration)
14+
- [Example Output](#example-output)
15+
16+
<!-- markdown-toc end -->
17+
18+
![CleanShot 2025-07-07 at 13 27 54](https://github.com/user-attachments/assets/3eedd8e3-b864-4385-9b7b-46d573480e90)
19+
20+
This supports:
21+
22+
- client operation
23+
- server operation
24+
- ipv4/ipv6
25+
26+
## How to use example
27+
28+
### Build and Flash
29+
30+
Build the project and flash it to the board, then run monitor tool to view serial output:
31+
32+
```
33+
idf.py -p PORT flash monitor
34+
```
35+
36+
(Replace PORT with the name of the serial port to use.)
37+
38+
(To exit the serial monitor, type ``Ctrl-]``.)
39+
40+
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
41+
42+
### Configuration
43+
44+
This example uses WiFi (specifically WiFi STA), so you should use the `wifi`
45+
command line interface (CLI) menu that the example outputs over the serial
46+
monitor to configure the WiFi network.
47+
48+
Once you're connected, you can use the `iperf` menu to select the operation mode
49+
(client or server) and set the parameters for the test.
50+
51+
### Example Output
52+
53+
![CleanShot 2025-07-07 at 14 27 02@2x](https://github.com/user-attachments/assets/9053320f-40c6-45b6-9224-9f2c16ca7960)
54+
55+
![CleanShot 2025-07-07 at 13 27 54](https://github.com/user-attachments/assets/3eedd8e3-b864-4385-9b7b-46d573480e90)
56+
57+
58+
```console
59+
I (399) main_task: Calling app_main()
60+
[iperf_example/I][0.015]: Starting example...
61+
I (429) pp: pp rom version: e7ae62f
62+
I (429) net80211: net80211 rom version: e7ae62f
63+
I (439) wifi:wifi driver task: 3fcb05cc, prio:23, stack:6656, core=0
64+
I (449) wifi:wifi firmware version: 79fa3f41ba
65+
I (449) wifi:wifi certification version: v7.0
66+
I (449) wifi:config NVS flash: enabled
67+
I (449) wifi:config nano formatting: disabled
68+
I (449) wifi:Init data frame dynamic rx buffer num: 32
69+
I (449) wifi:Init static rx mgmt buffer num: 5
70+
I (449) wifi:Init management short buffer num: 32
71+
I (449) wifi:Init dynamic tx buffer num: 32
72+
I (449) wifi:Init static tx FG buffer num: 2
73+
I (449) wifi:Init static rx buffer size: 1600
74+
I (449) wifi:Init static rx buffer num: 10
75+
I (449) wifi:Init dynamic rx buffer num: 32
76+
I (449) wifi_init: rx ba win: 6
77+
I (449) wifi_init: accept mbox: 6
78+
I (449) wifi_init: tcpip mbox: 32
79+
I (449) wifi_init: udp mbox: 6
80+
I (449) wifi_init: tcp mbox: 6
81+
I (449) wifi_init: tcp tx win: 5760
82+
I (449) wifi_init: tcp rx win: 5760
83+
I (449) wifi_init: tcp mss: 1440
84+
I (449) wifi_init: WiFi IRAM OP enabled
85+
I (449) wifi_init: WiFi RX IRAM OP enabled
86+
[WifiSta/D][0.069]: SSID is empty, trying to load saved WiFi configuration
87+
[WifiSta/I][0.070]: Loaded saved WiFi configuration: SSID = 'HouseOfBoo'
88+
I (459) phy_init: phy_version 700,8582a7fd,Feb 10 2025,20:13:11
89+
I (489) wifi:mode : sta (f4:12:fa:5a:85:90)
90+
I (489) wifi:enable tsf
91+
I (499) wifi:new:<6,0>, old:<1,0>, ap:<255,255>, sta:<6,0>, prof:1, snd_ch_cfg:0x0
92+
I (499) wifi:state: init -> auth (0xb0)
93+
example> I (529) wifi:state: auth -> assoc (0x0)
94+
I (539) wifi:state: assoc -> run (0x10)
95+
I (659) wifi:connected with HouseOfBoo, aid = 1, channel 6, BW20, bssid = 3c:28:6d:bf:ed:ad
96+
I (669) wifi:security: WPA2-PSK, phy: bgn, rssi: -63
97+
I (669) wifi:pm start, type: 1
98+
99+
I (669) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
100+
I (669) wifi:set rx beacon pti, rx_bcn_pti: 0, bcn_timeout: 25000, mt_pti: 0, mt_time: 10000
101+
I (679) wifi:dp: 2, bi: 102400, li: 4, scale listen interval from 307200 us to 409600 us
102+
I (679) wifi:AP's beacon interval = 102400 us, DTIM period = 2
103+
I (689) wifi:<ba-add>idx:0 (ifx:0, 3c:28:6d:bf:ed:ad), tid:6, ssn:3, winSize:64
104+
I (1399) wifi:<ba-add>idx:1 (ifx:0, 3c:28:6d:bf:ed:ad), tid:0, ssn:0, winSize:64
105+
I (1889) esp_netif_handlers: sta ip: 192.168.86.32, mask: 255.255.255.0, gw: 192.168.86.1
106+
[WifiSta/I][1.502]: got ip: 192.168.86.32
107+
[iperf_example/I][1.503]: got IP: 192.168.86.32
108+
109+
example>
110+
example> iperf
111+
iperf> client_tcp 192.168.86.21 5001 0 10
112+
Using iperf config: iperf_cfg_t client { host: 358000832, dest port: 5001, source port: 5001, protocol: TCP, duration: 30, bandwidth: -1, buffer_size: 0 }
113+
iperf> I (23009) iperf: Successfully connected
114+
115+
Interval Bandwidth
116+
0.0-10.0 sec 6784.00 Kbits/sec
117+
10.0-20.0 sec 5964.80 Kbits/sec
118+
20.0-30.0 sec 4377.60 Kbits/sec
119+
0.0-30.0 sec 5708.80 Kbits/sec
120+
I (53029) iperf: TCP Socket client is closed.
121+
I (53029) iperf: iperf exit
122+
123+
iperf> client_udp 192.168.86.21 5001 0 1
124+
Using iperf config: iperf_cfg_t client { host: 358000832, dest port: 5001, source port: 5001, protocol: UDP, duration: 30, bandwidth: -1, buffer_size: 0 }
125+
iperf> I (101369) iperf: Socket created, sending to 358000832:5001
126+
127+
Interval Bandwidth
128+
0.0- 1.0 sec 8130.94 Kbits/sec
129+
1.0- 2.0 sec 7315.55 Kbits/sec
130+
```
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
idf_component_register(SRC_DIRS "."
2+
INCLUDE_DIRS ".")
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#include <chrono>
2+
#include <vector>
3+
4+
#include "sdkconfig.h"
5+
6+
#if CONFIG_ESP32_WIFI_NVS_ENABLED
7+
#include "nvs_flash.h"
8+
#endif
9+
10+
#include "logger.hpp"
11+
#include "task.hpp"
12+
#include "wifi_sta.hpp"
13+
14+
#if defined(CONFIG_COMPILER_CXX_EXCEPTIONS)
15+
#include "cli.hpp"
16+
#include "iperf_menu.hpp"
17+
#include "wifi_sta_menu.hpp"
18+
#endif
19+
20+
using namespace std::chrono_literals;
21+
22+
extern "C" void app_main(void) {
23+
espp::Logger logger({.tag = "iperf_example", .level = espp::Logger::Verbosity::INFO});
24+
logger.info("Starting example...");
25+
26+
#if CONFIG_ESP32_WIFI_NVS_ENABLED
27+
// Initialize NVS
28+
esp_err_t ret = nvs_flash_init();
29+
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
30+
ESP_ERROR_CHECK(nvs_flash_erase());
31+
ret = nvs_flash_init();
32+
}
33+
ESP_ERROR_CHECK(ret);
34+
#endif
35+
36+
#if CONFIG_COMPILER_CXX_EXCEPTIONS || defined(_DOXYGEN_)
37+
{
38+
//! [iperf menu example]
39+
espp::WifiSta wifi_sta({.ssid = "", // CONFIG_ESP_WIFI_SSID,
40+
.password = "", // CONFIG_ESP_WIFI_PASSWORD,
41+
.num_connect_retries = 5, // CONFIG_ESP_MAXIMUM_RETRY,
42+
.on_connected = nullptr,
43+
.on_disconnected = nullptr,
44+
.on_got_ip =
45+
[&](ip_event_got_ip_t *eventdata) {
46+
logger.info("got IP: {}.{}.{}.{}",
47+
IP2STR(&eventdata->ip_info.ip));
48+
},
49+
.log_level = espp::Logger::Verbosity::DEBUG});
50+
auto sta_menu = espp::WifiStaMenu(wifi_sta);
51+
52+
auto iperf_menu = espp::IperfMenu();
53+
54+
// Now make the cli and start it
55+
auto root_menu = std::make_unique<cli::Menu>("example");
56+
root_menu->Insert(sta_menu.get());
57+
root_menu->Insert(iperf_menu.get());
58+
cli::Cli cli(std::move(root_menu));
59+
cli::SetColor();
60+
cli.ExitAction([](auto &out) { out << "Goodbye and thanks for all the fish.\n"; });
61+
62+
espp::Cli input(cli);
63+
input.SetInputHistorySize(10);
64+
input.Start();
65+
//! [iperf menu example]
66+
}
67+
#else
68+
logger.error("C++ exceptions are not enabled. Please enable them in the menuconfig.");
69+
#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || defined(_DOXYGEN_)
70+
71+
logger.info("Example complete!");
72+
73+
while (true) {
74+
std::this_thread::sleep_for(1s);
75+
}
76+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# ESP-IDF Partition Table
2+
# Name, Type, SubType, Offset, Size, Flags
3+
nvs, data, nvs, 0x9000, 0x6000,
4+
phy_init, data, phy, 0xf000, 0x1000,
5+
factory, app, factory, 0x10000, 2000K,
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# NOTE: because this uses iperf, we have to use a larger min flash size
2+
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
3+
4+
# CONFIG_ESP32_WIFI_NVS_ENABLED=n
5+
6+
CONFIG_PARTITION_TABLE_CUSTOM=y
7+
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
8+
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
9+
CONFIG_PARTITION_TABLE_OFFSET=0x8000
10+
CONFIG_PARTITION_TABLE_MD5=y
11+
12+
# Common ESP-related
13+
#
14+
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096
15+
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
16+
17+
# the cli library requires exceptions right now...
18+
CONFIG_COMPILER_CXX_EXCEPTIONS=y
19+
20+
# for the example:
21+
CONFIG_FREERTOS_UNICORE=n
22+
CONFIG_FREERTOS_HZ=1000
23+
24+
CONFIG_ESP_INT_WDT=n
25+
CONFIG_ESP_TASK_WDT_EN=n
26+
27+
CONFIG_LWIP_ETHARP_TRUST_IP_MAC=n
28+
CONFIG_LWIP_IRAM_OPTIMIZATION=y
29+
CONFIG_LWIP_TCPIP_TASK_PRIO=23
30+
31+
CONFIG_IPERF_TRAFFIC_TASK_PRIORITY=23
32+
CONFIG_IPERF_REPORT_TASK_PRIORITY=24
33+
CONFIG_COMPILER_OPTIMIZATION_PERF=y

0 commit comments

Comments
 (0)