Merge branch 'feature/eth_test_all_chips' into 'master'

Ethernet related tests improvements

Closes IDF-5387

See merge request espressif/esp-idf!20982
This commit is contained in:
Ondrej Kosta
2022-11-30 17:53:48 +08:00
41 changed files with 1147 additions and 604 deletions

View File

@@ -354,6 +354,14 @@ component_ut_pytest_esp32_lan8720:
- build_pytest_components_esp32 - build_pytest_components_esp32
tags: [ esp32, lan8720 ] tags: [ esp32, lan8720 ]
component_ut_pytest_esp32_ethernet:
extends:
- .pytest_components_dir_template
- .rules:test:component_ut-esp32
needs:
- build_pytest_components_esp32
tags: [ esp32, ethernet ]
component_ut_pytest_esp32_flash_encryption: component_ut_pytest_esp32_flash_encryption:
extends: extends:
- .pytest_components_dir_template - .pytest_components_dir_template

View File

@@ -314,12 +314,8 @@ static esp_err_t dm9051_setup_default(emac_dm9051_t *emac)
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_RLENCR, 0x00), err, TAG, "write RLENCR failed"); ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_RLENCR, 0x00), err, TAG, "write RLENCR failed");
/* 3K-byte for TX and 13K-byte for RX */ /* 3K-byte for TX and 13K-byte for RX */
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_MEMSCR, 0x00), err, TAG, "write MEMSCR failed"); ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_MEMSCR, 0x00), err, TAG, "write MEMSCR failed");
/* reset tx and rx memory pointer */
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX | MPTRCR_RST_TX), err, TAG, "write MPTRCR failed");
/* clear network status: wakeup event, tx complete */ /* clear network status: wakeup event, tx complete */
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END), err, TAG, "write NSR failed"); ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END), err, TAG, "write NSR failed");
/* clear interrupt status */
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_ISR, ISR_CLR_STATUS), err, TAG, "write ISR failed");
return ESP_OK; return ESP_OK;
err: err:
return ret; return ret;
@@ -351,6 +347,10 @@ static esp_err_t emac_dm9051_start(esp_eth_mac_t *mac)
{ {
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
/* reset tx and rx memory pointer */
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX | MPTRCR_RST_TX), err, TAG, "write MPTRCR failed");
/* clear interrupt status */
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_ISR, ISR_CLR_STATUS), err, TAG, "write ISR failed");
/* enable only Rx related interrupts as others are processed synchronously */ /* enable only Rx related interrupts as others are processed synchronously */
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_IMR, IMR_PAR | IMR_PRI), err, TAG, "write IMR failed"); ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_IMR, IMR_PAR | IMR_PRI), err, TAG, "write IMR failed");
/* enable rx */ /* enable rx */

View File

@@ -1,5 +0,0 @@
idf_component_register(SRC_DIRS .
PRIV_INCLUDE_DIRS .
PRIV_REQUIRES cmock test_utils esp_eth esp_http_client esp_netif
EMBED_TXTFILES dl_espressif_com_root_cert.pem)
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@@ -1,6 +1,8 @@
# This is the project CMakeLists.txt file for the test subproject # This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp_eth_test) project(esp_eth_test)

View File

@@ -2,10 +2,8 @@
| Supported Targets | ESP32 | | Supported Targets | ESP32 |
| ----------------- | ----- | | ----------------- | ----- |
This test app is used to test MAC layer behavior with different PHY chips: This test app is used to test Ethernet MAC behavior with different chips.
- IP101
- LAN8720
## Prerequisites ## Prerequisites
Install third part Python packages: Install third part Python packages:

View File

@@ -1,5 +1,10 @@
idf_component_register(SRCS "esp_eth_test.c" idf_component_register(SRCS "esp_eth_test_apps.c"
"esp_eth_test_l2.c"
"esp_eth_test_hal.c"
"esp_eth_test_common.c"
"esp_eth_test_main.c"
INCLUDE_DIRS "." INCLUDE_DIRS "."
PRIV_INCLUDE_DIRS "." PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES unity esp_eth esp_netif) PRIV_REQUIRES unity test_utils esp_eth esp_netif esp_http_client
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") EMBED_TXTFILES dl_espressif_com_root_cert.pem
WHOLE_ARCHIVE)

View File

@@ -1,14 +1,70 @@
menu "esp_eth TEST_APPS Configuration" menu "esp_eth TEST_APPS Configuration"
choice TARGET_ETH_PHY_DEVICE choice TARGET_ETH_CONFIG
prompt "Ethernet peripheral device" prompt "Ethernet peripheral device"
default TARGET_ETH_PHY_DEVICE_IP101 default TARGET_USE_INTERNAL_ETHERNET
help help
Select one of the devices listed here Select type of Ethernet interface.
config TARGET_USE_INTERNAL_ETHERNET
depends on SOC_EMAC_SUPPORTED
select ETH_USE_ESP32_EMAC
bool "Internal EMAC"
help
Use internal Ethernet MAC controller.
config TARGET_USE_SPI_ETHERNET
bool "SPI Ethernet"
select ETH_USE_SPI_ETHERNET
help
Use external SPI-Ethernet module(s).
endchoice # TARGET_ETH_CONFIG
if TARGET_USE_INTERNAL_ETHERNET
choice TARGET_ETH_PHY_DEVICE
prompt "Ethernet PHY"
default TARGET_ETH_PHY_DEVICE_IP101
help
Select one of the devices listed here
config TARGET_ETH_PHY_DEVICE_IP101
bool "IP101"
config TARGET_ETH_PHY_DEVICE_LAN87XX
bool "LAN8720"
config TARGET_ETH_PHY_DEVICE_KSZ80XX
bool "KSZ80xx"
config TARGET_ETH_PHY_DEVICE_RTL8201
bool "RTL8201"
config TARGET_ETH_PHY_DEVICE_DP83848
bool "DP83848"
endchoice # TARGET_ETH_PHY_DEVICE
endif # TARGET_USE_INTERNAL_ETHERNET
if TARGET_USE_SPI_ETHERNET
choice TARGET_ETH_SPI_DEVICE
prompt "Ethernet SPI Module"
default TARGET_ETH_PHY_DEVICE_W5500
help
Select one of the devices listed here
config TARGET_ETH_PHY_DEVICE_W5500
bool "W5500"
select ETH_SPI_ETHERNET_W5500
config TARGET_ETH_PHY_DEVICE_KSZ8851SNL
bool "KSZ8851SNL"
select ETH_SPI_ETHERNET_KSZ8851SNL
config TARGET_ETH_PHY_DEVICE_DM9051
bool "DM9051"
select ETH_SPI_ETHERNET_DM9051
endchoice # TARGET_ETH_SPI_DEVICE
config TARGET_SPI_CLOCK_MHZ
int "SPI clock speed (MHz)"
range 5 80
default 12
help
Set the clock speed (MHz) of SPI interface.
endif # TARGET_USE_SPI_ETHERNET
config TARGET_ETH_PHY_DEVICE_IP101
bool "IP101"
config TARGET_ETH_PHY_DEVICE_LAN87XX
bool "LAN8720"
endchoice
endmenu endmenu

View File

