esp_netif: update netsuite test example to use I/O driver configuration

closes https://github.com/espressif/esp-idf/issues/4403
This commit is contained in:
David Cermak 2019-11-26 16:45:37 +01:00 committed by bot
parent f7b51c164d
commit bbbdcbfe4c
6 changed files with 220 additions and 208 deletions

View file

@ -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----------| <----- | | |
| +-----------------+ +--------------+ | | +---------+------------------------+ |
+---------------------------------------------------------+ +----------------------------------------+
```

View file

@ -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 ".")

View file

@ -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 <stdio.h>
#include <string.h>
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; i<p->len; 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);
}
}

View file

@ -7,28 +7,14 @@
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#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);
}
}

View file

@ -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<len; i++) {
printf("%02x", *data++);
}
printf("]\n");
return ESP_OK;
}
/**
* @brief Post attach adapter for netsuite i/o
*
* Used to exchange internal callbacks and context between esp-netif and the I/O object.
* In case of netsuite I/O, it only updates the driver config with internal callbacks and
* its instance pointer (const string in this case)
*
* @param esp_netif handle to esp-netif object
* @param args pointer to netsuite IO
*
* @return ESP_OK on success
*/
static esp_err_t netsuite_io_attach(esp_netif_t * esp_netif, void * args)
{
ESP_ERROR_CHECK(esp_netif_set_driver_config(esp_netif, &c_driver_ifconfig));
return ESP_OK;
}
/**
* @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;
}
/**
* 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;
}

View file

@ -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