Merge branch 'feature/net_test_suite' into 'master'

execute net test suite for esp32 network stack in ci as weekend tests

Closes IDF-210

See merge request idf/esp-idf!3439
This commit is contained in:
Angus Gratton 2019-06-06 15:25:03 +08:00
commit 19f176eb71
18 changed files with 645 additions and 1 deletions

View file

@ -1084,6 +1084,23 @@ test_weekend_mqtt:
ENV_FILE: "$CI_PROJECT_DIR/components/mqtt/weekend_test/env.yml"
CONFIG_FILE: "$CI_PROJECT_DIR/components/mqtt/weekend_test/config.yml"
test_weekend_network:
<<: *example_test_template
stage: target_test
image: $CI_DOCKER_REGISTRY/rpi-net-suite$BOT_DOCKER_IMAGE_TAG
tags:
- ESP32
- Example_WIFI
only:
variables:
- $BOT_LABEL_WEEKEND_TEST
variables:
TEST_CASE_PATH: "$CI_PROJECT_DIR/components/lwip/weekend_test"
TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw"
LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS"
ENV_FILE: "$CI_PROJECT_DIR/components/lwip/weekend_test/env.yml"
CONFIG_FILE: "$CI_PROJECT_DIR/components/lwip/weekend_test/config.yml"
.test_template: &test_template
stage: target_test
when: on_success

View file

@ -87,6 +87,7 @@ set(COMPONENT_SRCS "apps/dhcpserver/dhcpserver.c"
"port/esp32/freertos/sys_arch.c"
"port/esp32/netif/dhcp_state.c"
"port/esp32/netif/ethernetif.c"
"port/esp32/netif/nettestif.c"
"port/esp32/netif/wlanif.c")
if(CONFIG_LWIP_PPP_SUPPORT)

View file

@ -0,0 +1,33 @@
// Copyright 2015-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 _NETTEST_LWIP_IF_H_
#define _NETTEST_LWIP_IF_H_
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
err_t nettestif_init(struct netif *netif);
void nettestif_input(void *buffer, u16_t len);
#ifdef __cplusplus
}
#endif
#endif /* _NETTEST_LWIP_IF_H_ */

View file

@ -26,7 +26,7 @@
#define VALID_NETIF_ID(id) ((id < ESP_IF_MAX) && (id != ESP_IF_WIFI_AP))
static uint32_t restored_ip_addr[TCPIP_ADAPTER_IF_MAX];
static const char *interface_key[] = {"IF_STA", "IF_AP", "IF_ETH"};
static const char *interface_key[] = {"IF_STA", "IF_AP", "IF_ETH", "IF_TEST"};
_Static_assert(sizeof(interface_key) / sizeof(char*) == TCPIP_ADAPTER_IF_MAX,
"Number interface keys differs from number of interfaces");

View file