@@ -1,408 +0,0 @@
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_event.h"
#include "unity.h"
#include "esp_netif.h"
#include "esp_eth.h"
#include "sdkconfig.h"
#include "lwip/sockets.h"
#define ETH_START_BIT BIT(0)
#define ETH_STOP_BIT BIT(1)
#define ETH_CONNECT_BIT BIT(2)
#define ETH_BROADCAST_RECV_BIT BIT(0)
#define ETH_MULTICAST_RECV_BIT BIT(1)
#define ETH_UNICAST_RECV_BIT BIT(2)
#define POKE_REQ 0xFA
#define POKE_RESP 0xFB
#define DUMMY_TRAFFIC 0xFF
typedef struct {
uint8_t dest[6];
uint8_t src[6];
uint16_t proto;
uint8_t data[];
} __attribute__((__packed__)) emac_frame_t;
static void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data){
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg;
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
xEventGroupSetBits(eth_event_group, ETH_CONNECT_BIT);
break;
case ETHERNET_EVENT_DISCONNECTED:
break;
case ETHERNET_EVENT_START:
xEventGroupSetBits(eth_event_group, ETH_START_BIT);
break;
case ETHERNET_EVENT_STOP:
xEventGroupSetBits(eth_event_group, ETH_STOP_BIT);
break;
default:
break;
}
}
TEST_CASE("start_and_stop", "[esp_eth]")
{
EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ASSERT(eth_event_group != NULL);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); // apply default MAC configuration
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); // create MAC instance
TEST_ASSERT_NOT_NULL(mac);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); // apply default PHY configuration
#if defined(CONFIG_TARGET_ETH_PHY_DEVICE_IP101)
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); // create PHY instance
#elif defined(CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX)
esp_eth_phy_t *phy = esp_eth_phy_new_lan87xx(&phy_config);
#endif
TEST_ASSERT_NOT_NULL(phy);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // apply default driver configuration
esp_eth_handle_t eth_handle = NULL; // after driver installed, we will get the handle of the driver
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_driver_install(&config, &eth_handle)); // install driver
TEST_ASSERT_NOT_NULL(eth_handle);
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default());
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_event_group));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_start(eth_handle)); // start Ethernet driver state machine
EventBits_t bits = 0;
bits = xEventGroupWaitBits(eth_event_group, ETH_START_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_START_BIT) == ETH_START_BIT);
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_stop(eth_handle));
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_delete_default());
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_driver_uninstall(eth_handle));
phy->del(phy);
mac->del(mac);
vEventGroupDelete(eth_event_group);
}
TEST_CASE("get_set_mac", "[esp_eth]")
{
EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ASSERT(eth_event_group != NULL);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); // apply default MAC configuration
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); // create MAC instance
TEST_ASSERT_NOT_NULL(mac);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); // apply default PHY configuration
#if defined(CONFIG_TARGET_ETH_PHY_DEVICE_IP101)
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); // create PHY instance
#elif defined(CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX)
esp_eth_phy_t *phy = esp_eth_phy_new_lan87xx(&phy_config);
#endif
TEST_ASSERT_NOT_NULL(phy);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // apply default driver configuration
esp_eth_handle_t eth_handle = NULL; // after driver installed, we will get the handle of the driver
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_driver_install(&config, &eth_handle)); // install driver
TEST_ASSERT_NOT_NULL(eth_handle);
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default());
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_event_group));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_start(eth_handle)); // start Ethernet driver state machine
EventBits_t bits = 0;
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
uint8_t mac_addr[6] = {};
TEST_ASSERT_EQUAL(ESP_OK, mac->get_addr(mac, mac_addr));
TEST_ASSERT_BITS(0b00000011, 0b00, mac_addr[0]); // Check UL&IG, should be UI
mac_addr[5] ^= mac_addr[4];
TEST_ASSERT_EQUAL(ESP_OK, mac->set_addr(mac, mac_addr));
uint8_t new_mac_addr[6] = {};
TEST_ASSERT_EQUAL(ESP_OK, mac->get_addr(mac, new_mac_addr));
TEST_ASSERT_EQUAL(0, memcmp(mac_addr, new_mac_addr, 6));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_stop(eth_handle));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_delete_default());
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_driver_uninstall(eth_handle));
phy->del(phy);
mac->del(mac);
vEventGroupDelete(eth_event_group);
}
TEST_CASE("ethernet_broadcast_transmit", "[esp_eth]")
{
EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ASSERT(eth_event_group != NULL);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); // apply default MAC configuration
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); // create MAC instance
TEST_ASSERT_NOT_NULL(mac);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); // apply default PHY configuration
#if defined(CONFIG_TARGET_ETH_PHY_DEVICE_IP101)
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); // create PHY instance
#elif defined(CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX)
esp_eth_phy_t *phy = esp_eth_phy_new_lan87xx(&phy_config);
#endif
TEST_ASSERT_NOT_NULL(phy);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // apply default driver configuration
esp_eth_handle_t eth_handle = NULL; // after driver installed, we will get the handle of the driver
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_driver_install(&config, &eth_handle)); // install driver
TEST_ASSERT_NOT_NULL(eth_handle);
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default());
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_event_group));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_start(eth_handle)); // start Ethernet driver state machine
EventBits_t bits = 0;
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
// even if PHY (IP101) indicates autonegotiation done and link up, it sometimes may miss few packets after atonego reset, hence wait a bit
vTaskDelay(pdMS_TO_TICKS(100));
emac_frame_t *pkt = malloc(1024);
pkt->proto = 0x2222;
memset(pkt->dest, 0xff, 6); // broadcast addr
for (int i = 0; i < (1024 - ETH_HEADER_LEN); ++i){
pkt->data[i] = i & 0xff;
}
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_transmit(eth_handle, pkt, 1024));
vTaskDelay(pdMS_TO_TICKS(100));
free(pkt);
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_stop(eth_handle));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_delete_default());
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_driver_uninstall(eth_handle));
phy->del(phy);
mac->del(mac);
vEventGroupDelete(eth_event_group);
}
static uint8_t local_mac_addr[6] = {};
esp_err_t l2_packet_txrx_test_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv) {
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)priv;
emac_frame_t *pkt = (emac_frame_t *) buffer;
// check header
if (pkt->proto == 0x2222 && length == 1024) {
// check content
for (int i = 0; i < (length - ETH_HEADER_LEN); ++i) {
if (pkt->data[i] != (i & 0xff)) {
printf("payload mismatch\n");
return ESP_OK;
}
}
if (memcmp(pkt->dest, "\xff\xff\xff\xff\xff\xff", 6) == 0) {
printf("broadcast received...\n");
xEventGroupSetBits(eth_event_group, ETH_BROADCAST_RECV_BIT);
} else if (pkt->dest[0] & 0x1) {
printf("multicast received...\n");
xEventGroupSetBits(eth_event_group, ETH_MULTICAST_RECV_BIT);
} else if (memcmp(pkt->dest, local_mac_addr, 6) == 0) {
printf("unicast received...\n");
xEventGroupSetBits(eth_event_group, ETH_UNICAST_RECV_BIT);
}
} else {
printf("unexpected frame (protocol: 0x%x, length: %u)\n", pkt->proto, length);
}
return ESP_OK;
};
TEST_CASE("recv_pkt", "[esp_eth]")
{
EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ASSERT(eth_event_group != NULL);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); // apply default MAC configuration
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); // create MAC instance
TEST_ASSERT_NOT_NULL(mac);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); // apply default PHY configuration
#if defined(CONFIG_TARGET_ETH_PHY_DEVICE_IP101)
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); // create PHY instance
#elif defined(CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX)
esp_eth_phy_t *phy = esp_eth_phy_new_lan87xx(&phy_config);
#endif
TEST_ASSERT_NOT_NULL(phy);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // apply default driver configuration
esp_eth_handle_t eth_handle = NULL; // after driver installed, we will get the handle of the driver
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_driver_install(&config, &eth_handle)); // install driver
TEST_ASSERT_NOT_NULL(eth_handle);
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default());
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_start(eth_handle)); // start Ethernet driver state machine
TEST_ASSERT_EQUAL(ESP_OK, mac->get_addr(mac, local_mac_addr));
// test app will parse the DUT MAC from this line of log output
printf("DUT MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", local_mac_addr[0], local_mac_addr[1], local_mac_addr[2],
local_mac_addr[3], local_mac_addr[4], local_mac_addr[5]);
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_update_input_path(eth_handle, l2_packet_txrx_test_cb, eth_event_group));
EventBits_t bits = 0;
bits = xEventGroupWaitBits(eth_event_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT,
true, true, pdMS_TO_TICKS(5000));
TEST_ASSERT((bits & (ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT)) ==
(ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_stop(eth_handle));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_delete_default());
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_driver_uninstall(eth_handle));
phy->del(phy);
mac->del(mac);
vEventGroupDelete(eth_event_group);
}
typedef struct
{
SemaphoreHandle_t mutex;
int rx_pkt_cnt;
} recv_info_t;
static esp_err_t eth_recv_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv)
{
emac_frame_t *pkt = (emac_frame_t *)buffer;
recv_info_t *recv_info = (recv_info_t *)priv;
if (pkt->proto == 0x2222) {
switch (pkt->data[0])
{
case POKE_RESP:
xSemaphoreGive(recv_info->mutex);
break;
case DUMMY_TRAFFIC:
(recv_info->rx_pkt_cnt)++;
break;
default:
break;
}
}
free(buffer);
return ESP_OK;
}
TEST_CASE("start_stop_stress_test", "[esp_eth]")
{
recv_info_t recv_info;
recv_info.mutex = xSemaphoreCreateBinary();
TEST_ASSERT_NOT_NULL(recv_info.mutex);
recv_info.rx_pkt_cnt = 0;
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); // apply default MAC configuration
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); // create MAC instance
TEST_ASSERT_NOT_NULL(mac);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); // apply default PHY configuration
#if defined(CONFIG_TARGET_ETH_PHY_DEVICE_IP101)
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); // create PHY instance
#elif defined(CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX)
esp_eth_phy_t *phy = esp_eth_phy_new_lan87xx(&phy_config);
#endif
TEST_ASSERT_NOT_NULL(phy);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // apply default driver configuration
esp_eth_handle_t eth_handle = NULL; // after driver installed, we will get the handle of the driver
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_driver_install(&config, &eth_handle)); // install driver
TEST_ASSERT_NOT_NULL(eth_handle);
TEST_ASSERT_EQUAL(ESP_OK, mac->get_addr(mac, local_mac_addr));
// test app will parse the DUT MAC from this line of log output
printf("DUT MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", local_mac_addr[0], local_mac_addr[1], local_mac_addr[2],
local_mac_addr[3], local_mac_addr[4], local_mac_addr[5]);
TEST_ESP_OK(esp_eth_update_input_path(eth_handle, eth_recv_cb, &recv_info));
EventBits_t bits = 0;
EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ASSERT(eth_event_group != NULL);
TEST_ESP_OK(esp_event_loop_create_default());
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_event_group));
// create a control frame to control test flow between the UT and the Python test script
emac_frame_t *ctrl_pkt = calloc(1, 60);
ctrl_pkt->proto = 0x2222;
memset(ctrl_pkt->dest, 0xff, 6); // broadcast addr
memcpy(ctrl_pkt->src, local_mac_addr, 6);
// create dummy data packet used for traffic generation
emac_frame_t *pkt = calloc(1, 1500);
pkt->proto = 0x2222;
// we don't care about dest MAC address much, however it is better to not be broadcast or multifcast to not flood
// other network nodes
memset(pkt->dest, 0xBA, 6);
memcpy(pkt->src, local_mac_addr, 6);
printf("EMAC start/stop stress test under heavy Tx traffic\n");
for (int tx_i = 0; tx_i < 10; tx_i++) {
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_start(eth_handle)); // start Ethernet driver state machine
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
// even if PHY (IP101) indicates autonegotiation done and link up, it sometimes may miss few packets after atonego reset, hence wait a bit
vTaskDelay(pdMS_TO_TICKS(100));
// at first, check that Tx/Rx path works as expected by poking the test script
// this also serves as main PASS/FAIL criteria
ctrl_pkt->data[0] = POKE_REQ;
ctrl_pkt->data[1] = tx_i;
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_transmit(eth_handle, ctrl_pkt, 60));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(3000)));
printf("Tx Test iteration %d\n", tx_i);
// generate heavy Tx traffic
printf("Note: transmit errors are expected...\n");
for (int j = 0; j < 150; j++) {
// return value is not checked on purpose since it is expected that it may fail time to time because
// we may try to queue more packets than hardware is able to handle
pkt->data[0] = j & 0xFF;
esp_eth_transmit(eth_handle, pkt, 1500);
}
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_stop(eth_handle));
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
printf("Ethernet stopped\n");
}
printf("EMAC start/stop stress test under heavy Rx traffic\n");
for (int rx_i = 0; rx_i < 10; rx_i++) {
recv_info.rx_pkt_cnt = 0;
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_start(eth_handle)); // start Ethernet driver state machine
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
// even if PHY (IP101) indicates autonegotiation done and link up, it sometimes may miss few packets after atonego reset, hence wait a bit
vTaskDelay(pdMS_TO_TICKS(100));
ctrl_pkt->data[0] = POKE_REQ;
ctrl_pkt->data[1] = rx_i;
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_transmit(eth_handle, ctrl_pkt, 60));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(3000)));
printf("Rx Test iteration %d\n", rx_i);
vTaskDelay(pdMS_TO_TICKS(500));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_stop(eth_handle));
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
printf("Recv packets: %d\n", recv_info.rx_pkt_cnt);
TEST_ASSERT_GREATER_THAN_INT32(0, recv_info.rx_pkt_cnt);
printf("Ethernet stopped\n");
}
free(ctrl_pkt);
free(pkt);
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_delete_default());
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_driver_uninstall(eth_handle));
phy->del(phy);
mac->del(mac);
vEventGroupDelete(eth_event_group);
vSemaphoreDelete(recv_info.mutex);
}
void app_main(void)
{
unity_run_menu();
}

View File

