Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,20 @@ web.tar
.platformio
.local
.cache
.history

# macOS
.DS_Store
.DS_Store?
._*
.AppleDouble
.LSOverride
.Spotlight-V100
.Trashes
.fseventsd
.AppleDB
.AppleDesktop

Thumbs.db
.autotools
.built
Expand Down
16 changes: 9 additions & 7 deletions src/DebugConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,18 @@ extern "C" void logLegacy(const char *level, const char *fmt, ...);
// Default Bluetooth PIN
#define defaultBLEPin 123456

#if HAS_ETHERNET && defined(USE_CH390D)
#if HAS_ETHERNET
#if defined(USE_CH390D)
#include <ESP32_CH390.h>
#elif HAS_ETHERNET && !defined(USE_WS5500)
#include <RAK13800_W5100S.h>
#endif // HAS_ETHERNET

#if HAS_ETHERNET && defined(USE_WS5500)
#elif defined(USE_WS5500)
#include <ETHClass2.h>
#define ETH ETH2
#endif // HAS_ETHERNET
#elif defined(ESP32) && defined(ETH_PHY_TYPE)
#include <ETH.h>
#else
#include <RAK13800_W5100S.h>
#endif
#endif

#if HAS_WIFI
#include <WiFi.h>
Expand Down
4 changes: 3 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,17 @@ NimbleBluetooth *nimbleBluetooth = nullptr;
NRF52Bluetooth *nrf52Bluetooth = nullptr;
#endif

#if HAS_WIFI || defined(USE_WS5500) || defined(USE_CH390D)
#if HAS_WIFI || defined(USE_WS5500) || defined(USE_CH390D) || defined(ETH_PHY_TYPE)
#include "mesh/api/WiFiServerAPI.h"
#include "mesh/wifi/WiFiAPClient.h"
#endif

#if HAS_ETHERNET && !defined(USE_WS5500) && !defined(USE_CH390D)
#include "mesh/api/ethServerAPI.h"
#if !defined(ETH_PHY_TYPE)
#include "mesh/eth/ethClient.h"
#endif
#endif

#if !MESHTASTIC_EXCLUDE_MQTT
#include "mqtt/MQTT.h"
Expand Down
8 changes: 5 additions & 3 deletions src/mesh/InterfacesTemplates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@ template class SX126xInterface<STM32WLx>;

#if HAS_ETHERNET && !defined(USE_WS5500) && !defined(USE_CH390D)
#include "api/ethServerAPI.h"
template class ServerAPI<EthernetClient>;
template class APIServerPort<ethServerAPI, EthernetServer>;
#if !(defined(ESP32) && HAS_WIFI)
template class ServerAPI<MeshEthernetClient>;
#endif
template class APIServerPort<ethServerAPI, MeshEthernetServer>;
#endif

#if HAS_WIFI
#include "api/WiFiServerAPI.h"
template class ServerAPI<WiFiClient>;
template class APIServerPort<WiFiServerAPI, WiFiServer>;
#endif
#endif
49 changes: 37 additions & 12 deletions src/mesh/api/ServerAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@
#include "Throttle.h"
#include "configuration.h"
#include <Arduino.h>
#include <algorithm>

static constexpr uint32_t TCP_IDLE_TIMEOUT_MS = 15 * 60 * 1000UL;
#ifndef MESHTASTIC_TCP_API_IDLE_TIMEOUT_MS
#define MESHTASTIC_TCP_API_IDLE_TIMEOUT_MS (15 * 60 * 1000UL)
#endif

#ifndef MESHTASTIC_TCP_API_MAX_CLIENTS
#define MESHTASTIC_TCP_API_MAX_CLIENTS 1
#endif

static constexpr uint32_t TCP_IDLE_TIMEOUT_MS = MESHTASTIC_TCP_API_IDLE_TIMEOUT_MS;
static constexpr size_t TCP_API_MAX_CLIENTS = MESHTASTIC_TCP_API_MAX_CLIENTS;

template <typename T>
ServerAPI<T>::ServerAPI(T &_client) : StreamAPI(&client), concurrency::OSThread("ServerAPI"), client(_client)
Expand Down Expand Up @@ -55,9 +65,13 @@ template <class T, class U> void APIServerPort<T, U>::init()

