[ethernet] Check the manual IP table layout

The extern declaration now has its size, so a longer generated table fails to compile, and a codegen test checks the 20 octets and their order.
This commit is contained in:
J. Nick Koston committed 2026-10-26 18:38:27 -10:00
1 parent 0d7ff93bd3
commit de9449841e
4 files changed
+50 -2

No files matched your search

@@ -12,7 +12,7 @@ EthernetComponent::EthernetComponent() { global_eth_component = this; }
#ifdef USE_ETHERNET_MANUAL_IP
ManualIP load_manual_ip() {
uint8_t b[5 * 4]; // five IPv4 addresses
uint8_t b[ETHERNET_MANUAL_IP_SIZE];
progmem_memcpy(b, ETHERNET_MANUAL_IP, sizeof(b));
auto ip = [&b](size_t i) { return network::IPAddress(b[i], b[i + 1], b[i + 2], b[i + 3]); };
return ManualIP{ip(0), ip(4), ip(8), ip(12), ip(16)};
@@ -106,7 +106,8 @@ struct ManualIP {
#ifdef USE_ETHERNET_MANUAL_IP
/// The configured static IP, gateway, subnet, dns1 and dns2 as 4 octets each, generated by codegen
/// (components/ethernet/__init__.py) and kept in flash.
extern const uint8_t ETHERNET_MANUAL_IP[] PROGMEM;
static constexpr size_t ETHERNET_MANUAL_IP_SIZE = 5 * 4;
extern const uint8_t ETHERNET_MANUAL_IP[ETHERNET_MANUAL_IP_SIZE] PROGMEM;
ManualIP load_manual_ip();
#endif
@@ -0,0 +1,18 @@
esphome:
name: test
esp32:
board: esp32dev
ethernet:
type: LAN8720
mdc_pin: GPIO23
mdio_pin: GPIO18
clk:
mode: CLK_EXT_IN
pin: GPIO0
manual_ip:
static_ip: 192.168.1.50
gateway: 192.168.1.1
subnet: 255.255.255.0
dns1: 1.1.1.1
@@ -0,0 +1,29 @@
"""The manual IP table codegen emits must match the ETHERNET_MANUAL_IP layout in ethernet_component.h."""
from collections.abc import Callable
from pathlib import Path
def test_manual_ip_table_layout(
generate_main: Callable[[str | Path], str],
component_config_path: Callable[[str], Path],
) -> None:
"""Twenty octets: static IP, gateway, subnet, dns1, dns2 (unset DNS is zero)."""
main_cpp = generate_main(component_config_path("manual_ip.yaml"))
expected = (
"192, 168, 1, 50, 192, 168, 1, 1, 255, 255, 255, 0, 1, 1, 1, 1, 0, 0, 0, 0"
)
assert (
f"esphome::ethernet::ETHERNET_MANUAL_IP[] PROGMEM = {{{expected}}};" in main_cpp
)
assert "set_manual_ip(" not in main_cpp
def test_no_manual_ip_emits_no_table(
generate_main: Callable[[str | Path], str],
component_config_path: Callable[[str], Path],
) -> None:
main_cpp = generate_main(component_config_path("rmii_defaults.yaml"))
assert "ETHERNET_MANUAL_IP" not in main_cpp