example: add iperf example
Support iperf
This commit is contained in:
parent
845c3fba35
commit
05b0d567e5
12 changed files with 1188 additions and 7 deletions
|
@ -68,6 +68,36 @@ config LWIP_IP_REASSEMBLY
|
|||
help
|
||||
Enabling this option allows reassemblying incoming fragmented IP packets.
|
||||
|
||||
config LWIP_STATS
|
||||
bool "Enable LWIP statistics"
|
||||
default n
|
||||
help
|
||||
Enabling this option allows LWIP statistics
|
||||
|
||||
config LWIP_ETHARP_TRUST_IP_MAC
|
||||
bool "Enable LWIP ARP trust"
|
||||
default y
|
||||
help
|
||||
Enabling this option allows ARP table to be updated.
|
||||
|
||||
If this option is enabled, the incoming IP packets cause the ARP table to be
|
||||
updated with the source MAC and IP addresses supplied in the packet.
|
||||
You may want to disable this if you do not trust LAN peers to have the
|
||||
correct addresses, or as a limited approach to attempt to handle
|
||||
spoofing. If disabled, lwIP will need to make a new ARP request if
|
||||
the peer is not already in the ARP table, adding a little latency.
|
||||
The peer *is* in the ARP table if it requested our address before.
|
||||
Also notice that this slows down input processing of every IP packet!
|
||||
|
||||
|
||||
config TCPIP_RECVMBOX_SIZE
|
||||
int "TCPIP receive mail box size"
|
||||
default 32
|
||||
range 6 64
|
||||
help
|
||||
Set TCPIP receive mail box size. Generally bigger value means higher throughput
|
||||
but more memory. The value should be bigger than UDP/TCP mail box size.
|
||||
|
||||
menu "TCP"
|
||||
|
||||
config TCP_MAXRTX
|
||||
|
@ -131,7 +161,7 @@ config TCP_WND_DEFAULT
|
|||
config TCP_RECVMBOX_SIZE
|
||||
int "Default TCP receive mail box size"
|
||||
default 6
|
||||
range 6 32
|
||||
range 6 64
|
||||
help
|
||||
Set TCP receive mail box size. Generally bigger value means higher throughput
|
||||
but more memory. The recommended value is: TCP_WND_DEFAULT/TCP_MSS + 2, e.g. if
|
||||
|
@ -188,7 +218,7 @@ menu "UDP"
|
|||
config UDP_RECVMBOX_SIZE
|
||||
int "Default UDP receive mail box size"
|
||||
default 6
|
||||
range 6 32
|
||||
range 6 64
|
||||
help
|
||||
Set UDP receive mail box size. The recommended value is 6.
|
||||
|
||||
|
|
|
@ -416,7 +416,7 @@
|
|||
* The queue size value itself is platform-dependent, but is passed to
|
||||
* sys_mbox_new() when tcpip_init is called.
|
||||
*/
|
||||
#define TCPIP_MBOX_SIZE 32
|
||||
#define TCPIP_MBOX_SIZE CONFIG_TCPIP_RECVMBOX_SIZE
|
||||
|
||||
/**
|
||||
* DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a
|
||||
|
@ -520,10 +520,20 @@
|
|||
---------- Statistics options ----------
|
||||
----------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* LWIP_STATS==1: Enable statistics collection in lwip_stats.
|
||||
*/
|
||||
#define LWIP_STATS 0
|
||||
#define LWIP_STATS CONFIG_LWIP_STATS
|
||||
|
||||
#if LWIP_STATS
|
||||
|
||||
/**
|
||||
* LWIP_STATS_DISPLAY==1: Compile in the statistics output functions.
|
||||
*/
|
||||
#define LWIP_STATS_DISPLAY CONFIG_LWIP_STATS
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
---------------------------------
|
||||
|
@ -674,7 +684,7 @@
|
|||
* The peer *is* in the ARP table if it requested our address before.
|
||||
* Also notice that this slows down input processing of every IP packet!
|
||||
*/
|
||||
#define ETHARP_TRUST_IP_MAC 1
|
||||
#define ETHARP_TRUST_IP_MAC CONFIG_LWIP_ETHARP_TRUST_IP_MAC
|
||||
|
||||
|
||||
/* Enable all Espressif-only options */
|
||||
|
@ -692,8 +702,8 @@
|
|||
#define ESP_IP4_ATON 1
|
||||
#define ESP_LIGHT_SLEEP 1
|
||||
#define ESP_L2_TO_L3_COPY CONFIG_L2_TO_L3_COPY
|
||||
#define ESP_STATS_MEM 0
|
||||
#define ESP_STATS_DROP 0
|
||||
#define ESP_STATS_MEM CONFIG_LWIP_STATS
|
||||
#define ESP_STATS_DROP CONFIG_LWIP_STATS
|
||||
#define ESP_STATS_TCP 0
|
||||
#define ESP_DHCP_TIMER 1
|
||||
#define ESP_LWIP_LOGI(...) ESP_LOGI("lwip", __VA_ARGS__)
|
||||
|
|
8
examples/wifi/iperf/Makefile
Executable file
8
examples/wifi/iperf/Makefile
Executable file
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := iperf
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
52
examples/wifi/iperf/README.md
Normal file
52
examples/wifi/iperf/README.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
# Iperf Example
|
||||
|
||||
This example implements the protocol used by the common performance measurement tool [iPerf](https://iperf.fr/).
|
||||
Performance can be measured between two ESP32s running this example, or between a single ESP32 and a computer running the iPerf tool
|
||||
|
||||
Demo steps to test station TCP Tx performance:
|
||||
|
||||
1. Build the iperf example with sdkconfig.defaults, which contains performance test specific configurations
|
||||
|
||||
2. Run the demo as station mode and join the target AP
|
||||
sta ssid password
|
||||
|
||||
3. Run iperf as server on AP side
|
||||
iperf -s -i 3
|
||||
|
||||
4. Run iperf as client on ESP32 side
|
||||
iperf -c 192.168.10.42 -i 3 -t 60
|
||||
|
||||
The console output, which is printed by station TCP RX throughput test, looks like:
|
||||
|
||||
>esp32> sta aptest
|
||||
>
|
||||
>I (5325) iperf: sta connecting to 'aptest'
|
||||
>
|
||||
>esp32> I (6017) event: ip: 192.168.10.248, mask: 255.255.255.0, gw: 192.168.10.1
|
||||
>
|
||||
>esp32> iperf -s -i 3 -t 1000
|
||||
>
|
||||
>I (14958) iperf: mode=tcp-server sip=192.168.10.248:5001, dip=0.0.0.0:5001, interval=3, time=1000
|
||||
>
|
||||
>Interval Bandwidth
|
||||
>
|
||||
>esp32> accept: 192.168.10.42,62958
|
||||
>
|
||||
>0- 3 sec 8.43 Mbits/sec
|
||||
>
|
||||
>3- 6 sec 36.16 Mbits/sec
|
||||
>
|
||||
>6- 9 sec 36.22 Mbits/sec
|
||||
>
|
||||
>9- 12 sec 36.44 Mbits/sec
|
||||
>
|
||||
>12- 15 sec 36.25 Mbits/sec
|
||||
>
|
||||
>15- 18 sec 24.36 Mbits/sec
|
||||
>
|
||||
>18- 21 sec 27.79 Mbits/sec
|
||||
|
||||
|
||||
Steps to test station/soft-AP TCP/UDP RX/TX throughput are similar as test steps in station TCP TX.
|
||||
|
||||
See the README.md file in the upper level 'examples' directory for more information about examples.
|
11
examples/wifi/iperf/components/component.mk
Executable file
11
examples/wifi/iperf/components/component.mk
Executable file
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# Component Makefile
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
|
||||
# this will take the sources in the src/ directory, compile them and link them into
|
||||
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
|
||||
# please read the SDK documents if you need to do this.
|
||||
#
|
||||
|
||||
#include $(IDF_PATH)/make/component_common.mk
|
||||
COMPONENT_ADD_INCLUDEDIRS := .
|
455
examples/wifi/iperf/components/iperf.c
Normal file
455
examples/wifi/iperf/components/iperf.c
Normal file
|
@ -0,0 +1,455 @@
|
|||
/* Iperf Example - iperf implementation
|
||||
|
||||
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 <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "iperf.h"
|
||||
|
||||
typedef struct {
|
||||
iperf_cfg_t cfg;
|
||||
bool finish;
|
||||
uint32_t total_len;
|
||||
uint32_t buffer_len;
|
||||
uint8_t *buffer;
|
||||
uint32_t socket;
|
||||
} iperf_ctrl_t;
|
||||
|
||||
typedef struct {
|
||||
int32_t id;
|
||||
uint32_t sec;
|
||||
uint32_t usec;
|
||||
} iperf_udp_pkt_t;
|
||||
|
||||
static bool s_iperf_is_running = false;
|
||||
static iperf_ctrl_t s_iperf_ctrl;
|
||||
static const char *TAG = "iperf";
|
||||
|
||||
inline static bool iperf_is_udp_client(void)
|
||||
{
|
||||
return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_CLIENT) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_UDP));
|
||||
}
|
||||
|
||||
inline static bool iperf_is_udp_server(void)
|
||||
{
|
||||
return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_SERVER) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_UDP));
|
||||
}
|
||||
|
||||
inline static bool iperf_is_tcp_client(void)
|
||||
{
|
||||
return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_CLIENT) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_TCP));
|
||||
}
|
||||
|
||||
inline static bool iperf_is_tcp_server(void)
|
||||
{
|
||||
return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_SERVER) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_TCP));
|
||||
}
|
||||
|
||||
int iperf_get_socket_error_code(int socket)
|
||||
{
|
||||
uint32_t optlen = sizeof(int);
|
||||
int result;
|
||||
int err;
|
||||
|
||||
err = getsockopt(socket, SOL_SOCKET, SO_ERROR, &result, &optlen);
|
||||
if (err == -1) {
|
||||
ESP_LOGE(TAG, "getsockopt failed: ret=%d", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int iperf_show_socket_error_reason(const char *str, int socket)
|
||||
{
|
||||
int err = iperf_get_socket_error_code(socket);
|
||||
|
||||
if (err != 0) {
|
||||
ESP_LOGW(TAG, "%s error, error code: %d, reason: %s", str, err, strerror(err));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void iperf_report_task(void* arg)
|
||||
{
|
||||
TickType_t delay_interval = (s_iperf_ctrl.cfg.interval * 1000)/portTICK_RATE_MS;
|
||||
uint32_t interval = s_iperf_ctrl.cfg.interval;
|
||||
uint32_t time = s_iperf_ctrl.cfg.time;
|
||||
uint32_t last_len = 0;
|
||||
uint32_t cur = 0;
|
||||
|
||||
printf("\n%16s %s\n", "Interval", "Bandwidth");
|
||||
while (!s_iperf_ctrl.finish) {
|
||||
vTaskDelay(delay_interval);
|
||||
printf("%4d-%4d sec %.2f Mbits/sec\n", cur, cur+interval, (double)((s_iperf_ctrl.total_len - last_len)*8)/interval/1e6);
|
||||
cur += interval;
|
||||
last_len = s_iperf_ctrl.total_len;
|
||||
if (cur == time) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cur != 0) {
|
||||
printf("%4d-%4d sec %.2f Mbits/sec\n", 0, time, (double)(s_iperf_ctrl.total_len*8)/cur/1e6);
|
||||
}
|
||||
|
||||
s_iperf_ctrl.finish = true;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
esp_err_t iperf_start_report(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xTaskCreate(iperf_report_task, IPERF_REPORT_TASK_NAME, IPERF_REPORT_TASK_STACK, NULL, IPERF_REPORT_TASK_PRIORITY, NULL);
|
||||
if (ret != pdPASS) {
|
||||
ESP_LOGE(TAG, "create task %s failed", IPERF_REPORT_TASK_NAME);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iperf_run_tcp_server(void)
|
||||
{
|
||||
socklen_t addr_len = sizeof(struct sockaddr);
|
||||
struct sockaddr_in remote_addr;
|
||||
struct sockaddr_in addr;
|
||||
int actual_recv = 0;
|
||||
int want_recv = 0;
|
||||
uint8_t *buffer;
|
||||
int listen_socket;
|
||||
struct timeval t;
|
||||
int socket;
|
||||
int opt;
|
||||
|
||||
listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (listen_socket < 0) {
|
||||
iperf_show_socket_error_reason("tcp server create", listen_socket);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(s_iperf_ctrl.cfg.sport);
|
||||
addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
|
||||
if (bind(listen_socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
|
||||
iperf_show_socket_error_reason("tcp server bind", listen_socket);
|
||||
close(listen_socket);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (listen(listen_socket, 5) < 0) {
|
||||
iperf_show_socket_error_reason("tcp server listen", listen_socket);
|
||||
close(listen_socket);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
iperf_start_report();
|
||||
buffer = s_iperf_ctrl.buffer;
|
||||
want_recv = s_iperf_ctrl.buffer_len;
|
||||
while (!s_iperf_ctrl.finish) {
|
||||
|
||||
/*TODO need to change to non-block mode */
|
||||
socket = accept(listen_socket, (struct sockaddr*)&remote_addr, &addr_len);
|
||||
if (socket < 0) {
|
||||
iperf_show_socket_error_reason("tcp server listen", listen_socket);
|
||||
close(listen_socket);
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
printf("accept: %s,%d\n", inet_ntoa(remote_addr.sin_addr), htons(remote_addr.sin_port));
|
||||
|
||||
t.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
|
||||
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
|
||||
}
|
||||
|
||||
while (!s_iperf_ctrl.finish) {
|
||||
actual_recv = recv(socket, buffer, want_recv, 0);
|
||||
if (actual_recv < 0) {
|
||||
iperf_show_socket_error_reason("tcp server recv", listen_socket);
|
||||
break;
|
||||
} else {
|
||||
s_iperf_ctrl.total_len += actual_recv;
|
||||
}
|
||||
}
|
||||
|
||||
close(socket);
|
||||
}
|
||||
|
||||
s_iperf_ctrl.finish = true;
|
||||
close(listen_socket);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iperf_run_udp_server(void)
|
||||
{
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in addr;
|
||||
int actual_recv = 0;
|
||||
struct timeval t;
|
||||
int want_recv = 0;
|
||||
uint8_t *buffer;
|
||||
int socket;
|
||||
int opt;
|
||||
|
||||
socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (socket < 0) {
|
||||
iperf_show_socket_error_reason("udp server create", socket);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(s_iperf_ctrl.cfg.sport);
|
||||
addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
|
||||
if (bind(socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
|
||||
iperf_show_socket_error_reason("udp server bind", socket);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(s_iperf_ctrl.cfg.sport);
|
||||
addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
|
||||
|
||||
iperf_start_report();
|
||||
buffer = s_iperf_ctrl.buffer;
|
||||
want_recv = s_iperf_ctrl.buffer_len;
|
||||
ESP_LOGI(TAG, "want recv=%d", want_recv);
|
||||
|
||||
t.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
|
||||
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
|
||||
|
||||
while (!s_iperf_ctrl.finish) {
|
||||
actual_recv = recvfrom(socket, buffer, want_recv, 0, (struct sockaddr *)&addr, &addr_len);
|
||||
if (actual_recv < 0) {
|
||||
iperf_show_socket_error_reason("udp server recv", socket);
|
||||
} else {
|
||||
s_iperf_ctrl.total_len += actual_recv;
|
||||
}
|
||||
}
|
||||
|
||||
s_iperf_ctrl.finish = true;
|
||||
close(socket);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iperf_run_udp_client(void)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
iperf_udp_pkt_t *udp;
|
||||
int actual_send = 0;
|
||||
bool retry = false;
|
||||
uint32_t delay = 1;
|
||||
int want_send = 0;
|
||||
uint8_t *buffer;
|
||||
int socket;
|
||||
int opt;
|
||||
int err;
|
||||
int id;
|
||||
|
||||
socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (socket < 0) {
|
||||
iperf_show_socket_error_reason("udp server create", socket);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = 0;
|
||||
addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
|
||||
if (bind(socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
|
||||
iperf_show_socket_error_reason("udp server bind", socket);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(s_iperf_ctrl.cfg.dport);
|
||||
addr.sin_addr.s_addr = s_iperf_ctrl.cfg.dip;
|
||||
|
||||
iperf_start_report();
|
||||
buffer = s_iperf_ctrl.buffer;
|
||||
udp = (iperf_udp_pkt_t *)buffer;
|
||||
want_send = s_iperf_ctrl.buffer_len;
|
||||
id = 0;
|
||||
|
||||
while (!s_iperf_ctrl.finish) {
|
||||
if (false == retry) {
|
||||
id ++;
|
||||
udp->id = htonl(id);
|
||||
delay = 1;
|
||||
}
|
||||
|
||||
retry = false;
|
||||
actual_send = sendto(socket, buffer, want_send, 0, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
if (actual_send != want_send) {
|
||||
err = iperf_get_socket_error_code(socket);
|
||||
if (err == ENOMEM) {
|
||||
vTaskDelay(delay);
|
||||
if (delay < IPERF_MAX_DELAY) {
|
||||
delay <<= 1;
|
||||
}
|
||||
retry = true;
|
||||
continue;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "udp client send abort: err=%d", err);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
s_iperf_ctrl.total_len += actual_send;
|
||||
}
|
||||
}
|
||||
|
||||
s_iperf_ctrl.finish = true;
|
||||
close(socket);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t iperf_run_tcp_client(void)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
int actual_send = 0;
|
||||
int want_send = 0;
|
||||
uint8_t *buffer;
|
||||
int socket;
|
||||
int opt;
|
||||
|
||||
socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (socket < 0) {
|
||||
iperf_show_socket_error_reason("tcp client create", socket);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = 0;
|
||||
addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip;
|
||||
if (bind(socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
|
||||
iperf_show_socket_error_reason("tcp client bind", socket);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(s_iperf_ctrl.cfg.dport);
|
||||
addr.sin_addr.s_addr = s_iperf_ctrl.cfg.dip;
|
||||
if (connect(socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
iperf_show_socket_error_reason("tcp client connect", socket);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
iperf_start_report();
|
||||
buffer = s_iperf_ctrl.buffer;
|
||||
want_send = s_iperf_ctrl.buffer_len;
|
||||
while (!s_iperf_ctrl.finish) {
|
||||
actual_send = send(socket, buffer, want_send, 0);
|
||||
if (actual_send <= 0) {
|
||||
vTaskDelay(1);
|
||||
} else {
|
||||
s_iperf_ctrl.total_len += actual_send;
|
||||
}
|
||||
}
|
||||
|
||||
close(socket);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void iperf_task_traffic(void *arg)
|
||||
{
|
||||
if (iperf_is_udp_client()) {
|
||||
iperf_run_udp_client();
|
||||
} else if (iperf_is_udp_server()) {
|
||||
iperf_run_udp_server();
|
||||
} else if (iperf_is_tcp_client()) {
|
||||
iperf_run_tcp_client();
|
||||
} else {
|
||||
iperf_run_tcp_server();
|
||||
}
|
||||
|
||||
if (s_iperf_ctrl.buffer) {
|
||||
free(s_iperf_ctrl.buffer);
|
||||
s_iperf_ctrl.buffer = 0;
|
||||
}
|
||||
ESP_LOGI(TAG, "iperf exit");
|
||||
s_iperf_is_running = false;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
uint32_t iperf_get_buffer_len(void)
|
||||
{
|
||||
if (iperf_is_udp_client()) {
|
||||
return IPERF_UDP_TX_LEN;
|
||||
} else if (iperf_is_udp_server()) {
|
||||
return IPERF_UDP_RX_LEN;
|
||||
} else if (iperf_is_tcp_client()) {
|
||||
return IPERF_TCP_TX_LEN;
|
||||
} else {
|
||||
return IPERF_TCP_RX_LEN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_err_t iperf_start(iperf_cfg_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!cfg) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (s_iperf_is_running) {
|
||||
ESP_LOGW(TAG, "iperf is running");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
memset(&s_iperf_ctrl, 0, sizeof(s_iperf_ctrl));
|
||||
memcpy(&s_iperf_ctrl.cfg, cfg, sizeof(*cfg));
|
||||
s_iperf_is_running = true;
|
||||
s_iperf_ctrl.finish = false;
|
||||
s_iperf_ctrl.buffer_len = iperf_get_buffer_len();
|
||||
s_iperf_ctrl.buffer = (uint8_t *)malloc(s_iperf_ctrl.buffer_len);
|
||||
if (!s_iperf_ctrl.buffer) {
|
||||
ESP_LOGE(TAG, "create buffer: out of memory");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ret = xTaskCreate(iperf_task_traffic, IPERF_TRAFFIC_TASK_NAME, IPERF_TRAFFIC_TASK_STACK, NULL, IPERF_TRAFFIC_TASK_PRIORITY, NULL);
|
||||
if (ret != pdPASS) {
|
||||
ESP_LOGE(TAG, "create task %s failed", IPERF_TRAFFIC_TASK_NAME);
|
||||
free(s_iperf_ctrl.buffer);
|
||||
s_iperf_ctrl.buffer = 0;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iperf_stop(void)
|
||||
{
|
||||
if (s_iperf_is_running) {
|
||||
s_iperf_ctrl.finish = true;
|
||||
}
|
||||
|
||||
while (s_iperf_is_running) {
|
||||
ESP_LOGI(TAG, "wait current iperf to stop ...");
|
||||
vTaskDelay(300/portTICK_RATE_MS);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
61
examples/wifi/iperf/components/iperf.h
Normal file
61
examples/wifi/iperf/components/iperf.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* Iperf Example - iperf declaration
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __IPERF_H_
|
||||
#define __IPERF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define IPERF_FLAG_CLIENT (1)
|
||||
#define IPERF_FLAG_SERVER (1<<1)
|
||||
#define IPERF_FLAG_TCP (1<<2)
|
||||
#define IPERF_FLAG_UDP (1<<3)
|
||||
|
||||
#define IPERF_DEFAULT_PORT 5001
|
||||
#define IPERF_DEFAULT_INTERVAL 3
|
||||
#define IPERF_DEFAULT_TIME 30
|
||||
|
||||
#define IPERF_TRAFFIC_TASK_NAME "iperf_traffic"
|
||||
#define IPERF_TRAFFIC_TASK_PRIORITY 19
|
||||
#define IPERF_TRAFFIC_TASK_STACK 4096
|
||||
#define IPERF_REPORT_TASK_NAME "iperf_report"
|
||||
#define IPERF_REPORT_TASK_PRIORITY 10
|
||||
#define IPERF_REPORT_TASK_STACK 4096
|
||||
#define IPERF_REPORT_TASK_NAME "iperf_report"
|
||||
|
||||
#define IPERF_UDP_TX_LEN (1472)
|
||||
#define IPERF_UDP_RX_LEN (32<<10)
|
||||
#define IPERF_TCP_TX_LEN (32<<10)
|
||||
#define IPERF_TCP_RX_LEN (64<<10)
|
||||
|
||||
#define IPERF_MAX_DELAY 64
|
||||
|
||||
#define IPERF_SOCKET_RX_TIMEOUT 10
|
||||
#define IPERF_SOCKET_ACCEPT_TIMEOUT 5
|
||||
|
||||
typedef struct {
|
||||
uint32_t flag;
|
||||
uint32_t dip;
|
||||
uint32_t sip;
|
||||
uint16_t dport;
|
||||
uint16_t sport;
|
||||
uint32_t interval;
|
||||
uint32_t time;
|
||||
} iperf_cfg_t;
|
||||
|
||||
esp_err_t iperf_start(iperf_cfg_t *cfg);
|
||||
esp_err_t iperf_stop(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
14
examples/wifi/iperf/main/cmd_decl.h
Normal file
14
examples/wifi/iperf/main/cmd_decl.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* 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
|
||||
|
||||
// Register WiFi functions
|
||||
void register_wifi(void);
|
||||
void initialise_wifi(void);
|
||||
|
381
examples/wifi/iperf/main/cmd_wifi.c
Normal file
381
examples/wifi/iperf/main/cmd_wifi.c
Normal file
|
@ -0,0 +1,381 @@
|
|||
/* 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 "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 "tcpip_adapter.h"
|
||||
#include "esp_event_loop.h"
|
||||
#include "iperf.h"
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *ip;
|
||||
struct arg_lit *server;
|
||||
struct arg_lit *udp;
|
||||
struct arg_int *port;
|
||||
struct arg_int *interval;
|
||||
struct arg_int *time;
|
||||
struct arg_lit *abort;
|
||||
struct arg_end *end;
|
||||
} wifi_iperf_t;
|
||||
static wifi_iperf_t iperf_args;
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *ssid;
|
||||
struct arg_str *password;
|
||||
struct arg_end *end;
|
||||
} wifi_args_t;
|
||||
static wifi_args_t sta_args;
|
||||
static wifi_args_t ap_args;
|
||||
static bool reconnect = true;
|
||||
static const char *TAG="iperf";
|
||||
|
||||
static EventGroupHandle_t wifi_event_group;
|
||||
const int CONNECTED_BIT = BIT0;
|
||||
const int DISCONNECTED_BIT = BIT1;
|
||||
|
||||
static esp_err_t event_handler(void *ctx, system_event_t *event)
|
||||
{
|
||||
switch(event->event_id) {
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
xEventGroupClearBits(wifi_event_group, DISCONNECTED_BIT);
|
||||
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void initialise_wifi(void)
|
||||
{
|
||||
esp_log_level_set("wifi", ESP_LOG_WARN);
|
||||
static bool initialized = false;
|
||||
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
tcpip_adapter_init();
|
||||
wifi_event_group = xEventGroupCreate();
|
||||
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
|
||||
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() );
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
static bool wifi_cmd_sta_join(const char* ssid, const char* pass)
|
||||
{
|
||||
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) {
|
||||
strncpy((char*) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password));
|
||||
}
|
||||
|
||||
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_RATE_MS);
|
||||
}
|
||||
|
||||
reconnect = true;
|
||||
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
|
||||
ESP_ERROR_CHECK( esp_wifi_connect() );
|
||||
|
||||
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, 0, 1, 5000/portTICK_RATE_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]);
|
||||
wifi_cmd_sta_join(sta_args.ssid->sval[0], sta_args.password->sval[0]);
|
||||
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;
|
||||
strncpy((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;
|
||||
}
|
||||
strncpy((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(ESP_IF_WIFI_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);
|
||||
tcpip_adapter_if_t ifx = TCPIP_ADAPTER_IF_AP;
|
||||
tcpip_adapter_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) {
|
||||
ifx = TCPIP_ADAPTER_IF_STA;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "sta has no IP");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
tcpip_adapter_get_ip_info(ifx, &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));
|
||||
|
||||
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.dip = ipaddr_addr(iperf_args.ip->sval[0]);
|
||||
cfg.flag |= IPERF_FLAG_CLIENT;
|
||||
}
|
||||
|
||||
cfg.sip = wifi_get_local_ip();
|
||||
if (cfg.sip == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (iperf_args.udp->count == 0) {
|
||||
cfg.flag |= IPERF_FLAG_TCP;
|
||||
} else {
|
||||
cfg.flag |= IPERF_FLAG_UDP;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "mode=%s-%s sip=%d.%d.%d.%d:%d, dip=%d.%d.%d.%d:%d, interval=%d, time=%d",
|
||||
cfg.flag&IPERF_FLAG_TCP?"tcp":"udp",
|
||||
cfg.flag&IPERF_FLAG_SERVER?"server":"client",
|
||||
cfg.sip&0xFF, (cfg.sip>>8)&0xFF, (cfg.sip>>16)&0xFF, (cfg.sip>>24)&0xFF, cfg.sport,
|
||||
cfg.dip&0xFF, (cfg.dip>>8)&0xFF, (cfg.dip>>16)&0xFF, (cfg.dip>>24)&0xFF, cfg.dport,
|
||||
cfg.interval, cfg.time);
|
||||
|
||||
iperf_start(&cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int restart(int argc, char** argv)
|
||||
{
|
||||
ESP_LOGI(TAG, "Restarting");
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
void register_wifi()
|
||||
{
|
||||
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) );
|
||||
|
||||
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);
|
||||
|
||||
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) );
|
||||
|
||||
const esp_console_cmd_t restart_cmd = {
|
||||
.command = "restart",
|
||||
.help = "Restart the program",
|
||||
.hint = NULL,
|
||||
.func = &restart,
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&restart_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.port = arg_int0("p", "port", "<port>", "server port to listen on/connect to");
|
||||
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.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) );
|
||||
}
|
0
examples/wifi/iperf/main/component.mk
Normal file
0
examples/wifi/iperf/main/component.mk
Normal file
136
examples/wifi/iperf/main/main.c
Normal file
136
examples/wifi/iperf/main/main.c
Normal file
|
@ -0,0 +1,136 @@
|
|||
/* Iperf Example
|
||||
|
||||
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 <errno.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "esp_console.h"
|
||||
#include "esp_vfs_dev.h"
|
||||
#include "driver/uart.h"
|
||||
#include "linenoise/linenoise.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
#include "cmd_decl.h"
|
||||
|
||||
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
|
||||
static void initialize_console()
|
||||
{
|
||||
/* Disable buffering on stdin and stdout */
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
|
||||
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
|
||||
/* Move the caret to the beginning of the next line on '\n' */
|
||||
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
|
||||
|
||||
/* Install UART driver for interrupt-driven reads and writes */
|
||||
ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM,
|
||||
256, 0, 0, NULL, 0) );
|
||||
|
||||
/* Tell VFS to use UART driver */
|
||||
esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);
|
||||
|
||||
/* Initialize the console */
|
||||
esp_console_config_t console_config = {
|
||||
.max_cmdline_args = 32,
|
||||
.max_cmdline_length = 256,
|
||||
#if CONFIG_LOG_COLORS
|
||||
.hint_color = atoi(LOG_COLOR_CYAN)
|
||||
#endif
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_init(&console_config) );
|
||||
|
||||
/* Configure linenoise line completion library */
|
||||
/* Enable multiline editing. If not set, long commands will scroll within
|
||||
* single line.
|
||||
*/
|
||||
linenoiseSetMultiLine(1);
|
||||
|
||||
/* Tell linenoise where to get command completions and hints */
|
||||
linenoiseSetCompletionCallback(&esp_console_get_completion);
|
||||
linenoiseSetHintsCallback((linenoiseHintsCallback*) &esp_console_get_hint);
|
||||
|
||||
/* Set command history size */
|
||||
linenoiseHistorySetMaxLen(100);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
initialise_wifi();
|
||||
initialize_console();
|
||||
|
||||
/* Register commands */
|
||||
esp_console_register_help_command();
|
||||
register_wifi();
|
||||
|
||||
/* Prompt to be printed before each line.
|
||||
* This can be customized, made dynamic, etc.
|
||||
*/
|
||||
const char* prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
|
||||
|
||||
printf("\n ==================================================\n");
|
||||
printf(" | Steps to test WiFi throughput |\n");
|
||||
printf(" | |\n");
|
||||
printf(" | 1. Print 'help' to gain overview of commands |\n");
|
||||
printf(" | 2. Configure device to station or soft-AP |\n");
|
||||
printf(" | 3. Setup WiFi connection |\n");
|
||||
printf(" | 4. Run iperf to test UDP/TCP RX/TX throughput |\n");
|
||||
printf(" | |\n");
|
||||
printf(" =================================================\n\n");
|
||||
|
||||
/* Figure out if the terminal supports escape sequences */
|
||||
int probe_status = linenoiseProbe();
|
||||
if (probe_status) { /* zero indicates success */
|
||||
printf("\n"
|
||||
"Your terminal application does not support escape sequences.\n"
|
||||
"Line editing and history features are disabled.\n"
|
||||
"On Windows, try using Putty instead.\n");
|
||||
linenoiseSetDumbMode(1);
|
||||
#if CONFIG_LOG_COLORS
|
||||
/* Since the terminal doesn't support escape sequences,
|
||||
* don't use color codes in the prompt.
|
||||
*/
|
||||
prompt = "esp32> ";
|
||||
#endif //CONFIG_LOG_COLORS
|
||||
}
|
||||
|
||||
/* Main loop */
|
||||
while(true) {
|
||||
/* Get a line using linenoise.
|
||||
* The line is returned when ENTER is pressed.
|
||||
*/
|
||||
char* line = linenoise(prompt);
|
||||
if (line == NULL) { /* Ignore empty lines */
|
||||
continue;
|
||||
}
|
||||
/* Add the command to the history */
|
||||
linenoiseHistoryAdd(line);
|
||||
|
||||
/* Try to run the command */
|
||||
int ret;
|
||||
esp_err_t err = esp_console_run(line, &ret);
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
printf("Unrecognized command\n");
|
||||
} else if (err == ESP_OK && ret != ESP_OK) {
|
||||
printf("Command returned non-zero error code: 0x%x\n", ret);
|
||||
} else if (err != ESP_OK) {
|
||||
printf("Internal error: 0x%x\n", err);
|
||||
}
|
||||
/* linenoise allocates line buffer on the heap, so need to free it */
|
||||
linenoiseFree(line);
|
||||
}
|
||||
}
|
||||
|
23
examples/wifi/iperf/sdkconfig.defaults
Normal file
23
examples/wifi/iperf/sdkconfig.defaults
Normal file
|
@ -0,0 +1,23 @@
|
|||
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
|
||||
CONFIG_MEMMAP_SMP=y
|
||||
|
||||
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=16
|
||||
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=64
|
||||
CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=64
|
||||
CONFIG_ESP32_WIFI_TX_BA_WIN=16
|
||||
CONFIG_ESP32_WIFI_RX_BA_WIN=16
|
||||
|
||||
CONFIG_FREERTOS_UNICORE=
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
|
||||
CONFIG_INT_WDT=
|
||||
CONFIG_TASK_WDT=
|
||||
|
||||
CONFIG_TCP_SND_BUF_DEFAULT=65535
|
||||
CONFIG_TCP_WND_DEFAULT=65535
|
||||
CONFIG_TCP_RECVMBOX_SIZE=64
|
||||
CONFIG_UDP_RECVMBOX_SIZE=64
|
||||
CONFIG_TCPIP_RECVMBOX_SIZE=64
|
||||
CONFIG_LWIP_ETHARP_TRUST_IP_MAC=
|
||||
|
Loading…
Reference in a new issue