template <class T, class U> int32_t APIServerPort<T, U>::runOnce()
{
// Clean up previous connection if its client already disconnected
if (openAPI && !openAPI->checkIsConnected()) {
openAPI.reset();
// Clean up connections whose clients already disconnected.
for (auto api = openAPIs.begin(); api != openAPIs.end();) {
if (!(*api)->checkIsConnected()) {
api = openAPIs.erase(api);
} else {
++api;
}
}

#ifdef ARCH_ESP32
Expand All @@ -72,27 +86,38 @@ template <class T, class U> int32_t APIServerPort<T, U>::runOnce()
auto client = U::available();
#endif
if (client) {
// Close any previous connection (see FIXME in header file)
if (openAPI) {
if (openAPIs.size() >= TCP_API_MAX_CLIENTS) {
#if MESHTASTIC_TCP_API_MAX_CLIENTS <= 1
// Preserve historical single-client behavior unless a variant explicitly opts into a client pool.
#if RAK_4631
// RAK13800 Ethernet requests periodically take more time
// This backoff addresses most cases keeping max wait < 1s
// Reconnections are delayed by full wait time
// RAK13800 Ethernet requests periodically take more time.
// This backoff addresses most cases keeping max wait < 1s.
// Reconnections are delayed by full wait time.
if (waitTime < 400) {
waitTime *= 2;
LOG_INFO("Previous TCP connection still open, try again in %dms", waitTime);
return waitTime;
}
#endif
LOG_INFO("Force close previous TCP connection");
openAPI.reset();
openAPIs.clear();
#else
auto oldest =
std::min_element(openAPIs.begin(), openAPIs.end(), [](const std::unique_ptr<T> &a, const std::unique_ptr<T> &b) {
return a->getLastContactMsec() < b->getLastContactMsec();
});
if (oldest != openAPIs.end()) {
LOG_WARN("TCP API client limit reached (%u), closing oldest connection", (unsigned)TCP_API_MAX_CLIENTS);
openAPIs.erase(oldest);
}
#endif
}

openAPI.reset(new T(client));
openAPIs.emplace_back(new T(client));
}

#if RAK_4631
waitTime = 100;
#endif
return 100; // only check occasionally for incoming connections
}
}
14 changes: 8 additions & 6 deletions src/mesh/api/ServerAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "StreamAPI.h"
#include <memory>
#include <vector>

#define SERVER_API_DEFAULT_PORT 4403

Expand All @@ -25,6 +26,8 @@ template <class T> class ServerAPI : public StreamAPI, private concurrency::OSTh
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override;

uint32_t getLastContactMsec() const { return lastContactMsec; }

protected:
/// We override this method to prevent publishing EVENT_SERIAL_CONNECTED/DISCONNECTED for wifi links (we want the board to
/// stay in the POWERED state to prevent disabling wifi)
Expand All @@ -38,12 +41,11 @@ template <class T> class ServerAPI : public StreamAPI, private concurrency::OSTh
*/
template <class T, class U> class APIServerPort : public U, private concurrency::OSThread
{
/** The currently open port
*
* FIXME: We currently only allow one open TCP connection at a time, because we depend on the loop() call in this class to
* delegate to the worker. Once coroutines are implemented we can relax this restriction.
*/
std::unique_ptr<T> openAPI;
/// Active TCP API sessions for this listening port.
///
/// The listener owns session lifetimes only: each ServerAPI instance is also an OSThread and services its own client from
/// the main controller. Keep this pool bounded because every active TCP API session consumes memory and scheduler time.
std::vector<std::unique_ptr<T>> openAPIs;
#if defined(RAK_4631) || defined(RAK11310)
// Track wait time for RAK13800 Ethernet requests
int32_t waitTime = 100;
Expand Down
4 changes: 2 additions & 2 deletions src/mesh/api/WiFiServerAPI.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "configuration.h"
#include <Arduino.h>

#if HAS_WIFI
#if HAS_WIFI || defined(USE_WS5500) || defined(USE_CH390D)
#include "WiFiServerAPI.h"

static WiFiServerPort *apiPort;
Expand Down Expand Up @@ -30,4 +30,4 @@ WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : ServerAPI(_client)
}

WiFiServerPort::WiFiServerPort(int port) : APIServerPort(port) {}
#endif
#endif
6 changes: 5 additions & 1 deletion src/mesh/api/WiFiServerAPI.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#pragma once

#include "configuration.h"

#if HAS_WIFI || defined(USE_WS5500) || defined(USE_CH390D)
#include "ServerAPI.h"
#include <WiFi.h>

Expand Down Expand Up @@ -28,4 +31,5 @@ class WiFiServerPort : public APIServerPort<WiFiServerAPI, WiFiServer>
};

