Files
meshtastic_firmware/src/mesh/eth/ethClient.cpp
T
Thomas GöttgensJonathan BennettBen Meadorscopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>caveman99
64fd61706d ThinkNode M7 (#8077)
* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* ThinkNode G3, ETH support WIP

* rename variant and add guard macros

* older G3 operational. M7 next.

* Split out G3 and M7 to different variants. Completely new PCB design. The G3 stays on 'PRIVATE_HW'

* Define button behaviour and use all of the device flash

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: caveman99 <25002+caveman99@users.noreply.github.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2026-05-11 11:46:13 -05:00

264 lines
8.5 KiB
C++

#include "mesh/eth/ethClient.h"
#include "NodeDB.h"
#include "RTC.h"
#include "concurrency/Periodic.h"
#include "configuration.h"
#include "main.h"
#include "mesh/api/ethServerAPI.h"
#include "target_specific.h"
#include <RAK13800_W5100S.h>
#include <SPI.h>
#if HAS_NETWORKING && !defined(USE_WS5500) && !defined(USE_CH390D)
#ifndef DISABLE_NTP
#include <NTPClient.h>
// NTP
EthernetUDP ntpUDP;
NTPClient timeClient(ntpUDP, config.network.ntp_server);
uint32_t ntp_renew = 0;
#endif
EthernetUDP syslogClient;
meshtastic::Syslog syslog(syslogClient);
bool ethStartupComplete = 0;
using namespace concurrency;
static Periodic *ethEvent;
static int32_t reconnectETH()
{
if (config.network.eth_enabled) {
// Detect W5100S chip reset by verifying the MAC address register.
// PoE power instability can brownout the W5100S while the MCU keeps running,
// causing all chip registers (MAC, IP, sockets) to revert to defaults.
uint8_t currentMac[6];
Ethernet.MACAddress(currentMac);
uint8_t expectedMac[6];
getMacAddr(expectedMac);
expectedMac[0] &= 0xfe;
if (memcmp(currentMac, expectedMac, 6) != 0) {
LOG_WARN("W5100S MAC mismatch (chip reset detected), reinitializing Ethernet");
syslog.disable();
#if !MESHTASTIC_EXCLUDE_SOCKETAPI
deInitApiServer();
#endif
#if HAS_UDP_MULTICAST
if (udpHandler) {
udpHandler->stop();
}
#endif
ethStartupComplete = false;
#ifndef DISABLE_NTP
ntp_renew = 0;
#endif
#ifdef PIN_ETHERNET_RESET
pinMode(PIN_ETHERNET_RESET, OUTPUT);
digitalWrite(PIN_ETHERNET_RESET, LOW);
delay(100);
digitalWrite(PIN_ETHERNET_RESET, HIGH);
delay(100);
#endif
#ifdef RAK11310
ETH_SPI_PORT.setSCK(PIN_SPI0_SCK);
ETH_SPI_PORT.setTX(PIN_SPI0_MOSI);
ETH_SPI_PORT.setRX(PIN_SPI0_MISO);
ETH_SPI_PORT.begin();
#endif
Ethernet.init(ETH_SPI_PORT, PIN_ETHERNET_SS);
int status = 0;
if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_DHCP) {
status = Ethernet.begin(expectedMac);
} else if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_STATIC) {
Ethernet.begin(expectedMac, config.network.ipv4_config.ip, config.network.ipv4_config.dns,
config.network.ipv4_config.gateway, config.network.ipv4_config.subnet);
status = 1;
}
if (status == 0) {
LOG_ERROR("Ethernet re-initialization failed, will retry");
return 5000;
}
LOG_INFO("Ethernet reinitialized - IP %u.%u.%u.%u", Ethernet.localIP()[0], Ethernet.localIP()[1],
Ethernet.localIP()[2], Ethernet.localIP()[3]);
}
Ethernet.maintain();
if (!ethStartupComplete) {
// Start web server
LOG_INFO("Start Ethernet network services");
#ifndef DISABLE_NTP
LOG_INFO("Start NTP time client");
timeClient.setUpdateInterval(60 * 60); // Update once an hour
#endif
if (config.network.rsyslog_server[0]) {
LOG_INFO("Start Syslog client");
// Defaults
int serverPort = 514;
const char *serverAddr = config.network.rsyslog_server;
String server = String(serverAddr);
int delimIndex = server.indexOf(':');
if (delimIndex > 0) {
String port = server.substring(delimIndex + 1, server.length());
server[delimIndex] = 0;
serverPort = port.toInt();
serverAddr = server.c_str();
}
syslog.server(serverAddr, serverPort);
syslog.deviceHostname(getDeviceName());
syslog.appName("Meshtastic");
syslog.defaultPriority(LOGLEVEL_USER);
syslog.enable();
}
#if !MESHTASTIC_EXCLUDE_SOCKETAPI
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
initApiServer();
}
#endif
#if HAS_UDP_MULTICAST
if (udpHandler && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {
udpHandler->start();
}
#endif
ethStartupComplete = true;
}
}
#ifndef DISABLE_NTP
if (isEthernetAvailable() && (ntp_renew < millis())) {
LOG_INFO("Update NTP time from %s", config.network.ntp_server);
if (timeClient.update()) {
LOG_DEBUG("NTP Request Success - Set RTCQualityNTP if needed");
struct timeval tv;
tv.tv_sec = timeClient.getEpochTime();
tv.tv_usec = 0;
perhapsSetRTC(RTCQualityNTP, &tv);
ntp_renew = millis() + 43200 * 1000; // success, refresh every 12 hours
} else {
LOG_ERROR("NTP Update failed");
ntp_renew = millis() + 300 * 1000; // failure, retry every 5 minutes
}
timeClient.end(); // W5100S: release UDP socket for other services
}
#endif
return 5000; // every 5 seconds
}
// Startup Ethernet
bool initEthernet()
{
if (config.network.eth_enabled) {
#ifdef PIN_ETH_POWER_EN
pinMode(PIN_ETH_POWER_EN, OUTPUT);
digitalWrite(PIN_ETH_POWER_EN, HIGH); // Power up.
delay(100);
#endif
#ifdef PIN_ETHERNET_RESET
pinMode(PIN_ETHERNET_RESET, OUTPUT);
digitalWrite(PIN_ETHERNET_RESET, LOW); // Reset Time.
delay(100);
digitalWrite(PIN_ETHERNET_RESET, HIGH); // Reset Time.
#endif
#ifdef RAK11310 // Initialize the SPI port
ETH_SPI_PORT.setSCK(PIN_SPI0_SCK);
ETH_SPI_PORT.setTX(PIN_SPI0_MOSI);
ETH_SPI_PORT.setRX(PIN_SPI0_MISO);
ETH_SPI_PORT.begin();
#endif
Ethernet.init(ETH_SPI_PORT, PIN_ETHERNET_SS);
uint8_t mac[6];
int status = 0;
// createSSLCert();
getMacAddr(mac); // FIXME use the BLE MAC for now...
mac[0] &= 0xfe; // Make sure this is not a multicast MAC
if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_DHCP) {
LOG_INFO("Start Ethernet DHCP");
status = Ethernet.begin(mac);
} else if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_STATIC) {
LOG_INFO("Start Ethernet Static");
Ethernet.begin(mac, config.network.ipv4_config.ip, config.network.ipv4_config.dns, config.network.ipv4_config.gateway,
config.network.ipv4_config.subnet);
status = 1;
} else {
LOG_INFO("Ethernet Disabled");
return false;
}
if (status == 0) {
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
LOG_ERROR("Ethernet shield was not found");
return false;
} else if (Ethernet.linkStatus() == LinkOFF) {
LOG_ERROR("Ethernet cable is not connected");
return false;
} else {
LOG_ERROR("Unknown Ethernet error");
return false;
}
} else {
LOG_INFO("Local IP %u.%u.%u.%u", Ethernet.localIP()[0], Ethernet.localIP()[1], Ethernet.localIP()[2],
Ethernet.localIP()[3]);
LOG_INFO("Subnet Mask %u.%u.%u.%u", Ethernet.subnetMask()[0], Ethernet.subnetMask()[1], Ethernet.subnetMask()[2],
Ethernet.subnetMask()[3]);
LOG_INFO("Gateway IP %u.%u.%u.%u", Ethernet.gatewayIP()[0], Ethernet.gatewayIP()[1], Ethernet.gatewayIP()[2],
Ethernet.gatewayIP()[3]);
LOG_INFO("DNS Server IP %u.%u.%u.%u", Ethernet.dnsServerIP()[0], Ethernet.dnsServerIP()[1], Ethernet.dnsServerIP()[2],
Ethernet.dnsServerIP()[3]);
}
ethEvent = new Periodic("ethConnect", reconnectETH);
return true;
} else {
LOG_INFO("Not using Ethernet");
return false;
}
}
bool isEthernetAvailable()
{
if (!config.network.eth_enabled) {
syslog.disable();
return false;
} else if (Ethernet.hardwareStatus() == EthernetNoHardware) {
syslog.disable();
return false;
} else if (Ethernet.linkStatus() == LinkOFF) {
syslog.disable();
return false;
} else {
return true;
}
}
#endif