Skip to content

Support for RAK ethernet module#1983

Open
rgregg wants to merge 7 commits intomeshcore-dev:devfrom
rgregg:rak-ethernet
Open

Support for RAK ethernet module#1983
rgregg wants to merge 7 commits intomeshcore-dev:devfrom
rgregg:rak-ethernet

Conversation

@rgregg
Copy link

@rgregg rgregg commented Mar 9, 2026

This pull request adds Ethernet support to the companion_radio, simple_repeater, and simple_room_server examples for nRF52-based devices, enabling TCP CLI access and mesh command handling over Ethernet. It also updates the build workflow to include new Ethernet-enabled targets. The main changes are grouped below by theme.

Everything is compile-time gated by the ETH_ENABLE flag which is only enabled for a new environment profile for RAK firmware + Ethernet support.

Ethernet support for examples

  • Added Ethernet initialization, hardware setup, and DHCP management to examples/simple_repeater/main.cpp and examples/simple_room_server/main.cpp, including FreeRTOS task for background handling and unique MAC address generation. [1] [2]
  • Implemented TCP server and client handling for CLI access via Ethernet, including command parsing and reply formatting for both repeater and room server examples. [1] [2] [3] [4]
  • Added command handling logic for Ethernet CLI, including support for the "eth" command to report connection status and IP address. [1] [2] [3] [4]

Integration and initialization

  • Updated setup() and loop() functions in all examples to start Ethernet tasks, maintain connections, and handle mesh commands from both serial and Ethernet interfaces. [1] [2] [3] [4] [5] [6] [7] [8] [9]
  • Modified examples/companion_radio/main.cpp to support conditional inclusion of Ethernet interface and initialization, including debug output and error handling. [1] [2] [3] [4]

Build workflow updates

  • Added new Ethernet-enabled build targets for nRF52 devices in .github/workflows/pr-build-check.yml to ensure CI coverage for the new features.

These changes collectively enable robust Ethernet-based CLI and mesh communication for nRF52 devices, improving flexibility and connectivity options.

@rgregg rgregg marked this pull request as ready for review March 9, 2026 21:57
Copilot AI review requested due to automatic review settings March 9, 2026 21:57
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds compile-time-gated Ethernet (RAK13800/W5100S) support to nRF52 example apps to enable TCP-based CLI access and mesh command handling, and extends CI to build the new Ethernet-enabled targets.

Changes:

  • Added Ethernet initialization/DHCP + TCP CLI handling to simple_repeater and simple_room_server (behind ETH_ENABLED).
  • Added an nRF52 SerialEthernetInterface and wired it into companion_radio when ETH_ENABLED is set.
  • Introduced new RAK4631 PlatformIO environments + CI matrix entries for Ethernet-enabled builds.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
variants/rak4631/platformio.ini Adds new RAK4631 Ethernet-enabled PlatformIO envs and dependencies.
variants/rak4631/RAK4631Board.cpp Attempts to hook Ethernet init into board bring-up (macro-gated).
src/helpers/sensors/EnvironmentSensorManager.cpp Avoids treating the Ethernet power IO as a GPS-detect pin when Ethernet is enabled on RAK boards.
src/helpers/nrf52/SerialEthernetInterface.h Introduces Ethernet-backed serial interface abstraction for nRF52.
src/helpers/nrf52/SerialEthernetInterface.cpp Implements W5100S init, TCP server/client framing, and DHCP maintenance.
examples/simple_room_server/main.cpp Adds ETH task + TCP CLI parsing/command handling for room server example.
examples/simple_repeater/main.cpp Adds ETH task + TCP CLI parsing/command handling for repeater example.
examples/companion_radio/main.cpp Adds conditional Ethernet serial interface + ETH maintenance in main loop.
.github/workflows/pr-build-check.yml Adds CI builds for the new Ethernet-enabled RAK4631 targets.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rgregg rgregg force-pushed the rak-ethernet branch 2 times, most recently from 3c57a33 to 12a4f4b Compare March 9, 2026 22:54
@rgregg rgregg changed the base branch from main to dev March 11, 2026 02:36
rgregg and others added 2 commits March 10, 2026 20:43
…mpanion

Add W5100S Ethernet adapter support for RAK4631-based firmware, enabling
TCP CLI access on port 23 as an alternative to BLE/Serial connections.

- New SerialEthernetInterface for nRF52 with DHCP, reconnection handling,
  and shared WB_IO2 power pin management with GPS module
- Ethernet build targets for repeater, room server, and companion firmware
- Prevent GPS from toggling WB_IO2 when Ethernet module is active
- CI build check for all three ETH firmware targets

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add #pragma once to SerialEthernetInterface.h
- Rename TCP_PORT to ETH_TCP_PORT with #ifndef guard
- Fix typos: "initalizing" → "initializing"
- Fix #elif without condition → #else for STM32 block
- Replace infinite loop on ETH init failure with halt()
- Remove heartbeat Serial.print(".") output
- Remove dead beginETH() call (ETH_ENABLED, not RAK_ETH_ENABLE)
- Comment out MESH_DEBUG and ETH_DEBUG_LOGGING build flags

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rgregg
Copy link
Author

