Browse Source

Rebase PoE delta onto merged PR #1983 Ethernet foundation

#1983 landed a generic RAK4631 Ethernet base (repeater/room_server/companion
envs, single-client SerialEthernetInterface, EthernetCLI telnet CLI) and
independently added the same WB_IO2 rail-power fix we found for PoE boot.
Layer the remaining PoE-specific delta on top of it instead of duplicating:

- W5100SPoE: drop the now-redundant WB_IO2 early-ctor code (covered by
  #1983's own constructor), keep only the early W5100S RST release and the
  bit-bang activation/VERSIONR check.
- SerialEthernetInterface: add PoE-safe deferred bring-up (Ethernet.init/
  begin() moved out of begin() into loop(), gated by an _hwReady flag, so
  the disruptive PHY soft-reset + DHCP can't collapse the marginal PoE
  supply at cold start) and bounded DHCP with a static-IP fallback.
- EthernetCLI: same deferral (vTaskDelay before hardware bring-up) and
  bounded DHCP + static fallback for the repeater/room_server telnet path.
- platformio.ini: add RAK_4631_{repeater,room_server,companion_radio}
  _ethernet_poe envs extending #1983's _ethernet envs with WITH_W5100S_POE.

Verified: all three new _poe envs build, plus the plain _ethernet envs and
non-Ethernet variants (no cross-variant breakage).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
pull/2679/head
1sthandy 4 days ago
parent
commit
95b75d0c9c
  1. 43
      src/helpers/nrf52/EthernetCLI.h
  2. 2
      src/helpers/nrf52/SerialEthernetInterface.cpp
  3. 38
      variants/rak4631/W5100SPoE.cpp
  4. 26
      variants/rak4631/W5100SPoE.h
  5. 24
      variants/rak4631/platformio.ini

43
src/helpers/nrf52/EthernetCLI.h

@ -27,6 +27,26 @@ static SPIClass ETHERNET_SPI_PORT(NRF_SPIM1, PIN_SPI1_MISO, PIN_SPI1_SCK, PIN_SP
#define ETHERNET_RETRY_INTERVAL_MS 30000
#ifdef WITH_W5100S_POE
// Give the RAK19018 (Silvertel) PoE converter time to latch on the current
// the W5100S is already drawing (board.begin()'s early RST release +
// bit-bang soft-reset) before doing the *disruptive* Ethernet-library
// bring-up (another PHY soft-reset + blocking DHCP) — doing that
// immediately reliably collapsed the marginal PoE supply.
#ifndef ETH_POE_DEFER_MS
#define ETH_POE_DEFER_MS 6000
#endif
#ifndef ETH_STATIC_IP
#define ETH_STATIC_IP 192,168,1,50
#endif
#ifndef ETH_GATEWAY
#define ETH_GATEWAY 192,168,1,1
#endif
#ifndef ETH_SUBNET
#define ETH_SUBNET 255,255,255,0
#endif
#endif
static EthernetServer ethernet_server(ETHERNET_TCP_PORT);
static EthernetClient ethernet_client;
static volatile bool ethernet_running = false;
@ -35,6 +55,10 @@ static volatile bool ethernet_running = false;
static void ethernet_task(void* param) {
(void)param;
#ifdef WITH_W5100S_POE
vTaskDelay(pdMS_TO_TICKS(ETH_POE_DEFER_MS));
#endif
Serial.println("ETH: Initializing hardware");
// WB_IO2 (power enable) is already driven HIGH by early constructor
// in RAK4631Board.cpp to support POE boot.
@ -51,6 +75,22 @@ static void ethernet_task(void* param) {
Serial.printf("ETH: MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
#ifdef WITH_W5100S_POE
// Bounded DHCP with a static-IP fallback, so the node stays reachable even
// without a DHCP server (no infinite retry — this build has no battery and
// must always come up somewhere).
Serial.println("ETH: Attempting DHCP...");
if (Ethernet.begin(mac, 10000, 2000) == 0) {
Serial.println("ETH: DHCP failed -> static IP fallback");
IPAddress ip(ETH_STATIC_IP), gw(ETH_GATEWAY), sn(ETH_SUBNET);
Ethernet.begin(mac, ip, gw, gw, sn);
}
IPAddress ip = Ethernet.localIP();
Serial.printf("ETH: IP: %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
Serial.printf("ETH: Listening on TCP port %d\n", ETHERNET_TCP_PORT);
ethernet_server.begin();
ethernet_running = true;
#else
// Retry loop: keep trying until we get an IP
while (!ethernet_running) {
Serial.println("ETH: Attempting DHCP...");
@ -75,8 +115,9 @@ static void ethernet_task(void* param) {
ethernet_server.begin();
ethernet_running = true;
}
#endif
// DHCP succeeded, task is done
// DHCP succeeded (or static fallback applied), task is done
vTaskDelete(NULL);
}

2
src/helpers/nrf52/SerialEthernetInterface.cpp

@ -48,7 +48,7 @@ static void eth_init_spi_and_pins() {
}
// Bring up the DHCP/static IP + start listening. Returns true on success.
static bool eth_bring_up(const uint8_t mac[6]) {
static bool eth_bring_up(uint8_t mac[6]) {
#ifdef WITH_W5100S_POE
// Bounded DHCP with a static-IP fallback, so the node stays reachable even
// without a DHCP server and never blocks indefinitely at cold start.

38
variants/rak4631/W5100SPoE.cpp

@ -4,29 +4,15 @@
#include <nrf.h>
#include "W5100SPoE.h"
// ── Early power-rail + RST release (constructor priority 200) ────────────────
// Runs before setup(), right after SystemInit. Two jobs, as early as possible
// so the W5100S draws its full operating current before the RAK19018
// (Silvertel) converter folds back during PoE cold-start:
//
// 1. Drive PIN_3V3_EN (P1.02 / WB_IO2 / Arduino 34) HIGH — this is the
// RAK19007 3.3 V PERIPHERAL POWER ENABLE that feeds the RAK13800/W5100S.
// Meshtastic does this in initVariant(); stock MeshCore never did, so our
// W5100S was only weakly powered via a default path (responds on USB but
// can't pull its full ~130 mA on the marginal PoE rail).
// 2. Drive W5100S RST (P0.21 / WB_IO3 / Arduino 21) HIGH — out of reset.
// ── Early RST release (constructor priority 200) ─────────────────────────────
// Runs before setup(), right after SystemInit — earlier than the ETHERNET_ENABLED
// constructor in RAK4631Board.cpp that powers the peripheral rail (WB_IO2,
// priority 102 runs first) but well before setup()/board.begin(), so the
// W5100S starts drawing its full operating current as early as possible,
// before the RAK19018 (Silvertel) converter's foldback timer expires.
//
// Raw registers because the Arduino GPIO layer isn't up this early.
static void __attribute__((constructor(200))) w5100s_early_power_init() {
// P1.02 = 3V3_EN → HIGH (power the peripheral rail FIRST)
NRF_P1->PIN_CNF[2] =
(GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) |
(GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
(GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
(GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
NRF_P1->OUTSET = (1UL << 2);
static void __attribute__((constructor(200))) w5100s_early_rst_release() {
// P0.21 = W5100S RST → HIGH (release from reset)
NRF_P0->PIN_CNF[21] =
(GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) |
@ -83,13 +69,11 @@ static uint8_t bb_read_reg(uint16_t addr) {
}
// ── Full W5100S bring-up ────────────────────────────────────────────────────
// Called from RAK4631Board::begin(). Confirms the 3V3 rail + RST are driven
// (Arduino API, in case the core re-init touched them), then soft-resets and
// reads VERSIONR. Returns VERSIONR (0x51 = healthy W5100S).
// Called from RAK4631Board::begin(). Confirms RST is driven (Arduino API, in
// case the core re-init touched it), then soft-resets and reads VERSIONR.
// Returns VERSIONR (0x51 = healthy W5100S).
uint8_t w5100s_poe_init() {
// Make sure the peripheral power rail stays driven HIGH.
pinMode(W5100S_3V3_EN_PIN, OUTPUT); digitalWrite(W5100S_3V3_EN_PIN, HIGH);
delay(20); // let the rail/W5100S settle after enable
delay(20); // let the rail/W5100S settle after the ETHERNET_ENABLED ctor's WB_IO2 enable
// Park both chip-selects HIGH on the shared bus, RST released.
pinMode(LORA_NSS_PIN, OUTPUT); digitalWrite(LORA_NSS_PIN, HIGH);

26
variants/rak4631/W5100SPoE.h

@ -1,6 +1,7 @@
#pragma once
// W5100S activation for PoE operation on RAK10720 (RAK4631 + RAK13800 + RAK19018).
// W5100S early activation for PoE operation on RAK10720 (RAK4631 + RAK13800 +
// RAK19018).
//
// ROOT CAUSE (confirmed via RAK forum + Meshtastic rak4631_eth_gw variant):
// The RAK19018 PoE module (Silvertel Ag9905MT) enters a non-continuous
@ -8,14 +9,14 @@
// repeater draws only a few mA, so the converter never latches → the supply
// pulses and the device never boots (fade-in / brighten / die / repeat LED).
//
// The fix that lets Meshtastic boot on PoE without a battery: bring the
// W5100S PHY into its active state. An active W5100S draws ~120 mA — enough
// to keep the Silvertel converter latched in continuous mode.
//
// The W5100S has no power-enable pin on this board (always powered), but its
// RST must be HIGH for the PHY to run. We release RST as early as possible
// (before setup(), via a constructor) so the PHY draws current and latches
// the converter before its foldback timer expires.
// The fix: bring the W5100S PHY into its active state as early as possible.
// An active W5100S draws ~120 mA — enough to keep the Silvertel converter
// latched in continuous mode. The peripheral power rail (WB_IO2 / P1.02) is
// already driven HIGH by an early constructor in RAK4631Board.cpp whenever
// ETHERNET_ENABLED is set; this file only handles releasing RST (the rail
// alone isn't enough — the chip must actually be brought out of reset and
// made to draw its full current well before the Ethernet library's own
// (later, disruptive) bring-up runs).
//
// Pin mapping (from Meshtastic rak4631_eth_gw variant.h):
// RST → PIN_ETHERNET_RESET = 21 (P0.21 / WB_IO3)
@ -30,13 +31,6 @@
#define W5100S_CS_PIN 26 // WB_SPI_CS
#endif
// RAK19007 3.3 V peripheral power enable (feeds the RAK13800/W5100S).
// Must be driven HIGH or the W5100S is only weakly powered — exactly what
// Meshtastic's initVariant() does and stock MeshCore omits.
#ifndef W5100S_3V3_EN_PIN
#define W5100S_3V3_EN_PIN 34 // P1.02 / WB_IO2
#endif
// Called from RAK4631Board::begin(); fully brings up the W5100S (soft reset +
// activation) so it draws full operating current. Returns VERSIONR (0x51 = ok).
uint8_t w5100s_poe_init();

24
variants/rak4631/platformio.ini

@ -267,3 +267,27 @@ build_src_filter = ${rak4631.build_src_filter}
+<../examples/kiss_modem/>
lib_deps =
${rak4631.lib_deps}
; RAK10720 (RAK4631 + RAK13800/W5100S + RAK19018 PoE) variants.
; WITH_W5100S_POE adds: early W5100S RST release + activation (so the
; RAK19018/Silvertel converter latches on PoE with no battery), the
; no-battery boot-voltage bypass, and PoE-safe deferred Ethernet bring-up
; (DHCP with a bounded timeout + static-IP fallback, after the converter
; is solidly latched).
[env:RAK_4631_repeater_ethernet_poe]
extends = env:RAK_4631_repeater_ethernet
build_flags =
${env:RAK_4631_repeater_ethernet.build_flags}
-D WITH_W5100S_POE=1
[env:RAK_4631_room_server_ethernet_poe]
extends = env:RAK_4631_room_server_ethernet
build_flags =
${env:RAK_4631_room_server_ethernet.build_flags}
-D WITH_W5100S_POE=1
[env:RAK_4631_companion_radio_ethernet_poe]
extends = env:RAK_4631_companion_radio_ethernet
build_flags =
${env:RAK_4631_companion_radio_ethernet.build_flags}
-D WITH_W5100S_POE=1

Loading…
Cancel
Save