diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index d48e223d..a88da48f 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -163,7 +163,7 @@ void setup() { the_mesh.startInterface(serial_interface); #elif defined(ETHERNET_ENABLED) Serial.print("Waiting for serial to connect...\n"); - time_t timeout = millis(); + unsigned long timeout = millis(); while (!Serial) { if ((millis() - timeout) < 5000) { delay(100); } else { break; } } diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 00fad175..b9fa1aa8 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -9,112 +9,8 @@ #endif #ifdef ETHERNET_ENABLED - #include - #include - #include - - #define PIN_SPI1_MISO (29) - #define PIN_SPI1_MOSI (30) - #define PIN_SPI1_SCK (3) - SPIClass ETHERNET_SPI_PORT(NRF_SPIM1, PIN_SPI1_MISO, PIN_SPI1_SCK, PIN_SPI1_MOSI); - - #define PIN_ETHERNET_POWER_EN WB_IO2 - #define PIN_ETHERNET_RESET 21 - #define PIN_ETHERNET_SS 26 - - #ifndef ETHERNET_TCP_PORT - #define ETHERNET_TCP_PORT 23 // telnet port for CLI access - #endif - - #define ETHERNET_RETRY_INTERVAL_MS 30000 - - static EthernetServer ethernet_server(ETHERNET_TCP_PORT); - static EthernetClient ethernet_client; - static volatile bool ethernet_running = false; - - // FreeRTOS task: handles hw init, DHCP, and retries in the background - static void ethernet_task(void* param) { - (void)param; - - // Hardware init - Serial.println("ETH: Initializing hardware"); - pinMode(PIN_ETHERNET_POWER_EN, OUTPUT); - digitalWrite(PIN_ETHERNET_POWER_EN, HIGH); - vTaskDelay(pdMS_TO_TICKS(100)); - - pinMode(PIN_ETHERNET_RESET, OUTPUT); - digitalWrite(PIN_ETHERNET_RESET, LOW); - vTaskDelay(pdMS_TO_TICKS(100)); - digitalWrite(PIN_ETHERNET_RESET, HIGH); - - ETHERNET_SPI_PORT.begin(); - Ethernet.init(ETHERNET_SPI_PORT, PIN_ETHERNET_SS); - - uint8_t mac[6]; - generateEthernetMac(mac); - Serial.printf("ETH: MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - - // Retry loop: keep trying until we get an IP - while (!ethernet_running) { - if (Ethernet.hardwareStatus() == EthernetNoHardware) { - Serial.println("ETH: Hardware not found, giving up"); - vTaskDelete(NULL); - return; - } - - if (Ethernet.linkStatus() == LinkOFF) { - vTaskDelay(pdMS_TO_TICKS(ETHERNET_RETRY_INTERVAL_MS)); - continue; - } - - Serial.println("ETH: Link detected, attempting DHCP..."); - if (Ethernet.begin(mac, 10000, 2000) == 0) { - Serial.println("ETH: DHCP failed, will retry"); - vTaskDelay(pdMS_TO_TICKS(ETHERNET_RETRY_INTERVAL_MS)); - continue; - } - - 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; - } - - // DHCP succeeded, task is done - vTaskDelete(NULL); - } - - static void ethernet_start_task() { - xTaskCreate(ethernet_task, "eth_init", 1024, NULL, 1, NULL); - } - - // 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.status") == 0) { - if (!ethernet_running) { - strcpy(reply, "ETH: not connected"); - } else { - IPAddress ip = Ethernet.localIP(); - sprintf(reply, "ETH: %u.%u.%u.%u:%d", ip[0], ip[1], ip[2], ip[3], ETHERNET_TCP_PORT); - } - return true; - } - return false; - } - - // Check for new TCP client connections, replacing any existing connection - static void ethernet_check_client() { - auto newClient = ethernet_server.available(); - if (newClient) { - if (ethernet_client) ethernet_client.stop(); - ethernet_client = newClient; - IPAddress ip = ethernet_client.remoteIP(); - Serial.printf("ETH: Client connected from %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]); - ethernet_client.println("MeshCore Repeater CLI"); - } - } + #define ETHERNET_CLI_BANNER "MeshCore Repeater CLI" + #include #endif StdRNG fast_rng; @@ -255,37 +151,15 @@ void loop() { } #ifdef ETHERNET_ENABLED - if (ethernet_running) { - ethernet_check_client(); - Ethernet.maintain(); - } - - if (ethernet_running && ethernet_client && ethernet_client.connected()) { - int elen = strlen(ethernet_command); - while (ethernet_client.available() && elen < (int)sizeof(ethernet_command)-1) { - char c = ethernet_client.read(); - if (c == '\n' && elen == 0) continue; // ignore leading LF (from CR+LF) - if (c == '\r' || c == '\n') { ethernet_command[elen++] = '\r'; break; } - ethernet_command[elen++] = c; - ethernet_command[elen] = 0; - } - if (elen == sizeof(ethernet_command)-1) { - ethernet_command[sizeof(ethernet_command)-1] = '\r'; - } - - if (elen > 0 && ethernet_command[elen - 1] == '\r') { - ethernet_command[elen - 1] = 0; - ethernet_client.println(); - char reply[160]; - reply[0] = 0; - if (!ethernet_handle_command(ethernet_command, reply)) { - the_mesh.handleCommand(0, ethernet_command, reply); - } - if (reply[0]) { - ethernet_client.print(" -> "); ethernet_client.println(reply); - } - ethernet_command[0] = 0; + ethernet_loop_maintain(); + if (ethernet_read_line(ethernet_command, sizeof(ethernet_command))) { + char reply[160]; + reply[0] = 0; + if (!ethernet_handle_command(ethernet_command, reply)) { + the_mesh.handleCommand(0, ethernet_command, reply); } + ethernet_send_reply(reply); + ethernet_command[0] = 0; } #endif diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index 435d5628..8439f500 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -4,105 +4,8 @@ #include "MyMesh.h" #ifdef ETHERNET_ENABLED - #include - #include - #include - - #define PIN_SPI1_MISO (29) - #define PIN_SPI1_MOSI (30) - #define PIN_SPI1_SCK (3) - SPIClass ETHERNET_SPI_PORT(NRF_SPIM1, PIN_SPI1_MISO, PIN_SPI1_SCK, PIN_SPI1_MOSI); - - #define PIN_ETHERNET_POWER_EN WB_IO2 - #define PIN_ETHERNET_RESET 21 - #define PIN_ETHERNET_SS 26 - - #ifndef ETHERNET_TCP_PORT - #define ETHERNET_TCP_PORT 23 - #endif - - #define ETHERNET_RETRY_INTERVAL_MS 30000 - - static EthernetServer ethernet_server(ETHERNET_TCP_PORT); - static EthernetClient ethernet_client; - static volatile bool ethernet_running = false; - - static void ethernet_task(void* param) { - (void)param; - - Serial.println("ETH: Initializing hardware"); - pinMode(PIN_ETHERNET_POWER_EN, OUTPUT); - digitalWrite(PIN_ETHERNET_POWER_EN, HIGH); - vTaskDelay(pdMS_TO_TICKS(100)); - - pinMode(PIN_ETHERNET_RESET, OUTPUT); - digitalWrite(PIN_ETHERNET_RESET, LOW); - vTaskDelay(pdMS_TO_TICKS(100)); - digitalWrite(PIN_ETHERNET_RESET, HIGH); - - ETHERNET_SPI_PORT.begin(); - Ethernet.init(ETHERNET_SPI_PORT, PIN_ETHERNET_SS); - - uint8_t mac[6]; - generateEthernetMac(mac); - Serial.printf("ETH: MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - - while (!ethernet_running) { - if (Ethernet.hardwareStatus() == EthernetNoHardware) { - Serial.println("ETH: Hardware not found, giving up"); - vTaskDelete(NULL); - return; - } - if (Ethernet.linkStatus() == LinkOFF) { - vTaskDelay(pdMS_TO_TICKS(ETHERNET_RETRY_INTERVAL_MS)); - continue; - } - - Serial.println("ETH: Link detected, attempting DHCP..."); - if (Ethernet.begin(mac, 10000, 2000) == 0) { - Serial.println("ETH: DHCP failed, will retry"); - vTaskDelay(pdMS_TO_TICKS(ETHERNET_RETRY_INTERVAL_MS)); - continue; - } - - 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; - } - vTaskDelete(NULL); - } - - static void ethernet_start_task() { - xTaskCreate(ethernet_task, "eth_init", 1024, NULL, 1, NULL); - } - - static bool ethernet_handle_command(const char* command, char* reply) { - if (strcmp(command, "eth.status") == 0) { - if (!ethernet_running) { - strcpy(reply, "ETH: not connected"); - } else { - IPAddress ip = Ethernet.localIP(); - sprintf(reply, "ETH: %u.%u.%u.%u:%d", ip[0], ip[1], ip[2], ip[3], ETHERNET_TCP_PORT); - } - return true; - } - return false; - } - - // Check for new TCP client connections, replacing any existing connection - static void ethernet_check_client() { - auto newClient = ethernet_server.available(); - if (newClient) { - if (ethernet_client) ethernet_client.stop(); - ethernet_client = newClient; - IPAddress ip = ethernet_client.remoteIP(); - Serial.printf("ETH: Client connected from %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]); - ethernet_client.println("MeshCore Room Server CLI"); - } - } + #define ETHERNET_CLI_BANNER "MeshCore Room Server CLI" + #include #endif #ifdef DISPLAY_CLASS @@ -227,37 +130,15 @@ void loop() { } #ifdef ETHERNET_ENABLED - if (ethernet_running) { - ethernet_check_client(); - Ethernet.maintain(); - } - - if (ethernet_running && ethernet_client && ethernet_client.connected()) { - int elen = strlen(ethernet_command); - while (ethernet_client.available() && elen < (int)sizeof(ethernet_command)-1) { - char c = ethernet_client.read(); - if (c == '\n' && elen == 0) continue; // ignore leading LF (from CR+LF) - if (c == '\r' || c == '\n') { ethernet_command[elen++] = '\r'; break; } - ethernet_command[elen++] = c; - ethernet_command[elen] = 0; - } - if (elen == sizeof(ethernet_command)-1) { - ethernet_command[sizeof(ethernet_command)-1] = '\r'; - } - - if (elen > 0 && ethernet_command[elen - 1] == '\r') { - ethernet_command[elen - 1] = 0; - ethernet_client.println(); - char reply[160]; - reply[0] = 0; - if (!ethernet_handle_command(ethernet_command, reply)) { - the_mesh.handleCommand(0, ethernet_command, reply); - } - if (reply[0]) { - ethernet_client.print(" -> "); ethernet_client.println(reply); - } - ethernet_command[0] = 0; + ethernet_loop_maintain(); + if (ethernet_read_line(ethernet_command, sizeof(ethernet_command))) { + char reply[160]; + reply[0] = 0; + if (!ethernet_handle_command(ethernet_command, reply)) { + the_mesh.handleCommand(0, ethernet_command, reply); } + ethernet_send_reply(reply); + ethernet_command[0] = 0; } #endif diff --git a/src/helpers/nrf52/EthernetCLI.h b/src/helpers/nrf52/EthernetCLI.h new file mode 100644 index 00000000..6a59bda6 --- /dev/null +++ b/src/helpers/nrf52/EthernetCLI.h @@ -0,0 +1,156 @@ +#pragma once + +#ifdef ETHERNET_ENABLED + +#include +#include +#include +#include + +#define PIN_SPI1_MISO (29) +#define PIN_SPI1_MOSI (30) +#define PIN_SPI1_SCK (3) + +static SPIClass ETHERNET_SPI_PORT(NRF_SPIM1, PIN_SPI1_MISO, PIN_SPI1_SCK, PIN_SPI1_MOSI); + +#define PIN_ETHERNET_POWER_EN WB_IO2 +#define PIN_ETHERNET_RESET 21 +#define PIN_ETHERNET_SS 26 + +#ifndef ETHERNET_TCP_PORT + #define ETHERNET_TCP_PORT 23 // telnet port for CLI access +#endif + +#ifndef ETHERNET_CLI_BANNER + #define ETHERNET_CLI_BANNER "MeshCore CLI" +#endif + +#define ETHERNET_RETRY_INTERVAL_MS 30000 + +static EthernetServer ethernet_server(ETHERNET_TCP_PORT); +static EthernetClient ethernet_client; +static volatile bool ethernet_running = false; + +// FreeRTOS task: handles hw init, DHCP, and retries in the background +static void ethernet_task(void* param) { + (void)param; + + Serial.println("ETH: Initializing hardware"); + pinMode(PIN_ETHERNET_POWER_EN, OUTPUT); + digitalWrite(PIN_ETHERNET_POWER_EN, HIGH); + vTaskDelay(pdMS_TO_TICKS(100)); + + pinMode(PIN_ETHERNET_RESET, OUTPUT); + digitalWrite(PIN_ETHERNET_RESET, LOW); + vTaskDelay(pdMS_TO_TICKS(100)); + digitalWrite(PIN_ETHERNET_RESET, HIGH); + + ETHERNET_SPI_PORT.begin(); + Ethernet.init(ETHERNET_SPI_PORT, PIN_ETHERNET_SS); + + uint8_t mac[6]; + generateEthernetMac(mac); + Serial.printf("ETH: MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + // Retry loop: keep trying until we get an IP + while (!ethernet_running) { + Serial.println("ETH: Attempting DHCP..."); + if (Ethernet.begin(mac, 10000, 2000) == 0) { + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("ETH: Hardware not found, giving up"); + vTaskDelete(NULL); + return; + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("ETH: Cable not connected, will retry"); + } else { + Serial.println("ETH: DHCP failed, will retry"); + } + vTaskDelay(pdMS_TO_TICKS(ETHERNET_RETRY_INTERVAL_MS)); + continue; + } + + 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; + } + + // DHCP succeeded, task is done + vTaskDelete(NULL); +} + +static void ethernet_start_task() { + xTaskCreate(ethernet_task, "eth_init", 1024, NULL, 1, NULL); +} + +// 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.status") == 0) { + if (!ethernet_running) { + strcpy(reply, "ETH: not connected"); + } else { + IPAddress ip = Ethernet.localIP(); + sprintf(reply, "ETH: %u.%u.%u.%u:%d", ip[0], ip[1], ip[2], ip[3], ETHERNET_TCP_PORT); + } + return true; + } + return false; +} + +// Check for new TCP client connections, replacing any existing connection +static void ethernet_check_client() { + auto newClient = ethernet_server.available(); + if (newClient) { + if (ethernet_client) ethernet_client.stop(); + ethernet_client = newClient; + IPAddress ip = ethernet_client.remoteIP(); + Serial.printf("ETH: Client connected from %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]); + ethernet_client.println(ETHERNET_CLI_BANNER); + } +} + +// Call from loop() to maintain DHCP and check for new clients +static void ethernet_loop_maintain() { + if (ethernet_running) { + ethernet_check_client(); + Ethernet.maintain(); + } +} + +// Read a line from the Ethernet client into the command buffer. +// Returns true when a complete line is ready to process (command is null-terminated). +// The caller should process the command and then reset ethernet_command[0] = 0. +static bool ethernet_read_line(char* ethernet_command, size_t buf_size) { + if (!ethernet_running || !ethernet_client || !ethernet_client.connected()) return false; + + int elen = strlen(ethernet_command); + while (ethernet_client.available() && elen < (int)buf_size - 1) { + char c = ethernet_client.read(); + if (c == '\n' && elen == 0) continue; // ignore leading LF (from CR+LF) + if (c == '\r' || c == '\n') { ethernet_command[elen++] = '\r'; break; } + ethernet_command[elen++] = c; + ethernet_command[elen] = 0; + } + if (elen == (int)buf_size - 1) { + ethernet_command[buf_size - 1] = '\r'; + } + + if (elen > 0 && ethernet_command[elen - 1] == '\r') { + ethernet_command[elen - 1] = 0; + ethernet_client.println(); + return true; + } + return false; +} + +// Send a reply to the Ethernet client +static void ethernet_send_reply(const char* reply) { + if (reply[0]) { + ethernet_client.print(" -> "); ethernet_client.println(reply); + } +} + +#endif // ETHERNET_ENABLED