rgregg commented Mar 11, 2026

Updated to address all the issues in the Copilot feedback.

Copy link
Member

@liamcottle liamcottle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Howdy! Thanks for the PR. I've added some comments :)

@rgregg
Copy link
Author

rgregg commented Mar 11, 2026

Thanks @liamcottle for the review and the feedback - I've updated the PR to reflect your feedback, I appreciate your time!

@rgregg rgregg requested a review from liamcottle March 11, 2026 05:44
Copy link
Member

@liamcottle liamcottle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks for the adjustments. I've gone through again and have some extra comments. Once these are sorted, would be good if you can test it's all working before I ask Scott to do a code review.


### Ethernet (when Ethernet support is compiled in)

Ethernet support is available on RAK4631 boards with a RAK13800 (W5100S) Ethernet module. Use the `_eth` firmware variants (e.g. `RAK_4631_repeater_eth`) to enable this feature.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missed this one ;) _eth -> _ethernet.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed - also updated the port number in the example output and notes while I was in there.

docs/faq.md Outdated

**Firmware:**
Flash one of the Ethernet-enabled firmware variants:
- `RAK_4631_repeater_eth` - Repeater with Ethernet CLI access
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs update for new _ethernet suffix

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed - also corrected the port numbers: port 23 for repeater/room server CLI, port 5000 for companion radio.

