mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
Merge 6ba0d20b5e into dee3e26ac0
This commit is contained in:
commit
aaf31452eb
23 changed files with 1591 additions and 31 deletions
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"pioarduino.pioarduino-ide",
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
|
|
|
|||
51
boards/t_eth_elite.json
Normal file
51
boards/t_eth_elite.json
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"build": {
|
||||
"arduino":{
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"partitions": "default.csv",
|
||||
"memory_type": "qio_qspi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DARDUINO_USB_MODE=1",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [
|
||||
[
|
||||
"0x303A",
|
||||
"0x1001"
|
||||
]
|
||||
],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "esp32s3"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": [
|
||||
"esp-builtin"
|
||||
],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "LilyGo T-ETH-Elite (16MB Flash 8MB PSRAM)",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 8388608,
|
||||
"maximum_size": 16777216,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://lilygo.cc/products/t-eth-elite-1",
|
||||
"vendor": "LilyGo"
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ This document provides an overview of CLI commands that can be sent to MeshCore
|
|||
- [GPS](#gps-when-gps-support-is-compiled-in)
|
||||
- [Sensors](#sensors-when-sensor-support-is-compiled-in)
|
||||
- [Bridge](#bridge-when-bridge-support-is-compiled-in)
|
||||
- [Ethernet](#ethernet-when-use_ethernet-is-compiled-in)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -927,7 +928,7 @@ region save
|
|||
|
||||
---
|
||||
|
||||
#### View or change thevalue of a sensor
|
||||
#### View or change the value of a sensor
|
||||
**Usage:**
|
||||
- `sensor get <key>`
|
||||
- `sensor set <key> <value>`
|
||||
|
|
@ -1047,3 +1048,69 @@ region save
|
|||
**Note:** Returns an error on boards without power management support.
|
||||
|
||||
---
|
||||
|
||||
### Ethernet (When USE_ETHERNET is compiled in)
|
||||
|
||||
#### View or change this node's Ethernet IP address
|
||||
**Usage:**
|
||||
- `get ip`
|
||||
- `set ip <address>`
|
||||
|
||||
**Parameters:**
|
||||
- `address`: IPv4 address (e.g., `192.168.254.21`)
|
||||
|
||||
**Set by build flag:** `ETH_STATIC_IP`
|
||||
|
||||
**Default:** `0.0.0.0` (uses DHCP if not configured)
|
||||
|
||||
**Note:** Requires reboot to apply. Set to `0.0.0.0` to revert to DHCP. If `ETH_STATIC_IP` is defined in build flags and DHCP fails, that compile-time address is used as fallback.
|
||||
|
||||
---
|
||||
|
||||
#### View or change this node's Ethernet gateway
|
||||
**Usage:**
|
||||
- `get gw`
|
||||
- `set gw <address>`
|
||||
|
||||
**Parameters:**
|
||||
- `address`: IPv4 gateway address (e.g., `192.168.254.254`)
|
||||
|
||||
**Set by build flag:** `ETH_GATEWAY`
|
||||
|
||||
**Default:** `0.0.0.0`
|
||||
|
||||
**Note:** Requires reboot to apply
|
||||
|
||||
---
|
||||
|
||||
#### View or change this node's Ethernet subnet mask
|
||||
**Usage:**
|
||||
- `get subnet`
|
||||
- `set subnet <address>`
|
||||
|
||||
**Parameters:**
|
||||
- `address`: Subnet mask in dotted decimal notation (e.g., `255.255.255.0`)
|
||||
|
||||
**Set by build flag:** `ETH_SUBNET`
|
||||
|
||||
**Default:** `0.0.0.0`
|
||||
|
||||
**Note:** Requires reboot to apply
|
||||
|
||||
---
|
||||
|
||||
#### View or change this node's Ethernet DNS server
|
||||
**Usage:**
|
||||
- `get dns`
|
||||
- `set dns <address>`
|
||||
|
||||
**Parameters:**
|
||||
- `address`: IPv4 DNS address (e.g., `8.8.8.8`)
|
||||
|
||||
**Set by build flag:** `ETH_DNS`
|
||||
|
||||
**Default:** `0.0.0.0`
|
||||
|
||||
**Note:** Requires reboot to apply. Configures DNS1 (primary DNS server).
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
#include <Mesh.h>
|
||||
#include "MyMesh.h"
|
||||
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT) && defined(ADMIN_PASSWORD)
|
||||
#include <helpers/esp32/TCPConsole.h>
|
||||
TCPConsole tcp_console(nullptr); // prefs set in setup()
|
||||
#endif
|
||||
|
||||
// Believe it or not, this std C function is busted on some platforms!
|
||||
static uint32_t _atoi(const char* sp) {
|
||||
uint32_t n = 0;
|
||||
|
|
@ -35,7 +40,7 @@ static uint32_t _atoi(const char* sp) {
|
|||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
#ifdef WIFI_SSID
|
||||
#if defined(WIFI_SSID) || defined(USE_ETHERNET)
|
||||
#include <helpers/esp32/SerialWifiInterface.h>
|
||||
SerialWifiInterface serial_interface;
|
||||
#ifndef TCP_PORT
|
||||
|
|
@ -109,6 +114,10 @@ void setup() {
|
|||
Serial.begin(115200);
|
||||
|
||||
board.begin();
|
||||
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT) && defined(ADMIN_PASSWORD)
|
||||
tcp_console.begin();
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
DisplayDriver* disp = NULL;
|
||||
|
|
@ -122,7 +131,7 @@ void setup() {
|
|||
disp->endFrame();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (!radio_init()) { halt(); }
|
||||
|
||||
fast_rng.begin(radio_get_rng_seed());
|
||||
|
|
@ -143,6 +152,9 @@ void setup() {
|
|||
#endif
|
||||
store.begin();
|
||||
the_mesh.begin(
|
||||
|
||||
tcp_console.setPrefs(the_mesh.getNodePrefs());
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
disp != NULL
|
||||
#else
|
||||
|
|
@ -194,9 +206,12 @@ void setup() {
|
|||
);
|
||||
|
||||
#ifdef WIFI_SSID
|
||||
board.setInhibitSleep(true); // prevent sleep when WiFi is active
|
||||
board.setInhibitSleep(true);
|
||||
WiFi.begin(WIFI_SSID, WIFI_PWD);
|
||||
serial_interface.begin(TCP_PORT);
|
||||
#elif defined(USE_ETHERNET)
|
||||
serial_interface.begin(TCP_PORT);
|
||||
Serial.printf("TCP server started on port %d\n", TCP_PORT);
|
||||
#elif defined(BLE_PIN_CODE)
|
||||
serial_interface.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name, the_mesh.getBLEPin());
|
||||
#elif defined(SERIAL_RX)
|
||||
|
|
@ -224,9 +239,14 @@ void setup() {
|
|||
|
||||
void loop() {
|
||||
the_mesh.loop();
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT) && defined(ADMIN_PASSWORD)
|
||||
tcp_console.loop(the_mesh);
|
||||
#endif
|
||||
|
||||
sensors.loop();
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.loop();
|
||||
#endif
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.loop();
|
||||
#endif
|
||||
|
||||
rtc_clock.tick();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -740,8 +740,8 @@ void UITask::loop() {
|
|||
}
|
||||
#endif
|
||||
#if defined(PIN_USER_BTN_ANA)
|
||||
if (abs(millis() - _analogue_pin_read_millis) > 10) {
|
||||
ev = analog_btn.check();
|
||||
if (millis() - _analogue_pin_read_millis > 10) {
|
||||
auto ev = analog_btn.check();
|
||||
if (ev == BUTTON_EVENT_CLICK) {
|
||||
c = checkDisplayOn(KEY_NEXT);
|
||||
} else if (ev == BUTTON_EVENT_LONG_PRESS) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
#include "MyMesh.h"
|
||||
|
||||
#if defined(TCP_CONSOLE_PORT)
|
||||
#include <helpers/esp32/TCPConsole.h>
|
||||
TCPConsole tcp_console(nullptr); // prefs set in setup()
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include "UITask.h"
|
||||
static UITask ui_task(display);
|
||||
|
|
@ -34,6 +39,10 @@ void setup() {
|
|||
|
||||
board.begin();
|
||||
|
||||
#if defined(TCP_CONSOLE_PORT)
|
||||
tcp_console.begin();
|
||||
#endif
|
||||
|
||||
#if defined(MESH_DEBUG) && defined(NRF52_PLATFORM)
|
||||
// give some extra time for serial to settle so
|
||||
// boot debug messages can be seen on terminal
|
||||
|
|
@ -95,6 +104,17 @@ void setup() {
|
|||
|
||||
the_mesh.begin(fs);
|
||||
|
||||
#ifdef USE_ETHERNET
|
||||
NodePrefs* prefs = the_mesh.getNodePrefs();
|
||||
if (prefs->eth_ip != 0) {
|
||||
board.reconfigureEthernet(prefs->eth_ip, prefs->eth_gateway, prefs->eth_subnet, prefs->eth_dns1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TCP_CONSOLE_PORT)
|
||||
tcp_console.setPrefs(the_mesh.getNodePrefs());
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
|
||||
#endif
|
||||
|
|
@ -148,6 +168,10 @@ void loop() {
|
|||
#endif
|
||||
|
||||
the_mesh.loop();
|
||||
#if defined(TCP_CONSOLE_PORT)
|
||||
tcp_console.loop(the_mesh);
|
||||
#endif
|
||||
|
||||
sensors.loop();
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.loop();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
#include "MyMesh.h"
|
||||
|
||||
#if defined(TCP_CONSOLE_PORT)
|
||||
#include <helpers/esp32/TCPConsole.h>
|
||||
TCPConsole tcp_console(nullptr); // prefs set in setup()
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include "UITask.h"
|
||||
static UITask ui_task(display);
|
||||
|
|
@ -24,6 +29,10 @@ void setup() {
|
|||
|
||||
board.begin();
|
||||
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT)
|
||||
tcp_console.begin();
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
if (display.begin()) {
|
||||
display.startFrame();
|
||||
|
|
@ -72,6 +81,17 @@ void setup() {
|
|||
|
||||
the_mesh.begin(fs);
|
||||
|
||||
#ifdef USE_ETHERNET
|
||||
NodePrefs* prefs = the_mesh.getNodePrefs();
|
||||
if (prefs->eth_ip != 0) {
|
||||
board.reconfigureEthernet(prefs->eth_ip, prefs->eth_gateway, prefs->eth_subnet, prefs->eth_dns1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TCP_CONSOLE_PORT)
|
||||
tcp_console.setPrefs(the_mesh.getNodePrefs());
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
|
||||
#endif
|
||||
|
|
@ -108,9 +128,13 @@ void loop() {
|
|||
}
|
||||
|
||||
the_mesh.loop();
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT)
|
||||
tcp_console.loop(the_mesh);
|
||||
#endif
|
||||
|
||||
sensors.loop();
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.loop();
|
||||
#endif
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.loop();
|
||||
#endif
|
||||
rtc_clock.tick();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ public:
|
|||
virtual const char* getResetReasonString(uint32_t reason) { return "Not available"; }
|
||||
virtual uint8_t getShutdownReason() const { return 0; }
|
||||
virtual const char* getShutdownReasonString(uint8_t reason) { return "Not available"; }
|
||||
virtual void reconfigureEthernet(uint32_t ip, uint32_t gw, uint32_t subnet, uint32_t dns1 = 0) { /* no op */ }
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -26,6 +26,38 @@ static bool isValidName(const char *n) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Helper functions for IP address conversion
|
||||
// Returns UINT32_MAX on parse error or out-of-range octet. Returns 0 for 0.0.0.0 (DHCP/clear).
|
||||
static uint32_t ipStringToUint32(const char* ip_str) {
|
||||
unsigned int a = 0, b = 0, c = 0, d = 0;
|
||||
if (sscanf(ip_str, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) return UINT32_MAX;
|
||||
if (a > 255 || b > 255 || c > 255 || d > 255) return UINT32_MAX;
|
||||
return ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | d;
|
||||
}
|
||||
|
||||
static void uint32ToIPString(uint32_t ip, char* buffer, size_t size) {
|
||||
uint8_t b1 = (ip >> 24) & 0xFF;
|
||||
uint8_t b2 = (ip >> 16) & 0xFF;
|
||||
uint8_t b3 = (ip >> 8) & 0xFF;
|
||||
uint8_t b4 = ip & 0xFF;
|
||||
snprintf(buffer, size, "%d.%d.%d.%d", b1, b2, b3, b4);
|
||||
}
|
||||
|
||||
// Reject 0.x.x.x and multicast/reserved (>= 224.x.x.x). 0 is valid (means DHCP/clear).
|
||||
// Guards against stale bytes from older prefs-file layouts ending up at the netif.
|
||||
static bool isValidUnicastIp(uint32_t ip) {
|
||||
if (ip == 0) return true;
|
||||
uint8_t first = (ip >> 24) & 0xFF;
|
||||
return (first >= 1 && first <= 223);
|
||||
}
|
||||
|
||||
// Valid subnet mask = contiguous 1s followed by contiguous 0s.
|
||||
static bool isValidSubnetMask(uint32_t mask) {
|
||||
if (mask == 0) return true;
|
||||
uint32_t inv = ~mask;
|
||||
return (inv & (inv + 1)) == 0;
|
||||
}
|
||||
|
||||
void CommonCLI::loadPrefs(FILESYSTEM* fs) {
|
||||
if (fs->exists("/com_prefs")) {
|
||||
loadPrefsInt(fs, "/com_prefs"); // new filename
|
||||
|
|
@ -87,8 +119,13 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
|||
file.read((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
|
||||
file.read((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
|
||||
file.read((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
|
||||
file.read((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
|
||||
// next: 291
|
||||
file.read((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
|
||||
file.read((uint8_t *)&_prefs->eth_ip, sizeof(_prefs->eth_ip)); // 291
|
||||
file.read((uint8_t *)&_prefs->eth_gateway, sizeof(_prefs->eth_gateway)); // 295
|
||||
file.read((uint8_t *)&_prefs->eth_subnet, sizeof(_prefs->eth_subnet)); // 299
|
||||
file.read((uint8_t *)&_prefs->eth_dns1, sizeof(_prefs->eth_dns1)); // 303
|
||||
file.read((uint8_t *)&_prefs->eth_dns2, sizeof(_prefs->eth_dns2)); // 307
|
||||
// 311
|
||||
|
||||
// sanitise bad pref values
|
||||
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
|
||||
|
|
@ -119,6 +156,15 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
|||
// sanitise settings
|
||||
_prefs->rx_boosted_gain = constrain(_prefs->rx_boosted_gain, 0, 1); // boolean
|
||||
|
||||
// Sanitise eth_* fields: an older firmware version may have written different
|
||||
// data at these offsets. Drop anything that isn't a plausible unicast IP / mask
|
||||
// so we don't push garbage into esp_netif_set_ip_info() at boot.
|
||||
if (!isValidUnicastIp(_prefs->eth_ip)) _prefs->eth_ip = 0;
|
||||
if (!isValidUnicastIp(_prefs->eth_gateway)) _prefs->eth_gateway = 0;
|
||||
if (!isValidUnicastIp(_prefs->eth_dns1)) _prefs->eth_dns1 = 0;
|
||||
if (!isValidUnicastIp(_prefs->eth_dns2)) _prefs->eth_dns2 = 0;
|
||||
if (!isValidSubnetMask(_prefs->eth_subnet)) _prefs->eth_subnet = 0;
|
||||
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -178,9 +224,13 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
|
|||
file.write((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
|
||||
file.write((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
|
||||
file.write((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
|
||||
file.write((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
|
||||
// next: 291
|
||||
|
||||
file.write((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
|
||||
file.write((uint8_t *)&_prefs->eth_ip, sizeof(_prefs->eth_ip)); // 291
|
||||
file.write((uint8_t *)&_prefs->eth_gateway, sizeof(_prefs->eth_gateway)); // 295
|
||||
file.write((uint8_t *)&_prefs->eth_subnet, sizeof(_prefs->eth_subnet)); // 299
|
||||
file.write((uint8_t *)&_prefs->eth_dns1, sizeof(_prefs->eth_dns1)); // 303
|
||||
file.write((uint8_t *)&_prefs->eth_dns2, sizeof(_prefs->eth_dns2)); // 307
|
||||
// 311
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -285,7 +335,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
|
|||
// change admin password
|
||||
StrHelper::strncpy(_prefs->password, &command[9], sizeof(_prefs->password));
|
||||
savePrefs();
|
||||
sprintf(reply, "password now: %s", _prefs->password); // echo back just to let admin know for sure!!
|
||||
strcpy(reply, "OK - password changed");
|
||||
} else if (memcmp(command, "clear stats", 11) == 0) {
|
||||
_callbacks->clearStats();
|
||||
strcpy(reply, "(OK - stats reset)");
|
||||
|
|
@ -725,6 +775,44 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
|||
_prefs->adc_multiplier = 0.0f;
|
||||
strcpy(reply, "Error: unsupported by this board");
|
||||
};
|
||||
#ifdef USE_ETHERNET
|
||||
} else if (memcmp(config, "ip ", 3) == 0) {
|
||||
uint32_t ip = ipStringToUint32(&config[3]);
|
||||
if (ip == UINT32_MAX || (ip != 0 && !isValidUnicastIp(ip))) {
|
||||
strcpy(reply, "Error: invalid IP");
|
||||
} else {
|
||||
_prefs->eth_ip = ip;
|
||||
savePrefs();
|
||||
strcpy(reply, ip == 0 ? "OK - reboot to apply (will use DHCP)" : "OK - reboot to apply");
|
||||
}
|
||||
} else if (memcmp(config, "subnet ", 7) == 0) {
|
||||
uint32_t subnet = ipStringToUint32(&config[7]);
|
||||
if (subnet == UINT32_MAX || !isValidSubnetMask(subnet)) {
|
||||
strcpy(reply, "Error: invalid subnet mask");
|
||||
} else {
|
||||
_prefs->eth_subnet = subnet;
|
||||
savePrefs();
|
||||
strcpy(reply, "OK - reboot to apply");
|
||||
}
|
||||
} else if (memcmp(config, "gw ", 3) == 0) {
|
||||
uint32_t gw = ipStringToUint32(&config[3]);
|
||||
if (gw == UINT32_MAX || (gw != 0 && !isValidUnicastIp(gw))) {
|
||||
strcpy(reply, "Error: invalid IP");
|
||||
} else {
|
||||
_prefs->eth_gateway = gw;
|
||||
savePrefs();
|
||||
strcpy(reply, "OK - reboot to apply");
|
||||
}
|
||||
} else if (memcmp(config, "dns ", 4) == 0) {
|
||||
uint32_t dns = ipStringToUint32(&config[4]);
|
||||
if (dns == UINT32_MAX || (dns != 0 && !isValidUnicastIp(dns))) {
|
||||
strcpy(reply, "Error: invalid IP");
|
||||
} else {
|
||||
_prefs->eth_dns1 = dns;
|
||||
savePrefs();
|
||||
strcpy(reply, "OK - reboot to apply");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
sprintf(reply, "unknown config: %s", config);
|
||||
}
|
||||
|
|
@ -840,6 +928,24 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
|
|||
sprintf(reply, "> %d", (uint32_t)_prefs->bridge_channel);
|
||||
} else if (memcmp(config, "bridge.secret", 13) == 0) {
|
||||
sprintf(reply, "> %s", _prefs->bridge_secret);
|
||||
#endif
|
||||
#ifdef USE_ETHERNET
|
||||
} else if (memcmp(config, "ip", 2) == 0) {
|
||||
char ip_str[16];
|
||||
uint32ToIPString(_prefs->eth_ip, ip_str, sizeof(ip_str));
|
||||
sprintf(reply, "> %s", ip_str);
|
||||
} else if (memcmp(config, "subnet", 6) == 0) {
|
||||
char subnet_str[16];
|
||||
uint32ToIPString(_prefs->eth_subnet, subnet_str, sizeof(subnet_str));
|
||||
sprintf(reply, "> %s", subnet_str);
|
||||
} else if (memcmp(config, "gw", 2) == 0) {
|
||||
char gw_str[16];
|
||||
uint32ToIPString(_prefs->eth_gateway, gw_str, sizeof(gw_str));
|
||||
sprintf(reply, "> %s", gw_str);
|
||||
} else if (memcmp(config, "dns", 3) == 0) {
|
||||
char dns_str[16];
|
||||
uint32ToIPString(_prefs->eth_dns1, dns_str, sizeof(dns_str));
|
||||
sprintf(reply, "> %s", dns_str);
|
||||
#endif
|
||||
} else if (memcmp(config, "bootloader.ver", 14) == 0) {
|
||||
#ifdef NRF52_PLATFORM
|
||||
|
|
|
|||
|
|
@ -61,6 +61,12 @@ struct NodePrefs { // persisted to file
|
|||
uint8_t rx_boosted_gain; // power settings
|
||||
uint8_t path_hash_mode; // which path mode to use when sending
|
||||
uint8_t loop_detect;
|
||||
// Ethernet settings
|
||||
uint32_t eth_ip;
|
||||
uint32_t eth_gateway;
|
||||
uint32_t eth_subnet;
|
||||
uint32_t eth_dns1;
|
||||
uint32_t eth_dns2;
|
||||
};
|
||||
|
||||
class CommonCLICallbacks {
|
||||
|
|
|
|||
|
|
@ -3,18 +3,29 @@
|
|||
#include "ESP32Board.h"
|
||||
|
||||
#if defined(ADMIN_PASSWORD) && !defined(DISABLE_WIFI_OTA) // Repeater or Room Server only
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <AsyncElegantOTA.h>
|
||||
|
||||
#include <SPIFFS.h>
|
||||
|
||||
bool ESP32Board::startOTAUpdate(const char* id, char reply[]) {
|
||||
inhibit_sleep = true; // prevent sleep during OTA
|
||||
WiFi.softAP("MeshCore-OTA", NULL);
|
||||
#if defined(USE_ETHERNET)
|
||||
extern String eth_local_ip; // defined in TEthEliteBoard.cpp
|
||||
#else
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
bool ESP32Board::startOTAUpdate(const char* id, char reply[]) {
|
||||
inhibit_sleep = true;
|
||||
|
||||
#if defined(USE_ETHERNET)
|
||||
Serial.println("OTA: using ETH");
|
||||
sprintf(reply, "Started: http://%s/update", eth_local_ip.c_str());
|
||||
#else
|
||||
Serial.println("OTA: using WiFi SoftAP");
|
||||
WiFi.softAP("MeshCore-OTA", NULL);
|
||||
sprintf(reply, "Started: http://%s/update", WiFi.softAPIP().toString().c_str());
|
||||
#endif
|
||||
|
||||
MESH_DEBUG_PRINTLN("startOTAUpdate: %s", reply);
|
||||
|
||||
static char id_buf[60];
|
||||
|
|
@ -32,7 +43,7 @@ bool ESP32Board::startOTAUpdate(const char* id, char reply[]) {
|
|||
});
|
||||
|
||||
AsyncElegantOTA.setID(id_buf);
|
||||
AsyncElegantOTA.begin(server); // Start ElegantOTA
|
||||
AsyncElegantOTA.begin(server);
|
||||
server->begin();
|
||||
|
||||
return true;
|
||||
|
|
@ -44,4 +55,4 @@ bool ESP32Board::startOTAUpdate(const char* id, char reply[]) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif // ESP_PLATFORM
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@
|
|||
#include <WiFi.h>
|
||||
|
||||
void SerialWifiInterface::begin(int port) {
|
||||
// wifi setup is handled outside of this class, only starts the server
|
||||
server.begin(port);
|
||||
server = WiFiServer(port);
|
||||
server.begin();
|
||||
}
|
||||
|
||||
// ---------- public methods
|
||||
void SerialWifiInterface::enable() {
|
||||
if (_isEnabled) return;
|
||||
|
|
@ -169,4 +168,5 @@ size_t SerialWifiInterface::checkRecvFrame(uint8_t dest[]) {
|
|||
|
||||
bool SerialWifiInterface::isConnected() const {
|
||||
return deviceConnected; //pServer != NULL && pServer->getConnectedCount() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
153
src/helpers/esp32/TCPConsole.h
Normal file
153
src/helpers/esp32/TCPConsole.h
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT) && defined(ADMIN_PASSWORD)
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiServer.h>
|
||||
#include <helpers/CommonCLI.h> // for NodePrefs
|
||||
|
||||
#ifndef TCP_CONSOLE_MAX_CLIENTS
|
||||
#define TCP_CONSOLE_MAX_CLIENTS 2
|
||||
#endif
|
||||
|
||||
#ifndef TCP_CONSOLE_TIMEOUT_MS
|
||||
#define TCP_CONSOLE_TIMEOUT_MS 300000 // 5 minutes inactivity timeout
|
||||
#endif
|
||||
|
||||
class TCPConsole {
|
||||
WiFiServer _server;
|
||||
WiFiClient _clients[TCP_CONSOLE_MAX_CLIENTS];
|
||||
bool _authenticated[TCP_CONSOLE_MAX_CLIENTS];
|
||||
unsigned long _last_active[TCP_CONSOLE_MAX_CLIENTS];
|
||||
char _cmd_buf[TCP_CONSOLE_MAX_CLIENTS][160];
|
||||
int _cmd_len[TCP_CONSOLE_MAX_CLIENTS];
|
||||
NodePrefs* _prefs; // pointer to live NodePrefs — password is read at runtime
|
||||
|
||||
void sendToClient(int i, const char* msg) {
|
||||
if (_clients[i] && _clients[i].connected()) {
|
||||
_clients[i].print(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void disconnectClient(int i) {
|
||||
_clients[i].stop();
|
||||
_authenticated[i] = false;
|
||||
memset(_cmd_buf[i], 0, sizeof(_cmd_buf[i]));
|
||||
_cmd_len[i] = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
TCPConsole(NodePrefs* prefs)
|
||||
: _server(TCP_CONSOLE_PORT), _prefs(prefs) {
|
||||
for (int i = 0; i < TCP_CONSOLE_MAX_CLIENTS; i++) {
|
||||
_authenticated[i] = false;
|
||||
memset(_cmd_buf[i], 0, sizeof(_cmd_buf[i]));
|
||||
_cmd_len[i] = 0;
|
||||
_last_active[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void begin() {
|
||||
_server.begin();
|
||||
Serial.printf("TCP Console listening on port %d\n", TCP_CONSOLE_PORT);
|
||||
}
|
||||
|
||||
void setPrefs(NodePrefs* prefs) { _prefs = prefs; }
|
||||
|
||||
// Call this from loop(), passing the mesh's handleCommand function
|
||||
template<typename T>
|
||||
void loop(T& mesh) {
|
||||
// Accept new clients
|
||||
WiFiClient newClient = _server.available();
|
||||
if (newClient) {
|
||||
bool found = false;
|
||||
for (int i = 0; i < TCP_CONSOLE_MAX_CLIENTS; i++) {
|
||||
if (!_clients[i] || !_clients[i].connected()) {
|
||||
_clients[i] = newClient;
|
||||
_authenticated[i] = false;
|
||||
memset(_cmd_buf[i], 0, sizeof(_cmd_buf[i]));
|
||||
_cmd_len[i] = 0;
|
||||
_last_active[i] = millis();
|
||||
sendToClient(i, "MeshCore Console\r\nPassword: ");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
newClient.print("Server busy. Try again later.\r\n");
|
||||
newClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle connected clients
|
||||
for (int i = 0; i < TCP_CONSOLE_MAX_CLIENTS; i++) {
|
||||
if (!_clients[i] || !_clients[i].connected()) continue;
|
||||
|
||||
// Inactivity timeout
|
||||
if (millis() - _last_active[i] > TCP_CONSOLE_TIMEOUT_MS) {
|
||||
sendToClient(i, "\r\nTimeout. Disconnecting.\r\n");
|
||||
disconnectClient(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read available data
|
||||
while (_clients[i].available()) {
|
||||
_last_active[i] = millis();
|
||||
char c = _clients[i].read();
|
||||
|
||||
if (c == '\n') continue; // ignore LF, handle CR only
|
||||
|
||||
if (c != '\r' && _cmd_len[i] < 158) {
|
||||
_cmd_buf[i][_cmd_len[i]++] = c;
|
||||
_cmd_buf[i][_cmd_len[i]] = 0;
|
||||
if (!_authenticated[i]) {
|
||||
sendToClient(i, "*"); // mask password input
|
||||
} else {
|
||||
_clients[i].print(c); // echo command
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Got CR — process command
|
||||
sendToClient(i, "\r\n");
|
||||
_cmd_buf[i][_cmd_len[i]] = 0;
|
||||
|
||||
if (!_authenticated[i]) {
|
||||
// Compare full password field with memcmp to avoid short-circuit timing
|
||||
bool ok = _prefs != nullptr &&
|
||||
_cmd_len[i] == (int)strnlen(_prefs->password, sizeof(_prefs->password)) &&
|
||||
memcmp(_cmd_buf[i], _prefs->password, sizeof(_prefs->password)) == 0;
|
||||
if (ok) {
|
||||
_authenticated[i] = true;
|
||||
char welcome[80];
|
||||
snprintf(welcome, sizeof(welcome), "Welcome to %s console.\r\n> ", _prefs->node_name);
|
||||
sendToClient(i, welcome);
|
||||
} else {
|
||||
sendToClient(i, "Wrong password. Disconnecting.\r\n");
|
||||
disconnectClient(i);
|
||||
}
|
||||
} else {
|
||||
// Execute command
|
||||
if (strlen(_cmd_buf[i]) > 0) {
|
||||
char reply[160];
|
||||
reply[0] = 0;
|
||||
mesh.handleCommand(0, _cmd_buf[i], reply);
|
||||
if (reply[0]) {
|
||||
sendToClient(i, " -> ");
|
||||
sendToClient(i, reply);
|
||||
sendToClient(i, "\r\n");
|
||||
}
|
||||
}
|
||||
sendToClient(i, "> ");
|
||||
}
|
||||
|
||||
memset(_cmd_buf[i], 0, sizeof(_cmd_buf[i]));
|
||||
_cmd_len[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // ESP32 && TCP_CONSOLE_PORT && ADMIN_PASSWORD
|
||||
290
src/helpers/esp32/TEthEliteBoard.cpp
Normal file
290
src/helpers/esp32/TEthEliteBoard.cpp
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
#if defined(T_ETH_ELITE_SX1262) || defined(T_ETH_ELITE_SX1276)
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include "esp_eth.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_netif_defaults.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_mac.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "TEthEliteBoard.h"
|
||||
#include "target.h"
|
||||
#include "helpers/ui/MomentaryButton.h"
|
||||
#include <esp_task_wdt.h>
|
||||
|
||||
// Build IP addresses in lwIP's internal format (network byte order stored as LE uint32_t).
|
||||
// Using a variadic macro so that comma-expanded build flags like ETH_STATIC_IP work:
|
||||
// IP4_NBO(ETH_STATIC_IP) expands to _ip4_make(192,168,254,21) after arg expansion.
|
||||
static inline uint32_t _ip4_make(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
||||
return ((uint32_t)d << 24) | ((uint32_t)c << 16) | ((uint32_t)b << 8) | (uint32_t)a;
|
||||
}
|
||||
#define IP4_NBO(...) _ip4_make(__VA_ARGS__)
|
||||
|
||||
extern MomentaryButton user_btn;
|
||||
|
||||
uint32_t deviceOnline = 0x00;
|
||||
String eth_local_ip; // global, accessible from ESP32Board.cpp via extern
|
||||
|
||||
#ifdef USE_ETHERNET
|
||||
static esp_netif_t *eth_netif = NULL;
|
||||
static esp_eth_handle_t eth_handle = NULL;
|
||||
|
||||
// Refresh eth_local_ip from the current netif state.
|
||||
static void updateLocalIpString() {
|
||||
esp_netif_ip_info_t info = {};
|
||||
esp_netif_get_ip_info(eth_netif, &info);
|
||||
char buf[16];
|
||||
esp_ip4addr_ntoa(&info.ip, buf, sizeof(buf));
|
||||
eth_local_ip = String(buf);
|
||||
}
|
||||
|
||||
// Apply static IP config. All uint32_t params are already in network byte order
|
||||
// (ie. in the format accepted by esp_ip4_addr_t.addr). Pass dns_nbo=0 to skip DNS.
|
||||
static void applyStaticIp(uint32_t ip_nbo, uint32_t gw_nbo, uint32_t mask_nbo, uint32_t dns_nbo) {
|
||||
esp_netif_dhcpc_stop(eth_netif);
|
||||
|
||||
esp_netif_ip_info_t info = {};
|
||||
info.ip.addr = ip_nbo;
|
||||
info.gw.addr = gw_nbo;
|
||||
info.netmask.addr = mask_nbo;
|
||||
esp_netif_set_ip_info(eth_netif, &info);
|
||||
|
||||
if (dns_nbo != 0) {
|
||||
esp_netif_dns_info_t dns = {};
|
||||
dns.ip.u_addr.ip4.addr = dns_nbo;
|
||||
dns.ip.type = ESP_IPADDR_TYPE_V4;
|
||||
esp_netif_set_dns_info(eth_netif, ESP_NETIF_DNS_MAIN, &dns);
|
||||
}
|
||||
|
||||
updateLocalIpString();
|
||||
}
|
||||
#endif
|
||||
|
||||
void TEthEliteBoard::begin() {
|
||||
ESP32Board::begin();
|
||||
user_btn.begin();
|
||||
Wire1.begin(PIN_BOARD_SDA1, PIN_BOARD_SCL1);
|
||||
#if ENV_INCLUDE_GPS
|
||||
Serial1.begin(9600, SERIAL_8N1, PIN_GPS_RX, PIN_GPS_TX);
|
||||
#endif
|
||||
|
||||
#ifdef USE_ETHERNET
|
||||
WiFi.mode(WIFI_OFF);
|
||||
#endif
|
||||
startNetwork();
|
||||
|
||||
pinMode(P_LORA_TX_LED, OUTPUT);
|
||||
digitalWrite(P_LORA_TX_LED, LOW);
|
||||
|
||||
if (esp_reset_reason() == ESP_RST_DEEPSLEEP) {
|
||||
uint64_t wakeup_source = esp_sleep_get_ext1_wakeup_status();
|
||||
if (wakeup_source & (1ULL << P_LORA_WAKE_DIO)) {
|
||||
startup_reason = BD_STARTUP_RX_PACKET;
|
||||
}
|
||||
rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS);
|
||||
rtc_gpio_deinit((gpio_num_t)P_LORA_WAKE_DIO);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MESH_DEBUG
|
||||
void TEthEliteBoard::scanDevices(TwoWire *w)
|
||||
{
|
||||
uint8_t err, addr;
|
||||
int nDevices = 0;
|
||||
|
||||
Serial.println("Scanning I2C for Devices");
|
||||
for (addr = 1; addr < 127; addr++) {
|
||||
w->beginTransmission(addr); delay(2);
|
||||
err = w->endTransmission();
|
||||
if (err == 0) {
|
||||
nDevices++;
|
||||
switch (addr) {
|
||||
case 0x77:
|
||||
case 0x76:
|
||||
Serial.println("\tFound BME280 Sensor");
|
||||
deviceOnline |= BME280_ONLINE;
|
||||
break;
|
||||
case 0x34:
|
||||
Serial.println("\tFound AXP192/AXP2101 PMU");
|
||||
deviceOnline |= POWERMANAGE_ONLINE;
|
||||
break;
|
||||
case 0x3C:
|
||||
Serial.println("\tFound SSD1306/SH1106 display");
|
||||
deviceOnline |= DISPLAY_ONLINE;
|
||||
break;
|
||||
case 0x51:
|
||||
Serial.println("\tFound PCF8563 RTC");
|
||||
deviceOnline |= PCF8563_ONLINE;
|
||||
break;
|
||||
case 0x1C:
|
||||
Serial.println("\tFound QMC6310 MAG Sensor");
|
||||
deviceOnline |= QMC6310_ONLINE;
|
||||
break;
|
||||
default:
|
||||
Serial.printf("\tI2C device found at address 0x%02X\n", addr);
|
||||
break;
|
||||
}
|
||||
} else if (err == 4) {
|
||||
Serial.printf("Unknown error at address 0x%02X\n", addr);
|
||||
}
|
||||
}
|
||||
if (nDevices == 0)
|
||||
Serial.println("No I2C devices found");
|
||||
|
||||
Serial.println("Scan complete.");
|
||||
Serial.printf("GPS RX pin: %d, GPS TX pin: %d\n", PIN_GPS_RX, PIN_GPS_TX);
|
||||
}
|
||||
|
||||
void TEthEliteBoard::printPMU()
|
||||
{
|
||||
Serial.print("isCharging:"); Serial.println(PMU->isCharging() ? "YES" : "NO");
|
||||
Serial.print("isDischarge:"); Serial.println(PMU->isDischarge() ? "YES" : "NO");
|
||||
Serial.print("isVbusIn:"); Serial.println(PMU->isVbusIn() ? "YES" : "NO");
|
||||
Serial.print("getBattVoltage:"); Serial.print(PMU->getBattVoltage()); Serial.println("mV");
|
||||
Serial.print("getVbusVoltage:"); Serial.print(PMU->getVbusVoltage()); Serial.println("mV");
|
||||
Serial.print("getSystemVoltage:"); Serial.print(PMU->getSystemVoltage()); Serial.println("mV");
|
||||
if (PMU->isBatteryConnect()) {
|
||||
Serial.print("getBatteryPercent:"); Serial.print(PMU->getBatteryPercent()); Serial.println("%");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void TEthEliteBoard::startNetwork() {
|
||||
#ifdef USE_ETHERNET
|
||||
startEthernet();
|
||||
#elif defined(WIFI_SSID)
|
||||
startWifi();
|
||||
#endif
|
||||
}
|
||||
|
||||
void TEthEliteBoard::startEthernet() {
|
||||
#ifdef USE_ETHERNET
|
||||
// Arduino-ESP32 3.x does not initialize these until WiFi is actively used.
|
||||
// The native Ethernet path needs them up-front. Each returns ESP_ERR_INVALID_STATE
|
||||
// on second call — treat that as success.
|
||||
esp_err_t err = esp_netif_init();
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) ESP_ERROR_CHECK(err);
|
||||
err = esp_event_loop_create_default();
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) ESP_ERROR_CHECK(err);
|
||||
// W5500 driver calls gpio_isr_handler_add() on ETH_INT; needs ISR service running.
|
||||
err = gpio_install_isr_service(0);
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) ESP_ERROR_CHECK(err);
|
||||
|
||||
// Initialize SPI2 (FSPI) bus with W5500 pins. The LoRa radio uses the
|
||||
// default Arduino SPIClass, which on ESP32-S3 is HSPI → SPI3 — so W5500
|
||||
// must stay on SPI2 to keep the two drivers on separate buses.
|
||||
spi_bus_config_t buscfg = {};
|
||||
buscfg.mosi_io_num = ETH_MOSI;
|
||||
buscfg.miso_io_num = ETH_MISO;
|
||||
buscfg.sclk_io_num = ETH_SCLK;
|
||||
buscfg.quadwp_io_num = -1;
|
||||
buscfg.quadhd_io_num = -1;
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
|
||||
// W5500 SPI device: 16-bit address phase + 8-bit control byte
|
||||
spi_device_interface_config_t spi_devcfg = {};
|
||||
spi_devcfg.command_bits = 16;
|
||||
spi_devcfg.address_bits = 8;
|
||||
spi_devcfg.mode = 0;
|
||||
spi_devcfg.clock_speed_hz = 20 * 1000 * 1000;
|
||||
spi_devcfg.spics_io_num = ETH_CS;
|
||||
spi_devcfg.queue_size = 20;
|
||||
|
||||
spi_device_handle_t spi_handle = NULL;
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(SPI2_HOST, &spi_devcfg, &spi_handle));
|
||||
|
||||
// W5500 MAC + PHY via native ESP-IDF driver. Bump the receive task stack:
|
||||
// the default 2048 bytes overflows under load (observed w5500_tsk stack canary).
|
||||
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
|
||||
mac_config.rx_task_stack_size = 4096;
|
||||
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
|
||||
phy_config.phy_addr = ETH_ADDR;
|
||||
phy_config.reset_gpio_num = ETH_RST;
|
||||
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
|
||||
w5500_config.int_gpio_num = ETH_INT;
|
||||
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
|
||||
|
||||
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
|
||||
ESP_ERROR_CHECK(esp_eth_driver_install(ð_config, ð_handle));
|
||||
|
||||
// W5500 has no factory MAC — derive one from the ESP32 efuse base MAC and
|
||||
// program it into the driver. Without this, DHCP never completes and the
|
||||
// ETH interface transmits with MAC 00:00:00:00:00:00.
|
||||
uint8_t mac_addr[6];
|
||||
ESP_ERROR_CHECK(esp_read_mac(mac_addr, ESP_MAC_ETH));
|
||||
ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, mac_addr));
|
||||
|
||||
// Create default ETH netif and attach driver glue
|
||||
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
|
||||
eth_netif = esp_netif_new(&netif_cfg);
|
||||
ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)));
|
||||
|
||||
ESP_ERROR_CHECK(esp_eth_start(eth_handle));
|
||||
|
||||
// Wait for link up (netif up means PHY link is established)
|
||||
unsigned long t0 = millis();
|
||||
while (!esp_netif_is_netif_up(eth_netif) && millis() - t0 < 5000) {
|
||||
esp_task_wdt_reset();
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// Wait for DHCP IP assignment
|
||||
esp_netif_ip_info_t ip_info = {};
|
||||
t0 = millis();
|
||||
while (ip_info.ip.addr == 0 && millis() - t0 < 5000) {
|
||||
esp_task_wdt_reset();
|
||||
esp_netif_get_ip_info(eth_netif, &ip_info);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
if (ip_info.ip.addr == 0) {
|
||||
#ifdef ETH_STATIC_IP
|
||||
Serial.println("DHCP timeout, using static IP from build flags");
|
||||
#ifdef ETH_DNS
|
||||
applyStaticIp(IP4_NBO(ETH_STATIC_IP), IP4_NBO(ETH_GATEWAY),
|
||||
IP4_NBO(ETH_SUBNET), IP4_NBO(ETH_DNS));
|
||||
#else
|
||||
applyStaticIp(IP4_NBO(ETH_STATIC_IP), IP4_NBO(ETH_GATEWAY),
|
||||
IP4_NBO(ETH_SUBNET), 0);
|
||||
#endif
|
||||
#else
|
||||
Serial.println("DHCP timeout, using fallback IP");
|
||||
applyStaticIp(IP4_NBO(192, 168, 4, 2), IP4_NBO(192, 168, 4, 1),
|
||||
IP4_NBO(255, 255, 255, 0), 0);
|
||||
#endif
|
||||
} else {
|
||||
updateLocalIpString();
|
||||
}
|
||||
|
||||
Serial.printf("ETH MAC %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||
mac_addr[0], mac_addr[1], mac_addr[2],
|
||||
mac_addr[3], mac_addr[4], mac_addr[5]);
|
||||
Serial.printf("ETH IP %s\n", eth_local_ip.c_str());
|
||||
Serial.println(esp_netif_is_netif_up(eth_netif) ? "ETH LINK UP" : "ETH LINK DOWN");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_ETHERNET
|
||||
// Packed big-endian uint32 (b1 in MSB) → network-byte-order as stored in ip4_addr_t.addr
|
||||
// on little-endian ESP32. Host→net byte swap achieves exactly this layout.
|
||||
static inline uint32_t packedToNbo(uint32_t packed) {
|
||||
return __builtin_bswap32(packed);
|
||||
}
|
||||
#endif
|
||||
|
||||
void TEthEliteBoard::reconfigureEthernet(uint32_t ip, uint32_t gw, uint32_t subnet, uint32_t dns1) {
|
||||
#ifdef USE_ETHERNET
|
||||
if (ip == 0 || eth_netif == NULL) return;
|
||||
|
||||
applyStaticIp(packedToNbo(ip), packedToNbo(gw),
|
||||
packedToNbo(subnet), dns1 ? packedToNbo(dns1) : 0);
|
||||
Serial.printf("ETH reconfigured to %s\n", eth_local_ip.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
7
src/helpers/esp32/TEthEliteBoard.h
Normal file
7
src/helpers/esp32/TEthEliteBoard.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(T_ETH_ELITE_SX1262)
|
||||
#include "TEthEliteBoard_SX1262.h"
|
||||
#elif defined(T_ETH_ELITE_SX1276)
|
||||
#include "TEthEliteBoard_SX1276.h"
|
||||
#endif
|
||||
102
src/helpers/esp32/TEthEliteBoard_SX1262.h
Normal file
102
src/helpers/esp32/TEthEliteBoard_SX1262.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(T_ETH_ELITE_SX1262)
|
||||
|
||||
// Define pin mappings BEFORE including ESP32Board.h so sleep() can use P_LORA_DIO_1
|
||||
|
||||
// LoRa SX1262 pins (T-ETH Elite LoRa Shield)
|
||||
#define P_LORA_NSS 40 // CS
|
||||
#define P_LORA_RESET 46 // RESET
|
||||
#define P_LORA_BUSY 16 // BUSY
|
||||
#define P_LORA_DIO_0 -1 // NC
|
||||
#define P_LORA_DIO_1 8 // IRQ
|
||||
#define P_LORA_TX_LED 38
|
||||
#define P_LORA_SCLK 10
|
||||
#define P_LORA_MISO 9
|
||||
#define P_LORA_MOSI 11
|
||||
#define P_LORA_WAKE_DIO P_LORA_DIO_1 // DIO used as deep-sleep wake source
|
||||
|
||||
// ETH W5500 pins (T-ETH Elite main board)
|
||||
#define ETH_MISO 47
|
||||
#define ETH_MOSI 21
|
||||
#define ETH_SCLK 48
|
||||
#define ETH_CS 45
|
||||
#define ETH_INT 14
|
||||
#define ETH_RST -1
|
||||
#define ETH_ADDR 1
|
||||
|
||||
// I2C bus (Wire1)
|
||||
#define PIN_BOARD_SDA1 17
|
||||
#define PIN_BOARD_SCL1 18
|
||||
|
||||
// GPS pins (LoRa Shield)
|
||||
#define PIN_GPS_RX 39
|
||||
#define PIN_GPS_TX 42
|
||||
#define PIN_GPS_EN -1
|
||||
|
||||
// Analog button
|
||||
// #define PIN_USER_BTN_ANA 7
|
||||
|
||||
// Include headers AFTER pin definitions so ESP32Board::sleep() can use P_LORA_DIO_1
|
||||
#include <Wire.h>
|
||||
#include <Arduino.h>
|
||||
#include "XPowersLib.h"
|
||||
#include "helpers/ESP32Board.h"
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
class TEthEliteBoard : public ESP32Board {
|
||||
XPowersLibInterface *PMU = NULL;
|
||||
|
||||
enum {
|
||||
POWERMANAGE_ONLINE = _BV(0),
|
||||
DISPLAY_ONLINE = _BV(1),
|
||||
RADIO_ONLINE = _BV(2),
|
||||
GPS_ONLINE = _BV(3),
|
||||
PSRAM_ONLINE = _BV(4),
|
||||
SDCARD_ONLINE = _BV(5),
|
||||
AXDL345_ONLINE = _BV(6),
|
||||
BME280_ONLINE = _BV(7),
|
||||
BMP280_ONLINE = _BV(8),
|
||||
BME680_ONLINE = _BV(9),
|
||||
QMC6310_ONLINE = _BV(10),
|
||||
QMI8658_ONLINE = _BV(11),
|
||||
PCF8563_ONLINE = _BV(12),
|
||||
OSC32768_ONLINE = _BV(13),
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
#ifdef MESH_DEBUG
|
||||
void printPMU();
|
||||
void scanDevices(TwoWire *w);
|
||||
#endif
|
||||
void begin();
|
||||
void startNetwork();
|
||||
void startEthernet();
|
||||
void startWifi();
|
||||
void reconfigureEthernet(uint32_t ip, uint32_t gw, uint32_t subnet, uint32_t dns1 = 0);
|
||||
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_WAKE_DIO, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_WAKE_DIO);
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
uint64_t wake_mask = 1ULL << P_LORA_WAKE_DIO;
|
||||
if (pin_wake_btn >= 0) wake_mask |= 1ULL << pin_wake_btn;
|
||||
esp_sleep_enable_ext1_wakeup(wake_mask, ESP_EXT1_WAKEUP_ANY_HIGH);
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
uint16_t getBattMilliVolts() { return 0; }
|
||||
|
||||
const char* getManufacturerName() const { return "LilyGo T-ETH-Elite"; }
|
||||
};
|
||||
|
||||
#endif
|
||||
102
src/helpers/esp32/TEthEliteBoard_SX1276.h
Normal file
102
src/helpers/esp32/TEthEliteBoard_SX1276.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(T_ETH_ELITE_SX1276)
|
||||
|
||||
// Define pin mappings BEFORE including ESP32Board.h so sleep() can use P_LORA_DIO_0
|
||||
|
||||
// LoRa SX1276 pins (T-ETH Elite LoRa Shield)
|
||||
#define P_LORA_DIO_0 8 // IRQ (DIO0 on SX1276)
|
||||
#define P_LORA_DIO_1 16 // DIO1
|
||||
#define P_LORA_NSS 40 // CS
|
||||
#define P_LORA_RESET 46 // RESET
|
||||
#define P_LORA_BUSY -1 // SX1276 has no BUSY pin
|
||||
#define P_LORA_TX_LED 38
|
||||
#define P_LORA_SCLK 10
|
||||
#define P_LORA_MISO 9
|
||||
#define P_LORA_MOSI 11
|
||||
#define P_LORA_WAKE_DIO P_LORA_DIO_0 // DIO used as deep-sleep wake source
|
||||
|
||||
// ETH W5500 pins (T-ETH Elite main board)
|
||||
#define ETH_MISO 47
|
||||
#define ETH_MOSI 21
|
||||
#define ETH_SCLK 48
|
||||
#define ETH_CS 45
|
||||
#define ETH_INT 14
|
||||
#define ETH_RST -1
|
||||
#define ETH_ADDR 1
|
||||
|
||||
// I2C bus (Wire1)
|
||||
#define PIN_BOARD_SDA1 17
|
||||
#define PIN_BOARD_SCL1 18
|
||||
|
||||
// GPS pins (LoRa Shield)
|
||||
#define PIN_GPS_RX 39
|
||||
#define PIN_GPS_TX 42
|
||||
#define PIN_GPS_EN -1
|
||||
|
||||
// Analog button
|
||||
// #define PIN_USER_BTN_ANA 7
|
||||
|
||||
// Include headers AFTER pin definitions so ESP32Board::sleep() can use P_LORA_DIO_0
|
||||
#include <Wire.h>
|
||||
#include <Arduino.h>
|
||||
#include "XPowersLib.h"
|
||||
#include "helpers/ESP32Board.h"
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
class TEthEliteBoard : public ESP32Board {
|
||||
XPowersLibInterface *PMU = NULL;
|
||||
|
||||
enum {
|
||||
POWERMANAGE_ONLINE = _BV(0),
|
||||
DISPLAY_ONLINE = _BV(1),
|
||||
RADIO_ONLINE = _BV(2),
|
||||
GPS_ONLINE = _BV(3),
|
||||
PSRAM_ONLINE = _BV(4),
|
||||
SDCARD_ONLINE = _BV(5),
|
||||
AXDL345_ONLINE = _BV(6),
|
||||
BME280_ONLINE = _BV(7),
|
||||
BMP280_ONLINE = _BV(8),
|
||||
BME680_ONLINE = _BV(9),
|
||||
QMC6310_ONLINE = _BV(10),
|
||||
QMI8658_ONLINE = _BV(11),
|
||||
PCF8563_ONLINE = _BV(12),
|
||||
OSC32768_ONLINE = _BV(13),
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
#ifdef MESH_DEBUG
|
||||
void printPMU();
|
||||
void scanDevices(TwoWire *w);
|
||||
#endif
|
||||
void begin();
|
||||
void startNetwork();
|
||||
void startEthernet();
|
||||
void startWifi();
|
||||
void reconfigureEthernet(uint32_t ip, uint32_t gw, uint32_t subnet, uint32_t dns1 = 0);
|
||||
|
||||
void enterDeepSleep(uint32_t secs, int pin_wake_btn) {
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
rtc_gpio_set_direction((gpio_num_t)P_LORA_WAKE_DIO, RTC_GPIO_MODE_INPUT_ONLY);
|
||||
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_WAKE_DIO);
|
||||
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
|
||||
|
||||
uint64_t wake_mask = 1ULL << P_LORA_WAKE_DIO;
|
||||
if (pin_wake_btn >= 0) wake_mask |= 1ULL << pin_wake_btn;
|
||||
esp_sleep_enable_ext1_wakeup(wake_mask, ESP_EXT1_WAKEUP_ANY_HIGH);
|
||||
|
||||
if (secs > 0) {
|
||||
esp_sleep_enable_timer_wakeup(secs * 1000000);
|
||||
}
|
||||
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
uint16_t getBattMilliVolts() { return 0; }
|
||||
|
||||
const char* getManufacturerName() const { return "LilyGo T-ETH-Elite"; }
|
||||
};
|
||||
|
||||
#endif
|
||||
204
variants/lilygo_t_eth_elite_sx1262/platformio.ini
Normal file
204
variants/lilygo_t_eth_elite_sx1262/platformio.ini
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
[LilyGo_T_ETH_Elite_SX1262]
|
||||
extends = esp32_base
|
||||
board = t_eth_elite
|
||||
upload_protocol = esptool
|
||||
board_build.partitions = default_16MB.csv
|
||||
board_upload.flash_size = 16MB
|
||||
board_upload.maximum_size = 16777216
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-I variants/lilygo_t_eth_elite_sx1262
|
||||
-D T_ETH_ELITE_SX1262
|
||||
-D RADIO_CLASS=CustomSX1262
|
||||
-D WRAPPER_CLASS=CustomSX1262Wrapper
|
||||
-D SX126X_CURRENT_LIMIT=140
|
||||
-D SX126X_RX_BOOSTED_GAIN=1
|
||||
-D LORA_TX_POWER=22
|
||||
-D ENV_INCLUDE_GPS=1
|
||||
-D PIN_GPS_RX=39
|
||||
-D PIN_GPS_TX=42
|
||||
-D PIN_GPS_EN=-1
|
||||
-D PIN_USER_BTN_ANA=7
|
||||
|
||||
build_src_filter = ${esp32_base.build_src_filter}
|
||||
+<../variants/lilygo_t_eth_elite_sx1262>
|
||||
+<helpers/esp32/TEthEliteBoard.cpp>
|
||||
+<helpers/sensors>
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
lewisxhe/XPowersLib @ ^0.2.7
|
||||
stevemarple/MicroNMEA @ ^2.0.6
|
||||
adafruit/Adafruit BME280 Library @ ^2.3.0
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1262_repeater]
|
||||
extends = LilyGo_T_ETH_Elite_SX1262
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1262.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1262 Repeater"'
|
||||
-D ADVERT_LAT=0
|
||||
-D ADVERT_LON=0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1262.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1262_repeater_eth]
|
||||
extends = LilyGo_T_ETH_Elite_SX1262
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1262.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1262 Repeater eth"'
|
||||
-D ADVERT_LAT=0
|
||||
-D ADVERT_LON=0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D USE_ETHERNET
|
||||
-D ETH_STATIC_IP=192,168,254,21
|
||||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1262.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1262_repeater_bridge_espnow]
|
||||
extends = LilyGo_T_ETH_Elite_SX1262
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1262.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1262 ESPNow Bridge"'
|
||||
-D ADVERT_LAT=0
|
||||
-D ADVERT_LON=0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_ESPNOW_BRIDGE=1
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<helpers/bridges/ESPNowBridge.cpp>
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1262.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1262_repeater_bridge_espnow_eth]
|
||||
extends = LilyGo_T_ETH_Elite_SX1262
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1262.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1262 ESPNow Bridge eth"'
|
||||
-D ADVERT_LAT=0
|
||||
-D ADVERT_LON=0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_ESPNOW_BRIDGE=1
|
||||
-D USE_ETHERNET
|
||||
-D ETH_STATIC_IP=192,168,254,20
|
||||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<helpers/bridges/ESPNowBridge.cpp>
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1262.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1262_room_server]
|
||||
extends = LilyGo_T_ETH_Elite_SX1262
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1262.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1262 Room"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<../examples/simple_room_server>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1262.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1262_room_server_eth]
|
||||
extends = LilyGo_T_ETH_Elite_SX1262
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1262.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1262 Room eth"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D USE_ETHERNET
|
||||
-D ETH_STATIC_IP=192,168,254,20
|
||||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<../examples/simple_room_server>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1262.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1262_companion_radio_eth]
|
||||
extends = LilyGo_T_ETH_Elite_SX1262
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1262.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D MAX_CONTACTS=350
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D OFFLINE_QUEUE_SIZE=256
|
||||
-D USE_ETHERNET
|
||||
-D ETH_STATIC_IP=192,168,254,20
|
||||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1262.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1262_companion_radio_wifi]
|
||||
extends = LilyGo_T_ETH_Elite_SX1262
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1262.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D MAX_CONTACTS=350
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D OFFLINE_QUEUE_SIZE=256
|
||||
-D WIFI_SSID='"WIFI_SSID"'
|
||||
-D WIFI_PWD='"Password"'
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1262.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1262_companion_radio_ble]
|
||||
extends = LilyGo_T_ETH_Elite_SX1262
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1262.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D MAX_CONTACTS=350
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D BLE_PIN_CODE=123456
|
||||
-D OFFLINE_QUEUE_SIZE=256
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1262.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
62
variants/lilygo_t_eth_elite_sx1262/target.cpp
Normal file
62
variants/lilygo_t_eth_elite_sx1262/target.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include <Arduino.h>
|
||||
#include "helpers/ui/MomentaryButton.h"
|
||||
#include "target.h"
|
||||
|
||||
TEthEliteBoard board;
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
DISPLAY_CLASS display;
|
||||
#endif
|
||||
|
||||
#ifdef PIN_USER_BTN_ANA
|
||||
// If the analog pin is defined, use it for both button instances
|
||||
MomentaryButton user_btn(PIN_USER_BTN_ANA, 1000, true);
|
||||
MomentaryButton analog_btn(PIN_USER_BTN_ANA, 1000, true); // alias for UITask analog button support
|
||||
#else
|
||||
// If NOT defined, route user_btn to pin 0
|
||||
// and create analog_btn as a dummy alias to satisfy UITask requirements
|
||||
MomentaryButton user_btn(0, 1000, true);
|
||||
MomentaryButton analog_btn(0, 1000, true);
|
||||
#endif
|
||||
|
||||
static SPIClass spi;
|
||||
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
|
||||
|
||||
WRAPPER_CLASS radio_driver(radio, board);
|
||||
|
||||
ESP32RTCClock fallback_clock;
|
||||
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||
|
||||
#if ENV_INCLUDE_GPS
|
||||
#include <helpers/sensors/MicroNMEALocationProvider.h>
|
||||
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
|
||||
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
|
||||
#else
|
||||
EnvironmentSensorManager sensors;
|
||||
#endif
|
||||
|
||||
bool radio_init() {
|
||||
fallback_clock.begin();
|
||||
rtc_clock.begin(Wire1);
|
||||
return radio.std_init(&spi);
|
||||
}
|
||||
|
||||
uint32_t radio_get_rng_seed() {
|
||||
return radio.random(0x7FFFFFFF);
|
||||
}
|
||||
|
||||
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
|
||||
radio.setFrequency(freq);
|
||||
radio.setSpreadingFactor(sf);
|
||||
radio.setBandwidth(bw);
|
||||
radio.setCodingRate(cr);
|
||||
}
|
||||
|
||||
void radio_set_tx_power(int8_t dbm) {
|
||||
radio.setOutputPower(dbm);
|
||||
}
|
||||
|
||||
mesh::LocalIdentity radio_new_identity() {
|
||||
RadioNoiseListener rng(radio);
|
||||
return mesh::LocalIdentity(&rng);
|
||||
}
|
||||
32
variants/lilygo_t_eth_elite_sx1262/target.h
Normal file
32
variants/lilygo_t_eth_elite_sx1262/target.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#define RADIOLIB_STATIC_ONLY 1
|
||||
#include <RadioLib.h>
|
||||
#include <helpers/radiolib/RadioLibWrappers.h>
|
||||
#include <helpers/esp32/TEthEliteBoard.h>
|
||||
#include <helpers/radiolib/CustomSX1262Wrapper.h>
|
||||
#include <helpers/AutoDiscoverRTCClock.h>
|
||||
#include <helpers/sensors/EnvironmentSensorManager.h>
|
||||
#include <helpers/ui/MomentaryButton.h>
|
||||
|
||||
extern MomentaryButton user_btn;
|
||||
|
||||
#ifdef PIN_USER_BTN_ANA
|
||||
extern MomentaryButton analog_btn;
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include <helpers/ui/SH1106Display.h>
|
||||
extern DISPLAY_CLASS display;
|
||||
#endif
|
||||
|
||||
extern TEthEliteBoard board;
|
||||
extern WRAPPER_CLASS radio_driver;
|
||||
extern AutoDiscoverRTCClock rtc_clock;
|
||||
extern EnvironmentSensorManager sensors;
|
||||
|
||||
bool radio_init();
|
||||
uint32_t radio_get_rng_seed();
|
||||
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
|
||||
void radio_set_tx_power(int8_t dbm);
|
||||
mesh::LocalIdentity radio_new_identity();
|
||||
202
variants/lilygo_t_eth_elite_sx1276/platformio.ini
Normal file
202
variants/lilygo_t_eth_elite_sx1276/platformio.ini
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
[LilyGo_T_ETH_Elite_SX1276]
|
||||
extends = esp32_base
|
||||
board = t_eth_elite
|
||||
upload_protocol = esptool
|
||||
board_build.partitions = default_16MB.csv
|
||||
board_upload.flash_size = 16MB
|
||||
board_upload.maximum_size = 16777216
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-I variants/lilygo_t_eth_elite_sx1276
|
||||
-D T_ETH_ELITE_SX1276
|
||||
-D RADIO_CLASS=CustomSX1276
|
||||
-D WRAPPER_CLASS=CustomSX1276Wrapper
|
||||
-D SX127X_CURRENT_LIMIT=120
|
||||
-D LORA_TX_POWER=20
|
||||
-D ENV_INCLUDE_GPS=1
|
||||
-D PIN_GPS_RX=39
|
||||
-D PIN_GPS_TX=42
|
||||
-D PIN_GPS_EN=-1
|
||||
-D PIN_USER_BTN_ANA=7
|
||||
build_src_filter = ${esp32_base.build_src_filter}
|
||||
+<../variants/lilygo_t_eth_elite_sx1276>
|
||||
+<helpers/esp32/TEthEliteBoard.cpp>
|
||||
+<helpers/sensors>
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
lewisxhe/XPowersLib @ ^0.2.7
|
||||
stevemarple/MicroNMEA @ ^2.0.6
|
||||
adafruit/Adafruit BME280 Library @ ^2.3.0
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1276_repeater]
|
||||
extends = LilyGo_T_ETH_Elite_SX1276
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1276.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1276 Repeater"'
|
||||
-D ADVERT_LAT=0
|
||||
-D ADVERT_LON=0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1276.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1276_repeater_eth]
|
||||
extends = LilyGo_T_ETH_Elite_SX1276
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1276.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1276 Repeater eth"'
|
||||
-D ADVERT_LAT=0
|
||||
-D ADVERT_LON=0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D USE_ETHERNET
|
||||
-D ETH_STATIC_IP=192,168,254,21
|
||||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1276.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1276_repeater_bridge_espnow]
|
||||
extends = LilyGo_T_ETH_Elite_SX1276
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1276.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1276 ESPNow Bridge"'
|
||||
-D ADVERT_LAT=0
|
||||
-D ADVERT_LON=0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_ESPNOW_BRIDGE=1
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<helpers/bridges/ESPNowBridge.cpp>
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1276.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1276_repeater_bridge_espnow_eth]
|
||||
extends = LilyGo_T_ETH_Elite_SX1276
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1276.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1276 ESPNow Bridge eth"'
|
||||
-D ADVERT_LAT=0
|
||||
-D ADVERT_LON=0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_ESPNOW_BRIDGE=1
|
||||
-D USE_ETHERNET
|
||||
-D ETH_STATIC_IP=192,168,254,20
|
||||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<helpers/bridges/ESPNowBridge.cpp>
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1276.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1276_room_server]
|
||||
extends = LilyGo_T_ETH_Elite_SX1276
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1276.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1276 Room"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<../examples/simple_room_server>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1276.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1276_room_server_eth]
|
||||
extends = LilyGo_T_ETH_Elite_SX1276
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1276.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1276 Room eth"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D USE_ETHERNET
|
||||
-D ETH_STATIC_IP=192,168,254,20
|
||||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<../examples/simple_room_server>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1276.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1276_companion_radio_eth]
|
||||
extends = LilyGo_T_ETH_Elite_SX1276
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1276.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D MAX_CONTACTS=350
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D OFFLINE_QUEUE_SIZE=256
|
||||
-D USE_ETHERNET
|
||||
-D ETH_STATIC_IP=192,168,254,20
|
||||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1276.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1276_companion_radio_wifi]
|
||||
extends = LilyGo_T_ETH_Elite_SX1276
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1276.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D MAX_CONTACTS=350
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D OFFLINE_QUEUE_SIZE=256
|
||||
-D WIFI_SSID='"WIFI_SSID"'
|
||||
-D WIFI_PWD='"Password"'
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1276.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
|
||||
[env:LilyGo_T_ETH_Elite_SX1276_companion_radio_ble]
|
||||
extends = LilyGo_T_ETH_Elite_SX1276
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1276.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D MAX_CONTACTS=350
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D BLE_PIN_CODE=123456
|
||||
-D OFFLINE_QUEUE_SIZE=256
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_T_ETH_Elite_SX1276.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
65
variants/lilygo_t_eth_elite_sx1276/target.cpp
Normal file
65
variants/lilygo_t_eth_elite_sx1276/target.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#include <Arduino.h>
|
||||
#include "helpers/ui/MomentaryButton.h"
|
||||
#include "target.h"
|
||||
|
||||
TEthEliteBoard board;
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
DISPLAY_CLASS display;
|
||||
#endif
|
||||
|
||||
#ifdef PIN_USER_BTN_ANA
|
||||
// If the analog pin is defined, use it for both button instances
|
||||
MomentaryButton user_btn(PIN_USER_BTN_ANA, 1000, true);
|
||||
MomentaryButton analog_btn(PIN_USER_BTN_ANA, 1000, true); // alias for UITask analog button support
|
||||
#else
|
||||
// If NOT defined, route user_btn to pin 0
|
||||
// and create analog_btn as a dummy alias to satisfy UITask requirements
|
||||
MomentaryButton user_btn(0, 1000, true);
|
||||
MomentaryButton analog_btn(0, 1000, true);
|
||||
#endif
|
||||
|
||||
static SPIClass spi;
|
||||
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
|
||||
|
||||
WRAPPER_CLASS radio_driver(radio, board);
|
||||
|
||||
ESP32RTCClock fallback_clock;
|
||||
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||
|
||||
#if ENV_INCLUDE_GPS
|
||||
#include <helpers/sensors/MicroNMEALocationProvider.h>
|
||||
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
|
||||
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
|
||||
#else
|
||||
EnvironmentSensorManager sensors;
|
||||
#endif
|
||||
|
||||
bool radio_init() {
|
||||
fallback_clock.begin();
|
||||
rtc_clock.begin(Wire1);
|
||||
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
|
||||
bool ok = radio.std_init(&spi);
|
||||
delay(100); // allow SX1276 to stabilize after init
|
||||
return ok;
|
||||
}
|
||||
|
||||
uint32_t radio_get_rng_seed() {
|
||||
return radio.random(0x7FFFFFFF);
|
||||
}
|
||||
|
||||
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
|
||||
radio.setFrequency(freq);
|
||||
radio.setSpreadingFactor(sf);
|
||||
radio.setBandwidth(bw);
|
||||
radio.setCodingRate(cr);
|
||||
}
|
||||
|
||||
void radio_set_tx_power(int8_t dbm) {
|
||||
radio.setOutputPower(dbm);
|
||||
}
|
||||
|
||||
mesh::LocalIdentity radio_new_identity() {
|
||||
RadioNoiseListener rng(radio);
|
||||
return mesh::LocalIdentity(&rng);
|
||||
}
|
||||
32
variants/lilygo_t_eth_elite_sx1276/target.h
Normal file
32
variants/lilygo_t_eth_elite_sx1276/target.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#define RADIOLIB_STATIC_ONLY 1
|
||||
#include <RadioLib.h>
|
||||
#include <helpers/radiolib/RadioLibWrappers.h>
|
||||
#include <helpers/esp32/TEthEliteBoard.h>
|
||||
#include <helpers/radiolib/CustomSX1276Wrapper.h>
|
||||
#include <helpers/AutoDiscoverRTCClock.h>
|
||||
#include <helpers/sensors/EnvironmentSensorManager.h>
|
||||
#include <helpers/ui/MomentaryButton.h>
|
||||
|
||||
extern MomentaryButton user_btn;
|
||||
|
||||
#ifdef PIN_USER_BTN_ANA
|
||||
extern MomentaryButton analog_btn;
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include <helpers/ui/SH1106Display.h>
|
||||
extern DISPLAY_CLASS display;
|
||||
#endif
|
||||
|
||||
extern TEthEliteBoard board;
|
||||
extern WRAPPER_CLASS radio_driver;
|
||||
extern AutoDiscoverRTCClock rtc_clock;
|
||||
extern EnvironmentSensorManager sensors;
|
||||
|
||||
bool radio_init();
|
||||
uint32_t radio_get_rng_seed();
|
||||
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
|
||||
void radio_set_tx_power(int8_t dbm);
|
||||
mesh::LocalIdentity radio_new_identity();
|
||||
Loading…
Add table
Add a link
Reference in a new issue