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
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:
extends:
- .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");
/* 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");
/* 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 */
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;
err:
return ret;
@@ -351,6 +347,10 @@ static esp_err_t emac_dm9051_start(esp_eth_mac_t *mac)
{
esp_err_t ret = ESP_OK;
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 */
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_IMR, IMR_PAR | IMR_PRI), err, TAG, "write IMR failed");
/* 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
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_eth_test)

View File

@@ -2,10 +2,8 @@
| 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
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 "."
PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES unity esp_eth esp_netif)
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
PRIV_REQUIRES unity test_utils esp_eth esp_netif esp_http_client
EMBED_TXTFILES dl_espressif_com_root_cert.pem
WHOLE_ARCHIVE)

View File

@@ -1,14 +1,70 @@
menu "esp_eth TEST_APPS Configuration"
choice TARGET_ETH_PHY_DEVICE
choice TARGET_ETH_CONFIG
prompt "Ethernet peripheral device"
default TARGET_ETH_PHY_DEVICE_IP101
default TARGET_USE_INTERNAL_ETHERNET
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

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 <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.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_http_client.h"
#include "esp_rom_md5.h"
#include "soc/soc_caps.h"
#if SOC_EMAC_SUPPORTED
#include "esp_eth_test_common.h"
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_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 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)
{
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();
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 = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
// auto detect PHY address
phy_config.phy_addr = ESP_ETH_PHY_ADDR_AUTO;
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_mac_t *mac = mac_init(NULL, &mac_config);
TEST_ASSERT_NOT_NULL(mac);
esp_eth_phy_t *phy = phy_init(NULL);
TEST_ASSERT_NOT_NULL(phy);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
/* get MAC address */
uint8_t mac_addr[6];
extra_eth_config(eth_handle);
/* get default MAC address */
uint8_t mac_addr[ETH_ADDR_LEN];
memset(mac_addr, 0, sizeof(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",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
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 */
int phy_addr = -1;
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr));
ESP_LOGI(TAG, "Ethernet PHY Address: %d", phy_addr);
TEST_ASSERT(phy_addr >= 0 && phy_addr <= 31);
#endif
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
TEST_ESP_OK(phy->del(phy));
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;
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));
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
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 = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
// auto detect PHY address
phy_config.phy_addr = ESP_ETH_PHY_ADDR_AUTO;
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
esp_eth_mac_t *mac = mac_init(NULL, &mac_config);
TEST_ASSERT_NOT_NULL(mac);
esp_eth_phy_t *phy = phy_init(NULL);
TEST_ASSERT_NOT_NULL(phy);
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
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.
// 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.
// TODO: this test in this configuration may not work for all the chips (JIRA IDF-6186)
bool loopback_en = true;
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);
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);
ESP_LOGI(TAG, "try to change autonegotiation when driver is started...");
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_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);
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
ESP_LOGI(TAG, "disable the autonegotiation and change the speed/duplex...");
auto_nego_en = false;
TEST_ASSERT_EQUAL(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_S_AUTONEGO, &auto_nego_en));
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_AUTONEGO, &exp_autoneg_en));
TEST_ASSERT_EQUAL(false, exp_autoneg_en);
// 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
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
esp_eth_start(eth_handle);
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_EQUAL(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_DUPLEX_MODE, &exp_duplex));
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_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_LOGI(TAG, "change speed again...");
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
esp_eth_start(eth_handle);
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_EQUAL(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_SPEED, &exp_speed));
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_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_LOGI(TAG, "change duplex again...");
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
esp_eth_start(eth_handle);
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_EQUAL(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_DUPLEX_MODE, &exp_duplex));
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_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_SPEED, &speed));
TEST_ASSERT_EQUAL(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_DUPLEX_MODE, &exp_duplex));
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_SPEED_100M, exp_speed);
@@ -265,17 +228,17 @@ TEST_CASE("esp32 ethernet speed/duplex/autonegotiation", "[ethernet][test_env=UT
duplex = ETH_DUPLEX_HALF;
// 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
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
esp_eth_start(eth_handle);
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_EQUAL(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_DUPLEX_MODE, &exp_duplex));
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_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));
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(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_DUPLEX_MODE, &exp_duplex));
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &exp_speed));
// verify autonegotiation result (expecting the best link configuration)
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(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);
}
TEST_CASE("esp32 ethernet event test", "[ethernet][test_env=UT_T2_Ethernet]")
TEST_CASE("ethernet event test", "[ethernet]")
{
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));
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
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);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
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 eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
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)
TEST_ESP_OK(esp_eth_start(eth_handle));
/* 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(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);
}
TEST_CASE("esp32 ethernet dhcp test", "[ethernet][test_env=UT_T2_Ethernet]")
TEST_CASE("ethernet dhcp test", "[ethernet]")
{
EventBits_t bits = 0;
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
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&netif_cfg);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
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);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
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 eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
// install Ethernet driver
TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
extra_eth_config(eth_handle);
// combine driver with netif
esp_eth_netif_glue_handle_t glue = esp_eth_new_netif_glue(eth_handle);
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));
esp_netif_destroy(eth_netif);
TEST_ESP_OK(esp_event_loop_delete_default());
extra_cleanup();
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;
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
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&netif_cfg);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
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);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
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 eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
// install Ethernet driver
TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
extra_eth_config(eth_handle);
// combine driver with netif
esp_eth_netif_glue_handle_t glue = esp_eth_new_netif_glue(eth_handle);
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));
esp_netif_destroy(eth_netif);
TEST_ESP_OK(esp_event_loop_delete_default());
extra_cleanup();
vEventGroupDelete(eth_event_group);
}
@@ -494,7 +459,7 @@ static void eth_start_download(void)
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;
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
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&netif_cfg);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
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);
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
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 eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
// install Ethernet driver
TEST_ESP_OK(esp_eth_driver_install(&eth_config, &eth_handle));
extra_eth_config(eth_handle);
// combine driver with netif
esp_eth_netif_glue_handle_t glue = esp_eth_new_netif_glue(eth_handle);
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("\r\n");
TEST_ASSERT(memcmp(expect_digest, digest, sizeof(digest)) == 0);
TEST_ASSERT_EQUAL_UINT8_ARRAY(expect_digest, digest, sizeof(digest));
// stop Ethernet driver
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));
esp_netif_destroy(eth_netif);
TEST_ESP_OK(esp_event_loop_delete_default());
extra_cleanup();
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 os
import socket
import time
from multiprocessing import Pipe, Process, connection
from typing import Iterator
@@ -16,28 +17,34 @@ ETH_TYPE = 0x2222
class EthTestIntf(object):
def __init__(self, eth_type: int):
def __init__(self, eth_type: int, my_if: str = ''):
self.target_if = ''
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
netifs = os.listdir('/sys/class/net/')
logging.info('detected interfaces: %s', str(netifs))
for netif in netifs:
if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0:
self.target_if = netif
break
# if no interface defined, try to find it automatically
if my_if == '':
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 == '':
raise Exception('no network interface found')
raise Exception('network interface not found')
logging.info('Use %s for testing', self.target_if)
@contextlib.contextmanager
def configure_eth_if(self) -> Iterator[socket.socket]:
so = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(self.eth_type))
so.bind((self.target_if, 0))
try:
yield so
finally:
@@ -83,25 +90,34 @@ class EthTestIntf(object):
raise e
def actual_test(dut: Dut) -> None:
target_if = EthTestIntf(ETH_TYPE)
target_if.find_target_if()
def ethernet_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('"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_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:
so.settimeout(30)
dut.write('"ethernet_broadcast_transmit"')
dut.write('"ethernet broadcast transmit"')
eth_frame = Ether(so.recv(1024))
for i in range(0, 1010):
if eth_frame.load[i] != i & 0xff:
@@ -109,18 +125,19 @@ def actual_test(dut: Dut) -> None:
dut.expect_unity_test_output()
dut.expect_exact("Enter next test, or 'enter' to see menu")
dut.write('"recv_pkt"')
dut.write('"ethernet recv_pkt"')
res = dut.expect(
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})'
)
time.sleep(1)
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(res.group(2)) # unicast frame
dut.expect_unity_test_output(extra_before=res.group(1))
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(
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})'
@@ -144,21 +161,43 @@ def actual_test(dut: Dut) -> None:
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.ip101
@pytest.mark.parametrize('config', [
'ip101',
'default_ip101',
], indirect=True)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_esp_eth_ip101(dut: Dut) -> None:
actual_test(dut)
ethernet_l2_test(dut)
@pytest.mark.esp32
@pytest.mark.lan8720
@pytest.mark.parametrize('config', [
'lan8720',
'default_lan8720',
], indirect=True)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
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_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,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_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_LAN87XX=y
CONFIG_ETH_RMII_CLK_OUTPUT=y
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
components/esp_netif/test_apps:
components/esp_netif/test_apps/test_app_esp_netif:
disable:
- if: IDF_TARGET == "esp32c6"
temporary: true
@@ -9,3 +9,9 @@ components/esp_netif/test_apps:
- if: IDF_TARGET != "esp32s2"
temporary: true
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 <string.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 <unistd.h>
#include <errno.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
@@ -29,8 +30,6 @@
#include "esp_vfs_l2tap.h"
#if CONFIG_ESP_NETIF_L2_TAP
#define ETH_FILTER_LE 0x7A05
#define ETH_FILTER_BE 0x057A
@@ -240,7 +239,7 @@ static void send_task(void *task_param)
* @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;
@@ -344,7 +343,7 @@ static void close_task(void *task_param)
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;
@@ -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
*
*/
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;
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
*
*/
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;
int eth_tap_fd;
@@ -599,7 +598,7 @@ TEST_CASE("esp32 l2tap - blocking read", "[ethernet][test_env=UT_T2_Ethernet]")
* @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;
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++) {
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);
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;
@@ -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
*
*/
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;
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
*
*/
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;
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
*
*/
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;
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
*
*/
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;
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));
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!
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");
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);
spi_eth_module_config[0].mac_addr = local_mac_1;
#if CONFIG_EXAMPLE_SPI_ETHERNETS_NUM > 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;
esp_derive_local_mac(local_mac_2, base_mac_addr);
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