@@ -5,34 +5,17 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/event_groups.h" #include "freertos/event_groups.h"
#include "unity.h"
#include "test_utils.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_eth.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_http_client.h" #include "esp_http_client.h"
#include "esp_rom_md5.h" #include "esp_rom_md5.h"
#include "soc/soc_caps.h" #include "esp_eth_test_common.h"
#if SOC_EMAC_SUPPORTED
static const char *TAG = "esp32_eth_test"; static const char *TAG = "esp32_eth_test";
#define ETH_START_BIT BIT(0)
#define ETH_STOP_BIT BIT(1)
#define ETH_CONNECT_BIT BIT(2)
#define ETH_GOT_IP_BIT BIT(3)
#define ETH_START_TIMEOUT_MS (10000)
#define ETH_CONNECT_TIMEOUT_MS (40000)
#define ETH_STOP_TIMEOUT_MS (10000)
#define ETH_GET_IP_TIMEOUT_MS (60000)
#define ETH_DOWNLOAD_END_TIMEOUT_MS (240000)
extern const char dl_espressif_com_root_cert_pem_start[] asm("_binary_dl_espressif_com_root_cert_pem_start"); extern const char dl_espressif_com_root_cert_pem_start[] asm("_binary_dl_espressif_com_root_cert_pem_start");
extern const char dl_espressif_com_root_cert_pem_end[] asm("_binary_dl_espressif_com_root_cert_pem_end"); extern const char dl_espressif_com_root_cert_pem_end[] asm("_binary_dl_espressif_com_root_cert_pem_end");
@@ -40,48 +23,6 @@ extern const char dl_espressif_com_root_cert_pem_end[] asm("_binary_dl_espress
static md5_context_t md5_context; static md5_context_t md5_context;
static uint8_t digest[16]; static uint8_t digest[16];
/** Event handler for Ethernet events */
static void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg;
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
xEventGroupSetBits(eth_event_group, ETH_CONNECT_BIT);
ESP_LOGI(TAG, "Ethernet Link Up");
break;
case ETHERNET_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "Ethernet Link Down");
break;
case ETHERNET_EVENT_START:
xEventGroupSetBits(eth_event_group, ETH_START_BIT);
ESP_LOGI(TAG, "Ethernet Started");
break;
case ETHERNET_EVENT_STOP:
xEventGroupSetBits(eth_event_group, ETH_STOP_BIT);
ESP_LOGI(TAG, "Ethernet Stopped");
break;
default:
break;
}
}
/** Event handler for IP_EVENT_ETH_GOT_IP */
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg;
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
const esp_netif_ip_info_t *ip_info = &event->ip_info;
ESP_LOGI(TAG, "Ethernet Got IP Address");
ESP_LOGI(TAG, "~~~~~~~~~~~");
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
ESP_LOGI(TAG, "~~~~~~~~~~~");
xEventGroupSetBits(eth_event_group, ETH_GOT_IP_BIT);
}
static esp_err_t test_uninstall_driver(esp_eth_handle_t eth_hdl, uint32_t ms_to_wait) static esp_err_t test_uninstall_driver(esp_eth_handle_t eth_hdl, uint32_t ms_to_wait)
{ {
int i = 0; int i = 0;
@@ -99,37 +40,59 @@ static esp_err_t test_uninstall_driver(esp_eth_handle_t eth_hdl, uint32_t ms_to_
} }
} }
TEST_CASE("esp32 ethernet io test", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("ethernet io test", "[ethernet]")
{ {
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
mac_config.flags = ETH_MAC_FLAG_PIN_TO_CORE; // pin to core mac_config.flags = ETH_MAC_FLAG_PIN_TO_CORE; // pin to core
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); esp_eth_mac_t *mac = mac_init(NULL, &mac_config);
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); TEST_ASSERT_NOT_NULL(mac);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); esp_eth_phy_t *phy = phy_init(NULL);
// auto detect PHY address TEST_ASSERT_NOT_NULL(phy);
phy_config.phy_addr = ESP_ETH_PHY_ADDR_AUTO;
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL; esp_eth_handle_t eth_handle = NULL;
TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle)); TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
/* get MAC address */ extra_eth_config(eth_handle);
uint8_t mac_addr[6];
/* get default MAC address */
uint8_t mac_addr[ETH_ADDR_LEN];
memset(mac_addr, 0, sizeof(mac_addr)); memset(mac_addr, 0, sizeof(mac_addr));
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr));
ESP_LOGI(TAG, "Ethernet MAC Address: %02x:%02x:%02x:%02x:%02x:%02x", ESP_LOGI(TAG, "Ethernet MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
TEST_ASSERT(mac_addr[0] != 0); TEST_ASSERT(mac_addr[0] != 0);
// *** SPI Ethernet modules deviation ***
// Rationale: The SPI Ethernet modules don't have a burned default factory MAC address hence local MAC is used
#if !CONFIG_TARGET_USE_SPI_ETHERNET
TEST_ASSERT_BITS(0b00000011, 0b00, mac_addr[0]); // Check UL&IG, should be UI
#endif
/* set different MAC address */
mac_addr[5] ^= mac_addr[4];
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, mac_addr));
/* get new MAC address */
uint8_t mac_addr_new[ETH_ADDR_LEN] = { 0 };
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr_new));
ESP_LOGI(TAG, "Ethernet MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
mac_addr_new[0], mac_addr_new[1], mac_addr_new[2], mac_addr_new[3], mac_addr_new[4], mac_addr_new[5]);
TEST_ASSERT_EQUAL_UINT8_ARRAY(mac_addr_new, mac_addr, ETH_ADDR_LEN);
// *** SPI Ethernet modules deviation ***
// Rationale: SPI Ethernet modules PHYs and MACs are statically configured at one die, hence there is no need for PHY address
// from user's point of view
#if !CONFIG_TARGET_USE_SPI_ETHERNET
/* get PHY address */ /* get PHY address */
int phy_addr = -1; int phy_addr = -1;
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr));
ESP_LOGI(TAG, "Ethernet PHY Address: %d", phy_addr); ESP_LOGI(TAG, "Ethernet PHY Address: %d", phy_addr);
TEST_ASSERT(phy_addr >= 0 && phy_addr <= 31); TEST_ASSERT(phy_addr >= 0 && phy_addr <= 31);
#endif
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle)); TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
TEST_ESP_OK(phy->del(phy)); TEST_ESP_OK(phy->del(phy));
TEST_ESP_OK(mac->del(mac)); TEST_ESP_OK(mac->del(mac));
extra_cleanup();
} }
TEST_CASE("esp32 ethernet speed/duplex/autonegotiation", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("ethernet io speed/duplex/autonegotiation", "[ethernet]")
{ {
EventBits_t bits = 0; EventBits_t bits = 0;
EventGroupHandle_t eth_event_group = xEventGroupCreate(); EventGroupHandle_t eth_event_group = xEventGroupCreate();
@@ -138,19 +101,19 @@ TEST_CASE("esp32 ethernet speed/duplex/autonegotiation", "[ethernet][test_env=UT
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_event_group)); TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_event_group));
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
mac_config.flags = ETH_MAC_FLAG_PIN_TO_CORE; // pin to core mac_config.flags = ETH_MAC_FLAG_PIN_TO_CORE; // pin to core
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); esp_eth_mac_t *mac = mac_init(NULL, &mac_config);
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); TEST_ASSERT_NOT_NULL(mac);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); esp_eth_phy_t *phy = phy_init(NULL);
// auto detect PHY address TEST_ASSERT_NOT_NULL(phy);
phy_config.phy_addr = ESP_ETH_PHY_ADDR_AUTO;
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL; esp_eth_handle_t eth_handle = NULL;
TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle)); TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
extra_eth_config(eth_handle);
// Set PHY to loopback mode so we do not have to take care about link configuration of the other node. // Set PHY to loopback mode so we do not have to take care about link configuration of the other node.
// The reason behind is improbable, however, if the other node was configured to e.g. 100 Mbps and we // The reason behind is improbable, however, if the other node was configured to e.g. 100 Mbps and we
// tried to change the speed at ESP node to 10 Mbps, we could get into trouble to establish a link. // tried to change the speed at ESP node to 10 Mbps, we could get into trouble to establish a link.
// TODO: this test in this configuration may not work for all the chips (JIRA IDF-6186)
bool loopback_en = true; bool loopback_en = true;
esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en); esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en);
@@ -173,13 +136,13 @@ TEST_CASE("esp32 ethernet speed/duplex/autonegotiation", "[ethernet][test_env=UT
TEST_ASSERT_EQUAL(ETH_SPEED_100M, exp_speed); TEST_ASSERT_EQUAL(ETH_SPEED_100M, exp_speed);
bool exp_autoneg_en; bool exp_autoneg_en;
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_AUTONEGO, &exp_autoneg_en)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_AUTONEGO, &exp_autoneg_en));
TEST_ASSERT_EQUAL(true, exp_autoneg_en); TEST_ASSERT_EQUAL(true, exp_autoneg_en);
ESP_LOGI(TAG, "try to change autonegotiation when driver is started..."); ESP_LOGI(TAG, "try to change autonegotiation when driver is started...");
bool auto_nego_en = false; bool auto_nego_en = false;
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_eth_ioctl(eth_handle, ETH_CMD_S_AUTONEGO, &auto_nego_en)); TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_eth_ioctl(eth_handle, ETH_CMD_S_AUTONEGO, &auto_nego_en));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_AUTONEGO, &exp_autoneg_en)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_AUTONEGO, &exp_autoneg_en));
TEST_ASSERT_EQUAL(true, exp_autoneg_en); TEST_ASSERT_EQUAL(true, exp_autoneg_en);
ESP_LOGI(TAG, "stop the Ethernet driver and..."); ESP_LOGI(TAG, "stop the Ethernet driver and...");
@@ -195,22 +158,22 @@ TEST_CASE("esp32 ethernet speed/duplex/autonegotiation", "[ethernet][test_env=UT
// Disable autonegotiation and change speed to 10 Mbps and duplex to half // Disable autonegotiation and change speed to 10 Mbps and duplex to half
ESP_LOGI(TAG, "disable the autonegotiation and change the speed/duplex..."); ESP_LOGI(TAG, "disable the autonegotiation and change the speed/duplex...");
auto_nego_en = false; auto_nego_en = false;
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_S_AUTONEGO, &auto_nego_en)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_AUTONEGO, &auto_nego_en));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_AUTONEGO, &exp_autoneg_en)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_AUTONEGO, &exp_autoneg_en));
TEST_ASSERT_EQUAL(false, exp_autoneg_en); TEST_ASSERT_EQUAL(false, exp_autoneg_en);
// set new duplex mode // set new duplex mode
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_S_DUPLEX_MODE, &duplex)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_DUPLEX_MODE, &duplex));
// set new speed // set new speed
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &speed)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &speed));
// start the driver and wait for connection establish // start the driver and wait for connection establish
esp_eth_start(eth_handle); esp_eth_start(eth_handle);
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS)); bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT); TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &exp_duplex)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &exp_duplex));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed));
TEST_ASSERT_EQUAL(ETH_DUPLEX_HALF, exp_duplex); TEST_ASSERT_EQUAL(ETH_DUPLEX_HALF, exp_duplex);
TEST_ASSERT_EQUAL(ETH_SPEED_10M, exp_speed); TEST_ASSERT_EQUAL(ETH_SPEED_10M, exp_speed);
@@ -219,14 +182,14 @@ TEST_CASE("esp32 ethernet speed/duplex/autonegotiation", "[ethernet][test_env=UT
esp_eth_stop(eth_handle); esp_eth_stop(eth_handle);
ESP_LOGI(TAG, "change speed again..."); ESP_LOGI(TAG, "change speed again...");
speed = ETH_SPEED_100M; speed = ETH_SPEED_100M;
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &speed)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &speed));
// start the driver and wait for connection establish // start the driver and wait for connection establish
esp_eth_start(eth_handle); esp_eth_start(eth_handle);
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS)); bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT); TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &exp_duplex)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &exp_duplex));
TEST_ASSERT_EQUAL(ETH_DUPLEX_HALF, exp_duplex); TEST_ASSERT_EQUAL(ETH_DUPLEX_HALF, exp_duplex);
TEST_ASSERT_EQUAL(ETH_SPEED_100M, exp_speed); TEST_ASSERT_EQUAL(ETH_SPEED_100M, exp_speed);
@@ -234,14 +197,14 @@ TEST_CASE("esp32 ethernet speed/duplex/autonegotiation", "[ethernet][test_env=UT
esp_eth_stop(eth_handle); esp_eth_stop(eth_handle);
ESP_LOGI(TAG, "change duplex again..."); ESP_LOGI(TAG, "change duplex again...");
duplex = ETH_DUPLEX_FULL; duplex = ETH_DUPLEX_FULL;
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_S_DUPLEX_MODE, &duplex)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_DUPLEX_MODE, &duplex));
// start the driver and wait for connection establish // start the driver and wait for connection establish
esp_eth_start(eth_handle); esp_eth_start(eth_handle);
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS)); bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT); TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &exp_duplex)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &exp_duplex));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed));
TEST_ASSERT_EQUAL(ETH_DUPLEX_FULL, exp_duplex); TEST_ASSERT_EQUAL(ETH_DUPLEX_FULL, exp_duplex);
TEST_ASSERT_EQUAL(ETH_SPEED_100M, exp_speed); TEST_ASSERT_EQUAL(ETH_SPEED_100M, exp_speed);
@@ -253,8 +216,8 @@ TEST_CASE("esp32 ethernet speed/duplex/autonegotiation", "[ethernet][test_env=UT
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_eth_ioctl(eth_handle, ETH_CMD_S_DUPLEX_MODE, &duplex)); TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_eth_ioctl(eth_handle, ETH_CMD_S_DUPLEX_MODE, &duplex));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &speed)); TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &speed));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &exp_duplex)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &exp_duplex));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed));
TEST_ASSERT_EQUAL(ETH_DUPLEX_FULL, exp_duplex); TEST_ASSERT_EQUAL(ETH_DUPLEX_FULL, exp_duplex);
TEST_ASSERT_EQUAL(ETH_SPEED_100M, exp_speed); TEST_ASSERT_EQUAL(ETH_SPEED_100M, exp_speed);
@@ -265,17 +228,17 @@ TEST_CASE("esp32 ethernet speed/duplex/autonegotiation", "[ethernet][test_env=UT
duplex = ETH_DUPLEX_HALF; duplex = ETH_DUPLEX_HALF;
// set new duplex mode // set new duplex mode
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_S_DUPLEX_MODE, &duplex)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_DUPLEX_MODE, &duplex));
// set new speed // set new speed
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &speed)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &speed));
// start the driver and wait for connection establish // start the driver and wait for connection establish
esp_eth_start(eth_handle); esp_eth_start(eth_handle);
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS)); bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT); TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &exp_duplex)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &exp_duplex));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed));
TEST_ASSERT_EQUAL(ETH_DUPLEX_HALF, exp_duplex); TEST_ASSERT_EQUAL(ETH_DUPLEX_HALF, exp_duplex);
TEST_ASSERT_EQUAL(ETH_SPEED_10M, exp_speed); TEST_ASSERT_EQUAL(ETH_SPEED_10M, exp_speed);
@@ -287,11 +250,11 @@ TEST_CASE("esp32 ethernet speed/duplex/autonegotiation", "[ethernet][test_env=UT
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS)); bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT); TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_AUTONEGO, &exp_autoneg_en)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_AUTONEGO, &exp_autoneg_en));
TEST_ASSERT_EQUAL(true, exp_autoneg_en); TEST_ASSERT_EQUAL(true, exp_autoneg_en);
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &exp_duplex)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &exp_duplex));
TEST_ASSERT_EQUAL(ESP_OK, esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed)); TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed));
// verify autonegotiation result (expecting the best link configuration) // verify autonegotiation result (expecting the best link configuration)
TEST_ASSERT_EQUAL(ETH_DUPLEX_FULL, exp_duplex); TEST_ASSERT_EQUAL(ETH_DUPLEX_FULL, exp_duplex);
@@ -307,24 +270,25 @@ TEST_CASE("esp32 ethernet speed/duplex/autonegotiation", "[ethernet][test_env=UT
TEST_ESP_OK(mac->del(mac)); TEST_ESP_OK(mac->del(mac));
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler)); TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
TEST_ESP_OK(esp_event_loop_delete_default()); TEST_ESP_OK(esp_event_loop_delete_default());
extra_cleanup();
vEventGroupDelete(eth_event_group); vEventGroupDelete(eth_event_group);
} }
TEST_CASE("esp32 ethernet event test", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("ethernet event test", "[ethernet]")
{ {
EventBits_t bits = 0; EventBits_t bits = 0;
EventGroupHandle_t eth_event_group = xEventGroupCreate(); EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ASSERT(eth_event_group != NULL); TEST_ASSERT(eth_event_group != NULL);
TEST_ESP_OK(esp_event_loop_create_default()); TEST_ESP_OK(esp_event_loop_create_default());
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_event_group)); TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_event_group));
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); esp_eth_mac_t *mac = mac_init(NULL, NULL);
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); TEST_ASSERT_NOT_NULL(mac);
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); esp_eth_phy_t *phy = phy_init(NULL);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); TEST_ASSERT_NOT_NULL(phy);
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL; esp_eth_handle_t eth_handle = NULL;
TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle)); TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
extra_eth_config(eth_handle);
// this test only test layer2 event, so don't need to register input callback (i.e. esp_eth_update_input_path) // this test only test layer2 event, so don't need to register input callback (i.e. esp_eth_update_input_path)
TEST_ESP_OK(esp_eth_start(eth_handle)); TEST_ESP_OK(esp_eth_start(eth_handle));
/* wait for connection start */ /* wait for connection start */
@@ -344,10 +308,11 @@ TEST_CASE("esp32 ethernet event test", "[ethernet][test_env=UT_T2_Ethernet]")
TEST_ESP_OK(mac->del(mac)); TEST_ESP_OK(mac->del(mac));
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler)); TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
TEST_ESP_OK(esp_event_loop_delete_default()); TEST_ESP_OK(esp_event_loop_delete_default());
extra_cleanup();
vEventGroupDelete(eth_event_group); vEventGroupDelete(eth_event_group);
} }
TEST_CASE("esp32 ethernet dhcp test", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("ethernet dhcp test", "[ethernet]")
{ {
EventBits_t bits = 0; EventBits_t bits = 0;
EventGroupHandle_t eth_event_group = xEventGroupCreate(); EventGroupHandle_t eth_event_group = xEventGroupCreate();
@@ -357,16 +322,15 @@ TEST_CASE("esp32 ethernet dhcp test", "[ethernet][test_env=UT_T2_Ethernet]")
// create TCP/IP netif // create TCP/IP netif
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH(); esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&netif_cfg); esp_netif_t *eth_netif = esp_netif_new(&netif_cfg);
esp_eth_mac_t *mac = mac_init(NULL, NULL);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); TEST_ASSERT_NOT_NULL(mac);
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); esp_eth_phy_t *phy = phy_init(NULL);
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); TEST_ASSERT_NOT_NULL(phy);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL; esp_eth_handle_t eth_handle = NULL;
// install Ethernet driver // install Ethernet driver
TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle)); TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
extra_eth_config(eth_handle);
// combine driver with netif // combine driver with netif
esp_eth_netif_glue_handle_t glue = esp_eth_new_netif_glue(eth_handle); esp_eth_netif_glue_handle_t glue = esp_eth_new_netif_glue(eth_handle);
TEST_ESP_OK(esp_netif_attach(eth_netif, glue)); TEST_ESP_OK(esp_netif_attach(eth_netif, glue));
@@ -392,10 +356,11 @@ TEST_CASE("esp32 ethernet dhcp test", "[ethernet][test_env=UT_T2_Ethernet]")
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler)); TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
esp_netif_destroy(eth_netif); esp_netif_destroy(eth_netif);
TEST_ESP_OK(esp_event_loop_delete_default()); TEST_ESP_OK(esp_event_loop_delete_default());
extra_cleanup();
vEventGroupDelete(eth_event_group); vEventGroupDelete(eth_event_group);
} }
TEST_CASE("esp32 ethernet start/stop stress test", "[ethernet][test_env=UT_T2_Ethernet][timeout=240]") TEST_CASE("ethernet start/stop stress test with IP stack", "[ethernet]")
{ {
EventBits_t bits = 0; EventBits_t bits = 0;
EventGroupHandle_t eth_event_group = xEventGroupCreate(); EventGroupHandle_t eth_event_group = xEventGroupCreate();
@@ -405,16 +370,15 @@ TEST_CASE("esp32 ethernet start/stop stress test", "[ethernet][test_env=UT_T2_Et
// create TCP/IP netif // create TCP/IP netif
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH(); esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&netif_cfg); esp_netif_t *eth_netif = esp_netif_new(&netif_cfg);
esp_eth_mac_t *mac = mac_init(NULL, NULL);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); TEST_ASSERT_NOT_NULL(mac);
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); esp_eth_phy_t *phy = phy_init(NULL);
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); TEST_ASSERT_NOT_NULL(phy);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL; esp_eth_handle_t eth_handle = NULL;
// install Ethernet driver // install Ethernet driver
TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle)); TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
extra_eth_config(eth_handle);
// combine driver with netif // combine driver with netif
esp_eth_netif_glue_handle_t glue = esp_eth_new_netif_glue(eth_handle); esp_eth_netif_glue_handle_t glue = esp_eth_new_netif_glue(eth_handle);
TEST_ESP_OK(esp_netif_attach(eth_netif, glue)); TEST_ESP_OK(esp_netif_attach(eth_netif, glue));
@@ -444,6 +408,7 @@ TEST_CASE("esp32 ethernet start/stop stress test", "[ethernet][test_env=UT_T2_Et
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler)); TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
esp_netif_destroy(eth_netif); esp_netif_destroy(eth_netif);
TEST_ESP_OK(esp_event_loop_delete_default()); TEST_ESP_OK(esp_event_loop_delete_default());
extra_cleanup();
vEventGroupDelete(eth_event_group); vEventGroupDelete(eth_event_group);
} }
@@ -494,7 +459,7 @@ static void eth_start_download(void)
esp_rom_md5_final(digest, &md5_context); esp_rom_md5_final(digest, &md5_context);
} }
TEST_CASE("esp32 ethernet download test", "[ethernet][test_env=UT_T2_Ethernet][timeout=240]") TEST_CASE("ethernet download test", "[ethernet]")
{ {
EventBits_t bits = 0; EventBits_t bits = 0;
EventGroupHandle_t eth_event_group = xEventGroupCreate(); EventGroupHandle_t eth_event_group = xEventGroupCreate();
@@ -504,16 +469,15 @@ TEST_CASE("esp32 ethernet download test", "[ethernet][test_env=UT_T2_Ethernet][t
// create TCP/IP netif // create TCP/IP netif
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH(); esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&netif_cfg); esp_netif_t *eth_netif = esp_netif_new(&netif_cfg);
esp_eth_mac_t *mac = mac_init(NULL, NULL);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); TEST_ASSERT_NOT_NULL(mac);
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); esp_eth_phy_t *phy = phy_init(NULL);
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); TEST_ASSERT_NOT_NULL(phy);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL; esp_eth_handle_t eth_handle = NULL;
// install Ethernet driver // install Ethernet driver
TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle)); TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
extra_eth_config(eth_handle);
// combine driver with netif // combine driver with netif
esp_eth_netif_glue_handle_t glue = esp_eth_new_netif_glue(eth_handle); esp_eth_netif_glue_handle_t glue = esp_eth_new_netif_glue(eth_handle);
TEST_ESP_OK(esp_netif_attach(eth_netif, glue)); TEST_ESP_OK(esp_netif_attach(eth_netif, glue));
@@ -535,7 +499,7 @@ TEST_CASE("esp32 ethernet download test", "[ethernet][test_env=UT_T2_Ethernet][t
printf("%d ", digest[i]); printf("%d ", digest[i]);
} }
printf("\r\n"); printf("\r\n");
TEST_ASSERT(memcmp(expect_digest, digest, sizeof(digest)) == 0); TEST_ASSERT_EQUAL_UINT8_ARRAY(expect_digest, digest, sizeof(digest));
// stop Ethernet driver // stop Ethernet driver
TEST_ESP_OK(esp_eth_stop(eth_handle)); TEST_ESP_OK(esp_eth_stop(eth_handle));
@@ -551,7 +515,6 @@ TEST_CASE("esp32 ethernet download test", "[ethernet][test_env=UT_T2_Ethernet][t
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler)); TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
esp_netif_destroy(eth_netif); esp_netif_destroy(eth_netif);
TEST_ESP_OK(esp_event_loop_delete_default()); TEST_ESP_OK(esp_event_loop_delete_default());
extra_cleanup();
vEventGroupDelete(eth_event_group); vEventGroupDelete(eth_event_group);
} }
#endif // SOC_EMAC_SUPPORTED

