From bbbdcbfe4cbaad32fc1c5218fa4daacf0152fa8c Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 26 Nov 2019 16:45:37 +0100 Subject: [PATCH] esp_netif: update netsuite test example to use I/O driver configuration closes https://github.com/espressif/esp-idf/issues/4403 --- examples/system/network_tests/README.md | 8 +- .../system/network_tests/main/CMakeLists.txt | 2 +- .../network_tests/main/lwip_test_netif.c | 123 ------------- .../system/network_tests/main/net_suite.c | 93 ++-------- examples/system/network_tests/main/stdinout.c | 166 ++++++++++++++++++ examples/system/network_tests/main/stdinout.h | 36 ++++ 6 files changed, 220 insertions(+), 208 deletions(-) delete mode 100644 examples/system/network_tests/main/lwip_test_netif.c create mode 100644 examples/system/network_tests/main/stdinout.c create mode 100644 examples/system/network_tests/main/stdinout.h diff --git a/examples/system/network_tests/README.md b/examples/system/network_tests/README.md index 3c2581972b..9dd2c6caa9 100644 --- a/examples/system/network_tests/README.md +++ b/examples/system/network_tests/README.md @@ -14,7 +14,7 @@ Note: TTCN3 engine works reliably only on Linux and Windows. ## Setup TTCN3 -* Clone a repository https://github.com/intel/net-test-suites.git and install titan core a described in the README.md +* Clone a repository https://github.com/intel/net-test-suites.git and install titan core as described in the README.md * Copy files `esp32_netsuite.cfg` and `esp32_netsuite.ttcn` (located in `$IDF_PATH/components/lwip/weekend_test`) to `src` subdir of the cloned repository `net-test-suites` * Rebuild the netsuite tests (according to README.md in net-test-suite) by executing `source make.sh` in `src` subdir @@ -43,7 +43,7 @@ ttcn3_start test_suite esp32_netsuite.cfg Purpose of this test is to execute standard network suite on a ESP32 network stack. -DUT (Network stack under test) runs normally on target, but a specific interface `TCPIP_ADAPTER_IF_TEST` was created for passing arbitrary data to +DUT, Device (Network stack in this case) under test, runs normally on target, but a specific interface with configured esp-netif for passing arbitrary data to and from the network stack. Embedded code `net_suite.c` implements an application which serves stdin/stdout and propagates the data to/from this test interface. Standard Intel net suite executed by TTCN3 engine uses udp ports for input/ouput of network packets. Python script `net_suite.py` translates this communication @@ -58,8 +58,8 @@ Actual test execution, progress, evaluation and test reporting is done using sta | TTCN3 engine | | +----------------------------------+ | | | | | net_suite.c | | | +-----------------+ +--------------+ | | | +------------------------+ | -| | net-test-suite |--7777/udp--| net_suite.py |--stdout---------| -----> | tcpip_adapter/lwip | | -| | |--7771/udp--| |--stdin----------| <----- | TCPIP_ADAPTER_IF_TEST | | +| | net-test-suite |--7777/udp--| net_suite.py |--stdout---------| -----> | esp_netif / lwip | | +| | |--7771/udp--| |--stdin----------| <----- | | | | +-----------------+ +--------------+ | | +---------+------------------------+ | +---------------------------------------------------------+ +----------------------------------------+ ``` diff --git a/examples/system/network_tests/main/CMakeLists.txt b/examples/system/network_tests/main/CMakeLists.txt index db11fd0532..f06cf4bf61 100644 --- a/examples/system/network_tests/main/CMakeLists.txt +++ b/examples/system/network_tests/main/CMakeLists.txt @@ -1,2 +1,2 @@ -idf_component_register(SRCS "net_suite.c" "lwip_test_netif.c" +idf_component_register(SRCS "net_suite.c" "stdinout.c" INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/system/network_tests/main/lwip_test_netif.c b/examples/system/network_tests/main/lwip_test_netif.c deleted file mode 100644 index 859e518bb6..0000000000 --- a/examples/system/network_tests/main/lwip_test_netif.c +++ /dev/null @@ -1,123 +0,0 @@ -/* Net-suite test code: lwip netif API for creating test interface - - 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 "lwip/opt.h" - -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/pbuf.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "lwip/ethip6.h" -#include "netif/etharp.h" -#include "netif/wlanif.h" - -#include "esp_netif.h" - -#include -#include - -static struct netif *g_last_netif = NULL; - -// LWIP netif specific defines -struct esp_netif_netstack_config { - err_t (*init_fn)(struct netif*); - void (*input_fn)(struct netif *netif, void *buffer, size_t len, void *eb); -}; - -err_t testnetif_init(struct netif *netif); - -void testnetif_input(struct netif *netif, void *buffer, size_t len, void *eb); - -const struct esp_netif_netstack_config _g_test_netif_stack_config = { testnetif_init, testnetif_input}; - -err_t testnetif_output(struct netif *netif, struct pbuf *p) -{ - int i; - char *dat = p->payload; - - /* output the packet to stdout */ - printf("\nPacketOut:["); - for (i=0; ilen; i++) { - printf("%02x", *dat++); - } - printf("]\n"); - - return ERR_OK; -} - - -err_t testnetif_init(struct netif *netif) -{ - - g_last_netif = netif; - - netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME; - - /* - * Initialize the snmp variables and counters inside the struct netif. - * The last argument should be replaced with your link speed, in units - * of bits per second. - */ - NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100); - - /* We directly use etharp_output() here to save a function call. - * You can instead declare your own function an call etharp_output() - * from it if you have to do some checks before sending (e.g. if link - * is available...) */ - netif->output = etharp_output; -#if LWIP_IPV6 - netif->output_ip6 = ethip6_output; -#endif /* LWIP_IPV6 */ - netif->linkoutput = testnetif_output; - /* set MAC hardware address length */ - netif->hwaddr_len = ETHARP_HWADDR_LEN; - - /* set MAC hardware address */ - - /* maximum transfer unit */ - netif->mtu = 1500; - - /* device capabilities */ - /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ - netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; - -#if ESP_LWIP - #if LWIP_IGMP - netif->flags |= NETIF_FLAG_IGMP; -#endif -#endif - return ERR_OK; - -} - -void testnetif_input(struct netif *netif, void *buffer, size_t len, void *eb) -{ - struct pbuf *p; - if (g_last_netif == NULL) { - printf("error!"); - return; - } - - printf("simul in: %d\n", len); - if (len==0) return; - - p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM); - p->l2_owner = NULL; - memcpy(p->payload, buffer, len); - - /* full packet send to tcpip_thread to process - * on success - the packet is processed and deallocated in tcpip stack - * on failure - log error and deallocate the packet - */ - if (g_last_netif->input(p, g_last_netif) != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); - pbuf_free(p); - } - -} diff --git a/examples/system/network_tests/main/net_suite.c b/examples/system/network_tests/main/net_suite.c index 09bb037237..f9831f618d 100644 --- a/examples/system/network_tests/main/net_suite.c +++ b/examples/system/network_tests/main/net_suite.c @@ -7,28 +7,14 @@ CONDITIONS OF ANY KIND, either express or implied. */ #include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/event_groups.h" -#include "esp_system.h" -#include "esp_wifi.h" #include "esp_event.h" #include "esp_log.h" -#include "nvs_flash.h" -#include "driver/uart.h" -#include "esp_console.h" -#include "esp_vfs_dev.h" -#include "linenoise/linenoise.h" - +#include "stdinout.h" #include "lwip/err.h" -#include "lwip/sys.h" #include "lwip/debug.h" -#include "lwip/stats.h" #include "lwip/tcp.h" -extern const struct esp_netif_netstack_config _g_test_netif_stack_config; - -/* these data configures ARP cache so the test IPs are knows */ +/* these test data are used to populate the ARP cache so the IPs are known */ static char arp1[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x02, @@ -94,43 +80,6 @@ void test_tcp_init(void) } } -/** - * @brief Process line read from serial input, character by character - * - * Converts from hex string to byte stream, so it can be processed - * in test network interface - * - * @param line - * @param packet - * - * @return size of packet - */ -static size_t process_line(char* line, char* packet) -{ - size_t count = 0; - size_t i; - - for (i=0; i< strlen(line); i++) { - char c = line[i]; - // accept both separators between bytes - if (c == '-' || c == ' ') { - ++count; - // Processing numeric characters - } else if (c >= '0' && c <= '9') { - packet[count] *= 16; - packet[count] += c - '0'; - // Processing alpha-numeric hex characters - } else if (c >= 'a' && c <= 'f') { - packet[count] *= 16; - packet[count] += c - 'a' + 10; - } - } - - if (i>0 && strlen(line)>0) { - count++; - } - return count; -} void app_main(void) { @@ -143,22 +92,24 @@ void app_main(void) esp_netif_inherent_config_t netif_common_config = { .flags = ESP_NETIF_FLAG_AUTOUP, .ip_info = (esp_netif_ip_info_t*)&ip_info, + .if_key = "TEST", + .if_desc = "net_test_if" }; esp_netif_set_ip4_addr(&ip_info.ip, 10, 0 , 0, 1); esp_netif_set_ip4_addr(&ip_info.gw, 10, 0 , 0, 1); esp_netif_set_ip4_addr(&ip_info.netmask, 255, 255 , 255, 0); esp_netif_config_t config = { - .base = &netif_common_config, - .stack = &_g_test_netif_stack_config, - .driver = NULL + .base = &netif_common_config, // use specific behaviour configuration + .stack = ESP_NETIF_NETSTACK_DEFAULT_WIFI_STA, // use default WIFI-like network stack configuration }; - // Netif creation and configure + // Netif creation and configuration // esp_netif_init(); esp_netif_t* netif = esp_netif_new(&config); assert(netif); + esp_netif_attach(netif, netsuite_io_new()); // Start the netif in a manual way, no need for events // @@ -169,33 +120,15 @@ void app_main(void) test_tcp_init(); // Inject ARP packet to let the network stack know about IP/MAC of the counterpart esp_netif_receive(netif, arp1, sizeof(arp1), NULL); - // Initialize VFS & UART so we can use std::cout/cin - setvbuf(stdin, NULL, _IONBF, 0); - setvbuf(stdout, NULL, _IONBF, 0); - /* Install UART driver for interrupt-driven reads and writes */ - ESP_ERROR_CHECK( uart_driver_install( (uart_port_t)CONFIG_ESP_CONSOLE_UART_NUM, - 256, 0, 0, NULL, 0) ); - /* Tell VFS to use UART driver */ - esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); - 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); - linenoiseSetDumbMode(1); /* Now read from stdin and pass the data to test netif */ while (1) { - size_t size; - char* line = linenoise(""); - if (!line) { - continue; + /* read one packet from the I/O object */ + ssize_t len = netsuite_io_get_packet(packet, sizeof(packet)); + if (len > 0) { + /* input the packet to esp-netif */ + esp_netif_receive(netif, packet, len, NULL); } - - size = process_line(line, packet); - - esp_netif_receive(netif, packet, size, NULL); - - - linenoiseFree(line); } } diff --git a/examples/system/network_tests/main/stdinout.c b/examples/system/network_tests/main/stdinout.c new file mode 100644 index 0000000000..f10280d152 --- /dev/null +++ b/examples/system/network_tests/main/stdinout.c @@ -0,0 +1,166 @@ +// Copyright 2019 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 "esp_netif.h" +#include "esp_log.h" +#include "driver/uart.h" +#include "esp_console.h" +#include "esp_vfs_dev.h" +#include "linenoise/linenoise.h" + +// +// Internal functions declaration referenced in io object +// +static esp_err_t netsuite_io_transmit(void *h, void *buffer, size_t len); +static esp_err_t netsuite_io_attach(esp_netif_t * esp_netif, void * args); + +/** + * @brief IO object netif related configuration with data-path function callbacks + * and pointer to the IO object instance (unused as this is a singleton) + */ +const esp_netif_driver_ifconfig_t c_driver_ifconfig = { + .driver_free_rx_buffer = NULL, + .transmit = netsuite_io_transmit, + .handle = "netsuite-io-object" // this IO object is a singleton, its handle uses as a name +}; + +/** + * @brief IO object base structure used to point to internal attach function + */ +const esp_netif_driver_base_t s_driver_base = { + .post_attach = netsuite_io_attach +}; + +/** + * @brief Transmit function called from esp_netif to output network stack data + * + * Note: This API has to conform to esp-netif transmit prototype + * + * @param h Opaque pointer representing the io driver (unused, const string in this case) + * @param data data buffer + * @param length length of data to send + * + * @return ESP_OK on success + */ +static esp_err_t netsuite_io_transmit(void *h, void *buffer, size_t len) +{ + /* output the packet to stdout */ + char *data = buffer; + printf("\nPacketOut:["); + for (size_t i=0; i= '0' && c <= '9') { + packet[count] *= 16; + packet[count] += c - '0'; + // Processing alpha-numeric hex characters + } else if (c >= 'a' && c <= 'f') { + packet[count] *= 16; + packet[count] += c - 'a' + 10; + } + } + + if (i>0 && strlen(line)>0) { + count++; + } + return count; +} + +/** + * Created (initializes) the i/o object and returns handle ready to be attached to the esp-netif + */ +void * netsuite_io_new(void) +{ + // Initialize VFS & UART so we can use std::cout/cin + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + /* Install UART driver for interrupt-driven reads and writes */ + ESP_ERROR_CHECK( uart_driver_install( (uart_port_t)CONFIG_ESP_CONSOLE_UART_NUM, + 256, 0, 0, NULL, 0) ); + /* Tell VFS to use UART driver */ + esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); + 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); + linenoiseSetDumbMode(1); + return (void *)&s_driver_base; +} + +/** + * I/O receive function + */ +ssize_t netsuite_io_get_packet(char *packet, size_t max_len) +{ + size_t size; + + /* read packet from stdin */ + char* line = linenoise(""); + if (!line) { + return -1; + } + + /* convert to binary */ + size = process_line(line, packet); + + if (size > max_len) { + return -1; + } + + linenoiseFree(line); + + return size; +} diff --git a/examples/system/network_tests/main/stdinout.h b/examples/system/network_tests/main/stdinout.h new file mode 100644 index 0000000000..2b779a6de3 --- /dev/null +++ b/examples/system/network_tests/main/stdinout.h @@ -0,0 +1,36 @@ +// Copyright 2019 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. + +#ifndef _NET_SUITE_STDINOUT_H +#define _NET_SUITE_STDINOUT_H + +/** + * @brief Gets one packet from stdin + * + * @param packet ptr to the packet buffer + * @param max_len maximum size of allocated data buffer + * + * @return actual size of received packet (-1 in case of error) + */ + +ssize_t netsuite_io_get_packet(char *packet, size_t max_len); + +/** + * @brief Initializes the I/O object handle to be attached to esp-netif instance + * + * @return I/O object pointer + */ +void * netsuite_io_new(void); + +#endif //_NET_SUITE_STDINOUT_H