EPS network failures: investigation report

Expromo EPS power sequencer (Keyestudio KS0304: ATmega328P + WIZnet W5500), firmware v2.2 vs v3.0, v3.1, v3.2 and v3.3 Bench work 2026-10-08 13:00 – 2026-10-12 morning · Repo daveleo/EPS · Status as of 2026-10-12 · v3.3 is recommended as the official firmware (v3.2 + the gaps a code analysis found; see §5.25–5.26)


1. Summary

Units in the field drop off the network at random: no ping, no web page, no TCP control, until power is cycled. No failed unit has been examined in its failed state. Field units are usually set to a static IP; some AV networks have a DHCP server, sometimes not.

On the bench (two bare KS0304 boards on USB power, and since 2026-10-09 afternoon a real EPS box with its 10 V supply, six SSRs and the 22 µF reset capacitor; NETGEAR M4250 switch, a model with field failures):

  1. The field symptom means the W5500 is not answering at all. The chip answers ping and ARP by itself. v2.2's socket starvation leaves ping working, so it can't be the field failure on its own.
  2. Three mechanisms reproduce the full symptom on v2.2:
    • (a) DHCP mode: a DHCP outage strands the unit until it is power-cycled (measured with the M4250's DHCP server, §5.20). One unanswered renewal makes v2.2 restart itself: the Ethernet library's DHCP loop blocks longer than v2.2's 8 s watchdog. If the server doesn't answer within 60 s of that restart, v2.2 falls back to its static address and never asks again; with the server back it stays unreachable (link up, still transmitting) until restarted. A power cycle brought it back in 13 s. With this server v2.2 also restarted itself every ~4 min while the server was up. v3.0 recovered by itself in every case. Applies only to units in DHCP mode.
    • (b) The W5500 loses its settings (the effect of a supply dip or ESD, reproduced by one register write): v2.2 dead until reset (4/4); v3.0 recovers in 3–6 s (5/5). The real trigger is untested: no real loads switched yet; mains cuts of 0.2–10 s on the real box caused nothing (18/18).
    • (c) The W5500 goes deaf after a fresh link negotiation: link up, transmits, receives nothing, registers correct. On one board (unit 2): 4 in ≥ 536 resets and 1 in 134 switch-port flaps; once it cleared by itself after 97 s. Whether it can last until a power cycle is unknown: earlier tests always reset the unit after 60 s.
  3. Static-mode field failures are not explained yet. IP address conflicts are excluded (field knowledge). Remaining candidates: (b) triggered by load switching, and (c).
  4. v2.2 also has network defects of its own that cause partial failures (two idle connections block the control port while ping works; the web page blocks control for ~0.9 s; the stall watchdog can't see either). Part of this is the Arduino Ethernet library itself, which also writes its retry settings to W5100 register addresses on the W5500 (RTR = 72 ms, RCR = 8 instead of 200 ms × 2; §5.19).
  5. v3.0, a rewrite of the network layer, beats v2.2 on every pre-registered criterion except one lost ping, recovers from (a) and (b), and kept its lease through every DHCP event. v3.1 (v3.0 + network-standards work: DHCP timing and DECLINE, address conflict detection, TCP timers, HTTP methods, syslog) re-ran every non-soak test on its final build on the real box and passed (§5.22). v3.2 (v3.1 + a wider W5500 self-check covering the mode, retry and PHY registers) recovers from all 14 single-register chip faults — including the PHY power-down that reproduces the field symptom, which v2.2 and v3.1 both die on — with no regression (§5.24). v3.3 (v3.2 + the four gaps the code analysis of §5.25 found: the PHY reset bit, a link that stays down, a receiver check that works without a gateway and after a link-up, and a supply monitor) recovers from all 17 single-register faults including a PHY held in reset, on which v3.2 is dead, and passed the full regression overnight (§5.26); it is recommended as the official firmware. None is field-proven, and none has run on a box with real loads.
  6. Corrections made on 2026-10-09 (§5.17–5.19): a USB/DTR reset also resets the W5500 (its link renegotiates), so the deaf start-ups followed a W5500 hardware reset, not a CPU-only restart; the H4c rationale ("v2.2 never resets the PHY") is void; v2.2's own watchdog restarts never produced a deaf state (0 in 19+). Finding #7 (retransmission "3 tries, ~1.4 s") was wrong because of the library defect.
  7. Code analysis (§5.25): v2.2 cannot make a static unit stop answering by its own logic; the field failure needs an outside upset of the W5500, which v2.2 can never leave. The leading trigger hypothesis is a supply sag: the board's brown-out level is 2.7 V (measured on unit 3), below what the CPU (3.78 V at 16 MHz) and the W5500 (2.97 V) need. Untested: it needs USB unplugged.
  8. Standards (§5.23): on a pre-registered suite of 56 requirements from 10 standards, run on the same box, v3.1 passes 46 and v2.2 26. By standard, v3.1 passes 6 (IEEE 802.3, IEEE 802 MAC, ARP, RFC 5227, 802.1D, syslog) and v2.2 4 (it has no syslog). Both fail RFC 1122, DHCP, TCP and HTTP, but v3.1 on 8 items and v2.2 on 25. Two of the shared failures are limits of the W5500 chip that no firmware can fix. The suite measures conformance, not the field failure: v3.1's main gain over v2.2 is recovery from (a) and (b), which the suite doesn't test.

2. Background


3. Materials

3.1 Units

Unit 1 Unit 2
Origin the original showroom test unit (was 172.22.40.21, label EPS_Test) new, unflashed on arrival
USB (programming, serial, reset) COM5 COM6
IP now 192.168.0.94 static 192.168.0.93 static
MAC now 8C:1F:64:C3:90:24 (assigned; the MAC in the v2.2 sketch, assumed to be this unit's) 02:45:50:A3:4E:D9 (temporary, generated)
Label EPS_Test EPS_Test_2
Firmware now v3.0 production v3.0 production
M4250 switch port 0/6 0/12

Both boards are USB-powered from the PC; nothing is connected to the outputs.

Unit 3 (from 2026-10-09 ~12:30): a real EPS box as built for the field (photos in photos/EPS 6 channel workshop built/): KS0304 with v2.2, 10 V DIN PSU (1.8 A) soldered to the barrel jack, six KANE KSSR-14840DA SSRs on A0–A5, illuminated push-button on D2–D4 (RGB) and D6, 22 µF between RESET and GND (added because the 10 V PSU didn't restart the board reliably; it also blocks USB flashing). MAC 8C:1F:64:C3:90:58, M4250 port 0/9, USB unplugged, mains switched by a Netio PowerBOX 4KF (output 4, URL API). No loads on the outputs. Afternoon changes: unit 2 moved to 192.168.0.95; units 1–2 ran the v2.2 diagnostic builds, unit 1 v3.0 from ~15:15.

3.2 Network setups (chronological)

  1. Direct cable, "NovaHub" (generic USB2.0 10/100 adapter) → found to make the board deaf at 100 Mbps (§5.1); dropped.
  2. Direct cable, "LargeHUB" (ASIX USB gigabit adapter), PC 172.22.40.66, later 192.168.0.83.
  3. Ubiquiti 5-port switch connecting LargeHUB and both units; isolated from the office network (the office is on a separate NIC, no bridging, no IP forwarding, no connection sharing; checked).
  4. Windows Internet Connection Sharing on LargeHUB for one DHCP session (192.168.137.0/24), then removed.
  5. M4250 changes during the tests (running config only, never saved): port shutdown/no shutdown, a port mirror 0/12 → 0/20 (~13:55–15:15), the switch's own DHCP server (pool 192.168.0.100–.150, 2-min lease, from 15:17). An accidental EEE enable on 0/6 (CLI help query) was undone before any test.
  6. Direct cable to the PC's built-in NIC (192.168.0.23, 2026-10-09 evening and 2026-10-10): v3.1 tests and the conformance suite, unit 3 only.
  7. NETGEAR M4250-26G4XF-PoE+ (firmware 13.0.4.14), a model on which the failure occurred in the field. PC on port 0/1 (192.168.0.66), units on 0/6 and 0/12, switch management 192.168.0.250. Isolated. EEE and Energy-Detect off on all ports, RSTP (802.1w) on, BPDU guard off, clock not set (shows May 2023).

3.3 Firmware and builds

Build Source / flags Purpose
v2.2 Expromo_EPS_v2_2/ field firmware (MAC compiled in)
v2.2, unit 2 v2.2 with only the MAC changed v2.2 on unit 2 without a duplicate MAC
v2.2 diagnostic tools/v2_2_diag/ (-DBENCH_UNIT2 for unit 2's MAC) v2.2 + start-up report on USB serial (W5500 found, link, IP, MAC, gateway, mask, socket states every 2 s for 60 s); no behaviour change
v2.2 fault scratch copy of v2.2 + hidden TEST_W5500_RESET imitate a W5500 glitch
Bare library tools/lib_minimal_test/ Ethernet 2.0.2 with two servers, no EPS code
v3.0 Expromo_EPS_v3_0/ the rewrite (production build: no flags); tagged v3.0-baseline
v3.1 (final) Expromo_EPS_v3_1/, branch v3.1-standards, commit 5284db6, per unit -DEPS_MAC_SUFFIX=0x058 v3.0 + standards work (§5.22); 31,120 B flash, 1,364 B RAM; same test flags as v3.0
EEPROM wipe tools/eeprom_wipe/ all EEPROM to 0xFF, so the firmware starts from defaults (conformance suite)
v3.3 Expromo_EPS_v3_3/, per unit -DEPS_MAC_SUFFIX=0x058 v3.2 + G1–G5 (§5.26); 32,094 B flash, 1,407 B RAM; test builds v33_poke (TEST_POKE_BUILD, TEST_SLIM), v33_poke_nog1 (+NO_PHY_RST_CHECK), v33_fault, v33_rollover
v3.0 test flags -DNET_DEBUG=1 (socket/link log on serial), -DFAULT_INJECTION=1 (TEST_W5500_RESET, TEST_HANG, TEST_STACK), -DMILLIS_ROLLOVER_TEST=1 (clock wraps 60 s after boot), -DMAC_GEN_TEST, -DEPS_MAC_SUFFIX=0x024 (per-unit MAC) tests
H1 / H2 firmware tools/w5500_spi_stress/, tools/w5500_phy_cycle/ built, not run yet

3.4 Tools (all in tools/)

eps_loadtest.py (read-only load test), idle_dose_test.py, eps_power_test.py (switches outputs), dhcp_test_server.py, run_comparison.ps1 + analyze_comparison.py, soak_monitor.py, reset_startup_test.py, hang_harness.py (H1/H2, not run), persistent_client_test.py, junk_input_test.py, m4250.py (switch CLI over SSH); added 2026-10-09: event_check.py (single-event checks, Netio control), repeat_flap.py, flap_capture.py, serial_logger.py (with a command file), decode_diag2.py, novahub_check.py, dhcp_watch.py, link_flap_test.py; diagnostic build v2_2_diag2/ (W5500 registers once a second); added 2026-10-10: v31_dhcp_test.py, v31_http_check.py, v31_fault_check.py, v31_link10_check.py, v31_rollover_check.py, v31_stack_run.py, udp_services.py, conformance_suite.py + conformance_report.py. PC tools: Python 3.12, pyserial, Wireshark (tshark, dumpcap), nmap, arduino-cli (from Arduino IDE 2), PuTTY plink, Scapy (installed, not used for traffic injection).


4. Methods


5. Results

5.1 Code review of v2.2 (2026-10-08) — Code-read, later partly measured

5.2 Link-partner interoperability (2026-10-08) — Measured

Unit 1 cabled straight to the NovaHub adapter:

Condition Result
100 Mbps full (auto) deaf: sends its keepalive ARP every 30.08 s, answers no ARP, no unicast ping, no TCP SYN (not even RST)
after RESET button / power cycle / adapter EEE off still deaf
adapter forced to 10 Mbps full works (ping, TCP, web)
back to 100 Mbps deaf
ASIX adapter at 100 Mbps works at once

Same signature as §5.12 below.

5.3 v2.2 under load (2026-10-08 14:33) — Measured

eps_loadtest.py, unit 1, direct ASIX link.

Phase Port 5000 OK
baseline / 1 idle web connection 20/20 · 20/20
2 idle web connections 1/30
+ idle control connection (refused) 3/86
released 20/20
mixed load: Companion-like (1 Hz, 700 ms timeout) 44/60, failures every 3 s with the browser
mixed load: eXcontrol-like (4 Hz, 4 s timeout) 67/70

Port 5000 was unreachable 107 s, ping 100 % throughout. Web page: 3,598 TCP segments for 3,696 bytes (3,519 single-byte), 890–938 ms.

5.4 v3.0 development results (2026-10-08) — Measured

5.5 DHCP with a real server (Windows sharing, 2026-10-08 16:56–17:10) — Measured

Step Result
Unit in DHCP mode on fallback .93, sharing turned on 16:59:17 lease 192.168.137.24 at 16:59:34, no reboot
Load test on the DHCP address 1,086/1,086, control ~12 ms, page ~43 ms
Reboots first build: new IP each time (.24 → .137 → .223) → fixed (last lease stored, requested again): 3 reboots → .223 each time, bound ~5 s after boot
PHYRESET=1 after sharing was enabled caused by link bounces (adapter reconfigured) making announcement probes count as failures → fixed
Cable out 27 s, back LINKDOWNS=1, same IP, bound again 4 s after replug, PHYRESET=0, no reboot

5.6 Second unit and duplicate MAC (2026-10-08) — Measured

The temporary MAC was derived from the ATmega's serial bytes, which were identical on both boards: both units came up as 02:45:50:2F:69:FD. Reachability: 12/20 and 8/20; after giving unit 2 a different MAC: 20/20 each. Fixed: the temporary MAC is random on first boot (watchdog-oscillator jitter) and then stored; 20 distinct values on 2 boards × 2 boots.

5.7 Library isolation (2026-10-08) — Measured

Unit 2 ran the bare library sketch, and unit 1 ran v3.0 alongside it, both polled by eXcontrol. idle_dose_test.py:

Idle connections held Bare library :5000 / :80 v3.0
0–2 20/20 / 20/20 100 %
3 16/20 (idle on :80), 15/20 (idle on :5000) / 20/20 100 %
4 (5th refused) 0/10 / 0/10 100 %
held 60 s more 0/30 / 0/30 60/60
released 20/20 / 20/20 100 %

The library also sent its replies one byte per packet.

5.8 A/B crossover comparison (2026-10-08 18:00–19:05) — Measured

Pre-registered (§4). 3 load-test runs + 1 dose test per firmware per phase; phase A unit 1 = v3.0, unit 2 = v2.2; phase B swapped.

Criterion v2.2 (6 runs, 2 boards) v3.0 (6 runs, 2 boards)
C1 no lost requests FAIL (127–162 lost per run) FAIL (0 in 5 runs, 1 ping in 1 run)
C2 availability ≥ 99.9 % FAIL (84.2–86.6 %) PASS (99.91–100 %)
C3 port 5000 outage ≤ 5 s FAIL (79–121 s) PASS (0 s)
C4 control p99 ≤ 100 ms FAIL (1,031–1,532 ms) PASS (31–47 ms)
C5 web p95 ≤ 500 ms FAIL (906–1,375 ms) PASS (47–62 ms)
C6 dose ≥ 99 % at every step FAIL (0 %) PASS (100 %)

The same on both boards. Seen in the dose tests: with 3 sockets stuck, v2.2's stall watchdog reboots the unit after ~60 s; a v2.2 reboot switches the outputs off unless "restore after reboot" is on. Full table: docs/comparison-results.md.

5.9 W5500 loses its settings (fault injection, 2026-10-08 18:2x–18:5x) — Measured

v2.2 v3.0
After one W5500 soft reset no ping, no ARP, no TCP, no web the same for ~3 s
Recovered by itself 0 / 4 (watched 60–150 s) 5 / 5 (3.0, 3.5, 4.1, 4.1, 6.0 s; REINIT counted)
Brought back by USB reset (2.8 s) or power cycle —

Observed on the dead v2.2 unit (user, at the bench): RGB blue; holding D9 blinked the red LED (drawn by the main loop, so the CPU was running); one D6 press gave no visible reaction (unexplained; procedure not verified); unplugging the USB power brought it back.

5.10 v3.0 flight recorder (2026-10-08 19:0x) — Measured

A 96-event ring in EEPROM (survives power cuts; ~20 events/hour max). It logs boots with their reason, link up/down with speed/duplex, W5500 re-inits with the wrong registers, PHY resets, gateway silent/back, IP conflicts, DHCP lease/fallback, settings, factory reset, and every power/output command with its source. Bench test: all events logged correctly; the injected glitch was recorded as W5500_REINIT version=0x04 wrong=GATEWAY,MASK,MAC,IP,ALL_ZERO(chip_reset); the log survived a reset and is readable via NET_LOG and on the web page.

5.11 Overnight side-by-side run (2026-10-08 19:07 – 2026-10-09 00:14) — Measured

v2.2 (unit 1) and v3.0 with recorder (unit 2), Ubiquiti switch, eXcontrol polling; soak_monitor.py: ping and TCP once a second, web every 30 s.

5 h 08 min v2.2 v3.0
Ping 18,374 / 18,374 18,412 / 18,412
TCP 18,374 / 18,374 18,412 / 18,412
Web 613 / 613 614 / 614
Worst TCP reply per minute: median / max 188 / 625 ms 16 / 16 ms
v3.0 counters — all 0, 22,535 connections

Under normal traffic neither firmware failed. (The packet capture of this run stopped writing after 1 min; no lost pings, so nothing was lost.)

5.12 Start-up after a reset (H4, H4b; 2026-10-09) — Measured, rate preliminary

USB reset (DTR). Correction (2026-10-09, §5.17): this also resets the W5500 (its link renegotiates); it is not a CPU-only reset. A reset fails if there's no answer to POWER_STATUS within 15 s; failures were watched 60 s.

Run Unit 1 Unit 2
H4 first run, v2.2 (00:2x, stopped early) not run (USB port busy) reset 36 failed (≥ 36 resets)
H4 re-run, v2.2 diagnostic (08:05–08:21) 200/200, median 2.23 s 198/200 (resets 129, 191 failed)
H4b-1, fuller diagnostic + capture (08:25–08:42) 300/300 299/300 (reset 275 failed)
H4b-2 (08:44–09:09) v2.2 diagnostic: 300/300 v3.0: 300/300, median 3.73 s (it renegotiates the link at start-up)

What a failed start-up looks like (unit 2; diagnostics every 2 s for 60 s):

Totals (v2.2): unit 2 4 deaf start-ups in ≥ 536 resets = 0.75 % (95 % CI 0.20–1.90 %); unit 1 0 in 800 (≤ 0.37 %). Board/port difference: one-sided Fisher p = 0.026, confounded with the switch port (port swap pending). v3.0 on unit 2: 0 in 300 (≤ 0.99 %); against v2.2's rate, P(0 in 300) = 0.106.

5.13 Bench batch for v3.0 (2026-10-09 09:30–10:10) — Measured

Test Result
Controllers that keep connections open (change: idle control connections kept 5 min instead of 5 s; oldest idle one evicted when all four are taken; still closed after each answer) quiet 90 s then command: answered; 4 quiet clients hold all sockets, a 5th is served in 0.02 s; oldest evicted, newest works (6/6); dose test 100 %
Per-unit MAC build -DEPS_MAC_SUFFIX=0x024, then generic build MAC 8C:1F:64:C3:90:24, MAC_ASSIGNED=YES, kept by the generic build
Fixed 10 Mbps half duplex negotiated 10HALF with an Auto switch; 30/30 commands, page 63 ms; back to 100FULL
Junk input (junk_input_test.py) 16/16; settings unchanged
millis() rollover (test build) power test 21/21 and short load test across it (sequence not timed to the exact wrap)
Stack high-water mark (test build) ≥ 464 B free at the lowest point
Hung main loop (test build) restart after 19 s, RESTART=WATCHDOG, logged
IP conflict (both units on one IP) both detected it within ~75 s (2 and 4 events)
Companion module live test and parser correct answers; parsed as protocol 2.x with all fields

Upgrade note: when a unit's MAC changes, a Windows PC kept the old MAC in its ARP cache until cleared; with per-unit builds the MAC does not change on upgrade.

5.14 NETGEAR M4250 baseline (2026-10-09, read-only)

Ports 0/6 and 0/12 at 100 Mbps full (auto), 0 receive/transmit errors, no link flaps; EEE and Energy-Detect off on all ports; RSTP on; LLDP active; log shows link-ups and SSH sessions. Port mapping confirmed from the MAC table.


5.15 Three units on v2.2: power, outputs, self-restart (2026-10-09 12:50–13:04) — Measured

Pre-registered single events (docs/m4250-stress-tests.md, amendment 2), 3 tries each; a unit counts as unresponsive with no answer for 60 s after the event.

Event Unit-tries Unresponsive Time to answer
Unit 3 mains off 10 s (Netio) 3 0 5.6–6.7 s
Unit 3 mains off 0.2 / 0.5 / 0.9 / 1.5 / 3 s 15 0 5.6–7.2 s
POWER_ON → POWER_OFF; OUT1–6 on/off (all units) 18 0 ≤ 0.8 s
Settings saved unchanged (v2.2 restarts through its watchdog) 9 0 0.8 s

The real box's supply holds the board ~0.9 s after a mains cut.

5.16 Switch-port flaps and the 13:05 event (2026-10-09 13:05–14:31) — Measured

Run Flaps Unit-tries Unresponsive
All three ports down 0.5 s / 10 s, 3 each 6 18 1 (unit 2, 0.5 s, 13:05)
Replication, all ports 0.5 s 20 60 0
v2.2 watchdog restart, then 60 s later the flap 10 30 0
Port 0/12 only, 0.5 s, mirrored and instrumented 98 98 0

The 13:05 event: ports down 13:05:02–04, up 13:05:05–06; the switch logged Link Up on 0/12 at 13:05:08. Units 1 and 3 answered by 13:05:11–14. Unit 2: no ping, no ARP, no TCP from 13:05:04 to ~13:06:44, then answered again with no link event on 0/12 until the next flap at 13:07:00. Not recorded for this event: capture, serial, switch counters (instrumentation started 13:11). Over 12:49–14:31 the every-second poller saw no other unexplained outage ≥ 10 s on any unit. Unit 2's per-flap rate: 1 in 134 (95 % CI 0.02–4.1 %).

5.17 Which resets touch the W5500 (switch link log) — Measured

Reset Count Link drops seen by the switch
USB/DTR reset 11 per unit 12 per port (~2 s down each)
v2.2 watchdog restart (settings save) 19 0

So the W5500's reset follows the board's RESET line (most likely; continuity not checked), and the M4250's ~3 s forwarding delay after a link-up (ports are "auto edge" in RSTP) explains why units answered 5.1 s after a DTR reset here vs 2.2 s on the Ubiquiti switch.

5.18 Host and switch checks (2026-10-09 afternoon) — Measured

PC: only LargeHUB holds 192.168.0.x, one route, correct neighbour entries for all units. When a unit goes silent, Windows also tries a Hyper-V adapter's default route (vEthernet (Agent) entries appear): a consequence, not a cause. A second NIC with a 192.168.0.x address gave the PC two routes for a while (~13:40–13:55, after the 13:05 event); fixed before further tests. Switch: RSTP 802.1w, unit ports auto-edge, no BPDUs from the units, port security off, broadcast storm control 5 % (no action).

5.19 W5500 registers once a second (v2_2_diag2) and a library defect — Measured

The dump shows on v2.2: MR 0, correct GAR/SUBR/SHAR/SIPR, VERSIONR 4, PHYCFGR as the chip sees its link. It also shows RTR = 0x02D0 (72 ms), RCR = 8, SIMR = 0xD0, although v2.2 sets 200 ms and 2 retries. Cause (source of Ethernet 2.0.2): RTR and RCR are defined at the W5100 addresses 0x0017/0x0019 and used for the W5500 too, where those addresses are SIR/SIMR and the RTR high byte. This explains the "8 ARP tries 73 ms apart" seen on 2026-10-08 and corrects finding #7. Not linked to the silence.

5.20 DHCP environment (2026-10-09 15:17–15:42, M4250 DHCP server, 2-min lease) — Measured

Unit 1 v3.0 (control), unit 2 v2.2 diagnostic, unit 3 v2.2 real box; fallback addresses in another subnet (192.168.137.20/.21/.22). Evidence: DHCP and ARP capture, unit 2's serial log, the switch's binding table.

Step Unit 1 (v3.0) Units 2, 3 (v2.2)
Server switched on lease by itself in 17 s need a restart (no retry after fallback); then lease in 2.6 s / ~15 s
10 min of renewals kept its lease, 0 restarts renewals ACKed, then one unanswered → ~10 s blocked in the library's DHCP loop → watchdog restart → same lease; every 3–4 min
Server off 5 min kept its address to the lease end, fell back, asked every 30 s next renewal unanswered → restart → 60.8 s DHCP wait → static fallback → no DHCP request since
Server on again lease again in 6 s 0 DHCP packets in 5.5 min: stranded, unreachable from the DHCP subnet
Unit 3 mains off 10 s — lease again, answering 13 s after power on

Unit 3 then kept restarting about every 4 min while left on this server (visible as the LED going dark). Why the switch dropped the v2.2 bindings although it ACKed their renewals (broadcast, client address 0.0.0.0) is not established; v3.0's renewals (unicast, with its address) kept its binding.

5.21 Link partner at 100 Mbps (NovaHub adapter, 2026-10-09 14:41–14:55) — Measured, set aside

Units 1 and 2, each cabled straight to the NovaHub USB 10/100 adapter: at 100 Mbps (any duplex) no frame reached the W5500's sockets (UDP receive counter 0, no ping, no ARP, no TCP) while the chip reported link up with the right speed and duplex; at 10 Mbps everything worked (230/230 bytes, 10/10 pings); a PHY reset didn't help. Same on both boards and cables. The adapter has been removed from the bench; this line was set aside as a false lead for the field question.

5.22 v3.1: standards work and the final build (2026-10-09 17:20 – 2026-10-10 18:46) — Measured

v3.1 is v3.0 plus changes for network-standards conformance (docs/v3.1-standards.md). IPv6 and security features are out of scope by decision. All tests ran on unit 3 (the real box), cabled straight to the PC.

Changes from v3.0:

Final build 5284db6: 31,120 B flash (1,136 free), 1,364 B RAM. Every non-soak test was re-run on it (2026-10-10 17:51–18:46); all pass:

Test Result
DHCP sequence (no server → fallback; lease; renewals; expiry; address in use → DECLINE ×4; free address) pass, every step as RFC 2131 requires
Syslog pass: every event (boot, link, settings, power/output commands with source, DHCP)
Static start-up, 3 resets pass ×3: 3 probes 1.08–1.99 s apart, 2 announcements 2.0 s apart, no false conflict
HTTP / TCP checks 21/21
Persistent control clients 6/6; with every control socket held idle, a new client is served in 0.02 s
Idle-connection dose (0–5 idle on :80, then :5000) 800/800 probes answered
10 Mbps half duplex pass; one ping lost under load in each of 2 runs (TCP 1,086/1,086)
Stack low-water (test build, every heavy path) 243 B free
W5500 settings loss ×10 10/10 recovered in 2.1–6.9 s; outputs stayed on throughout
Main-loop hang ×3 3/3 watchdog restart, answering ~25 s later
millis() rollover 6/6

Found: with a configured gateway that doesn't answer (normal on a closed AV network), the once-a-minute gateway check makes the chip send ~20 ARP requests in 3.8 s; RFC 1122 recommends ≤ 1 per second. Negligible load; listed as a known deviation (§5.23).

Not yet tested on v3.1: D5/D6/D9 inputs and LED colours by hand; real power cycles from the Netio with USB unplugged; real loads.

5.23 Conformance suite: v3.1 vs v2.2 (2026-10-10 19:06–19:44) — Measured

Fifty-six requirements from ten standards, each with a pass criterion, committed before either firmware was run (docs/conformance-suite.md). The same tool (tools/conformance_suite.py) ran on both firmwares on unit 3, cabled straight to the PC. It covers link (PC NIC forced to 10/100 half), resets, an 8 s link outage, a bench DHCP server (no server, lease, server gone, NAK, address in use), a static address equal to the PC's, and fragmented pings. No forged traffic. A standard passes only if every applicable requirement passes. Results: docs/conformance-results.md.

Standard v3.1 v2.2
IEEE 802.3 Ethernet PASS PASS
IEEE 802 MAC addressing PASS PASS
RFC 826 ARP PASS PASS
RFC 1122 host requirements FAIL (2 MUST, 1 SHOULD) FAIL (2 MUST, 1 SHOULD)
RFC 5227 address conflict detection PASS (2 not verified) FAIL (4 MUST, 2 SHOULD)
RFC 2131/2132 DHCP client FAIL (1 MUST) FAIL (4 MUST, 3 SHOULD)
TCP (RFC 9293 / 1122) FAIL (1 MUST) FAIL (1 MUST, 1 SHOULD)
HTTP (RFC 9110 / 9112) FAIL (3 MUST) FAIL (6 MUST, 1 SHOULD)
IEEE 802.1D/Q (end station) PASS PASS
RFC 5424/5426 syslog PASS N/A (no syslog)
Requirements passed (of 56) 46 (8 fail, 2 not verified) 26 (25 fail, 1 not verified, 4 n/a)

Why the failures happen:

No firmware on this board can fix either.

Corrections after the runs (all listed in the results file): tool errors in the first v3.1 run (C3, L2/L3, H3, D3–D5, T6) were fixed and the phases re-run or re-analysed before v2.2 was run. C7 had a criterion error, flagged as an amendment after data. v2.2's MAC item (M3) was first scored FAIL because the sketch has one constant MAC; in production that constant is set per unit before flashing (Expromo's MA-S block; unit 3 left the workshop with …90:58). It was rescored PASS.

What the suite doesn't measure: recovery from the field mechanisms (§6). Conformance and robustness are separate questions; v3.1's main gain is on the second.


5.24 Single-register W5500 faults: v3.1 vs v2.2, and the v3.2 candidate (2026-10-10/11) — Measured

§5.9 reproduced one kind of chip fault: a full W5500 reset (every register zero), which v3.1's 5 s health check repairs. A real SPI glitch or an ESD event is more likely to flip a single register. This test (protocol docs/fault-matrix-tests.md, committed before any data) wrote one fault at a time into unit 3's own chip — the unit's own firmware pokes the register, the PC sends only ping, POWER_STATUS and GET /, no crafted traffic — and watched each service for 120 s, three trials per fault, on v3.1's final build (5284db6) and on v2.2. A trial passes only if every service is back within 60 s with the registers restored and the outputs unmoved; a fault passes only if all three trials pass. Full data and every trial: docs/fault-matrix-results.md.

Fault (single register) v3.1 v2.2
Chip soft reset (all zero) recovered 6–10 s dead 3/3
IP .93 → .99 recovered ≤10 s dead 3/3
MAC …58 → …59 recovered 5–10 s (one trial on/off ~60 s, then back) wrong MAC kept 3/3
Gateway .1 → .99 repaired (no effect on a direct link) wrong gateway kept 3/3
Mask → /32 recovered 4–7 s dead 3/3
Ping block (MR) dead 3/3 (ping only; TCP/web fine) dead 3/3
PHY power-down (PHYCFGR) dead 3/3 dead 3/3
Forced 10 Mbps half (PHYCFGR) service back 4 s, stays at 10 half 3/3 same 3/3
Retry count 0 (RCR) dead 3/3 (ping ok, TCP/web not) dead 3/3
Listeners closed / RX buffer 0 no effect no effect
Control/web listen port moved no effect dead (that service lost)

What it shows. v3.1's health check repairs every register it covers — chip version, gateway, mask, MAC, IP — usually in 4–10 s, with no reset and the outputs untouched; v2.2 needs a power cycle for the chip reset, a wrong IP or a wrong mask (9/9 dead) and keeps a wrong MAC or gateway for good. v3.1 also survives every socket fault, including a listener moved to another port, which v2.2 does not. But four faults fall outside v3.1's check and leave it dead on both firmwares: the mode register's ping block, the retry count at 0, a forced 10-half link, and — the important one — PHY power-down, which produces the exact field symptom (no ping, no web, no TCP until a power cycle). Of the faults tested, PHY power-down (and, on v2.2, the chip reset and wrong IP that v3.1 does repair) is the one that still matches the field failure on v3.1. This says which faults could produce the field symptom, not which one does; the field trigger is still untested (§7).

v3.2 candidate — the fix, and the same matrix re-run (Measured, 2026-10-11). The fix suggested by this result is to widen v3.1's 5 s comparison to the registers it currently ignores: the mode register MR (ping block), the retransmission registers RTR/RCR (retry count) and the PHYCFGR configuration bits (PHY power-down and forced link mode). On a mismatch v3.2 takes the same re-init path it already uses for a bad address, which re-applies all of these and renegotiates the link. Built on branch v3.2-health-check (Expromo_EPS_v3_2, production 31,238 B of 32,256; +118 B over v3.1), flashed to unit 3, first confirmed not to false-trigger a reinit-loop (REINIT=0, PHYRESET=0 over 90 s), then run through the same 14-fault matrix (3 trials each). Result: the four faults v3.1 could not recover — ping block, PHY power-down, forced 10-half and retry count 0 — now recover on v3.2. Forced 10-half and retry-0 pass 3/3; ping block and PHY power-down recover in 2 of 3 trials, the third failing only the end-of-run stray-ping check (which also fired on faults that cannot affect ping, confirming it as a ~0.4 %/ping artefact, not service loss). The field-matching F7 PHY power-down comes back in 11–12 s with no reset. No trial on v3.2 produced a "dead/needs-reset" outcome anywhere in the matrix, no relay moved, and no spurious reinit was seen — so the wider check recovers the field-matching fault without regressing anything or destabilising steady state, at a cost of +118 B flash and three extra SPI reads per 5 s cycle. On these results v3.2 is recommended as the field candidate in place of v3.1. Full per-trial data: docs/fault-matrix-results.md.

Reset start-up (Test 2b). The other planned test asks how often the real box comes up deaf after a fresh start — the deaf start-up seen on unit 2 (§5.12). 200 USB/DTR resets on each firmware (a DTR reset also resets the W5500, §5.17): v3.1 came up 200 of 200, v2.2 200 of 200, no deaf event on either (median time to answer 9.1 s for v3.1, 2.9 s for v2.2 — v3.1 is slower because it runs the RFC 5227 probe/announce and negotiates the PHY twice before using its address). This matches every earlier run on units 1 and 3; the deaf start-up has only ever appeared on unit 2 (4 events). The link-drop half (2a) was set aside: the bench method that drives it (disabling the PC's adapter) stopped being reliable, and a unit-side method was deferred.

5.25 Code analysis: v2.2 (with the Ethernet library), v3.1, v3.2 (2026-10-12) — Code-read, datasheet

All three firmwares and the Arduino Ethernet 2.0.2 source were read in full against the W5500 datasheet v1.1.0 (text extracted from WIZnet's PDF), the RFCs and AVR practice; stack frames were compiled with -fstack-usage. Full text with code references: docs/code-analysis.md.

5.26 v3.3: the gaps closed, tested overnight against every version (2026-10-12) — Measured

v3.3 = v3.2 + the §5.25 gaps (G1 PHY reset bit in the health check; G2 PHY reset after 30 s without link, backing off; G3 receiver check by one raw ARP request to the gateway or the last client, listening to every frame for 2 s and counting a silent check only if nothing at all was heard, "answered" surviving a link-up; G5 5 V supply via the internal bandgap in NET_STATUS and logged with every re-init; BOD fuse readout; 414 for an over-long target). 32,094 B of 32,256 (162 B free), 1,407 B RAM. Protocol and pass criteria committed before the run (docs/v3.3-tests.md, amendment 1 before any affected data); unattended run on unit 3, direct cable, USB connected, reset capacitor removed. Changes and builds: docs/v3.3.md.

Fault matrix (51 trials on v3.3). All 17 faults recovered by themselves (3–10 s) or had no effect; no dead, latent or slow trial; outputs 111111 throughout; four tail-only trials (stray ping, two on faults that can't affect ping). F15 (PHY held in reset): v3.3 3–6 s; v2.2, v3.1 and v3.2 dead 3/3 each (power cycle needed), as the code analysis predicted (gap G1). F16 (F15 with only the link-down recovery): back at 40 s in 3/3. F17 (PHYCFGR power-down written once): v3.3 recovered 6–7 s; v3.2 recovered 5–26 s; on v3.1 and v2.2 the PHY kept running with the wrong value in the register (latent): a mode written without the RST toggle doesn't take effect until the next PHY reset. The field-matching F7 PHY power-down now recovers in 4–6 s (v3.2: 11–12 s). Background ping loss in recovered trials: v3.3 0.52 %, v3.2 1.09 %, v3.1 1.97 % — the raw-frame listening doesn't add loss.

Receiver check. Gateway present then gone (N6): v3.3 sent one ARP request per check (11 in 12 min to the vanished gateway, never more than one per second) and made no PHY reset (the PC's own frames proved the receiver works); on v2.2, v3.1 and v3.2 the prediction (ARP bursts, PHY resets) was wrong for a reason worth knowing: their check (v2.2: keepalive) is a UDP send, and without MR.FARP the W5500 reuses the gateway MAC it cached at the first send, so after the gateway vanished they sent no ARP request at all in 12 min and their checks kept "succeeding". On v3.1/v3.2 this means the receiver check can never notice a deaf receiver once a gateway has answered once; v3.3's raw ARP request needs a reply every time. Deaf receiver by emulation (N4, TEST_DEAF): exactly one recovery PHY reset after three silent checks, none after; at 6 min instead of the pre-registered 3–5 min, because with a configured gateway that never answers, gateway and client take turns (strict verdict FAIL on timing).

Link down 180 s (N5, v3.3 only, amendment 1): PC adapter disabled for 180 s, twice: service back 8.3 and 8.6 s after it was enabled, 2 PHY resets during each outage (at 30 s and 90 s, as designed), no restart, outputs kept (PASS); the PC adapter survived both cycles.

Regression (production build). Power 21/21; load test 541/541; junk input 16/16; HTTP 21/21 and 414 for a 600-byte target; persistent clients 6/6; idle dose all answered (0–5 idle connections per port); DHCP A–E with syslog (renewals acknowledged while the receiver check ran); 10 Mbps half duplex (load 543/543); 50/50 USB-reset start-ups (median 9.16 s); millis rollover; stack low-water 190 B (FAULT_INJECTION build). NET_STATUS on unit 3: VCC=5096, VCC_MIN=5073 mV (USB supply), BOD=2.7 — the brown-out level the code analysis inferred, now measured.

Settings loss. In the first run (10 trials + 3 watchdog hangs) trial 8 was followed by a ~3.5-min outage that cleared by itself without a restart; three later steps fell in it (10/14). An instrumented re-run of 20 trials (capture, ping, PC address state, unit counters) passed 20/20, as did 20 trials on v3.1. A re-run under the original conditions (50 USB resets, then 10 trials) caught a second episode with the capture running: trial 5 answered only after 47 s; the unit sent its own ARP request with its correct address, then answered none of ~35 ARP requests from the PC for ~38 s with the link up, sent no address-check probes, and recovered by itself with no re-init, PHY reset or link change. A deaf receiver after the re-init's link renegotiation — mechanism (c), until now seen only on unit 2. The 03:48 outage had the same signature (~3.5 min). Tonight: 2 episodes in 40 settings-loss trials on v3.3 (two link negotiations each), 0 in 30 on v3.1; not significantly different, consistent with a chip/board property. Both cleared before v3.3's deaf check acted (~6 min on this bench, where gateway and client take turns). The event log couldn't show this either: each re-init now writes four records, and the hourly budget ran out (a log-economy fix is in §9).

Conformance (N8): same suite and criteria as §5.23, unit 3, 05:44–06:01 (data/conformance/v33_*). 48 of 56 requirements pass (v3.1/v3.2 46, v2.2 26), 6 fail, 2 not verifiable without forged traffic. Newly passing: H6 (one ARP request per check, 1 to the gateway and 1 to the PC in 137 s) and W8 (414). Failing: H2, H3 (W5500 chip limits), D4 (DHCP from the fallback address), T6 (2-s send timeout), W7 (no Host check, kept for control systems that send hand-written HTTP), W9 (GET switching, kept). C7 measured exactly as on v3.1 (3 probes and the first announcement before use) and is scored by the same documented rule (RFC 5227 allows use after the first announcement): pass. Standards: 6 of 10 pass, as v3.1; RFC 1122 now fails only on the chip limits.

6. Discussion

What explains the field symptom. The total loss (no ping, no ARP) can only come from the W5500 not answering at all:

Mechanism Matches v2.2 recovers v3.0 / v3.1 recovers Trigger
DHCP strand: an unanswered renewal → v2.2 restart → no server within 60 s → static fallback for good exactly (DHCP mode only) no, until power cycle yes, by itself (6 s after the server returns) any DHCP outage or non-answer at renewal time
W5500 loses its settings exactly no yes, 3–6 s (v3.1: 2.1–6.9 s, 10/10, outputs kept) unknown; supply dip / ESD suspected; load switching untested
W5500 deaf after a link negotiation (sends, receives nothing) exactly unknown beyond 60 s; once cleared by itself after 97 s v3.0–v3.2: no recovery (their check runs on a cached gateway address, §5.26); v3.3: PHY reset after three silent checks ~1 in 130 negotiations on unit 2; on unit 3 seen twice after v3.3 re-inits (38 s and ~3.5 min, both cleared by themselves; one captured)
Socket starvation no (ping works) sometimes, via a watchdog reboot never starves idle / half-open connections
Duplicate MAC / IP partly no reports IP conflicts process error

DHCP sites. The DHCP strand matches the field description exactly and needs no hardware fault: a router or DHCP server that is down, rebooting or slow when a v2.2 unit renews leaves that unit unreachable until someone power-cycles it. It does not apply to units set to static.

Static sites. Two candidates remain: the W5500 losing its settings (trigger untested: load switching), and deafness after a link negotiation (rare, persistence unknown). Withdrawn (2026-10-09): the earlier chain "v2.2's own CPU-only reboots come up deaf"; the deaf start-ups followed DTR resets, which also reset the W5500, and 19+ watchdog restarts never came up deaf.

Why v3.0 had 0/300 deaf start-ups is open: both firmwares got a W5500 hardware reset at each DTR reset; v3.0 additionally resets the PHY in software and negotiates a second time.

The Arduino Ethernet library is responsible for the starvation behaviour and the one-byte-per-packet output (§5.7). v2.2 made it worse (the permanent keepalive socket) and did not compensate.

v3.0 assessment. It fixes the reproduced defects and mechanism (a), and it matches or beats v2.2 everywhere it was measured. Five bugs were found and fixed during two days of testing (0x11 state, DHCP address per reboot, PHY reset on link bounce, PHY recovery assuming a gateway, identical temporary MACs). That is the expected cost of a rewrite; more may remain.

v3.1 assessment. It keeps v3.0's network layer and recovery, and adds standards conformance. On the final build every non-soak test passed, including settings loss with the outputs kept on, and v3.1 passed 46 of 56 conformance requirements against v2.2's 26. Its remaining failures are two chip limits, three small fixable items (ARP rate, Host, 414) and three deliberate trade-offs (DHCP from the fallback address, the 2-s send timeout, GET actions). Two bugs were found and fixed during the v3.1 work (a false conflict from the PC's own probe, and a timer in the split-command fix). It is not field-proven.

v3.2 assessment (recommended as the official firmware). It is v3.1 with the 5 s self-check widened to the mode (MR), retransmission (RTR/RCR) and PHY configuration (PHYCFGR) registers. In the pre-registered single-register fault matrix it recovered from all 14 faults with no "dead/needs-reset" outcome and the outputs never moving — including the four v3.1 died on (ping block, retry count 0, forced 10-half, and the PHY power-down that reproduces the field symptom, back in 11–12 s), and with no regression on the faults v3.1 already handled (§5.24). It scores the same 46 of 56 on the conformance suite (the change does not touch anything the suite measures). Cost: +118 B flash (31,238 of 32,256) and three extra SPI reads per 5 s cycle; the TCP protocol, stored settings and the v2.2 EEPROM downgrade path are unchanged. It is not field-proven; adoption should be followed by the hands-on and real-load checks and a pilot (§7).

v3.3 assessment (recommended as the official firmware). It is v3.2 with the gaps of §5.25 closed. In the overnight run it recovered from all 17 single-register faults (51 trials, 3–10 s, outputs never moved), including the PHY held in reset that leaves v3.2 dead; the link-down recovery alone brings a stuck PHY back in 40 s; the new receiver check sent one ARP request per check and made no false PHY reset when the gateway vanished; the whole regression suite passed. Twice in 40 settings-loss trials the chip came back deaf after the re-init's link renegotiation and cleared by itself (38 s, ~3.5 min; captured once, §5.26): mechanism (c), now seen on unit 3 too; faster detection after a re-init is the next step. Program memory is 99.5 % full (162 B free), so any later feature needs something taken out. It is not field-proven.

Is v2.2 as good as v3.1/v3.2 on standards? No. Several standards show FAIL for both, because one failed item fails a standard, but v2.2 fails 25 requirements against v3.1/v3.2's 8. Only v2.2 lacks conflict detection, gives up on TCP after 18.4 s, deviates from RFC 2131 in its DHCP client and mishandles HTTP methods.


7. Limits of the evidence


8. Conclusions

Conclusion Grade
The field symptom means the W5500 stops answering; socket starvation alone can't cause it Measured
DHCP mode: after a DHCP outage at renewal time, v2.2 stays unreachable until power-cycled; v3.0 recovers by itself Measured (one server)
On v2.2, one unanswered DHCP renewal makes the unit restart itself (outputs off unless "restore") Measured
If the W5500 loses its settings, v2.2 stays dead until reset; v3.0 recovers in 3–6 s Measured
After some link negotiations a W5500 goes deaf (registers correct, receives nothing); ~1 in 130 on one board Measured (rate preliminary; persistence unknown)
A USB/DTR reset also resets the W5500; a v2.2 watchdog restart doesn't Measured
Ethernet 2.0.2 writes RTR/RCR to the wrong W5500 registers Measured
v3.0 avoids the deaf start-up Preliminary (p = 0.106)
v3.0 beats v2.2 on all pre-registered criteria except one lost ping Measured
What makes static-mode units drop off in the field Unknown
v3.1 passes every non-soak bench test on its final build, including settings loss with outputs kept Measured
On 56 standards requirements, v3.1 passes 46 and v2.2 26; two shared failures are W5500 chip limits Measured (one bench, own tools)
v2.2 cannot make a static unit stop answering ping by its own logic; every outside upset of the W5500 is permanent on it Code-read (§5.25)
Unit 3's brown-out level is 2.7 V (Uno default) Measured (v3.3 BOD=2.7)
A supply sag is the static-mode trigger Hypothesis (untested)
A PHY held in reset leaves v3.2 dead; v3.3 recovers in 3–6 s Measured (§5.26)
v3.3 recovers from all 17 single-register faults and passes the full regression Measured (§5.26; two self-clearing deaf episodes after re-inits)
A W5500 can come back deaf after a link renegotiation on unit 3 as well (2 in 40 settings-loss trials on v3.3, cleared by themselves after 38 s and ~3.5 min) Measured (one episode captured)
v3.0–v3.3 prevent the field failure Unknown (needs a pilot)

9. Next steps

  1. Supply-sag test (hands-on, highest value): unit on a lab supply (or the 5 V rail sagged with a MOSFET), USB unplugged; sags to 2.8–4.5 V for 10–500 ms and slow power-ups (0.1–2 s), with and without the 22 µF; v2.2 vs v3.3, pre-registered. Decides the leading hypothesis (§5.25).
  2. Hardware for the next board revision: brown-out level 4.3 V (extended fuse 0xFC, ISP), a reset supervisor instead of the 22 µF capacitor, the W5500 reset pin on a free GPIO, the blue LED off D4.
  3. v3.3.1 candidates: fold the supply value into the re-init log record (log budget); stop alternating to a gateway that has stayed silent several times (faster deaf detection, §5.26); skip the receiver check while DHCP is renewing; faster deaf detection after a re-init (the two deaf episodes lasted 38 s and ~3.5 min; v3.3 acts after ~6 min where the configured gateway never answers).
  4. Field facts: for each failing site, DHCP or static; DHCP server/router type and whether it was down or rebooted around the failure.
  5. Field check before power-cycling a dead unit: on the site switch, is the unit's MAC still in the MAC table and is its port's receive counter rising? Yes → the unit still transmits (deaf receiver); no → it lost its settings or stopped.
  6. v3.1 by hand on unit 3, then on the showroom box with real loads: D5/D6/D9 and LEDs; real power cycles from the Netio with USB unplugged; flash with the box's own MAC (-DEPS_MAC_SUFFIX), capacitor removed for the upload; switch the loads with the poller and flight recorder running. Any REINIT/PHYRESET count or logged W5500 re-init is the finding.
  7. Persistence of the deaf state: catch a deaf start-up on unit 2 (DTR resets, register dump, switch counters) and leave it alone for ≥ 10 min.
  8. DHCP: a switch reload with the M4250 as DHCP server (the realistic outage); another DHCP server type.
  9. Pilot: v3.3 + flight recorder with per-unit MACs at sites that had failures. With no failure in N unit-days, the 95 % bound is ≈ 3/N.

Appendix A: documents

docs/network-investigation.md (v2.2 analysis and early bench results) · docs/v3.0.md (v3.0 design, changes, test notes) · docs/comparison-protocol.md + docs/comparison-results.md · docs/w5500-hang-tests.md + docs/w5500-hang-results.md · docs/eps-firmware-review.html (an earlier, internal summary page) · docs/v3.1-standards.md (v3.1 changes and tests) · docs/conformance-suite.md + docs/conformance-results.md (standards suite, v3.1 vs v2.2) · docs/fault-matrix-tests.md + docs/fault-matrix-results.md (single-register W5500 faults and link/reset tests, v3.1 vs v2.2) · docs/code-analysis.md (code analysis of v2.2 with the Ethernet library, v3.1 and v3.2, 2026-10-12) · docs/v3.3.md (v3.3 changes and builds) · docs/v3.3-tests.md (v3.3 protocol, amendment and results) · docs/HANDOVER.md (bench state and how to continue).

Appendix B: chronology

When What
10-08 afternoon Code review; NovaHub deafness; v2.2 load test; v3.0 written and flashed; 0x11 bug found/fixed
10-08 ~15–17 h DHCP bench server; power test; Windows-sharing DHCP; sticky-IP and PHY-reset fixes
10-08 ~17–18 h Second unit; duplicate-MAC bug; library isolation; comparison protocol committed
10-08 18:00–19:05 A/B phases A and B; fault injection; flight recorder
10-08 19:07 – 10-09 00:14 Overnight side-by-side run
10-09 00:15 W5500 hang-test protocol committed; H4 first run (stopped)
10-09 08:05–09:09 H4 re-run, H4b-1, H4b-2
10-09 09:30–10:10 Persistent connections; v3.0 bench batch
10-09 late morning NETGEAR M4250 connected; access and read-only baseline
10-09 ~12:30 Unit 3 (real EPS box) and Netio PowerBOX added
10-09 12:50–13:04 Single events: power cuts, outputs, self-restarts (all fine)
10-09 13:05 Unit 2 silent ~97 s after a 0.5 s port flap
10-09 13:11–14:31 Replications (0/30 flaps), instrumented single-port flaps (0/98); DTR resets the W5500; library RTR/RCR defect
10-09 14:41–14:55 NovaHub at 100 Mbps: deaf on both boards (set aside)
10-09 15:17–15:42 DHCP tests: v2.2 restarts at renewals and strands after an outage; v3.0 recovers
10-09 17:20–18:40 v3.1 (standards work) on unit 3: start-up check, HTTP, DHCP, syslog; review fixes
10-10 17:51–18:46 v3.1 final build: every non-soak test re-run, all pass; ARP rate found
10-10 19:06–19:44 Conformance suite (pre-registered) on v3.1, then v2.2
10-10 23:49 – 10-11 02:49 Fault matrix Test 1 (pre-registered): 14 single-register faults ×3 on v3.1, then v2.2
10-11 07:19–11:20 Fault matrix Test 2 re-run: 16 valid v3.1 link drops, then the PC's adapter failed; aborted
10-11 12:49–13:38 Test 2 part 2b (USB-reset start-up) on v3.1 and v2.2: 200 each, 0 deaf
10-11 13:44–15:12 v3.2 candidate built; same 14-fault matrix ×3 on v3.2: recovers F6–F9 (incl. PHY power-down), no dead outcome; unit 3 restored to v3.1 production
10-12 ~00:00 Code analysis of v2.2 (+ Ethernet 2.0.2), v3.1, v3.2 (§5.25)
10-12 00:30–00:56 v3.3 built (G1–G5, BOD, 414); protocol committed; overnight run started
10-12 00:56–02:52 v3.3 test build: boot sanity, deaf emulation, 17-fault matrix ×3, F16
10-12 02:52–04:02 v3.3 production: gateway-gone test, full regression, fault/stack/rollover builds; the 03:48 outage
10-12 04:02–04:10 Instrumented settings-loss re-runs on v3.3 and v3.1 (20 each, all pass)
10-12 04:10– F15/F17 and gateway-gone on v3.2, v3.1, v2.2; link-down on v3.3; conformance v3.3; reproduction run catches a deaf episode (06:10)