View File

@@ -0,0 +1,173 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_event.h"
#include "esp_log.h"
#if CONFIG_TARGET_USE_SPI_ETHERNET
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_mac.h"
#endif // CONFIG_TARGET_USE_SPI_ETHERNET
#include "sdkconfig.h"
#include "esp_eth_test_common.h"
#if CONFIG_TARGET_USE_SPI_ETHERNET
#define DEFAULT_TARGET_SPI_HOST 1
#define DEFAULT_TARGET_SPI_MISO_GPIO 12
#define DEFAULT_TARGET_SPI_MOSI_GPIO 13
#define DEFAULT_TARGET_SPI_SCLK_GPIO 14
#define DEFAULT_TARGET_SPI_CS_GPIO 15
#endif // CONFIG_TARGET_USE_SPI_ETHERNET
static const char *TAG = "esp32_eth_test_common";
esp_eth_mac_t *mac_init(void *vendor_emac_config, eth_mac_config_t *mac_config)
{
esp_eth_mac_t *mac = NULL;
eth_mac_config_t mac_config_default = ETH_MAC_DEFAULT_CONFIG();
if (mac_config == NULL) {
mac_config = &mac_config_default;
}
#if CONFIG_TARGET_USE_INTERNAL_ETHERNET
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
if (vendor_emac_config == NULL) {
vendor_emac_config = &esp32_emac_config;
}
mac = esp_eth_mac_new_esp32(vendor_emac_config, mac_config);
#elif CONFIG_TARGET_USE_SPI_ETHERNET
// Install GPIO ISR handler to be able to service SPI Eth modlues interrupts
gpio_install_isr_service(0);
spi_bus_config_t buscfg = {
.miso_io_num = DEFAULT_TARGET_SPI_MISO_GPIO,
.mosi_io_num = DEFAULT_TARGET_SPI_MOSI_GPIO,
.sclk_io_num = DEFAULT_TARGET_SPI_SCLK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
};
TEST_ESP_OK(spi_bus_initialize(DEFAULT_TARGET_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
spi_device_interface_config_t devcfg = {
.mode = 0,
.spics_io_num = DEFAULT_TARGET_SPI_CS_GPIO,
.clock_speed_hz = CONFIG_TARGET_SPI_CLOCK_MHZ * 1000 * 1000,
.queue_size = 20
};
#if CONFIG_TARGET_ETH_PHY_DEVICE_W5500
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(DEFAULT_TARGET_SPI_HOST, &devcfg);
if (vendor_emac_config == NULL) {
vendor_emac_config = &w5500_config;
}
mac = esp_eth_mac_new_w5500(vendor_emac_config, mac_config);
#elif CONFIG_TARGET_ETH_PHY_DEVICE_KSZ8851SNL
eth_ksz8851snl_config_t ksz8851snl_config = ETH_KSZ8851SNL_DEFAULT_CONFIG(DEFAULT_TARGET_SPI_HOST, &devcfg);
ksz8851snl_config.int_gpio_num = 4;
if (vendor_emac_config == NULL) {
vendor_emac_config = &ksz8851snl_config;
}
mac = esp_eth_mac_new_ksz8851snl(vendor_emac_config, mac_config);
#elif CONFIG_TARGET_ETH_PHY_DEVICE_DM9051
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(DEFAULT_TARGET_SPI_HOST, &devcfg);
if (vendor_emac_config == NULL) {
vendor_emac_config = &dm9051_config ;
}
mac = esp_eth_mac_new_dm9051(vendor_emac_config, mac_config);
#endif // CONFIG_TARGET_ETH_PHY_DEVICE_W5500
#endif // CONFIG_TARGET_USE_INTERNAL_ETHERNET
return mac;
}
esp_eth_phy_t *phy_init(eth_phy_config_t *phy_config)
{
esp_eth_phy_t *phy = NULL;
eth_phy_config_t phy_config_default = ETH_PHY_DEFAULT_CONFIG();
if (phy_config == NULL) {
phy_config = &phy_config_default;
}
#if CONFIG_TARGET_USE_INTERNAL_ETHERNET
phy_config->phy_addr = ESP_ETH_PHY_ADDR_AUTO;
#if CONFIG_TARGET_ETH_PHY_DEVICE_IP101
phy = esp_eth_phy_new_ip101(phy_config);
#elif CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX
phy = esp_eth_phy_new_lan87xx(phy_config);
#elif CONFIG_TARGET_ETH_PHY_DEVICE_KSZ80XX
phy = esp_eth_phy_new_ksz80xx(phy_config);
#elif CONFIG_TARGET_ETH_PHY_DEVICE_RTL8201
phy = esp_eth_phy_new_rtl8201(phy_config);
#elif CONFIG_TARGET_ETH_PHY_DEVICE_DP83848
phy = esp_eth_phy_new_dp83848(phy_config);
#endif // CONFIG_TARGET_ETH_PHY_DEVICE_IP101
#elif CONFIG_TARGET_USE_SPI_ETHERNET
phy_config->reset_gpio_num = -1;
#if CONFIG_TARGET_ETH_PHY_DEVICE_W5500
phy = esp_eth_phy_new_w5500(phy_config);
#elif CONFIG_TARGET_ETH_PHY_DEVICE_KSZ8851SNL
phy = esp_eth_phy_new_ksz8851snl(phy_config);
#elif CONFIG_TARGET_ETH_PHY_DEVICE_DM9051
phy = esp_eth_phy_new_dm9051(phy_config);
#endif // CONFIG_TARGET_ETH_PHY_DEVICE_W5500
#endif // CONFIG_TARGET_USE_INTERNAL_ETHERNET
return phy;
}
void extra_eth_config(esp_eth_handle_t eth_handle)
{
// *** SPI Ethernet modules deviation ***
// Rationale: The SPI Ethernet modules don't have a burned default factory MAC address
#if CONFIG_TARGET_USE_SPI_ETHERNET
uint8_t base_mac_addr[ETH_ADDR_LEN];
TEST_ESP_OK(esp_efuse_mac_get_default(base_mac_addr));
uint8_t local_mac[ETH_ADDR_LEN];
TEST_ESP_OK(esp_derive_local_mac(local_mac, base_mac_addr));
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, local_mac));
#endif
}
void extra_cleanup(void)
{
#if CONFIG_TARGET_USE_SPI_ETHERNET
TEST_ESP_OK(spi_bus_free(DEFAULT_TARGET_SPI_HOST));
#endif
}
/** Event handler for Ethernet events */
void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg;
switch (event_id) {
case ETHERNET_EVENT_CONNECTED:
xEventGroupSetBits(eth_event_group, ETH_CONNECT_BIT);
break;
case ETHERNET_EVENT_DISCONNECTED:
break;
case ETHERNET_EVENT_START:
xEventGroupSetBits(eth_event_group, ETH_START_BIT);
break;
case ETHERNET_EVENT_STOP:
xEventGroupSetBits(eth_event_group, ETH_STOP_BIT);
break;
default:
break;
}
}
/** Event handler for IP_EVENT_ETH_GOT_IP */
void got_ip_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)arg;
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
const esp_netif_ip_info_t *ip_info = &event->ip_info;
ESP_LOGI(TAG, "Ethernet Got IP Address");
ESP_LOGI(TAG, "~~~~~~~~~~~");
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
ESP_LOGI(TAG, "~~~~~~~~~~~");
xEventGroupSetBits(eth_event_group, ETH_GOT_IP_BIT);
}