Serial.println("Initializing Ethernet adapter...");
if (!serial_interface.begin()) {
Serial.println("ETH: Init failed, halting");
halt();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if the firmware should still run as normal if ethernet fails to come up? That way remote management over LoRa would still work, and it could be rebooted remotely over the mesh?

Otherwise if firmware was to shutdown due to low voltage, and ethernet failed to come up on reboot, maybe due to still having low power, the unit would be bricked until physically rebooted.

Not sure if this would cause issues reading/writing commands to non initialised ethernet driver...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point - I think we can guard for that issue. I'll see how difficult that would be.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Changed to log the failure and continue without the Ethernet interface - the mesh runs normally over LoRa so the unit can be recovered remotely.


// Format ethernet status into reply buffer. Returns true if command was handled.
static bool ethernet_handle_command(const char* command, char* reply) {
if (strcmp(command, "eth") != 0) return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we switch the logic, so instead of returning false for a non match for the only command, wrap the status response inside an if block, and return false from ethernet_handle_command by default to indicate it didn't handle it. More so for when you add new commands later, this doesn't need a refactor. e.g:

static bool ethernet_handle_command(const char* command, char* reply) {
  if (strcmp(command, "eth.status") == 0) {
    if (!ethernet_running) {
      strcpy(reply, "not connected");
    } else {
      IPAddress ip = Ethernet.localIP();
      sprintf(reply, "IP: %u.%u.%u.%u:%d", ip[0], ip[1], ip[2], ip[3], ETHERNET_TCP_PORT);
    }
    return true;
  }
  
  // not handled
  return false;
}

Maybe we could rename it to eth.status or eth.ip. I'll leave that one up to you.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored as suggested and went with eth.status.


// Check for new TCP client connections
static void ethernet_check_client() {
if (ethernet_client && ethernet_client.connected()) return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this check would prevent new clients from being able to connect until the existing client disconnects. The WiFi firmware allows new connections to kick off old connections. We should allow the same here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed - removed the early return guard so server.available() is always called. New connections now replace existing ones.

}

static void ethernet_check_client() {
if (ethernet_client && ethernet_client.connected()) return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comments as repeater feedback about return preventing new clients connecting

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

the_mesh.handleCommand(0, command, reply); // NOTE: there is no sender_timestamp via serial!
#endif
if (reply[0]) {
Serial.print(" -> "); Serial.println(reply);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was originally wondering if the reply is meant to be going back out of the ethernet_interface instead of the Serial, but noted further down the reply is sent out as expected. I guess this just means the reply is sent out on main serial and on ethernet. Not sure if that's an issue.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The channels are already separate - serial commands reply only to Serial, ethernet commands reply only to ethernet_client. No change needed.

if (reply[0]) {
ethernet_client.print(" -> "); ethernet_client.println(reply);
}
ethernet_client.print("> ");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as noted on repeater firmware

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed - dropped the prompt.


#include <Arduino.h>

static inline void generateDeviceMac(uint8_t mac[6]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could maybe rename it so it's clearer? generateEthernetMac? Haven't looked to see what NRF_FICR->DEVICEID does, but I'm assuming we are generating an ethernet mac address, from the existing hardware mac address or device id.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to generateEthernetMac. It uses NRF_FICR->DEVICEID (the chip's unique hardware ID) to derive a stable MAC address, with the locally-administered bit set so it's valid for private use without conflicting with real hardware MACs.

size_t SerialEthernetInterface::checkRecvFrame(uint8_t dest[]) {
// check if new client connected
if (client && client.connected()) {
// Avoid polling for new clients while an active connection exists.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should allow new clients to connect and kick off the old client

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed - removed the guard that skipped server.available() while a connection was active. New connections now replace existing ones.

@JDat
Copy link

JDat commented Mar 11, 2026

Can this be made to work with W5500-EVB-PICO (Wiznet5500 + RPi Pi Pico RP2040) board because RAK is no the only toy with Ethernet.

@neopiccolorat
Copy link

This PR comes at the right time!
I have this RAK13800 and I'm currently using with Meshtastic, but I wanted to switch this node to Meshcore and still being able to connect to it by its ip.

@rgregg
Copy link
Author

rgregg commented Mar 11, 2026

Can this be made to work with W5500-EVB-PICO (Wiznet5500 + RPi Pi Pico RP2040) board because RAK is no the only toy with Ethernet.

Should be possible to extend. I don't have that hardware to test/validate with though.

- Rename eth command to eth.status for consistency with other commands
- Rename generateDeviceMac to generateEthernetMac for clarity
- Refactor ethernet_handle_command to return false by default
- Allow new TCP clients to replace existing connections (repeater, room server, SerialEthernetInterface)
- Boot companion radio without Ethernet on init failure (LoRa-only recovery mode)
- Remove > prompt from ethernet CLI for consistency with serial interface
- Fix variable redeclaration compile error in SerialEthernetInterface when ETHERNET_STATIC_IP is defined
- Fix TCP socket leak when duplicate client detection fires
- Remove dead recv_queue and adv_restart_time members from SerialEthernetInterface
- Fix port numbers in docs (port 23 for repeater/room server CLI, port 5000 for companion radio)
- Clarify eth.status command is only available in repeater and room server firmware

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@JDat
Copy link

JDat commented Mar 12, 2026

Can this be made to work with W5500-EVB-PICO (Wiznet5500 + RPi Pi Pico RP2040) board because RAK is no the only toy with Ethernet.

Should be possible to extend. I don't have that hardware to test/validate with though.

I have this board and I am OK to solder/wire LoRA module with board, and do some tests.

…ate CLI code

The Ethernet retry loop in repeater and room server checked
hardwareStatus() and linkStatus() before calling Ethernet.begin(),
which always returned EthernetNoHardware since hardware detection
only happens during begin(). Extract shared Ethernet CLI code into
EthernetCLI.h to prevent future divergence. Also fix time_t type
mismatch in companion radio Ethernet init.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rgregg
Copy link
Author

rgregg commented Mar 13, 2026

All three Ethernet-enabled firmwares have been tested on RAK4631 hardware with the RAK13800 W5100S Ethernet module and are working as expected:

  • RAK_4631_repeater_ethernet — DHCP + CLI over telnet (port 23) ✅
  • RAK_4631_room_server_ethernet — DHCP + CLI over telnet (port 23) ✅
  • RAK_4631_companion_radio_ethernet — DHCP + companion protocol (port 5000) ✅

Resolve conflicts: keep both Ethernet CLI and SenseCAP power-off
button code in repeater, keep both Ethernet docs and power management
CLI docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rgregg
Copy link
Author

rgregg commented Mar 13, 2026

@liamcottle - let me know if there is anything else, otherwise I think this is ready to merge.

@JDat
Copy link

JDat commented Mar 14, 2026

For what reason Ethernet header sit inside nRF52 helper directory? What if Ethernet need to be added to ESP32 and RP2040 microcontrollers. What a crazy platform dependent b**t! If you want Ethernet support, make it platform independent instead or only board laying on your table!

@rgregg
Copy link
Author

rgregg commented Mar 14, 2026

For what reason Ethernet header sit inside nRF52 helper directory? What if Ethernet need to be added to ESP32 and RP2040 microcontrollers. What a crazy platform dependent b**t! If you want Ethernet support, make it platform independent instead or only board laying on your table!

This follows the existing pattern of SerialBLEInterface which lives in the esp32 and nrf52 folders. Firmware development is often very hardware specific - if it turns out we can reuse the same code, it'll be easy enough to refactor it accordingly when someone with the hardware can verify it works. There's no need to be rude about it.

@JDat
Copy link

JDat commented Mar 14, 2026

For what reason Ethernet header sit inside nRF52 helper directory? What if Ethernet need to be added to ESP32 and RP2040 microcontrollers. What a crazy platform dependent b**t! If you want Ethernet support, make it platform independent instead or only board laying on your table!

This follows the existing pattern of SerialBLEInterface which lives in the esp32 and nrf52 folders. Firmware development is often very hardware specific - if it turns out we can reuse the same code, it'll be easy enough to refactor it accordingly when someone with the hardware can verify it works. There's no need to be rude about it.

Why not to refactor things correctly as soon as they are developed? Is this future of vibe coding or what?

@rgregg rgregg requested a review from liamcottle March 14, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants