diff --git a/examples/performance/README.md b/examples/performance/README.md new file mode 100644 index 000000000..d53a8de78 --- /dev/null +++ b/examples/performance/README.md @@ -0,0 +1,44 @@ +# Wifi Performance Examples + +Some simple codes help to test the wifi performance. + +Including TCP/UDP TX/RX throughput. + +# tcp_perf + +This example is used to test tcp throughput and delay time. + +Step1: Set options in `make menuconfig` like ssid, password, server ip and server port. And choose what the esp32 will work as. + +* AP or STA. You can set one esp32 as AP and another esp32 as STA with same ssid & password, also you can use Router or wifi adapter instead of one of these. + +* Client or server. Make sure the client has correct server ip & port so they can get connected. It's okay if you create a tcp server & client using PC since one of the wifi device is't esp32. + +* Send or receive. Set one of them sending data and the other receiving. + +Step2: Exit menuconfig, saving the new settings. Then build the app and flash it to the ESP32. + +Step3: Start test. And here are some things that might help you do the test easily. + +* You'd better turn on the AP before the STA. +* The tcp server should be started before the tcp client. +* If you use a esp32 as AP, you'd better use it as tcp server also. +* Once the tcp connection crashed, esp32 should be restarted to re-establish TCP connection. + +Step4: View the result. After connection established, TCP server and TCP client can send data to each other. The result of throughput will be printed in the serial log. + +See [main.c](./tcp_perf/main/main.c) for full details. + +# udp_perf + +This example is similar to tcp_perf. Also the steps is similar to tcp_perf. + +There's a obvious difference between udp_perf and tcp perf: + +Before formal sending & receiving, a packet will be send from client to server. So the server can know the ip&port of client. It is usually eaiser to set the UDP server as the receiver. + +See [main.c](./udp_perf/main/main.c) for full details. + +# More + +See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples. diff --git a/examples/performance/tcp_perf/Makefile b/examples/performance/tcp_perf/Makefile new file mode 100644 index 000000000..03fb85528 --- /dev/null +++ b/examples/performance/tcp_perf/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := tcp_perf + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/performance/tcp_perf/main/Kconfig.projbuild b/examples/performance/tcp_perf/main/Kconfig.projbuild new file mode 100644 index 000000000..92bf8387f --- /dev/null +++ b/examples/performance/tcp_perf/main/Kconfig.projbuild @@ -0,0 +1,118 @@ +menu "Example Configuration" + +#choice +# prompt "TCP_PERF_MODE " +# default MODE_TCP_SHIELDBOX +# help +# This option set performance mode. +# +# - Testing in shieldbox for "Performance in shieldbox" setting. +# +# - Testing in air for "Performance in air" setting. +# +# - Testing in long distance for "Performance in long distance" setting. +# +# +#config MODE_TCP_SHIELDBOX +# bool "Performance in shieldbox" +#config MODE_TCP_AIR +# bool "Performance in air" +#config MODE_TCP_LONG_DISTANCE +# bool "Performance in long distance" +#endchoice + +choice TCP_PERF_WIFI_MODE + prompt "AP or STA" + default TCP_PERF_ESP_IS_STATION + help + Whether the esp32 is softAP or station. + +config TCP_PERF_ESP_IS_SOFTAP + bool "SoftAP" +config TCP_PERF_ESP_IS_STATION + bool "Station" +endchoice + +config TCP_PERF_WIFI_MODE_AP + bool + default y if TCP_PERF_ESP_IS_SOFTAP + default n if TCP_PERF_ESP_IS_STATION + +choice TCP_PERF_SERVER_CLIENT + prompt "server or client" + default TCP_PERF_ESP_IS_CLIENT + help + Whether the esp32 is tcp server or client. + + We suggest to choose "client" if you choose "station" in "wifi mode". + +config TCP_PERF_ESP_IS_SERVER + bool "server" +config TCP_PERF_ESP_IS_CLIENT + bool "client" +endchoice + +config TCP_PERF_SERVER + bool + default y if TCP_PERF_ESP_IS_SERVER + default n if TCP_PERF_ESP_IS_CLIENT + +choice TCP_PERF_TX_RX + prompt "send or receive" + default TCP_PERF_ESP_RECV + help + Whether the esp32 will send or receive. + +config TCP_PERF_ESP_SEND + bool "send" +config TCP_PERF_ESP_RECV + bool "receive" +endchoice + +config TCP_PERF_TX + bool + default y if TCP_PERF_ESP_SEND + default n if TCP_PERF_ESP_RECV + +config TCP_PERF_DELAY_DEBUG + bool "TCP performance delay info enable" + depends on TCP_PERF_TX + default n + help + Show TCP performance delay info. + + Ignore in TCP RX. + +config TCP_PERF_WIFI_SSID + string "WiFi SSID" + default "esp_wifi_test1" + help + SSID (network name) for the example to connect to. + +config TCP_PERF_WIFI_PASSWORD + string "WiFi Password" + default "1234567890" + help + WiFi password (WPA or WPA2) for the example to use. + +config TCP_PERF_SERVER_PORT + int "TCP server port" + default 4567 + help + Which will the tcp server use. + +config TCP_PERF_SERVER_IP + string "TCP server ip" + default "192.168.4.1" + help + IP of TCP server. + + Ignore in TCP server. + +config TCP_PERF_PKT_SIZE + int "Size of TCP packet" + default 1460 + help + the data send&recv packet size. + +endmenu diff --git a/examples/performance/tcp_perf/main/component.mk b/examples/performance/tcp_perf/main/component.mk new file mode 100644 index 000000000..61f8990c3 --- /dev/null +++ b/examples/performance/tcp_perf/main/component.mk @@ -0,0 +1,8 @@ +# +# Main component makefile. +# +# This Makefile can be left empty. By default, it 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 ESP-IDF documents if you need to do this. +# diff --git a/examples/performance/tcp_perf/main/tcp_main.c b/examples/performance/tcp_perf/main/tcp_main.c new file mode 100644 index 000000000..fbb65c0f0 --- /dev/null +++ b/examples/performance/tcp_perf/main/tcp_main.c @@ -0,0 +1,110 @@ + + +/* +tcp_perf example + +Using this example to test tcp throughput performance. +esp<->esp or esp<->ap + +step1: + init wifi as AP/STA using config SSID/PASSWORD. + +step2: + create a tcp server/client socket using config PORT/(IP). + if server: wating for connect. + if client connect to server. +step3: + send/receive data to/from each other. + if the tcp connect established. esp will send or receive data. + you can see the info in serial output. +*/ + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_err.h" + +#include "tcp_perf.h" + + + +//this task establish a TCP connection and receive data from TCP +static void tcp_conn(void *pvParameters) +{ + ESP_LOGI(TAG, "task tcp_conn start."); + /*wating for connecting to AP*/ + do + { + vTaskDelay(100); + } + while (!connectedflag); + ESP_LOGI(TAG, "sta has connected to ap."); + + /*create tcp socket*/ + int socket_ret; + +#if ESP_TCP_MODE_SERVER + vTaskDelay(3000 / portTICK_RATE_MS); + ESP_LOGI(TAG, "create_tcp_server."); + socket_ret=create_tcp_server(); +#else /*ESP_TCP_MODE_SERVER*/ + vTaskDelay(20000 / portTICK_RATE_MS); + ESP_LOGI(TAG, "create_tcp_client."); + socket_ret = create_tcp_client(); +#endif + if(ESP_FAIL == socket_ret) { + ESP_LOGI(TAG, "create tcp socket error,stop."); + vTaskDelete(NULL); + } + + /*create a task to tx/rx data*/ + TaskHandle_t tx_rx_task; +#if ESP_TCP_PERF_TX + xTaskCreate(&send_data, "send_data", 4096, NULL, 4, &tx_rx_task); +#else /*ESP_TCP_PERF_TX*/ + xTaskCreate(&recv_data, "recv_data", 4096, NULL, 4, &tx_rx_task); +#endif + int pps; + while (1) { + total_data = 0; + vTaskDelay(3000 / portTICK_RATE_MS);//every 3s + pps = total_data / 3; + if (total_data <= 0) { + int err_ret = check_socket_error_code(); + if (err_ret == ECONNRESET) { + ESP_LOGI(TAG, "disconnected... stop."); + break; + } + } + +#if ESP_TCP_PERF_TX + ESP_LOGI(TAG, "tcp send %d byte per sec!", pps); +#if ESP_TCP_DELAY_INFO + ESP_LOGI(TAG, "tcp send packet total:%d succeed:%d failed:%d\n" + "time(ms):0-30:%d 30-100:%d 100-300:%d 300-1000:%d 1000+:%d\n", + total_pack, send_success, send_fail, delay_classify[0], + delay_classify[1], delay_classify[2], delay_classify[3], delay_classify[4]); +#endif /*ESP_TCP_DELAY_INFO*/ +#else + ESP_LOGI(TAG, "tcp recv %d byte per sec!\n", pps); +#endif /*ESP_TCP_PERF_TX*/ + } + close_socket(); + vTaskDelete(tx_rx_task); + vTaskDelete(NULL); +} + + + +void app_main(void) +{ +#if ESP_WIFI_MODE_AP + ESP_LOGI(TAG, "ESP_WIFI_MODE_AP\n"); + wifi_init_softap(); +#else /*ESP_WIFI_MODE_AP*/ + ESP_LOGI(TAG, "ESP_WIFI_MODE_STA\n"); + wifi_init_sta(); +#endif + xTaskCreate(&tcp_conn, "tcp_conn", 4096, NULL, 5, NULL); +} diff --git a/examples/performance/tcp_perf/main/tcp_perf.c b/examples/performance/tcp_perf/main/tcp_perf.c new file mode 100644 index 000000000..0b8447ee9 --- /dev/null +++ b/examples/performance/tcp_perf/main/tcp_perf.c @@ -0,0 +1,339 @@ +// Copyright 2013-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" +#include "esp_log.h" + + +#include "tcp_perf.h" + +/*socket*/ +static int server_socket = 0; +static struct sockaddr_in server_addr; +static struct sockaddr_in client_addr; +static unsigned int socklen = sizeof(client_addr); +static int connect_socket = 0; + +int connectedflag = 0; +int total_data = 0; + +#if ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO + +int total_pack = 0; +int send_success = 0; +int send_fail = 0; +int delay_classify[5] = { 0 }; + +#endif /*ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO*/ + + +static esp_err_t event_handler(void *ctx, system_event_t *event) +{ + switch(event->event_id) { + case SYSTEM_EVENT_STA_START: + esp_wifi_connect(); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + esp_wifi_connect(); + break; + case SYSTEM_EVENT_STA_CONNECTED: + break; + case SYSTEM_EVENT_STA_GOT_IP: + ESP_LOGI(TAG, "event_handler:SYSTEM_EVENT_STA_GOT_IP!"); + ESP_LOGI(TAG, "got ip:%s\n", + ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip)); + connectedflag = 1; + break; + case SYSTEM_EVENT_AP_STACONNECTED: + ESP_LOGI(TAG, "station:"MACSTR" join,AID=%d\n", + MAC2STR(event->event_info.sta_connected.mac), + event->event_info.sta_connected.aid); + connectedflag = 1; + break; + case SYSTEM_EVENT_AP_STADISCONNECTED: + ESP_LOGI(TAG, "station:"MACSTR"leave,AID=%d\n", + MAC2STR(event->event_info.sta_disconnected.mac), + event->event_info.sta_disconnected.aid); + connectedflag = 0; + break; + default: + break; + } + return ESP_OK; +} + +//send data +void send_data(void *pvParameters) +{ + int len = 0; + char databuff[DEFAULT_PKTSIZE]; + memset(databuff, PACK_BYTE_IS, DEFAULT_PKTSIZE); + vTaskDelay(100/portTICK_RATE_MS); + ESP_LOGI(TAG, "start sending..."); +#if ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO + //delaytime + struct timeval tv_start; + struct timeval tv_finish; + unsigned long send_delay_ms; +#endif /*ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO*/ + while(1) { + +#if ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO + total_pack++; + gettimeofday(&tv_start, NULL); +#endif /*ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO*/ + + //send function + len = send(connect_socket, databuff, DEFAULT_PKTSIZE, 0); + +#if ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO + gettimeofday(&tv_finish, NULL); +#endif /*ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO*/ + if(len > 0) { + total_data += len; + +#if ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO + send_success++; + send_delay_ms = (tv_finish.tv_sec - tv_start.tv_sec) * 1000 + + (tv_finish.tv_usec - tv_start.tv_usec) / 1000; + if(send_delay_ms < 30) + delay_classify[0]++; + else if(send_delay_ms < 100) + delay_classify[1]++; + else if(send_delay_ms < 300) + delay_classify[2]++; + else if(send_delay_ms < 1000) + delay_classify[3]++; + else + delay_classify[4]++; +#endif /*ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO*/ + + }/*if(len > 0)*/ + else { + +#if ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO + send_fail++; +#endif /*ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO*/ + + /*Most of the error code will be send window full. + *So, for faster sending,don't show error code. + *if it can't work as expectations,unnote the two lines here. + **/ + //show_socket_error_code(connect_socket); + //vTaskDelay(500/portTICK_RATE_MS); + } + } +} +//receive data +void recv_data(void *pvParameters) +{ + int len = 0; + char databuff[DEFAULT_PKTSIZE]; + while (1) { + len = recv(connect_socket, databuff, DEFAULT_PKTSIZE, 0); + if (len > 0) { + total_data += len; + } + else { + show_socket_error_code(connect_socket); + vTaskDelay(500 / portTICK_RATE_MS); + } + } +} + + +//use this esp32 as a tcp server. return ESP_OK:success ESP_FAIL:error +esp_err_t create_tcp_server() +{ + ESP_LOGI(TAG, "server socket....port=%d\n", DEFAULT_PORT); + server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (server_socket < 0) { + show_socket_error_code(server_socket); + return ESP_FAIL; + } + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(DEFAULT_PORT); + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { + show_socket_error_code(server_socket); + close(server_socket); + return ESP_FAIL; + } + if (listen(server_socket, 5) < 0) { + show_socket_error_code(server_socket); + close(server_socket); + return ESP_FAIL; + } + connect_socket = accept(server_socket, (struct sockaddr*)&client_addr, &socklen); + if (connect_socket<0) { + show_socket_error_code(connect_socket); + close(server_socket); + return ESP_FAIL; + } + /*connection established,now can send/recv*/ + ESP_LOGI(TAG, "tcp connection established!"); + return ESP_OK; +} +//use this esp32 as a tcp client. return ESP_OK:success ESP_FAIL:error +esp_err_t create_tcp_client() +{ + ESP_LOGI(TAG, "client socket....serverip:port=%s:%d\n", + DEFAULT_SERVER_IP, DEFAULT_PORT); + connect_socket = socket(AF_INET, SOCK_STREAM, 0); + if (connect_socket < 0) { + show_socket_error_code(connect_socket); + return ESP_FAIL; + } + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(DEFAULT_PORT); + server_addr.sin_addr.s_addr = inet_addr(DEFAULT_SERVER_IP); + ESP_LOGI(TAG, "connecting to server..."); + if (connect(connect_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + show_socket_error_code(connect_socket); + return ESP_FAIL; + } + ESP_LOGI(TAG, "connect to server success!"); + return ESP_OK; +} + +//wifi_init_sta +void wifi_init_sta() +{ + tcpip_adapter_init(); + 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)); + wifi_config_t wifi_config = { + .sta = { + .ssid = DEFAULT_SSID, + .password = DEFAULT_PWD + }, + }; + + 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_start() ); + + ESP_LOGI(TAG, "wifi_init_sta finished."); + ESP_LOGI(TAG, "connect to ap SSID:%s password:%s \n", + DEFAULT_SSID,DEFAULT_PWD); +} +//wifi_init_softap +void wifi_init_softap() +{ + tcpip_adapter_init(); + 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)); + wifi_config_t wifi_config = { + .ap = { + .ssid = DEFAULT_SSID, + .ssid_len = 0, + .max_connection=MAX_STA_CONN, + .password = DEFAULT_PWD, + .authmode = WIFI_AUTH_WPA_WPA2_PSK + }, + }; + if (strlen(DEFAULT_PWD) ==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)); + ESP_ERROR_CHECK(esp_wifi_start()); + + ESP_LOGI(TAG, "wifi_init_softap finished.SSID:%s password:%s \n", + DEFAULT_SSID, DEFAULT_PWD); +} + + + + +char* tcpip_get_reason(int err) +{ + switch (err) { + case 0: + return "reason: other reason"; + case ENOMEM: + return "reason: out of memory"; + case ENOBUFS: + return "reason: buffer error"; + case EWOULDBLOCK: + return "reason: timeout, try again"; + case EHOSTUNREACH: + return "reason: routing problem"; + case EINPROGRESS: + return "reason: operation in progress"; + case EINVAL: + return "reason: invalid value"; + case EADDRINUSE: + return "reason: address in use"; + case EALREADY: + return "reason: conn already connected"; + case EISCONN: + return "reason: conn already established"; + case ECONNABORTED: + return "reason: connection aborted"; + case ECONNRESET: + return "reason: connection is reset"; + case ENOTCONN: + return "reason: connection closed"; + case EIO: + return "reason: invalid argument"; + case -1: + return "reason: low level netif error"; + default: + return "reason not found"; + } +} + +int show_socket_error_code(int socket) +{ + int result; + u32_t optlen = sizeof(int); + getsockopt(socket, SOL_SOCKET, SO_ERROR, &result, &optlen); + ESP_LOGI(TAG, "socket error %d reason: %s", result, tcpip_get_reason(result)); + return result; +} + +int check_socket_error_code() +{ + int ret; +#if ESP_TCP_MODE_SERVER + ESP_LOGI(TAG, "check server_socket"); + ret = show_socket_error_code(server_socket); + if(ret == ECONNRESET) + return ret; +#endif + ESP_LOGI(TAG, "check connect_socket"); + ret = show_socket_error_code(connect_socket); + if(ret == ECONNRESET) + return ret; + return 0; +} + +void close_socket() +{ + close(connect_socket); + close(server_socket); +} + + diff --git a/examples/performance/tcp_perf/main/tcp_perf.h b/examples/performance/tcp_perf/main/tcp_perf.h new file mode 100644 index 000000000..e29215b5b --- /dev/null +++ b/examples/performance/tcp_perf/main/tcp_perf.h @@ -0,0 +1,70 @@ +#ifndef __TCP_PERF_H__ +#define __TCP_PERF_H__ + + + +#ifdef __cplusplus +extern "C" { +#endif + +/*AP info and tcp_server info*/ +#define DEFAULT_SSID CONFIG_TCP_PERF_WIFI_SSID +#define DEFAULT_PWD CONFIG_TCP_PERF_WIFI_PASSWORD +#define DEFAULT_PORT CONFIG_TCP_PERF_SERVER_PORT +#define DEFAULT_SERVER_IP CONFIG_TCP_PERF_SERVER_IP +#define DEFAULT_PKTSIZE CONFIG_TCP_PERF_PKT_SIZE +#define MAX_STA_CONN 1 //how many sta can be connected(AP mode) +/*test options*/ +#define ESP_WIFI_MODE_AP CONFIG_TCP_PERF_WIFI_MODE_AP //TRUE:AP FALSE:STA +#define ESP_TCP_MODE_SERVER CONFIG_TCP_PERF_SERVER //TRUE:server FALSE:client +#define ESP_TCP_PERF_TX CONFIG_TCP_PERF_TX //TRUE:send FALSE:receive +#define ESP_TCP_DELAY_INFO CONFIG_TCP_PERF_DELAY_DEBUG //TRUE:show delay time info + + +#define PACK_BYTE_IS 97 //'a' +#define TAG "tcp_perf:" + + +extern int connectedflag; +extern int total_data; + +#if ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO +extern int total_pack; +extern int send_success; +extern int send_fail; +extern int delay_classify[5]; +#endif/*ESP_TCP_PERF_TX && ESP_TCP_DELAY_INFO*/ + + +//using esp as station +void wifi_init_sta(); +//using esp as softap +void wifi_init_softap(); + +//create a tcp server socket. return ESP_OK:success ESP_FAIL:error +esp_err_t create_tcp_server(); +//create a tcp client socket. return ESP_OK:success ESP_FAIL:error +esp_err_t create_tcp_client(); + +//send data task +void send_data(void *pvParameters); +//receive data task +void recv_data(void *pvParameters); + +//close all socket +void close_socket(); + +//show socket error code. return: error code +int show_socket_error_code(int socket); + +//check working socket +int check_socket_error_code(); + + +#ifdef __cplusplus +} +#endif + + +#endif /*#ifndef __TCP_PERF_H__*/ + diff --git a/examples/performance/udp_perf/Makefile b/examples/performance/udp_perf/Makefile new file mode 100644 index 000000000..97d6eaa13 --- /dev/null +++ b/examples/performance/udp_perf/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := udp_perf + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/performance/udp_perf/main/Kconfig.projbuild b/examples/performance/udp_perf/main/Kconfig.projbuild new file mode 100644 index 000000000..72d40cb98 --- /dev/null +++ b/examples/performance/udp_perf/main/Kconfig.projbuild @@ -0,0 +1,111 @@ +menu "Example Configuration" + +#choice +# prompt "UDP_PERF_MODE " +# default MODE_UDP_SHIELDBOX +# help +# This option set performance mode. +# +# - Testing in shieldbox for "Performance in shieldbox" setting. +# +# - Testing in air for "Performance in air" setting. +# +# - Testing in long distance for "Performance in long distance" setting. +# +# +#config MODE_UDP_SHIELDBOX +# bool "Performance in shieldbox" +#config MODE_UDP_AIR +# bool "Performance in air" +#config MODE_UDP_LONG_DISTANCE +# bool "Performance in long distance" +#endchoice +# + +choice UDP_PERF_WIFI_MODE + prompt "AP or STA" + default UDP_PERF_ESP_IS_STATION + help + Whether the esp32 is softAP or station. + +config UDP_PERF_ESP_IS_SOFTAP + bool "SoftAP" +config UDP_PERF_ESP_IS_STATION + bool "Station" +endchoice + +config UDP_PERF_WIFI_MODE_AP + bool + default y if UDP_PERF_ESP_IS_SOFTAP + default n if UDP_PERF_ESP_IS_STATION + +choice UDP_PERF_SERVER_CLIENT + prompt "server or client" + default UDP_PERF_ESP_IS_CLIENT + help + Whether the esp32 is tcp server or client. + + We suggest to choose "client" if you choose "station" in "wifi mode". + +config UDP_PERF_ESP_IS_SERVER + bool "server" +config UDP_PERF_ESP_IS_CLIENT + bool "client" +endchoice + +config UDP_PERF_SERVER + bool + default y if UDP_PERF_ESP_IS_SERVER + default n if UDP_PERF_ESP_IS_CLIENT + +choice UDP_PERF_TX_RX + prompt "send or receive" + default UDP_PERF_ESP_RECV + help + Whether the esp32 will send or receive. + +config UDP_PERF_ESP_SEND + bool "send" +config UDP_PERF_ESP_RECV + bool "receive" +endchoice + +config UDP_PERF_TX + bool + default y if UDP_PERF_ESP_SEND + default n if UDP_PERF_ESP_RECV + + +config UDP_PERF_WIFI_SSID + string "WiFi SSID" + default "esp_wifi_test1" + help + SSID (network name) for the example to connect to. + +config UDP_PERF_WIFI_PASSWORD + string "WiFi Password" + default "1234567890" + help + WiFi password (WPA or WPA2) for the example to use. + +config UDP_PERF_SERVER_PORT + int "UDP server port" + default 4567 + help + Which will the udp server use. + +config UDP_PERF_SERVER_IP + string "UDP server ip" + default "192.168.4.1" + help + IP of UDP server. + + Ignore in UDP server. + +config UDP_PERF_PKT_SIZE + int "Size of UDP packet" + default 1460 + help + the data send&recv packet size. + +endmenu diff --git a/examples/performance/udp_perf/main/component.mk b/examples/performance/udp_perf/main/component.mk new file mode 100644 index 000000000..61f8990c3 --- /dev/null +++ b/examples/performance/udp_perf/main/component.mk @@ -0,0 +1,8 @@ +# +# Main component makefile. +# +# This Makefile can be left empty. By default, it 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 ESP-IDF documents if you need to do this. +# diff --git a/examples/performance/udp_perf/main/udp_main.c b/examples/performance/udp_perf/main/udp_main.c new file mode 100644 index 000000000..60f59e9b3 --- /dev/null +++ b/examples/performance/udp_perf/main/udp_main.c @@ -0,0 +1,93 @@ + + +/* +udp_perf example + +Using this example to test udp throughput performance. +esp<->esp or esp<->ap + +step1: + init wifi as AP/STA using config SSID/PASSWORD. + +step2: + create a udp server/client socket using config PORT/(IP). + if server: wating for the first message of client. + if client: sending a packet to server first. + +step3: + send/receive data to/from each other. + you can see the info in serial output. +*/ + + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_err.h" + +#include "udp_perf.h" + + +//this task establish a UDP connection and receive data from UDP +static void udp_conn(void *pvParameters) +{ + ESP_LOGI(TAG, "task udp_conn start."); + /*wating for connecting to AP*/ + do + { + vTaskDelay(100); + } + while (!connectedflag); + ESP_LOGI(TAG, "sta has connected to ap."); + + /*create udp socket*/ + int socket_ret; + +#if ESP_UDP_MODE_SERVER + vTaskDelay(3000 / portTICK_RATE_MS); + ESP_LOGI(TAG, "create_udp_server."); + socket_ret=create_udp_server(); +#else /*ESP_UDP_MODE_SERVER*/ + vTaskDelay(20000 / portTICK_RATE_MS); + ESP_LOGI(TAG, "create_udp_client."); + socket_ret = create_udp_client(); +#endif + if(ESP_FAIL == socket_ret) { + ESP_LOGI(TAG, "create udp socket error,stop."); + vTaskDelete(NULL); + } + + /*create a task to tx/rx data*/ + TaskHandle_t tx_rx_task; + xTaskCreate(&send_recv_data, "send_recv_data", 4096, NULL, 4, &tx_rx_task); + + int pps; + while (1) { + total_data = 0; + vTaskDelay(3000 / portTICK_RATE_MS);//every 3s + pps = total_data / 3; + +#if ESP_UDP_PERF_TX + ESP_LOGI(TAG, "udp send %d byte per sec! total pack: %d \n", pps, success_pack); +#else + ESP_LOGI(TAG, "udp recv %d byte per sec! total pack: %d \n", pps, success_pack); +#endif /*ESP_UDP_PERF_TX*/ + } + close_socket(); + vTaskDelete(tx_rx_task); + vTaskDelete(NULL); +} + + + +void app_main(void) +{ +#if ESP_WIFI_MODE_AP + ESP_LOGI(TAG, "ESP_WIFI_MODE_AP\n"); + wifi_init_softap(); +#else /*ESP_WIFI_MODE_AP*/ + ESP_LOGI(TAG, "ESP_WIFI_MODE_STA\n"); + wifi_init_sta(); +#endif + xTaskCreate(&udp_conn, "udp_conn", 4096, NULL, 5, NULL); +} diff --git a/examples/performance/udp_perf/main/udp_perf.c b/examples/performance/udp_perf/main/udp_perf.c new file mode 100644 index 000000000..22a55ad90 --- /dev/null +++ b/examples/performance/udp_perf/main/udp_perf.c @@ -0,0 +1,270 @@ +// Copyright 2013-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" +#include "esp_log.h" + + +#include "udp_perf.h" + + + +static int mysocket; + +static struct sockaddr_in remote_addr; +static unsigned int socklen; + +int connectedflag = 0; +int total_data = 0; +int success_pack = 0; + + +static esp_err_t event_handler(void *ctx, system_event_t *event) +{ + switch(event->event_id) { + case SYSTEM_EVENT_STA_START: + esp_wifi_connect(); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + esp_wifi_connect(); + break; + case SYSTEM_EVENT_STA_CONNECTED: + break; + case SYSTEM_EVENT_STA_GOT_IP: + ESP_LOGI(TAG, "event_handler:SYSTEM_EVENT_STA_GOT_IP!"); + ESP_LOGI(TAG, "got ip:%s\n", + ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip)); + connectedflag=1; + break; + case SYSTEM_EVENT_AP_STACONNECTED: + ESP_LOGI(TAG, "station:"MACSTR" join,AID=%d\n", + MAC2STR(event->event_info.sta_connected.mac), + event->event_info.sta_connected.aid); + connectedflag=1; + break; + case SYSTEM_EVENT_AP_STADISCONNECTED: + ESP_LOGI(TAG, "station:"MACSTR"leave,AID=%d\n", + MAC2STR(event->event_info.sta_disconnected.mac), + event->event_info.sta_disconnected.aid); + break; + default: + break; + } + return ESP_OK; +} + + +//wifi_init_sta +void wifi_init_sta() +{ + tcpip_adapter_init(); + 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)); + wifi_config_t wifi_config = { + .sta = { + .ssid = DEFAULT_SSID, + .password = DEFAULT_PWD + }, + }; + + 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_start() ); + + ESP_LOGI(TAG, "wifi_init_sta finished."); + ESP_LOGI(TAG, "connect to ap SSID:%s password:%s \n", + DEFAULT_SSID,DEFAULT_PWD); +} +//wifi_init_softap +void wifi_init_softap() +{ + tcpip_adapter_init(); + 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)); + wifi_config_t wifi_config = { + .ap = { + .ssid = DEFAULT_SSID, + .ssid_len=0, + .max_connection=MAX_STA_CONN, + .password = DEFAULT_PWD, + .authmode=WIFI_AUTH_WPA_WPA2_PSK + }, + }; + if (strlen(DEFAULT_PWD) ==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)); + ESP_ERROR_CHECK(esp_wifi_start()); + + ESP_LOGI(TAG, "wifi_init_softap finished.SSID:%s password:%s \n", + DEFAULT_SSID, DEFAULT_PWD); +} + +//create a udp server socket. return ESP_OK:success ESP_FAIL:error +esp_err_t create_udp_server() +{ + ESP_LOGI(TAG, "create_udp_server()"); + mysocket = socket(AF_INET, SOCK_DGRAM, 0); + if (mysocket < 0) { + show_socket_error_code(mysocket); + return ESP_FAIL; + } + struct sockaddr_in server_addr; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(DEFAULT_PORT); + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(mysocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + show_socket_error_code(mysocket); + close(mysocket); + return ESP_FAIL; + } + return ESP_OK; +} + +//create a udp client socket. return ESP_OK:success ESP_FAIL:error +esp_err_t create_udp_client() +{ + ESP_LOGI(TAG, "create_udp_client()"); + mysocket = socket(AF_INET, SOCK_DGRAM, 0); + if (mysocket < 0) { + show_socket_error_code(mysocket); + return ESP_FAIL; + } + /*for client remote_addr is also server_addr*/ + remote_addr.sin_family = AF_INET; + remote_addr.sin_port = htons(DEFAULT_PORT); + remote_addr.sin_addr.s_addr = inet_addr(DEFAULT_SERVER_IP); + + return ESP_OK; +} + + +//send or recv data task +void send_recv_data(void *pvParameters) +{ + ESP_LOGI(TAG, "task send_recv_data start!\n"); + + int len; + char databuff[DEFAULT_PKTSIZE]; + + /*send&receive first packet*/ + socklen = sizeof(remote_addr); + memset(databuff, PACK_BYTE_IS, DEFAULT_PKTSIZE); +#if ESP_UDP_MODE_SERVER + ESP_LOGI(TAG, "first recvfrom:"); + len = recvfrom(mysocket, databuff, DEFAULT_PKTSIZE, 0, (struct sockaddr *)&remote_addr, &socklen); +#else + ESP_LOGI(TAG, "first sendto:"); + len = sendto(mysocket, databuff, DEFAULT_PKTSIZE, 0, (struct sockaddr *)&remote_addr, sizeof(remote_addr)); +#endif + + if (len > 0) { + ESP_LOGI(TAG, "transfer data with %s:%u\n", + inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port)); + } else { + show_socket_error_code(mysocket); + close(mysocket); + vTaskDelete(NULL); + } + +#if ESP_UDP_PERF_TX + vTaskDelay(500 / portTICK_RATE_MS); +#endif + ESP_LOGI(TAG, "start count!\n"); + while(1) + { + /*you can add delay time for fixed-frequency*/ + //vTaskDelay(5 / portTICK_RATE_MS); +#if ESP_UDP_PERF_TX + len = sendto(mysocket, databuff, DEFAULT_PKTSIZE, 0, (struct sockaddr *)&remote_addr, sizeof(remote_addr)); +#else + len = recvfrom(mysocket, databuff, DEFAULT_PKTSIZE, 0, (struct sockaddr *)&remote_addr, &socklen); +#endif + if (len > 0) { + total_data += len; + success_pack++; + } else { + //show_socket_error_code(mysocket); + /*you'd better turn off watch dog in menuconfig + *Component config->ESP32-specific->Task watchdog. + **/ + //vTaskDelay(1/portTICK_RATE_MS); + } + } +} + + +char* tcpip_get_reason(int err) +{ + switch (err) { + case 0: + return "reason: other reason"; + case ENOMEM: + return "reason: out of memory"; + case ENOBUFS: + return "reason: buffer error"; + case EWOULDBLOCK: + return "reason: timeout, try again"; + case EHOSTUNREACH: + return "reason: routing problem"; + case EINPROGRESS: + return "reason: operation in progress"; + case EINVAL: + return "reason: invalid value"; + case EADDRINUSE: + return "reason: address in use"; + case EALREADY: + return "reason: conn already connected"; + case EISCONN: + return "reason: conn already established"; + case ECONNABORTED: + return "reason: connection aborted"; + case ECONNRESET: + return "reason: connection is reset"; + case ENOTCONN: + return "reason: connection closed"; + case EIO: + return "reason: invalid argument"; + case -1: + return "reason: low level netif error"; + default: + return "reason not found"; + } +} + +int show_socket_error_code(int socket) +{ + int result; + u32_t optlen = sizeof(int); + getsockopt(socket, SOL_SOCKET, SO_ERROR, &result, &optlen); + ESP_LOGI(TAG, "socket error %d reason: %s", result, tcpip_get_reason(result)); + return result; +} + + +void close_socket() +{ + close(mysocket); +} diff --git a/examples/performance/udp_perf/main/udp_perf.h b/examples/performance/udp_perf/main/udp_perf.h new file mode 100644 index 000000000..0f8221559 --- /dev/null +++ b/examples/performance/udp_perf/main/udp_perf.h @@ -0,0 +1,60 @@ +#ifndef __UDP_PERF_H__ +#define __UDP_PERF_H__ + + + +#ifdef __cplusplus +extern "C" { +#endif + +/*AP info and tcp_server info*/ +#define DEFAULT_SSID CONFIG_UDP_PERF_WIFI_SSID +#define DEFAULT_PWD CONFIG_UDP_PERF_WIFI_PASSWORD +#define DEFAULT_PORT CONFIG_UDP_PERF_SERVER_PORT +#define DEFAULT_SERVER_IP CONFIG_UDP_PERF_SERVER_IP +#define DEFAULT_PKTSIZE CONFIG_UDP_PERF_PKT_SIZE +#define MAX_STA_CONN 1 //how many sta can be connected(AP mode) +/*test options*/ +#define ESP_WIFI_MODE_AP CONFIG_UDP_PERF_WIFI_MODE_AP //TRUE:AP FALSE:STA +#define ESP_UDP_MODE_SERVER CONFIG_UDP_PERF_SERVER //TRUE:server FALSE:client +#define ESP_UDP_PERF_TX CONFIG_UDP_PERF_TX //TRUE:send FALSE:receive +#define PACK_BYTE_IS 97 //'a' + +#define TAG "udp_perf:" + + +extern int connectedflag; +extern int total_data; +extern int success_pack; + + +//using esp as station +void wifi_init_sta(); +//using esp as softap +void wifi_init_softap(); + +//create a udp server socket. return ESP_OK:success ESP_FAIL:error +esp_err_t create_udp_server(); +//create a udp client socket. return ESP_OK:success ESP_FAIL:error +esp_err_t create_udp_client(); + +//send or recv data task +void send_recv_data(void *pvParameters); + +//show socket error code. return: error code +int show_socket_error_code(int socket); + +//close all socket +void close_socket(); + + + + + +#ifdef __cplusplus +} +#endif + + +#endif /*#ifndef __UDP_PERF_H__*/ +