View File

@@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
#include "unity.h"
#include "test_utils.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_eth.h"
#define ETH_START_BIT BIT(0)
#define ETH_STOP_BIT BIT(1)
#define ETH_CONNECT_BIT BIT(2)
#define ETH_GOT_IP_BIT BIT(3)
#define ETH_START_TIMEOUT_MS (10000)
#define ETH_CONNECT_TIMEOUT_MS (40000)
#define ETH_STOP_TIMEOUT_MS (10000)
#define ETH_GET_IP_TIMEOUT_MS (60000)
#define ETH_DOWNLOAD_END_TIMEOUT_MS (240000)
typedef struct {
uint8_t dest[ETH_ADDR_LEN];
uint8_t src[ETH_ADDR_LEN];
uint16_t proto;
uint8_t data[];
} __attribute__((__packed__)) emac_frame_t;
esp_eth_mac_t *mac_init(void *vendor_emac_config, eth_mac_config_t *mac_config);
esp_eth_phy_t *phy_init(eth_phy_config_t *phy_config);
void extra_eth_config(esp_eth_handle_t eth_handle);
void extra_cleanup(void);
/** Event handler for Ethernet events */
void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data);
/** Event handler for IP_EVENT_ETH_GOT_IP */
void got_ip_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data);

View File