void initApiServer(int port = SERVER_API_DEFAULT_PORT);
void deInitApiServer();
void deInitApiServer();
#endif
31 changes: 21 additions & 10 deletions src/mesh/api/ethServerAPI.cpp
Original file line number Diff line number Diff line change
@@ -1,37 +1,48 @@
#include "configuration.h"
#include <Arduino.h>

#if HAS_ETHERNET && !defined(USE_WS5500) && !defined(USE_CH390D)
#include <Arduino.h>

#include "ethServerAPI.h"

static ethServerPort *apiPort;
#if HAS_ETHERNET && !defined(USE_WS5500) && !defined(USE_CH390D)

void initApiServer(int port)
static ethServerPort *apiPort = nullptr;

void initEthApiServer(int port)
{
// Start API server on port 4403
if (!apiPort) {
apiPort = new ethServerPort(port);
LOG_INFO("API server listening on TCP port %d", port);
LOG_INFO("Ethernet API server listening on TCP port %d", port);
apiPort->init();
}
}

void deInitApiServer()
void deInitEthApiServer()
{
if (apiPort) {
LOG_INFO("Deinit API server");
LOG_INFO("Deinit Ethernet API server");
delete apiPort;
apiPort = nullptr;
}
}

ethServerAPI::ethServerAPI(EthernetClient &_client) : ServerAPI(_client)
#if !HAS_WIFI
void initApiServer(int port)
{
initEthApiServer(port);
}
void deInitApiServer()
{
deInitEthApiServer();
}
#endif

ethServerAPI::ethServerAPI(MeshEthernetClient &_client) : ServerAPI(_client)
{
LOG_INFO("Incoming ethernet connection");
api_type = TYPE_ETH;
}

ethServerPort::ethServerPort(int port) : APIServerPort(port) {}

#endif
#endif
25 changes: 21 additions & 4 deletions src/mesh/api/ethServerAPI.h
Original file line number Diff line number Diff line change
@@ -1,28 +1,45 @@
#pragma once

#include "configuration.h"

#include "ServerAPI.h"
#if !defined(USE_WS5500) && !defined(USE_CH390D)

#if HAS_ETHERNET && !defined(USE_WS5500) && !defined(USE_CH390D)
#if defined(ESP32) && defined(ETH_PHY_TYPE)
#include <ETH.h>
#include <WiFi.h>
typedef WiFiClient MeshEthernetClient;
typedef WiFiServer MeshEthernetServer;
#else
#include <RAK13800_W5100S.h>
typedef EthernetClient MeshEthernetClient;
typedef EthernetServer MeshEthernetServer;
#endif

/**
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs
* (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs).
*/
class ethServerAPI : public ServerAPI<EthernetClient>
class ethServerAPI : public ServerAPI<MeshEthernetClient>
{
public:
explicit ethServerAPI(EthernetClient &_client);
explicit ethServerAPI(MeshEthernetClient &_client);
};

/**
* Listens for incoming connections and does accepts and creates instances of EthernetServerAPI as needed
*/
class ethServerPort : public APIServerPort<ethServerAPI, EthernetServer>
class ethServerPort : public APIServerPort<ethServerAPI, MeshEthernetServer>
{
public:
explicit ethServerPort(int port);
};

void initEthApiServer(int port = SERVER_API_DEFAULT_PORT);
void deInitEthApiServer();

#if !HAS_WIFI
void initApiServer(int port = SERVER_API_DEFAULT_PORT);
void deInitApiServer();
#endif
#endif
2 changes: 1 addition & 1 deletion src/mesh/eth/ethClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ static int32_t reconnectETH()

#if !MESHTASTIC_EXCLUDE_SOCKETAPI
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
initApiServer();
initApiServer(SERVER_API_DEFAULT_PORT);
}
#endif
#if HAS_UDP_MULTICAST
Expand Down
Loading