@ -0,0 +1,105 @@
#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 <stdio.h>
#include <string.h>
#include "tcpip_adapter.h"
static struct netif *g_last_netif = NULL;
err_t nettestif_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 nettestif_init(struct netif *netif)
{
g_last_netif = netif;
netif->hostname = "espressif";
/*
* 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 = nettestif_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 nettestif_input(void *buffer, u16_t len)
{
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

@ -0,0 +1,3 @@
CaseConfig:
- name: lwip_test_suite

View file

View file

@ -0,0 +1,11 @@
[LOGGING]
FileMask := LOG_ALL | DEBUG | TTCN_DEBUG
ConsoleMask := LOG_ALL | DEBUG | TTCN_DEBUG
LogSourceInfo := Yes
[MODULE_PARAMETERS]
libtest.m_ip_dst := "10.0.0.1"
libtest.m_ip_src := "10.0.0.2"
[EXECUTE]
esp32_netsuite.control

View file

@ -0,0 +1,11 @@
module esp32_netsuite {
import from tcp_suite all;
control {
execute(tc_tcp_002());
execute(tc_tcp_003());
execute(tc_tcp_004());
execute(tc_tcp_005());
}
}

View file

@ -0,0 +1,164 @@
import re
import os
import sys
import socket
from threading import Thread, Event
import subprocess
import time
from shutil import copyfile
try:
import IDF
except ImportError:
# this is a test case write with tiny-test-fw.
# to run test cases outside tiny-test-fw,
# we need to set environment variable `TEST_FW_PATH`,
# then get and insert `TEST_FW_PATH` to sys path before import FW module
test_fw_path = os.getenv("TEST_FW_PATH")
if test_fw_path and test_fw_path not in sys.path:
sys.path.insert(0, test_fw_path)
import IDF
import DUT
import Utility
stop_sock_listener = Event()
stop_io_listener = Event()
sock = None
client_address = None
manual_test = False
def io_listener(dut1):
global sock
global client_address
data = b''
while not stop_io_listener.is_set():
try:
data = dut1.expect(re.compile(r"PacketOut:\[([a-fA-F0-9]+)\]"), timeout=5)
except DUT.ExpectTimeout:
continue
if data != () and data[0] != b'':
packet_data = data[0]
print("Packet_data>{}<".format(packet_data))
response = bytearray.fromhex(packet_data.decode())
print("Sending to socket:")
packet = ' '.join(format(x, '02x') for x in bytearray(response))
print("Packet>{}<".format(packet))
if client_address is not None:
sock.sendto(response, ('127.0.0.1', 7777))
def sock_listener(dut1):
global sock
global client_address
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(5)
server_address = '0.0.0.0'
server_port = 7771
server = (server_address, server_port)
sock.bind(server)
try:
while not stop_sock_listener.is_set():
try:
payload, client_address = sock.recvfrom(1024)
packet = ' '.join(format(x, '02x') for x in bytearray(payload))
print("Received from address {}, data {}".format(client_address, packet))
dut1.write(str.encode(packet))
except socket.timeout:
pass
finally:
sock.close()
sock = None
@IDF.idf_example_test(env_tag="Example_WIFI")
def lwip_test_suite(env, extra_data):
global stop_io_listener
global stop_sock_listener
"""
steps: |
1. Rebuilds test suite with esp32_netsuite.ttcn
2. Starts listeners on stdout and socket
3. Execute ttcn3 test suite
4. Collect result from ttcn3
"""
dut1 = env.get_dut("net_suite", "examples/system/network_tests")
# check and log bin size
binary_file = os.path.join(dut1.app.binary_path, "net_suite.bin")
bin_size = os.path.getsize(binary_file)
IDF.log_performance("net_suite", "{}KB".format(bin_size // 1024))
IDF.check_performance("net_suite", bin_size // 1024)
dut1.start_app()
thread1 = Thread(target=sock_listener, args=(dut1, ))
thread2 = Thread(target=io_listener, args=(dut1, ))
if not manual_test:
# Variables refering to esp32 ttcn test suite
TTCN_SRC = 'esp32_netsuite.ttcn'
TTCN_CFG = 'esp32_netsuite.cfg'
# System Paths
netsuite_path = os.getenv("NETSUITE_PATH")
netsuite_src_path = os.path.join(netsuite_path, "src")
test_dir = os.path.dirname(os.path.realpath(__file__))
# Building the suite
print("Rebuilding the test suite")
print("-------------------------")
# copy esp32 specific files to ttcn net-suite dir
copyfile(os.path.join(test_dir, TTCN_SRC), os.path.join(netsuite_src_path, TTCN_SRC))
copyfile(os.path.join(test_dir, TTCN_CFG), os.path.join(netsuite_src_path, TTCN_CFG))
proc = subprocess.Popen(['bash', '-c', 'cd ' + netsuite_src_path + ' && source make.sh'],
cwd=netsuite_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = proc.stdout.read()
print("Note: First build step we expect failure (titan/net_suite build system not suitable for multijob make)")
print(output)
proc = subprocess.Popen(['bash', '-c', 'cd ' + netsuite_src_path + ' && make'],
cwd=netsuite_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print("Note: This time all dependencies shall be generated -- multijob make shall pass")
output = proc.stdout.read()
print(output)
# Executing the test suite
thread1.start()
thread2.start()
time.sleep(2)
print("Executing the test suite")
print("------------------------")
proc = subprocess.Popen(['ttcn3_start', os.path.join(netsuite_src_path,'test_suite'), os.path.join(netsuite_src_path, TTCN_CFG)],
stdout=subprocess.PIPE)
output = proc.stdout.read()
print(output)
print("Collecting results")
print("------------------")
verdict_stats = re.search('(Verdict statistics:.*)', output)
if verdict_stats:
verdict_stats = verdict_stats.group(1)
else:
verdict_stats = b""
verdict = re.search('Overall verdict: pass', output)
if verdict:
print("Test passed!")
Utility.console_log(verdict_stats, "green")
else:
Utility.console_log(verdict_stats, "red")
raise ValueError('Test failed with: {}'.format(verdict_stats))
else:
try:
# Executing the test suite
thread1.start()
thread2.start()
time.sleep(2)
while True:
time.sleep(0.5)
except KeyboardInterrupt:
pass
print("Executing done, waiting for tests to finish")
print("-------------------------------------------")
stop_io_listener.set()
stop_sock_listener.set()
thread1.join()
thread2.join()
if __name__ == '__main__':
print("Manual execution, please build and start ttcn in a separate console")
manual_test = True
lwip_test_suite()

View file

@ -96,6 +96,7 @@ typedef enum {
TCPIP_ADAPTER_IF_STA = 0, /**< Wi-Fi STA (station) interface */
TCPIP_ADAPTER_IF_AP, /**< Wi-Fi soft-AP interface */
TCPIP_ADAPTER_IF_ETH, /**< Ethernet interface */
TCPIP_ADAPTER_IF_TEST, /**< tcpip stack test interface */
TCPIP_ADAPTER_IF_MAX
} tcpip_adapter_if_t;
@ -692,6 +693,19 @@ esp_err_t tcpip_adapter_get_netif(tcpip_adapter_if_t tcpip_if, void ** netif);
*/
bool tcpip_adapter_is_netif_up(tcpip_adapter_if_t tcpip_if);
/**
* @brief Cause the TCP/IP stack to start the test interface with specified MAC and IP.
* Test interface is used to exercise network stack with injected packets from SW.
*
* @param[in] mac Set MAC address of this interface
* @param[in] ip_info Set IP address of this interface
*
* @return
* - ESP_OK
* - ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS
* - ESP_ERR_NO_MEM
*/
esp_err_t tcpip_adapter_test_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info);
/**
* @brief Install default event handlers for Ethernet interface

View file

@ -32,6 +32,7 @@
#endif
#include "netif/wlanif.h"
#include "netif/ethernetif.h"
#include "netif/nettestif.h"
#include "dhcpserver/dhcpserver.h"
#include "dhcpserver/dhcpserver_options.h"
@ -161,6 +162,8 @@ static esp_err_t tcpip_adapter_update_default_netif(void)
netif_set_default(esp_netif[TCPIP_ADAPTER_IF_ETH]);
} else if (netif_is_up(esp_netif[TCPIP_ADAPTER_IF_AP])) {
netif_set_default(esp_netif[TCPIP_ADAPTER_IF_AP]);
} else if (netif_is_up(esp_netif[TCPIP_ADAPTER_IF_TEST])) {
netif_set_default(esp_netif[TCPIP_ADAPTER_IF_TEST]);
}
return ESP_OK;
@ -210,6 +213,8 @@ static esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac,
dhcps_status = TCPIP_ADAPTER_DHCP_STARTED;
}
} else if (tcpip_if == TCPIP_ADAPTER_IF_TEST) {
netif_set_up(esp_netif[tcpip_if]);
}
tcpip_adapter_update_default_netif();
@ -229,6 +234,13 @@ esp_err_t tcpip_adapter_sta_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info
return tcpip_adapter_start(TCPIP_ADAPTER_IF_STA, mac, ip_info);
}
esp_err_t tcpip_adapter_test_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info)
{
esp_netif_init_fn[TCPIP_ADAPTER_IF_TEST] = nettestif_init;
return tcpip_adapter_start(TCPIP_ADAPTER_IF_TEST, mac, ip_info);
}
esp_err_t tcpip_adapter_ap_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info)
{
esp_netif_init_fn[TCPIP_ADAPTER_IF_AP] = wlanif_init_ap;

View file

@ -0,0 +1,6 @@
# 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)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(net_suite)

View file

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

View file

@ -0,0 +1,66 @@
# Intel net test suite for LwIP network stack
This project provides a test interface to esp32 network stack in order to execute standard set of
Intel network test suite defined in TTCN3 framework.
## Important notice
*This is an internal ESP-IDF test and not a user project example*
## Execute net test suite
These network tests could be executed in both manual or automated mode in CI.
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
* 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
## Build application
```
cd $IDF_PATH/examples/system/network_tests
make defconfig
make -j4
make flash
```
## Run test
Open two terminals (1) and (2)
1) Start the test server which would pass packets from TTCN3 test suite into ESP32 board in `$IDF_PATH/components/lwip/weekend_test`
```
python net_suite_test.py
```
2) Start test suite in TTCN3 environment in `src` subdir of the cloned repository `net-test-suites.git`
```
ttcn3_start test_suite esp32_netsuite.cfg
```
## Internal connection
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
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
from/to those udp ports to stdin/stdout, where after propagating over USB/UART to the ESP32 board are processed in the network stack (on the target).
Actual test execution, progress, evaluation and test reporting is done using standard net-test-suite scripts running on PC.
```
PC
+---------------------------------------------------------+ ESP32 board
| | +----------------------------------------+
| TTCN3 engine | | +----------------------------------+ |
| | | | net_suite.c | |
| +-----------------+ +--------------+ | | | +------------------------+ |
| | net-test-suite |--7777/udp--| net_suite.py |--stdout---------| -----> | tcpip_adapter/lwip | |
| | |--7771/udp--| |--stdin----------| <----- | TCPIP_ADAPTER_IF_TEST | |
| +-----------------+ +--------------+ | | +---------+------------------------+ |
+---------------------------------------------------------+ +----------------------------------------+
```

View file

@ -0,0 +1,4 @@
set(COMPONENT_SRCS "net_suite.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()

View file

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

View file

@ -0,0 +1,180 @@
/* Net-suite test code
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 "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.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 "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/tcp.h"
void nettestif_input(void *buffer, u16_t len);
/* these data configures ARP cache so the test IPs are knows */
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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01
};
/* Test data (ICMP packet) for verification of tcp ip test netif
00-00-00-00-00-01-00-00-00-00-00-02-08-00-45-00-00-1c-00-00-00-00-ff-01-a7-de-0a-00-00-02-0a-00-00-01-08-00-f7-fd-00-01-00-01
*/
/* creating test pcb */
static struct tcp_pcb *test_pcb;
err_t test_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
return ERR_OK;
}
void test_error(void *arg, err_t err)
{
printf("Error CB from pcb %d\n", err);
}
err_t test_poll(void *arg, struct tcp_pcb *tpcb)
{
return ERR_OK;
}
err_t test_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
tcp_setprio(newpcb, TCP_PRIO_MIN);
tcp_arg(newpcb, NULL);
tcp_recv(newpcb, test_recv);
tcp_err(newpcb, test_error);
tcp_poll(newpcb, test_poll, 0);
return ERR_OK;
}
void test_tcp_init(void)
{
test_pcb = tcp_new();
if (test_pcb != NULL) {
err_t err;
/* Binding this test_pcb to 4242 to accept connections on this port
* - this has to be configured as DUT endpoint
* - all network traffic from and to network stack is tracked in nettestif
*/
err = tcp_bind(test_pcb, IP_ADDR_ANY, 4242);
if (err == ERR_OK) {
test_pcb = tcp_listen(test_pcb);
tcp_accept(test_pcb, test_accept);
} else {
printf("cannot bind test_pcb\n");
abort();
}
} else {
printf("cannot create test_pcb\n");
abort();
}
}
/**
* @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()
{
char packet[128];
tcpip_adapter_ip_info_t ip_info;
uint8_t ap_mac[6] = { 0,0,0,0,0,1};
IP4_ADDR(&ip_info.ip, 10, 0 , 0, 1);
IP4_ADDR(&ip_info.gw, 10, 0 , 0, 1);
IP4_ADDR(&ip_info.netmask, 255, 255 , 255, 0);
tcpip_adapter_init();
tcpip_adapter_test_start(ap_mac, &ip_info);
// initializes TCP endpoint on DUT per https://github.com/intel/net-test-suites#21-endpoints
test_tcp_init();
// Inject ARP packet to let the network stack know about IP/MAC of the counterpart
nettestif_input(arp1, sizeof(arp1));
// 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_CONSOLE_UART_NUM,
256, 0, 0, NULL, 0) );
/* Tell VFS to use UART driver */
esp_vfs_dev_uart_use_driver(CONFIG_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;
}
size = process_line(line, packet);
nettestif_input(packet, size);
linenoiseFree(line);
}
}