@@ -0,0 +1,255 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "esp_eth_test_common.h"
#define ETHERTYPE_TX_STD 0x2222 // frame transmitted via emac_hal_transmit_frame
#define ETHERTYPE_TX_MULTI_2 0x2223 // frame transmitted via emac_hal_transmit_multiple_buf_frame (2 buffers)
#define ETHERTYPE_TX_MULTI_3 0x2224 // frame transmitted via emac_hal_transmit_multiple_buf_frame (3 buffers)
static const char *TAG = "esp32_eth_test_hal";
typedef struct
{
SemaphoreHandle_t mutex;
uint16_t expected_size;
uint16_t expected_size_2;
uint16_t expected_size_3;
} recv_hal_check_info_t;
static esp_err_t eth_recv_hal_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv)
{
emac_frame_t *pkt = (emac_frame_t *)buffer;
recv_hal_check_info_t *recv_info = (recv_hal_check_info_t *)priv;
uint16_t expected_size = recv_info->expected_size + recv_info->expected_size_2 + recv_info->expected_size_3;
ESP_LOGI(TAG, "recv frame size: %" PRIu16, expected_size);
TEST_ASSERT_EQUAL(expected_size, length);
// frame transmitted via emac_hal_transmit_frame
if (pkt->proto == ETHERTYPE_TX_STD) {
for (int i = 0; i < recv_info->expected_size - ETH_HEADER_LEN; i++) {
TEST_ASSERT_EQUAL(pkt->data[i], i & 0xFF);
}
// frame transmitted via emac_hal_transmit_multiple_buf_frame (2 buffers)
} else if (pkt->proto == ETHERTYPE_TX_MULTI_2) {
uint8_t *data_p = pkt->data;
for (int i = 0; i < recv_info->expected_size - ETH_HEADER_LEN; i++) {
TEST_ASSERT_EQUAL(*(data_p++), i & 0xFF);
}
int j = ETH_MAX_PAYLOAD_LEN;
for (int i = 0; i < recv_info->expected_size_2; i++) {
TEST_ASSERT_EQUAL(*(data_p++), j & 0xFF);
j--;
}
// frame transmitted via emac_hal_transmit_multiple_buf_frame (3 buffers)
} else if (pkt->proto == ETHERTYPE_TX_MULTI_3) {
uint8_t *data_p = pkt->data;
for (int i = 0; i < recv_info->expected_size - ETH_HEADER_LEN; i++) {
TEST_ASSERT_EQUAL(*(data_p++), i & 0xFF);
}
int j = ETH_MAX_PAYLOAD_LEN;
for (int i = 0; i < recv_info->expected_size_2; i++) {
TEST_ASSERT_EQUAL(*(data_p++), j & 0xFF);
j--;
}
for (int i = 0; i < recv_info->expected_size_3; i++) {
TEST_ASSERT_EQUAL(*(data_p++), i & 0xFF);
}
} else {
TEST_FAIL();
}
memset(buffer, 0, length);
free(buffer);
xSemaphoreGive(recv_info->mutex);
return ESP_OK;
}
TEST_CASE("hal receive/transmit", "[emac_hal]")
{
recv_hal_check_info_t recv_info;
recv_info.mutex = xSemaphoreCreateBinary();
TEST_ASSERT_NOT_NULL(recv_info.mutex);
recv_info.expected_size = 0;
recv_info.expected_size_2 = 0;
recv_info.expected_size_3 = 0;
EventBits_t bits = 0;
EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ASSERT(eth_event_group != NULL);
TEST_ESP_OK(esp_event_loop_create_default());
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_event_group));
esp_eth_mac_t *mac = mac_init(NULL, NULL);
TEST_ASSERT_NOT_NULL(mac);
esp_eth_phy_t *phy = phy_init(NULL);
TEST_ASSERT_NOT_NULL(phy);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // apply default driver configuration
esp_eth_handle_t eth_handle = NULL; // after driver installed, we will get the handle of the driver
TEST_ESP_OK(esp_eth_driver_install(&config, &eth_handle)); // install driver
TEST_ASSERT_NOT_NULL(eth_handle);
extra_eth_config(eth_handle);
// loopback greatly simplifies the test
bool loopback_en = true;
esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en);
TEST_ESP_OK(esp_eth_update_input_path(eth_handle, eth_recv_hal_check_cb, &recv_info));
// start the driver
TEST_ESP_OK(esp_eth_start(eth_handle));
// wait for connection start
bits = xEventGroupWaitBits(eth_event_group, ETH_START_BIT, true, true, pdMS_TO_TICKS(ETH_START_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_START_BIT) == ETH_START_BIT);
// wait for connection establish
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
// create test frame
emac_frame_t *test_pkt = calloc(1, ETH_MAX_PACKET_SIZE);
test_pkt->proto = ETHERTYPE_TX_STD;
memset(test_pkt->dest, 0xff, ETH_ADDR_LEN); // broadcast addr
uint8_t local_mac_addr[ETH_ADDR_LEN] = { 0 };
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, local_mac_addr));
memcpy(test_pkt->src, local_mac_addr, ETH_ADDR_LEN);
// fill with data
for (int i = 0; i < ETH_MAX_PAYLOAD_LEN; i++) {
test_pkt->data[i] = i & 0xFF;
}
// verify that HAL driver correctly processes frame from EMAC descriptors
uint16_t transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE;
ESP_LOGI(TAG, "transmit frame size: %" PRIu16, transmit_size);
recv_info.expected_size = transmit_size;
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(500)));
transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE - 1;
ESP_LOGI(TAG, "transmit frame size: %" PRIu16, transmit_size);
recv_info.expected_size = transmit_size;
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(500)));
transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE + 1;
ESP_LOGI(TAG, "transmit frame size: %" PRIu16, transmit_size);
recv_info.expected_size = transmit_size;
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(500)));
transmit_size = 2 * CONFIG_ETH_DMA_BUFFER_SIZE;
ESP_LOGI(TAG, "transmit frame size: %" PRIu16, transmit_size);
recv_info.expected_size = transmit_size;
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(500)));
transmit_size = 2 * CONFIG_ETH_DMA_BUFFER_SIZE - 1;
ESP_LOGI(TAG, "transmit frame size: %" PRIu16, transmit_size);
recv_info.expected_size = transmit_size;
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(500)));
transmit_size = 2 * CONFIG_ETH_DMA_BUFFER_SIZE + 1;
ESP_LOGI(TAG, "transmit frame size: %" PRIu16, transmit_size);
recv_info.expected_size = transmit_size;
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(500)));
// verify transmission of multiple buffers
uint16_t transmit_size_2;
// allocated the second buffer
uint8_t *pkt_data_2 = malloc(ETH_MAX_PAYLOAD_LEN);
// fill with data (reverse order to differentiate the buffers)
int j = ETH_MAX_PAYLOAD_LEN;
for (int i = 0; i < ETH_MAX_PAYLOAD_LEN; i++) {
pkt_data_2[i] = j & 0xFF;
j--;
}
// change protocol number so the cb function is aware that frame was joint from two buffers
test_pkt->proto = ETHERTYPE_TX_MULTI_2;
transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE;
transmit_size_2 = CONFIG_ETH_DMA_BUFFER_SIZE;
recv_info.expected_size = transmit_size;
recv_info.expected_size_2 = transmit_size_2;
ESP_LOGI(TAG, "transmit joint frame size: %" PRIu16, transmit_size + transmit_size_2);
TEST_ESP_OK(esp_eth_transmit_vargs(eth_handle, 2, test_pkt, transmit_size, pkt_data_2, transmit_size_2));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(500)));
transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE - 1;
transmit_size_2 = CONFIG_ETH_DMA_BUFFER_SIZE;
recv_info.expected_size = transmit_size;
recv_info.expected_size_2 = transmit_size_2;
ESP_LOGI(TAG, "transmit joint frame size: %" PRIu16, transmit_size + transmit_size_2);
TEST_ESP_OK(esp_eth_transmit_vargs(eth_handle, 2, test_pkt, transmit_size, pkt_data_2, transmit_size_2));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(500)));
transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE + 1;
transmit_size_2 = CONFIG_ETH_DMA_BUFFER_SIZE;
recv_info.expected_size = transmit_size;
recv_info.expected_size_2 = transmit_size_2;
ESP_LOGI(TAG, "transmit joint frame size: %" PRIu16, transmit_size + transmit_size_2);
TEST_ESP_OK(esp_eth_transmit_vargs(eth_handle, 2, test_pkt, transmit_size, pkt_data_2, transmit_size_2));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(500)));
uint16_t transmit_size_3 = 256;
// allocated the third buffer
uint8_t *pkt_data_3 = malloc(256);
// fill with data
for (int i = 0; i < 256; i++) {
pkt_data_3[i] = i & 0xFF;
}
// change protocol number so the cb function is aware that frame was joint from three buffers
test_pkt->proto = ETHERTYPE_TX_MULTI_3;
transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE;
transmit_size_2 = CONFIG_ETH_DMA_BUFFER_SIZE;
transmit_size_3 = 256;
recv_info.expected_size = transmit_size;
recv_info.expected_size_2 = transmit_size_2;
recv_info.expected_size_3 = transmit_size_3;
ESP_LOGI(TAG, "transmit joint frame size (3 buffs): %" PRIu16, transmit_size + transmit_size_2 + transmit_size_3);
TEST_ESP_OK(esp_eth_transmit_vargs(eth_handle, 3, test_pkt, transmit_size, pkt_data_2, transmit_size_2, pkt_data_3, transmit_size_3));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(500)));
transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE - 1;
transmit_size_2 = CONFIG_ETH_DMA_BUFFER_SIZE;
transmit_size_3 = 256;
recv_info.expected_size = transmit_size;
recv_info.expected_size_2 = transmit_size_2;
recv_info.expected_size_3 = transmit_size_3;
ESP_LOGI(TAG, "transmit joint frame size (3 buffs): %" PRIu16, transmit_size + transmit_size_2 + transmit_size_3);
TEST_ESP_OK(esp_eth_transmit_vargs(eth_handle, 3, test_pkt, transmit_size, pkt_data_2, transmit_size_2, pkt_data_3, transmit_size_3));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(500)));
transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE + 1;
transmit_size_2 = CONFIG_ETH_DMA_BUFFER_SIZE;
transmit_size_3 = 256;
recv_info.expected_size = transmit_size;
recv_info.expected_size_2 = transmit_size_2;
recv_info.expected_size_3 = transmit_size_3;
ESP_LOGI(TAG, "transmit joint frame size (3 buffs): %" PRIu16, transmit_size + transmit_size_2 + transmit_size_3);
TEST_ESP_OK(esp_eth_transmit_vargs(eth_handle, 3, test_pkt, transmit_size, pkt_data_2, transmit_size_2, pkt_data_3, transmit_size_3));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(500)));
free(test_pkt);
free(pkt_data_2);
free(pkt_data_3);
// stop Ethernet driver
TEST_ESP_OK(esp_eth_stop(eth_handle));
/* wait for connection stop */
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
TEST_ESP_OK(phy->del(phy));
TEST_ESP_OK(mac->del(mac));
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
TEST_ESP_OK(esp_event_loop_delete_default());
extra_cleanup();
vEventGroupDelete(eth_event_group);
vSemaphoreDelete(recv_info.mutex);
}

View File

@@ -0,0 +1,277 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_eth_test_common.h"
#define ETH_BROADCAST_RECV_BIT BIT(0)
#define ETH_MULTICAST_RECV_BIT BIT(1)
#define ETH_UNICAST_RECV_BIT BIT(2)
#define POKE_REQ 0xFA
#define POKE_RESP 0xFB
#define DUMMY_TRAFFIC 0xFF
TEST_CASE("ethernet broadcast transmit", "[ethernet_l2]")
{
EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ASSERT(eth_event_group != NULL);
esp_eth_mac_t *mac = mac_init(NULL, NULL);
TEST_ASSERT_NOT_NULL(mac);
esp_eth_phy_t *phy = phy_init(NULL);
TEST_ASSERT_NOT_NULL(phy);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // apply default driver configuration
esp_eth_handle_t eth_handle = NULL; // after driver installed, we will get the handle of the driver
TEST_ESP_OK(esp_eth_driver_install(&config, &eth_handle)); // install driver
TEST_ASSERT_NOT_NULL(eth_handle);
extra_eth_config(eth_handle);
TEST_ESP_OK(esp_event_loop_create_default());
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_event_group));
TEST_ESP_OK(esp_eth_start(eth_handle)); // start Ethernet driver state machine
EventBits_t bits = 0;
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
// if DUT is connected in network with switch: even if link is indicated up, it may take some time the switch
// starts switching the associated port (e.g. it runs RSTP at first)
vTaskDelay(pdMS_TO_TICKS(1000));
emac_frame_t *pkt = malloc(1024);
pkt->proto = 0x2222;
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, pkt->src));
memset(pkt->dest, 0xff, ETH_ADDR_LEN); // broadcast addr
for (int i = 0; i < (1024 - ETH_HEADER_LEN); ++i){
pkt->data[i] = i & 0xff;
}
TEST_ESP_OK(esp_eth_transmit(eth_handle, pkt, 1024));
vTaskDelay(pdMS_TO_TICKS(100));
free(pkt);
TEST_ESP_OK(esp_eth_stop(eth_handle));
TEST_ESP_OK(esp_event_loop_delete_default());
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
phy->del(phy);
mac->del(mac);
extra_cleanup();
vEventGroupDelete(eth_event_group);
}
static uint8_t local_mac_addr[ETH_ADDR_LEN] = {};
esp_err_t l2_packet_txrx_test_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv) {
EventGroupHandle_t eth_event_group = (EventGroupHandle_t)priv;
emac_frame_t *pkt = (emac_frame_t *) buffer;
// check header
if (pkt->proto == 0x2222 && length == 1024) {
// check content
for (int i = 0; i < (length - ETH_HEADER_LEN); ++i) {
if (pkt->data[i] != (i & 0xff)) {
printf("payload mismatch\n");
return ESP_OK;
}
}
if (memcmp(pkt->dest, "\xff\xff\xff\xff\xff\xff", ETH_ADDR_LEN) == 0) {
printf("broadcast received...\n");
xEventGroupSetBits(eth_event_group, ETH_BROADCAST_RECV_BIT);
} else if (pkt->dest[0] & 0x1) {
printf("multicast received...\n");
xEventGroupSetBits(eth_event_group, ETH_MULTICAST_RECV_BIT);
} else if (memcmp(pkt->dest, local_mac_addr, ETH_ADDR_LEN) == 0) {
printf("unicast received...\n");
xEventGroupSetBits(eth_event_group, ETH_UNICAST_RECV_BIT);
}
} else {
printf("unexpected frame (protocol: 0x%x, length: %" PRIu32 ")\n", pkt->proto, length);
}
return ESP_OK;
};
TEST_CASE("ethernet recv_pkt", "[ethernet_l2]")
{
EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ASSERT(eth_event_group != NULL);
esp_eth_mac_t *mac = mac_init(NULL, NULL);
TEST_ASSERT_NOT_NULL(mac);
esp_eth_phy_t *phy = phy_init(NULL);
TEST_ASSERT_NOT_NULL(phy);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // apply default driver configuration
esp_eth_handle_t eth_handle = NULL; // after driver installed, we will get the handle of the driver
TEST_ESP_OK(esp_eth_driver_install(&config, &eth_handle)); // install driver
TEST_ASSERT_NOT_NULL(eth_handle);
extra_eth_config(eth_handle);
TEST_ESP_OK(esp_event_loop_create_default());
TEST_ESP_OK(esp_eth_start(eth_handle)); // start Ethernet driver state machine
TEST_ESP_OK(mac->get_addr(mac, local_mac_addr));
// test app will parse the DUT MAC from this line of log output
printf("DUT MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", local_mac_addr[0], local_mac_addr[1], local_mac_addr[2],
local_mac_addr[3], local_mac_addr[4], local_mac_addr[5]);
TEST_ESP_OK(esp_eth_update_input_path(eth_handle, l2_packet_txrx_test_cb, eth_event_group));
EventBits_t bits = 0;
bits = xEventGroupWaitBits(eth_event_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT,
true, true, pdMS_TO_TICKS(5000));
TEST_ASSERT((bits & (ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT)) ==
(ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT));
TEST_ESP_OK(esp_eth_stop(eth_handle));
TEST_ESP_OK(esp_event_loop_delete_default());
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
phy->del(phy);
mac->del(mac);
extra_cleanup();
vEventGroupDelete(eth_event_group);
}
typedef struct
{
SemaphoreHandle_t mutex;
int rx_pkt_cnt;
} recv_info_t;
static esp_err_t eth_recv_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv)
{
emac_frame_t *pkt = (emac_frame_t *)buffer;
recv_info_t *recv_info = (recv_info_t *)priv;
if (pkt->proto == 0x2222) {
switch (pkt->data[0])
{
case POKE_RESP:
xSemaphoreGive(recv_info->mutex);
break;
case DUMMY_TRAFFIC:
(recv_info->rx_pkt_cnt)++;
break;
default:
break;
}
}
free(buffer);
return ESP_OK;
}
TEST_CASE("ethernet start/stop stress test under heavy traffic", "[ethernet_l2]")
{
recv_info_t recv_info;
recv_info.mutex = xSemaphoreCreateBinary();
TEST_ASSERT_NOT_NULL(recv_info.mutex);
recv_info.rx_pkt_cnt = 0;
esp_eth_mac_t *mac = mac_init(NULL, NULL);
TEST_ASSERT_NOT_NULL(mac);
esp_eth_phy_t *phy = phy_init(NULL);
TEST_ASSERT_NOT_NULL(phy);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); // apply default driver configuration
esp_eth_handle_t eth_handle = NULL; // after driver installed, we will get the handle of the driver
TEST_ESP_OK(esp_eth_driver_install(&config, &eth_handle)); // install driver
TEST_ASSERT_NOT_NULL(eth_handle);
extra_eth_config(eth_handle);
TEST_ESP_OK(mac->get_addr(mac, local_mac_addr));
// test app will parse the DUT MAC from this line of log output
printf("DUT MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", local_mac_addr[0], local_mac_addr[1], local_mac_addr[2],
local_mac_addr[3], local_mac_addr[4], local_mac_addr[5]);
TEST_ESP_OK(esp_eth_update_input_path(eth_handle, eth_recv_cb, &recv_info));
EventBits_t bits = 0;
EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ASSERT(eth_event_group != NULL);
TEST_ESP_OK(esp_event_loop_create_default());
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, eth_event_group));
// create a control frame to control test flow between the UT and the Python test script
emac_frame_t *ctrl_pkt = calloc(1, 60);
ctrl_pkt->proto = 0x2222;
memset(ctrl_pkt->dest, 0xff, ETH_ADDR_LEN); // broadcast addr
memcpy(ctrl_pkt->src, local_mac_addr, ETH_ADDR_LEN);
// create dummy data packet used for traffic generation
emac_frame_t *pkt = calloc(1, 1500);
pkt->proto = 0x2222;
// we don't care about dest MAC address much, however it is better to not be broadcast or multifcast to not flood
// other network nodes
memset(pkt->dest, 0xBA, ETH_ADDR_LEN);
memcpy(pkt->src, local_mac_addr, ETH_ADDR_LEN);
printf("EMAC start/stop stress test under heavy Tx traffic\n");
for (int tx_i = 0; tx_i < 10; tx_i++) {
TEST_ESP_OK(esp_eth_start(eth_handle)); // start Ethernet driver state machine
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
// if DUT is connected in network with switch: even if link is indicated up, it may take some time the switch
// starts switching the associated port (e.g. it runs RSTP at first)
vTaskDelay(pdMS_TO_TICKS(1000));
// at first, check that Tx/Rx path works as expected by poking the test script
// this also serves as main PASS/FAIL criteria
ctrl_pkt->data[0] = POKE_REQ;
ctrl_pkt->data[1] = tx_i;
TEST_ESP_OK(esp_eth_transmit(eth_handle, ctrl_pkt, 60));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(3000)));
printf("Tx Test iteration %d\n", tx_i);
// generate heavy Tx traffic
printf("Note: transmit errors are expected...\n");
for (int j = 0; j < 150; j++) {
// return value is not checked on purpose since it is expected that it may fail time to time because
// we may try to queue more packets than hardware is able to handle
pkt->data[0] = j & 0xFF; // sequence number
esp_eth_transmit(eth_handle, pkt, 1500);
}
TEST_ESP_OK(esp_eth_stop(eth_handle));
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
printf("Ethernet stopped\n");
}
printf("EMAC start/stop stress test under heavy Rx traffic\n");
for (int rx_i = 0; rx_i < 10; rx_i++) {
recv_info.rx_pkt_cnt = 0;
TEST_ESP_OK(esp_eth_start(eth_handle)); // start Ethernet driver state machine
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
// if DUT is connected in network with switch: even if link is indicated up, it may take some time the switch
// starts switching the associated port (e.g. it runs RSTP at first)
vTaskDelay(pdMS_TO_TICKS(1000));
ctrl_pkt->data[0] = POKE_REQ;
ctrl_pkt->data[1] = rx_i;
TEST_ESP_OK(esp_eth_transmit(eth_handle, ctrl_pkt, 60));
TEST_ASSERT(xSemaphoreTake(recv_info.mutex, pdMS_TO_TICKS(3000)));
printf("Rx Test iteration %d\n", rx_i);
vTaskDelay(pdMS_TO_TICKS(500));
TEST_ESP_OK(esp_eth_stop(eth_handle));
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(3000));
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
printf("Recv packets: %d\n", recv_info.rx_pkt_cnt);
TEST_ASSERT_GREATER_THAN_INT32(0, recv_info.rx_pkt_cnt);
printf("Ethernet stopped\n");
}
free(ctrl_pkt);
free(pkt);
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
TEST_ESP_OK(esp_event_loop_delete_default());
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
phy->del(phy);
mac->del(mac);
extra_cleanup();
vEventGroupDelete(eth_event_group);
vSemaphoreDelete(recv_info.mutex);
}

