DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
physical.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file physical.cpp
6 * @brief Layer 1 (Physical) - link bring-up and egress reporting.
7 *
8 * WiFi station bring-up is asynchronous (poll wifi_ready()). det_net_egress()
9 * reports the live default-route interface (lwIP `netif_default`) and classifies
10 * it against the WiFi IPs; the stack owns failover, so there is nothing to poll
11 * or track here. The IP classifier is pure and host-tested.
12 */
13
14#include "physical.h"
15
16#ifdef ARDUINO
17#include "lwip/ip_addr.h"
18#include "lwip/netif.h"
19#include <WiFi.h>
20#if DETWS_ENABLE_ETHERNET
21#include <ETH.h>
22#endif
23
24bool init_wifi_physical(const char *ssid, const char *password)
25{
26 WiFi.begin(ssid, password);
27 return true;
28}
29
31{
32 return WiFi.isConnected();
33}
34
35#if DETWS_ENABLE_ETHERNET
36bool init_eth_physical(void)
37{
38#if defined(DETWS_ETH_W5500) && DETWS_ETH_W5500 && ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
39 // W5500 SPI Ethernet (arduino-esp32 3.x ETH SPI API): the HSPI host (SPI3) clocks the W5500 on the
40 // DETWS_ETH_W5500_* pins (CS/INT/RST + SCK/MISO/MOSI). Needs CONFIG_ETH_SPI_ETHERNET_W5500 in the SDK
41 // (default on for the S3). W5500 SPI is arduino-esp32 3.x only - the 2.x ETH library has no W5500.
42 return ETH.begin(ETH_PHY_W5500, 1 /*phy addr*/, DETWS_ETH_W5500_CS, DETWS_ETH_W5500_INT, DETWS_ETH_W5500_RST,
45#else
46 // RMII PHY: pins / type / clock come from the ETH_PHY_* build flags (ETH.begin() defaults).
47 return ETH.begin();
48#endif
49}
50bool eth_ready(void)
51{
52 return ETH.linkUp() && (uint32_t)ETH.localIP() != 0;
53}
54#else
56{
57 return false; // Ethernet not enabled (DETWS_ENABLE_ETHERNET)
58}
59bool eth_ready(void)
60{
61 return false;
62}
63#endif
64
65#if DETWS_ENABLE_IPV6
66#include "lwip/ip6_addr.h"
67#include <string.h>
68
69bool init_ipv6_physical(void)
70{
71 // The WiFi wrapper's enable call was renamed in Arduino-ESP32 3.0; the address readout
72 // below goes straight to lwIP, which is stable across both cores.
73#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
74 return WiFi.enableIPv6(true);
75#else
76 return WiFi.enableIpV6();
77#endif
78}
79
80bool net_global_ipv6(DetIp *out)
81{
82 if (!out || !netif_default)
83 return false;
84 for (int8_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++)
85 {
86 if (!ip6_addr_isvalid(netif_ip6_addr_state(netif_default, i)))
87 continue;
88 const ip6_addr_t *a6 = netif_ip6_addr(netif_default, i);
89 if (!ip6_addr_isglobal(a6))
90 continue;
92 memcpy(out->bytes, a6->addr, 16); // lwIP holds the 16 bytes in network order
93 return true;
94 }
95 return false;
96}
97
98bool ipv6_ready(void)
99{
100 DetIp tmp;
101 return net_global_ipv6(&tmp);
102}
103#else
105{
106 return false; // IPv6 not enabled (DETWS_ENABLE_IPV6)
107}
109{
110 return false;
111}
112bool ipv6_ready(void)
113{
114 return false;
115}
116#endif
117
118uint32_t det_net_egress_ip(void)
119{
120 // netif_default is the current default-route interface (the egress).
121 return netif_default ? ip4_addr_get_u32(ip_2_ip4(&netif_default->ip_addr)) : 0;
122}
123
125{
126 uint32_t egress = det_net_egress_ip();
127 if (egress == 0)
129 uint32_t sta = WiFi.isConnected() ? (uint32_t)WiFi.localIP() : 0;
130 uint32_t ap = (WiFi.getMode() & WIFI_AP) ? (uint32_t)WiFi.softAPIP() : 0;
131 return det_net_classify_ip(egress, sta, ap);
132}
133
134#else // host build - no radio / stack
135
136bool init_wifi_physical(const char *, const char *)
137{
138 return true;
139}
140bool wifi_ready()
141{
142 return true;
143}
144bool init_eth_physical(void)
145{
146 return false; // no Ethernet PHY on a host build
147}
148bool eth_ready(void)
149{
150 return false;
151}
152bool init_ipv6_physical(void)
153{
154 return false; // no netif on a host build
155}
157{
158 return false;
159}
160bool ipv6_ready(void)
161{
162 return false;
163}
164uint32_t det_net_egress_ip(void)
165{
166 return 0;
167}
169{
171}
172
173#endif // ARDUINO
174
175// Pure classifier (always compiled, host-tested).
176DetIface det_net_classify_ip(uint32_t egress_ip, uint32_t sta_ip, uint32_t ap_ip)
177{
178 if (egress_ip == 0)
180 if (sta_ip != 0 && egress_ip == sta_ip)
182 if (ap_ip != 0 && egress_ip == ap_ip)
184 return DetIface::DETIFACE_ETH; // a live route that is neither WiFi IP -> wired
185}
DetIface
Network interface a connection arrived on (for per-route filtering).
@ DETIFACE_ETH
Ethernet interface (wired PHY).
@ DETIFACE_STA
Station interface (joined to an AP / your LAN).
@ DETIFACE_ANY
Unknown / no filter (matches any interface).
@ DETIFACE_AP
softAP interface (clients joined to the device).
#define DETWS_ETH_W5500_MOSI
HSPI MOSI (S3-DevKitC default)
#define DETWS_ETH_W5500_RST
reset
#define DETWS_ETH_W5500_CS
chip select
#define DETWS_ETH_W5500_SCK
HSPI clock (S3-DevKitC default)
#define DETWS_ETH_W5500_SPI_MHZ
W5500 SPI clock (MHz); raise for throughput on clean wiring.
#define DETWS_ETH_W5500_INT
interrupt
#define DETWS_ETH_W5500_MISO
HSPI MISO (S3-DevKitC default)
@ DET_IP_V6
IPv6 (bytes[0..15])
uint32_t det_net_egress_ip(void)
IPv4 (network byte order) of the current egress interface, or 0 if none.
Definition physical.cpp:118
bool ipv6_ready(void)
True once the interface has a global IPv6 address (see net_global_ipv6()).
Definition physical.cpp:112
bool eth_ready(void)
True if the Ethernet link is up and an IP is assigned.
Definition physical.cpp:59
bool wifi_ready()
True if the WiFi station link is up (associated + an IP is assigned).
Definition physical.cpp:30
bool init_wifi_physical(const char *ssid, const char *password)
Connect to a WiFi access point.
Definition physical.cpp:24
DetIface det_net_egress(void)
Which interface currently carries outbound traffic.
Definition physical.cpp:124
bool init_ipv6_physical(void)
Enable IPv6 (dual-stack) on the Wi-Fi interface (DETWS_ENABLE_IPV6).
Definition physical.cpp:104
bool init_eth_physical(void)
Bring up a wired Ethernet link (DETWS_ENABLE_ETHERNET).
Definition physical.cpp:55
DetIface det_net_classify_ip(uint32_t egress_ip, uint32_t sta_ip, uint32_t ap_ip)
Classify an egress IPv4 against the WiFi station / softAP IPs (pure helper, exposed for unit testing)...
Definition physical.cpp:176
bool net_global_ipv6(DetIp *)
The interface's global (routable) IPv6 address, if it has one.
Definition physical.cpp:108
Layer 1 (Physical) - link bring-up and live egress-interface reporting.
A v4 or v6 address in network (big-endian) byte order.
Definition ip.h:52
uint8_t bytes[16]
network order; v4 uses the first 4
Definition ip.h:54
DetIpFamily family
address family tag
Definition ip.h:53