Ethernet
The espp::Ethernet component wraps the ESP-IDF esp_eth APIs and
brings up an Ethernet interface over either RMII (internal EMAC, on SoCs with
SOC_EMAC_SUPPORTED) or SPI (an external MAC+PHY chip such as the WIZnet
W5500), plus a pre-built-driver escape hatch for any other chip.
One class owns the boilerplate that BSPs otherwise duplicate - netif, event loop,
netif glue, DHCP client/server, static IP, hostname, MAC assignment (explicit or
eFuse-derived) and link/IP event dispatch to std::function callbacks - and,
unlike the inline BSP implementations it replaces, provides a symmetric teardown
(deinitialize() + destructor).
The interface-specific configuration is a single tagged Config::interface
member (a std::variant of RmiiConfig / SpiConfig / DriverConfig);
the rest of Config (DHCP mode, static IP, hostname, MAC, callbacks) is shared.
Note
The RMII path uses the generic 802.3 PHY driver in esp_eth core (no extra
dependency). The concrete SPI chip drivers (W5500, DM9051, ENC28J60) are
managed components pulled in only when the matching CONFIG_ESPP_ETHERNET_*
Kconfig option is enabled.
API Reference
Header File
Classes
-
class Ethernet : public espp::BaseComponent
Cross-interface Ethernet wrapper around the ESP-IDF esp_eth APIs.
One class drives both RMII (internal EMAC, on SoCs with
SOC_EMAC_SUPPORTED- esp32 / esp32-p4) and SPI (external MAC+PHY chips such as the WIZnet W5500) interfaces, plus a pre-built-driver escape hatch for any other chip. It owns all of the common boilerplate - netif, event loop, glue, attach, DHCP client/server, static IP, hostname, MAC assignment, link/IP event dispatch and, unlike the inline BSP implementations it replaces, a symmetric teardown (deinitialize + destructor).The interface-specific part is a single tagged Config member: RmiiConfig, SpiConfig, or DriverConfig.
RMII Example
// RMII on the ESP32-Ethernet-Kit (IP101 PHY on GPIO0 ref-clock). Adjust for your board. espp::Ethernet eth(with_callbacks({ .interface = espp::Ethernet::RmiiConfig{.mdc_gpio = 23, .mdio_gpio = 18, .phy_addr = 1, .phy_reset_gpio = 5, .clock_ext_in = true, .clock_gpio = 0}, })); eth.initialize();
SPI (W5500) Example
// Bring up the SPI bus the W5500 lives on (adjust pins for your board). spi_bus_config_t buscfg = {}; buscfg.miso_io_num = 13; buscfg.mosi_io_num = 11; buscfg.sclk_io_num = 12; buscfg.quadwp_io_num = -1; buscfg.quadhd_io_num = -1; buscfg.max_transfer_sz = 1600; ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO)); // One reactor-owned W5500 over that bus, DHCP client. espp::Ethernet eth(with_callbacks({ .interface = espp::Ethernet::SpiConfig{.host = SPI2_HOST, .cs_gpio = 10, .int_gpio = 14, .reset_gpio = 21, .chip = espp::Ethernet::SpiChip::W5500}, })); eth.initialize();
Note
The concrete SPI chip drivers (W5500, DM9051, ENC28J60) are ESP-IDF managed components pulled in only when the matching
CONFIG_ESPP_ETHERNET_*option is enabled. The RMII path uses the generic 802.3 PHY driver inesp_ethcore (no extra dependency), which supports common PHYs (IP101, LAN87xx, DP83848, RTL8201, KSZ8041).Public Types
-
enum class DhcpMode
DHCP operating mode.
Values:
-
enumerator CLIENT
Acquire an IP from an upstream DHCP server (or use a static IP if ip_info is set).
-
enumerator SERVER
Run a DHCP server on this interface and assign IPs to connected hosts.
-
enumerator CLIENT
-
enum class PhyModel
PHY model hint for the RMII path. All are handled by the generic 802.3 driver in v1; the field is advisory (kept for a future specific-driver option) and does not change behavior today.
Values:
-
enumerator GENERIC
-
enumerator IP101
-
enumerator LAN87XX
-
enumerator DP83848
-
enumerator RTL8201
-
enumerator KSZ80XX
-
enumerator GENERIC
-
enum class SpiChip
Supported built-in SPI ethernet chips.
Values:
-
enumerator W5500
-
enumerator DM9051
-
enumerator ENC28J60
-
enumerator W5500
-
using LinkCallback = std::function<void()>
Callback for link up/down and IP-lost. Runs in the esp event-loop task context - keep it short and non-blocking.
-
using IpCallback = std::function<void(esp_ip4_addr_t ip)>
Callback for IP acquisition. Runs in the esp event-loop task context.
-
using ClientIpCallback = std::function<void(esp_ip4_addr_t ip, MacAddress mac)>
Callback (SERVER mode) invoked for each DHCP lease the server assigns.
Public Functions
-
explicit Ethernet(const Config &config)
Construct (does not start the interface; call initialize()).
- Parameters:
config – The configuration.
-
~Ethernet()
Destroy - deinitializes the interface if still running.
-
bool initialize(std::error_code &ec)
Bring up the interface (create driver, attach netif, register events, apply IP/hostname/MAC, start). Idempotent.
- Parameters:
ec – Set to a specific error on failure; cleared on success.
- Returns:
true on success (interface started).
-
bool initialize()
Convenience overload that logs on failure.
- Returns:
true on success.
-
bool deinitialize(std::error_code &ec)
Stop and fully tear down the interface (reverse-order unwind). Idempotent. Does not undo the process-global netif/event-loop init.
- Parameters:
ec – Set on failure; cleared on success.
- Returns:
true on success.
-
void deinitialize()
Convenience overload that logs on failure.
-
inline bool is_initialized() const
- Returns:
true if the interface has been initialized/started.
-
inline bool is_connected() const
- Returns:
true if the link is up AND an IP address is held.
-
inline bool link_up() const
- Returns:
true if the physical link is up.
-
esp_ip4_addr_t ip() const
- Returns:
The current IPv4 address (0 if none).
-
std::string get_ip_address() const
- Returns:
The current IPv4 address as a dotted quad (“0.0.0.0” if none).
-
std::string get_mac_address() const
- Returns:
The interface MAC as “aa:bb:cc:dd:ee:ff” (empty if not initialized).
-
std::optional<std::pair<int, bool>> link_speed_duplex() const
- Returns:
{speed_mbps, full_duplex} if the link is up, else nullopt.
-
inline esp_eth_handle_t native_handle() const
- Returns:
The raw esp_eth driver handle (nullptr if not initialized).
-
inline esp_netif_t *netif() const
- Returns:
The raw esp_netif handle (nullptr if not initialized).
-
inline const std::string &get_name() const
Get the name of the component
Note
This is the tag of the logger
- Returns:
A const reference to the name of the component
-
inline void set_log_tag(const std::string_view &tag)
Set the tag for the logger
- Parameters:
tag – The tag to use for the logger
-
inline espp::Logger::Verbosity get_log_level() const
Get the log level for the logger
See also
See also
- Returns:
The verbosity level of the logger
-
inline void set_log_level(espp::Logger::Verbosity level)
Set the log level for the logger
See also
See also
- Parameters:
level – The verbosity level to use for the logger
-
inline void set_log_verbosity(espp::Logger::Verbosity level)
Set the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls set_log_level
- Parameters:
level – The verbosity level to use for the logger
-
inline espp::Logger::Verbosity get_log_verbosity() const
Get the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls get_log_level
- Returns:
The verbosity level of the logger
-
inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
Set the rate limit for the logger
See also
Note
Only calls to the logger that have _rate_limit suffix will be rate limited
- Parameters:
rate_limit – The rate limit to use for the logger
-
struct Config
Full configuration.
Public Members
-
std::variant<RmiiConfig, SpiConfig, DriverConfig> interface
The interface: RMII (internal EMAC), SPI (external chip), or a pre-built driver.
-
std::optional<MacAddress> mac_address = {}
Explicit MAC; else eFuse (ESP_MAC_ETH) for chips needing one.
-
std::string hostname = {}
netif hostname (empty = ESP-IDF default).
-
esp_netif_ip_info_t ip_info = {}
CLIENT: if ip.addr != 0, use this as a static IP (DHCP client is stopped); else DHCP. SERVER: the interface/gateway IP for the DHCP server (0 -> 192.168.4.1/24).
-
LinkCallback on_link_up = {}
Physical link came up.
-
LinkCallback on_link_down = {}
Physical link went down.
-
IpCallback on_got_ip = {}
Interface obtained an IPv4 address.
-
LinkCallback on_lost_ip = {}
Interface lost its IPv4 address.
-
ClientIpCallback on_client_assigned = {}
SERVER mode: a client was assigned an IP.
-
std::variant<RmiiConfig, SpiConfig, DriverConfig> interface
-
struct DriverConfig
Pre-built-driver escape hatch: the caller creates the MAC+PHY for any chip and hands them over. The component takes ownership (they are freed by esp_eth_driver_uninstall on teardown).
Public Members
-
esp_eth_mac_t *mac = {nullptr}
Caller-created MAC (ownership transfers on initialize()).
-
esp_eth_phy_t *phy = {nullptr}
Caller-created PHY (ownership transfers on initialize()).
-
bool needs_isr_service{false}
true if the driver uses a GPIO INT line (installs the ISR service).
-
bool needs_mac_assignment{false}
true if the chip has no factory MAC (assign from config/eFuse).
-
esp_eth_mac_t *mac = {nullptr}
-
struct RmiiConfig
RMII / internal-EMAC interface configuration (esp32 / esp32-p4 only).
Public Members
-
int mdc_gpio = {-1}
SMI management clock (MDC) GPIO (required).
-
int mdio_gpio = {-1}
SMI management data (MDIO) GPIO (required).
-
int phy_addr = {-1}
PHY SMI address; -1 auto-detects.
-
int phy_reset_gpio = {-1}
Active-low PHY reset GPIO; -1 = none.
-
bool clock_ext_in = {true}
true: external RMII 50 MHz ref-clock in; false: internal out.
-
int clock_gpio = {0}
RMII REF_CLK GPIO (fixed set on esp32; routable on esp32-p4).
-
struct DataPins
RMII data-plane pins. Only used on SoCs with routable EMAC pins (esp32-p4); ignored on esp32 where they are fixed via IO_MUX.
-
int mdc_gpio = {-1}
-
struct SpiConfig
SPI interface configuration (external MAC+PHY chip on a caller-owned, already-initialized SPI bus). Works on any SoC.
Public Members
-
spi_host_device_t host{SPI2_HOST}
SPI host whose bus the caller already initialized (required).
-
int cs_gpio = {-1}
Chip-select GPIO (required).
-
int reset_gpio = {-1}
Chip reset GPIO; -1 = none.
-
int clock_speed_hz = {20000000}
SPI clock (W5500 max ~33 MHz; conservative default).
-
int phy_addr = {1}
PHY address (W5500 = 1).
-
spi_host_device_t host{SPI2_HOST}
-
enum class DhcpMode