Przeglądaj źródła

socket-example: Add tcp client example for multiple interfaces

Liu Han 6 lat temu
rodzic
commit
547210f7a5

+ 10 - 0
examples/protocols/sockets/tcp_client_multi_net/CMakeLists.txt

@@ -0,0 +1,10 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+# (Not part of the boilerplate)
+# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
+set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(tcp_client_multiple)

+ 11 - 0
examples/protocols/sockets/tcp_client_multi_net/Makefile

@@ -0,0 +1,11 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := tcp_client_multiple
+
+EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
+
+include $(IDF_PATH)/make/project.mk
+

+ 133 - 0
examples/protocols/sockets/tcp_client_multi_net/README.md

@@ -0,0 +1,133 @@
+# Multiple Ethernet Example
+(See the README.md file in the upper level 'examples' directory for more information about examples.)
+
+## Overview
+
+This example demonstrates basic usage of Ethernet interface and WiFi station together. The workflow of the example could be as follow:
+
+1. Connects to both WiFi and Ethernet using common-connect component
+2. Starts two tasks, one for each interface to resolve configured host name and connect to it periodically
+3. Connection to host endpoint is handled by:
+    - creating a socket as TCP client
+    - binding it to the related interface (Ethernet of WiFi)
+    - send and receive a trivial HTTP request and response
+
+If you have a new multiple interface application to go (for example, connect to IoT cloud via Ethernet and WiFi), try this as a basic template, then add your own code.
+
+## How to use example
+
+### Hardware Required
+
+To run this example, you need to have one ESP32 development board integrated with an Ethernet interface, for example, ESP32-Ethernet-Kit, or just connect your ESP32-DevkitC board to a breakout board which features RMII Ethernet PHY.
+
+### Configure the project
+
+Enter project configuration by `idf.py menuconfig` (or `make menuconfig` if using legacy GNU Make build system) and navigate into:
+
+* `Example Connection Configuration` menu to choose the connection details:
+
+    - Enter SSID and password for WiFi connection
+    - Set Ethernet type and configuration for Ethernet connection
+    - Note that the project is preconfigured to have both WiFi and Ethernet interface enabled by default
+    - See the [README.md](../../README.md) for more details about common example connection component
+
+* `Example Configuration` menu:
+
+    - Set host name and port for the tcp_client to connect to
+
+### Build and Flash
+
+Run `idf.py -p PORT flash monitor` to build and flash the project..
+
+(To exit the serial monitor, type ``Ctrl-]``.)
+
+See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
+
+## Example Output
+
+```bash
+I (695) example_connect: Connecting to DavidsAP...
+I (795) phy: phy_version: 4180, cb3948e, Sep 12 2019, 16:39:13, 0, 0
+I (795) wifi:mode : sta (30:ae:a4:c6:b4:f8)
+W (795) event: handler already registered, overwriting
+I (815) esp_eth.netif.glue: 30:ae:a4:c6:b4:fb
+I (815) esp_eth.netif.glue: ethernet attached to netif
+I (825) example_connect: Waiting for IP(s)
+I (1525) wifi:new:<6,0>, old:<1,0>, ap:<255,255>, sta:<6,0>, prof:1
+I (2295) wifi:state: init -> auth (b0)
+I (2295) wifi:state: auth -> assoc (0)
+I (2305) wifi:state: assoc -> run (10)
+I (2315) wifi:connected with DavidsAP, aid = 2, channel 6, BW20, bssid = 16:f7:28:37:58:36
+I (2315) wifi:security type: 3, phy: bgn, rssi: -35
+I (2315) wifi:pm start, type: 1
+
+I (2325) wifi:AP's beacon interval = 102400 us, DTIM period = 3
+I (3125) esp_netif_handlers: example_connect: sta ip: 192.168.2.15, mask: 255.255.255.0, gw: 192.168.2.1
+I (3125) example_connect: Interface desciption example_connect: sta
+I (3135) example_connect: Interface "example_connect: sta" got IPv4 address: 192.168.2.15
+I (3625) example_connect: Interface "example_connect: sta" got IPv6 address: fe80:0000:0000:0000:32ae:a4ff:fec6:b4f8, type: ESP_IP6_ADDR_IS_LINK_LOCAL
+I (4825) example_connect: Ethernet Link Up
+I (5625) esp_netif_handlers: example_connect: eth ip: 192.168.32.148, mask: 255.255.252.0, gw: 192.168.32.3
+I (5625) example_connect: Interface desciption example_connect: eth
+I (5635) example_connect: Interface "example_connect: eth" got IPv4 address: 192.168.32.148
+I (6625) example_connect: Interface "example_connect: eth" got IPv6 address: fe80:0000:0000:0000:32ae:a4ff:fec6:b4fb, type: ESP_IP6_ADDR_IS_LINK_LOCAL
+I (6625) example_connect: Connected to example_connect: eth
+I (6635) example_connect: - IPv4 address: 192.168.32.148
+I (6635) example_connect: - IPv6 address: fe80:0000:0000:0000:32ae:a4ff:fec6:b4fbtype: ESP_IP6_ADDR_IS_LINK_LOCAL
+I (6645) example_connect: Connected to example_connect: sta
+I (6655) example_connect: - IPv4 address: 192.168.2.15
+I (6655) example_connect: - IPv6 address: fe80:0000:0000:0000:32ae:a4ff:fec6:b4f8type: ESP_IP6_ADDR_IS_LINK_LOCAL
+I (6675) example_connect: Connected to Ethernet
+I (6675) tcp_client_multiple: netif described as "sta" corresponds to esp-netif ptr:0x3ffba3ac
+I (6675) tcp_client_multiple: netif described as "eth" corresponds to esp-netif ptr:0x3ffc608c
+I (6895) tcp_client_multiple: "example_connect: eth" Socket created
+I (6895) tcp_client_multiple: "example_connect: sta" Socket created
+I (6895) tcp_client_multiple: "example_connect: eth" Successfully connected
+I (6905) tcp_client_multiple: "example_connect: sta" Successfully connected
+I (6965) tcp_client_multiple: "example_connect: eth" Received Data 127 bytes
+I (6965) tcp_client_multiple: HTTP/1.1 200 OK
+Date: Thu, 23 Apr 2020 07:02:58 GMT
+Expires: -1
+Cache-Control: private, max-age=0
+Content-Type: text/html; 
+I (6965) tcp_client_multiple: "example_connect: sta" Received Data 127 bytes
+I (6985) tcp_client_multiple: HTTP/1.1 200 OK
+Date: Thu, 23 Apr 2020 07:02:58 GMT
+Expires: -1
+Cache-Control: private, max-age=0
+Content-Type: text/html; 
+I (7675) tcp_client_multiple: "example_connect: eth" Socket created
+I (7675) tcp_client_multiple: "example_connect: eth" Successfully connected
+I (7695) tcp_client_multiple: "example_connect: sta" Socket created
+I (7705) tcp_client_multiple: "example_connect: sta" Successfully connected
+I (7735) tcp_client_multiple: "example_connect: eth" Received Data 127 bytes
+I (7735) tcp_client_multiple: HTTP/1.1 200 OK
+Date: Thu, 23 Apr 2020 07:02:59 GMT
+Expires: -1
+Cache-Control: private, max-age=0
+Content-Type: text/html; 
+I (7955) tcp_client_multiple: "example_connect: sta" Received Data 127 bytes
+I (7955) tcp_client_multiple: HTTP/1.1 200 OK
+Date: Thu, 23 Apr 2020 07:02:59 GMT
+Expires: -1
+Cache-Control: private, max-age=0
+Content-Type: text/html; 
+I (8445) tcp_client_multiple: "example_connect: eth" Socket created
+I (8445) tcp_client_multiple: "example_connect: eth" Successfully connected
+I (8505) tcp_client_multiple: "example_connect: eth" Received Data 127 bytes
+I (8505) tcp_client_multiple: HTTP/1.1 200 OK
+Date: Thu, 23 Apr 2020 07:03:00 GMT
+Expires: -1
+Cache-Control: private, max-age=0
+Content-Type: text/html; 
+I (8675) tcp_client_multiple: "example_connect: sta" Socket created
+```
+
+## Troubleshooting
+
+* When connecting using Ethernet, please consult troubleshooting described in [Ethernet common readme](../../../ethernet/README.md)
+or [Ethernet documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_eth.html).
+If using Ethernet for the first time, it is recommended to start with the [Ethernet example readme](../../../ethernet/basic/README.md), which contains instructions for connecting and configuring the PHY. 
+Once Ethernet example obtains IP address successfully, proceed to this example.
+
+* When connecting using Wi-Fi, please refer to the WiFi examples in [examples/wifi/getting_started/](../wifi/getting_started).