View File

@@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "test_utils.h"
void app_main(void)
{
unity_run_menu();
}

View File

@@ -5,6 +5,7 @@ import contextlib
import logging import logging
import os import os
import socket import socket
import time
from multiprocessing import Pipe, Process, connection from multiprocessing import Pipe, Process, connection
from typing import Iterator from typing import Iterator
@@ -16,28 +17,34 @@ ETH_TYPE = 0x2222
class EthTestIntf(object): class EthTestIntf(object):
def __init__(self, eth_type: int): def __init__(self, eth_type: int, my_if: str = ''):
self.target_if = '' self.target_if = ''
self.eth_type = eth_type self.eth_type = eth_type
self.find_target_if(my_if)
def find_target_if(self) -> None: def find_target_if(self, my_if: str = '') -> None:
# try to determine which interface to use # try to determine which interface to use
netifs = os.listdir('/sys/class/net/') netifs = os.listdir('/sys/class/net/')
logging.info('detected interfaces: %s', str(netifs)) logging.info('detected interfaces: %s', str(netifs))
for netif in netifs: for netif in netifs:
if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: # if no interface defined, try to find it automatically
self.target_if = netif if my_if == '':
break if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0:
self.target_if = netif
break
else:
if netif.find(my_if) == 0:
self.target_if = my_if
break
if self.target_if == '': if self.target_if == '':
raise Exception('no network interface found') raise Exception('network interface not found')
logging.info('Use %s for testing', self.target_if) logging.info('Use %s for testing', self.target_if)
@contextlib.contextmanager @contextlib.contextmanager
def configure_eth_if(self) -> Iterator[socket.socket]: def configure_eth_if(self) -> Iterator[socket.socket]:
so = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(self.eth_type)) so = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(self.eth_type))
so.bind((self.target_if, 0)) so.bind((self.target_if, 0))
try: try:
yield so yield so
finally: finally:
@@ -83,25 +90,34 @@ class EthTestIntf(object):
raise e raise e
def actual_test(dut: Dut) -> None: def ethernet_test(dut: Dut) -> None:
target_if = EthTestIntf(ETH_TYPE)
target_if.find_target_if()
dut.expect_exact('Press ENTER to see the list of tests') dut.expect_exact('Press ENTER to see the list of tests')
dut.write('\n') dut.write('\n')
dut.expect_exact('Enter test for running.') dut.expect_exact('Enter test for running.')
dut.write('"start_and_stop"') dut.write('[ethernet]')
dut.expect_unity_test_output(timeout=980)
def ethernet_int_emac_hal_test(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('\n')
dut.expect_exact('Enter test for running.')
dut.write('[emac_hal]')
dut.expect_unity_test_output() dut.expect_unity_test_output()
dut.expect_exact("Enter next test, or 'enter' to see menu")
dut.write('"get_set_mac"')
dut.expect_unity_test_output()
dut.expect_exact("Enter next test, or 'enter' to see menu") def ethernet_l2_test(dut: Dut) -> None:
target_if = EthTestIntf(ETH_TYPE)
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('\n')
dut.expect_exact('Enter test for running.')
with target_if.configure_eth_if() as so: with target_if.configure_eth_if() as so:
so.settimeout(30) so.settimeout(30)
dut.write('"ethernet_broadcast_transmit"') dut.write('"ethernet broadcast transmit"')
eth_frame = Ether(so.recv(1024)) eth_frame = Ether(so.recv(1024))
for i in range(0, 1010): for i in range(0, 1010):
if eth_frame.load[i] != i & 0xff: if eth_frame.load[i] != i & 0xff:
@@ -109,18 +125,19 @@ def actual_test(dut: Dut) -> None:
dut.expect_unity_test_output() dut.expect_unity_test_output()
dut.expect_exact("Enter next test, or 'enter' to see menu") dut.expect_exact("Enter next test, or 'enter' to see menu")
dut.write('"recv_pkt"') dut.write('"ethernet recv_pkt"')
res = dut.expect( res = dut.expect(
r'([\s\S]*)' r'([\s\S]*)'
r'DUT MAC: ([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2})' r'DUT MAC: ([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2})'
) )
time.sleep(1)
target_if.send_eth_packet('ff:ff:ff:ff:ff:ff') # broadcast frame target_if.send_eth_packet('ff:ff:ff:ff:ff:ff') # broadcast frame
target_if.send_eth_packet('01:00:00:00:00:00') # multicast frame target_if.send_eth_packet('01:00:00:00:00:00') # multicast frame
target_if.send_eth_packet(res.group(2)) # unicast frame target_if.send_eth_packet(res.group(2)) # unicast frame
dut.expect_unity_test_output(extra_before=res.group(1)) dut.expect_unity_test_output(extra_before=res.group(1))
dut.expect_exact("Enter next test, or 'enter' to see menu") dut.expect_exact("Enter next test, or 'enter' to see menu")
dut.write('"start_stop_stress_test"') dut.write('"ethernet start/stop stress test under heavy traffic"')
res = dut.expect( res = dut.expect(
r'([\s\S]*)' r'([\s\S]*)'
r'DUT MAC: ([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2})' r'DUT MAC: ([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2})'
@@ -144,21 +161,43 @@ def actual_test(dut: Dut) -> None:
dut.expect_unity_test_output(extra_before=res.group(1)) dut.expect_unity_test_output(extra_before=res.group(1))
@pytest.mark.esp32
@pytest.mark.ethernet
@pytest.mark.parametrize('config', [
'default_ip101',
'release_ip101',
'single_core_ip101'
], indirect=True)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_esp_ethernet(dut: Dut) -> None:
ethernet_test(dut)
@pytest.mark.esp32
@pytest.mark.ethernet
@pytest.mark.parametrize('config', [
'default_ip101',
], indirect=True)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_esp_emac_hal(dut: Dut) -> None:
ethernet_int_emac_hal_test(dut)
@pytest.mark.esp32 @pytest.mark.esp32
@pytest.mark.ip101 @pytest.mark.ip101
@pytest.mark.parametrize('config', [ @pytest.mark.parametrize('config', [
'ip101', 'default_ip101',
], indirect=True) ], indirect=True)
@pytest.mark.flaky(reruns=3, reruns_delay=5) @pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_esp_eth_ip101(dut: Dut) -> None: def test_esp_eth_ip101(dut: Dut) -> None:
actual_test(dut) ethernet_l2_test(dut)
@pytest.mark.esp32 @pytest.mark.esp32
@pytest.mark.lan8720 @pytest.mark.lan8720
@pytest.mark.parametrize('config', [ @pytest.mark.parametrize('config', [
'lan8720', 'default_lan8720',
], indirect=True) ], indirect=True)
@pytest.mark.flaky(reruns=3, reruns_delay=5) @pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_esp_eth_lan8720(dut: Dut) -> None: def test_esp_eth_lan8720(dut: Dut) -> None:
actual_test(dut) ethernet_l2_test(dut)

View File

@@ -0,0 +1,8 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ESP_TASK_WDT=n
CONFIG_TARGET_USE_SPI_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_DM9051=y

View File

@@ -0,0 +1,9 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_DP83848=y

View File

@@ -1,7 +1,9 @@
CONFIG_IDF_TARGET="esp32" CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ETH_USE_ESP32_EMAC=y CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT=n CONFIG_ESP_TASK_WDT=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y

View File

@@ -0,0 +1,11 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_KSZ80XX=y
CONFIG_ETH_RMII_CLK_OUTPUT=y
CONFIG_ETH_RMII_CLK_OUT_GPIO=17

View File

@@ -0,0 +1,8 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ESP_TASK_WDT=n
CONFIG_TARGET_USE_SPI_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_KSZ8851SNL=y

View File

@@ -1,9 +1,11 @@
CONFIG_IDF_TARGET="esp32" CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ETH_USE_ESP32_EMAC=y CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT=n CONFIG_ESP_TASK_WDT=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX=y CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX=y
CONFIG_ETH_RMII_CLK_OUTPUT=y CONFIG_ETH_RMII_CLK_OUTPUT=y
CONFIG_ETH_RMII_CLK_OUT_GPIO=17 CONFIG_ETH_RMII_CLK_OUT_GPIO=17

View File

@@ -0,0 +1,9 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_RTL8201=y

View File

@@ -0,0 +1,8 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ESP_TASK_WDT=n
CONFIG_TARGET_USE_SPI_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_W5500=y

View File

@@ -0,0 +1,12 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y

View File

@@ -0,0 +1,13 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_MEMMAP_SMP=n
CONFIG_FREERTOS_UNICORE=y
CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY=y
CONFIG_ESP32_RTCDATA_IN_FAST_MEM=y
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_TASK_WDT=n
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y

View File

@@ -1,6 +1,6 @@
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps # Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
components/esp_netif/test_apps: components/esp_netif/test_apps/test_app_esp_netif:
disable: disable:
- if: IDF_TARGET == "esp32c6" - if: IDF_TARGET == "esp32c6"
temporary: true temporary: true
@@ -9,3 +9,9 @@ components/esp_netif/test_apps:
- if: IDF_TARGET != "esp32s2" - if: IDF_TARGET != "esp32s2"
temporary: true temporary: true
reason: lack of runners reason: lack of runners
components/esp_netif/test_apps/test_app_vfs_l2tap:
disable:
- if: SOC_EMAC_SUPPORTED != 1
temporary: false
reason: test uses internal EMAC

View File

@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "unity.h" #include "unity.h"

View File

@@ -0,0 +1,10 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp_vfs_l2tap_test)
idf_component_get_property(lib esp_netif COMPONENT_LIB)
target_compile_options(${lib} PRIVATE "-fsanitize=undefined" "-fno-sanitize=shift-base")

View File

@@ -0,0 +1,2 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |

View File

@@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS "."
PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES cmock test_utils esp_netif driver esp_eth)

View File

@@ -11,6 +11,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/event_groups.h" #include "freertos/event_groups.h"
@@ -29,8 +30,6 @@
#include "esp_vfs_l2tap.h" #include "esp_vfs_l2tap.h"
#if CONFIG_ESP_NETIF_L2_TAP
#define ETH_FILTER_LE 0x7A05 #define ETH_FILTER_LE 0x7A05
#define ETH_FILTER_BE 0x057A #define ETH_FILTER_BE 0x057A
@@ -240,7 +239,7 @@ static void send_task(void *task_param)
* @brief Verifies vfs register/unregister functions * @brief Verifies vfs register/unregister functions
* *
*/ */
TEST_CASE("esp32 l2tap - vfs register", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("esp32 l2tap - vfs register", "[ethernet]")
{ {
int eth_tap_fd; int eth_tap_fd;
@@ -344,7 +343,7 @@ static void close_task(void *task_param)
vTaskDelete(NULL); vTaskDelete(NULL);
} }
TEST_CASE("esp32 l2tap - open/close", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("esp32 l2tap - open/close", "[ethernet]")
{ {
test_vfs_eth_network_t eth_network_hndls; test_vfs_eth_network_t eth_network_hndls;
@@ -415,7 +414,7 @@ TEST_CASE("esp32 l2tap - open/close", "[ethernet][test_env=UT_T2_Ethernet]")
* @brief Verifies that read does not block when fd is opened in non-blocking mode * @brief Verifies that read does not block when fd is opened in non-blocking mode
* *
*/ */
TEST_CASE("esp32 l2tap - non blocking read", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("esp32 l2tap - non blocking read", "[ethernet]")
{ {
test_vfs_eth_network_t eth_network_hndls; test_vfs_eth_network_t eth_network_hndls;
int eth_tap_fd; int eth_tap_fd;
@@ -536,7 +535,7 @@ TEST_CASE("esp32 l2tap - non blocking read", "[ethernet][test_env=UT_T2_Ethernet
* @brief Verifies that read blocks when fd opened in blocking mode * @brief Verifies that read blocks when fd opened in blocking mode
* *
*/ */
TEST_CASE("esp32 l2tap - blocking read", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("esp32 l2tap - blocking read", "[ethernet]")
{ {
test_vfs_eth_network_t eth_network_hndls; test_vfs_eth_network_t eth_network_hndls;
int eth_tap_fd; int eth_tap_fd;
@@ -599,7 +598,7 @@ TEST_CASE("esp32 l2tap - blocking read", "[ethernet][test_env=UT_T2_Ethernet]")
* @brief Verifies write * @brief Verifies write
* *
*/ */
TEST_CASE("esp32 l2tap - write", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("esp32 l2tap - write", "[ethernet]")
{ {
test_vfs_eth_network_t eth_network_hndls; test_vfs_eth_network_t eth_network_hndls;
int eth_tap_fd; int eth_tap_fd;
@@ -718,12 +717,12 @@ static void multi_fds_task (void *task_param)
for (int i = 0; i < sizeof(eth_tap_fds) / sizeof(int); i++) { for (int i = 0; i < sizeof(eth_tap_fds) / sizeof(int); i++) {
TEST_ASSERT_EQUAL(0, close(eth_tap_fds[i])); TEST_ASSERT_EQUAL(0, close(eth_tap_fds[i]));
} }
ESP_LOGI(TAG, "multi_fds_task %u done", task_info->task_id); ESP_LOGI(TAG, "multi_fds_task %" PRIu16 "done", task_info->task_id);
xSemaphoreGive(task_info->semaphore); xSemaphoreGive(task_info->semaphore);
vTaskDelete(NULL); vTaskDelete(NULL);
} }
TEST_CASE("esp32 l2tap - read/write multiple fd's used by multiple tasks", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("esp32 l2tap - read/write multiple fd's used by multiple tasks", "[ethernet]")
{ {
test_vfs_eth_network_t eth_network_hndls; test_vfs_eth_network_t eth_network_hndls;
@@ -752,7 +751,7 @@ TEST_CASE("esp32 l2tap - read/write multiple fd's used by multiple tasks", "[eth
* @brief Verifies proper functionality of ioctl RCV_FILTER option * @brief Verifies proper functionality of ioctl RCV_FILTER option
* *
*/ */
TEST_CASE("esp32 l2tap - ioctl - RCV_FILTER", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("esp32 l2tap - ioctl - RCV_FILTER", "[ethernet]")
{ {
test_vfs_eth_network_t eth_network_hndls; test_vfs_eth_network_t eth_network_hndls;
int eth_tap_fd; int eth_tap_fd;
@@ -849,7 +848,7 @@ TEST_CASE("esp32 l2tap - ioctl - RCV_FILTER", "[ethernet][test_env=UT_T2_Etherne
* @brief Verifies proper functionality of ioctl INTF_DEVICE option * @brief Verifies proper functionality of ioctl INTF_DEVICE option
* *
*/ */
TEST_CASE("esp32 l2tap - ioctl - INTF_DEVICE/DEVICE_DRV_HNDL", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("esp32 l2tap - ioctl - INTF_DEVICE/DEVICE_DRV_HNDL", "[ethernet]")
{ {
test_vfs_eth_network_t eth_network_hndls; test_vfs_eth_network_t eth_network_hndls;
int eth_tap_fd; int eth_tap_fd;
@@ -939,7 +938,7 @@ TEST_CASE("esp32 l2tap - ioctl - INTF_DEVICE/DEVICE_DRV_HNDL", "[ethernet][test_
* @brief Verifies proper functionality of ioctl unknown option * @brief Verifies proper functionality of ioctl unknown option
* *
*/ */
TEST_CASE("esp32 l2tap - ioctl - unknown", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("esp32 l2tap - ioctl - unknown", "[ethernet]")
{ {
test_vfs_eth_network_t eth_network_hndls; test_vfs_eth_network_t eth_network_hndls;
int eth_tap_fd; int eth_tap_fd;
@@ -964,7 +963,7 @@ TEST_CASE("esp32 l2tap - ioctl - unknown", "[ethernet][test_env=UT_T2_Ethernet]"
* @brief Verifies proper functionality of fcntl * @brief Verifies proper functionality of fcntl
* *
*/ */
TEST_CASE("esp32 l2tap - fcntl", "[ethernet][test_env=UT_T2_Ethernet]") TEST_CASE("esp32 l2tap - fcntl", "[ethernet]")
{ {
test_vfs_eth_network_t eth_network_hndls; test_vfs_eth_network_t eth_network_hndls;
int eth_tap_fd; int eth_tap_fd;
@@ -1064,4 +1063,8 @@ TEST_CASE("esp32 l2tap - fcntl", "[ethernet][test_env=UT_T2_Ethernet]")
TEST_ASSERT_EQUAL(ESP_OK, esp_vfs_l2tap_intf_unregister(NULL)); TEST_ASSERT_EQUAL(ESP_OK, esp_vfs_l2tap_intf_unregister(NULL));
ethernet_deinit(&eth_network_hndls); ethernet_deinit(&eth_network_hndls);
} }
#endif // CONFIG_ESP_NETIF_L2_TAP
void app_main(void)
{
unity_run_menu();
}

View File

@@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.ethernet
def test_esp_netif(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('\n')
dut.expect_exact('Enter test for running.')
dut.write('*')
dut.expect_unity_test_output()

View File

@@ -0,0 +1,4 @@
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ESP_NETIF_L2_TAP=y

View File

@@ -255,12 +255,12 @@ esp_err_t example_eth_init(esp_eth_handle_t *eth_handles_out[], uint8_t *eth_cnt
// Note that Locally Administered OUI range should be used only when testing on a LAN under your control! // Note that Locally Administered OUI range should be used only when testing on a LAN under your control!
uint8_t base_mac_addr[ETH_ADDR_LEN]; uint8_t base_mac_addr[ETH_ADDR_LEN];
ESP_GOTO_ON_ERROR(esp_efuse_mac_get_default(base_mac_addr), err, TAG, "get EFUSE MAC failed"); ESP_GOTO_ON_ERROR(esp_efuse_mac_get_default(base_mac_addr), err, TAG, "get EFUSE MAC failed");
u_int8_t local_mac_1[ETH_ADDR_LEN]; uint8_t local_mac_1[ETH_ADDR_LEN];
esp_derive_local_mac(local_mac_1, base_mac_addr); esp_derive_local_mac(local_mac_1, base_mac_addr);
spi_eth_module_config[0].mac_addr = local_mac_1; spi_eth_module_config[0].mac_addr = local_mac_1;
#if CONFIG_EXAMPLE_SPI_ETHERNETS_NUM > 1 #if CONFIG_EXAMPLE_SPI_ETHERNETS_NUM > 1
INIT_SPI_ETH_MODULE_CONFIG(spi_eth_module_config, 1); INIT_SPI_ETH_MODULE_CONFIG(spi_eth_module_config, 1);
u_int8_t local_mac_2[ETH_ADDR_LEN]; uint8_t local_mac_2[ETH_ADDR_LEN];
base_mac_addr[ETH_ADDR_LEN - 1] += 1; base_mac_addr[ETH_ADDR_LEN - 1] += 1;
esp_derive_local_mac(local_mac_2, base_mac_addr); esp_derive_local_mac(local_mac_2, base_mac_addr);
spi_eth_module_config[1].mac_addr = local_mac_2; spi_eth_module_config[1].mac_addr = local_mac_2;

View File

@@ -1,3 +0,0 @@
CONFIG_IDF_TARGET="esp32"
TEST_COMPONENTS=esp_netif
CONFIG_ESP_NETIF_L2_TAP=y