+ 2 - 0
examples/protocols/sockets/tcp_client_multi_net/main/CMakeLists.txt

@@ -0,0 +1,2 @@
+idf_component_register(SRCS "tcp_client_multiple.c"
+                    INCLUDE_DIRS ".")

+ 16 - 0
examples/protocols/sockets/tcp_client_multi_net/main/Kconfig.projbuild

@@ -0,0 +1,16 @@
+menu "Example Configuration"
+
+    config EXAMPLE_HOST_NAME
+        string "Host Name"
+        default "baidu.com"
+        help
+            host name
+
+    config EXAMPLE_HOST_PORT
+        int "Host Port"
+        default 80
+        range 0 65535
+        help
+            host port
+
+endmenu

+ 4 - 0
examples/protocols/sockets/tcp_client_multi_net/main/component.mk

@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

+ 144 - 0
examples/protocols/sockets/tcp_client_multi_net/main/tcp_client_multiple.c

@@ -0,0 +1,144 @@
+/* multiple network interface 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 <string.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_netif.h"
+#include "esp_eth.h"
+#include "esp_event.h"
+#include "esp_log.h"
+#include "sdkconfig.h"
+#include "nvs_flash.h"
+#include "esp_netif.h"
+#include <sys/socket.h>
+#include <netdb.h>
+#include "protocol_examples_common.h"
+
+static const char *TAG = "tcp_client_multiple";
+
+#define HOST_NAME CONFIG_EXAMPLE_HOST_NAME
+#define HOST_IP_PORT CONFIG_EXAMPLE_HOST_PORT
+
+static const char *payload = "GET / HTTP/1.1\r\n\r\n";
+
+static void app_multiple_handle(esp_ip4_addr_t *ip4_addr, esp_netif_t *esp_netif)
+{
+    esp_netif_ip_info_t ip;
+    char rx_buffer[128] = {0};
+    const char *netif_name = esp_netif_get_desc(esp_netif);
+
+    /* Create a socket */
+    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+    if (sock < 0) {
+        ESP_LOGE(TAG, "\"%s\" Unable to create socket: errno %d", netif_name, errno);
+        goto app_multiple_handle_fail;
+    }
+    ESP_LOGI(TAG, "\"%s\" Socket created", netif_name);
+
+    /* Bind local IP of the network interface */
+    memset(&ip, 0, sizeof(esp_netif_ip_info_t));
+    ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif, &ip));
+
+    struct sockaddr_in addr;
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(0);
+    addr.sin_addr.s_addr = ip.ip.addr;
+            
+    int ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
+    if (ret < 0) {
+        ESP_LOGE(TAG, "\"%s\" Unable to bind socket: errno %d", netif_name, errno);
+        goto app_multiple_handle_fail;
+    }
+
+    /* Connect to the host by the network interface */
+    struct sockaddr_in destAddr;
+    destAddr.sin_addr.s_addr = ip4_addr->addr;
+    destAddr.sin_family = AF_INET;
+    destAddr.sin_port = htons(HOST_IP_PORT);
+    ret = connect(sock, (struct sockaddr *)&destAddr, sizeof(destAddr));
+    if (ret != 0) {
+        ESP_LOGE(TAG, "\"%s\" Socket unable to connect: errno %d", netif_name, errno);
+        goto app_multiple_handle_fail;
+    }
+    ESP_LOGI(TAG, "\"%s\" Successfully connected", netif_name);
+
+    ret = send(sock, payload, strlen(payload), 0);
+    if (ret < 0) {
+        ESP_LOGE(TAG, "\"%s\" Error occured during sending: errno %d", netif_name, errno);
+        goto app_multiple_handle_fail;
+    }
+
+    ret = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
+    if (ret < 0) {
+        ESP_LOGE(TAG, "\"%s\" Error occured during receiving: errno %d", netif_name, errno);
+    } else if (ret > 0){
+        rx_buffer[ret] = 0; // Null-terminate whatever we received and treat like a string
+        ESP_LOGI(TAG, "\"%s\" Received Data %d bytes", netif_name, ret);
+        ESP_LOGI(TAG, "%s", rx_buffer);
+    } else {
+        ESP_LOGE(TAG, "\"%s\" Closed connection during receiving", netif_name);
+    }
+
+app_multiple_handle_fail:
+    close(sock); 
+}
+
+static void app_connection_task(void *pvParameters)
+{
+    esp_ip4_addr_t ip4_addr;
+    const char *netif_desc = pvParameters;
+
+    esp_netif_t *netif = get_example_netif_from_desc(netif_desc);
+    ESP_LOGD(TAG, "netif described as \"%s\" corresponds to esp-netif ptr:%p", netif_desc, netif);
+    while(netif) {
+        /* Wait for the host name to get */
+        const struct addrinfo hints = {
+                .ai_family = AF_INET,
+                .ai_socktype = SOCK_STREAM,
+        };
+        struct addrinfo *res;
+
+        int err = getaddrinfo(HOST_NAME, NULL, &hints, &res);
+        if(err != 0 || res == NULL) {
+            ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
+            break;
+        }
+        memcpy(&ip4_addr, &((struct sockaddr_in *)(res->ai_addr))->sin_addr, sizeof(ip4_addr));
+        freeaddrinfo(res);
+
+        /* Connect the host using the corresponding network interface */
+        app_multiple_handle(&ip4_addr, netif);
+        
+        vTaskDelay(500 / portTICK_PERIOD_MS);
+    }
+    ESP_LOGE(TAG, "%s with netif desc:%s Failed! exiting", __func__, netif_desc);
+    vTaskDelete(NULL);
+}
+
+void app_main(void)
+{
+    //Initialize NVS
+    esp_err_t ret = nvs_flash_init();
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+      ESP_ERROR_CHECK(nvs_flash_erase());
+      ret = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK(ret);
+
+    esp_netif_init();
+
+    ESP_ERROR_CHECK(esp_event_loop_create_default());
+
+    ESP_ERROR_CHECK(example_connect());
+
+    xTaskCreate(&app_connection_task, "app_ethernet_task", 4096, "eth", 5, NULL);
+    xTaskCreate(&app_connection_task, "app_wifi_task", 4096, "sta", 5, NULL);
+}

+ 2 - 0
examples/protocols/sockets/tcp_client_multi_net/sdkconfig.defaults

@@ -0,0 +1,2 @@
+CONFIG_EXAMPLE_CONNECT_WIFI=y
+CONFIG_EXAMPLE_CONNECT_ETHERNET=y