mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-11-04 10:57:27 +00:00
Detect SX126x and SX127x in universal T-Beam and T3 S3 builds
This commit is contained in:
1 parent
14b6a0aed1
commit
23f94adf3d
16 files changed
+1135
-13
No files matched your search
+17
-9
@@ -506,6 +506,8 @@ for section, options in data:
|
||||
Ebyte_EoRa-S3_companion_radio_ble
|
||||
Tbeam_SX1262_companion_radio_ble
|
||||
Tbeam_SX1276_companion_radio_ble
|
||||
Tbeam_companion_radio_ble
|
||||
LilyGo_T3S3_companion_radio_ble
|
||||
T_Beam_S3_Supreme_SX1262_companion_radio_ble
|
||||
heltec_v4_expansionkit_tft_companion_radio_ble_femon
|
||||
)
|
||||
@@ -2482,8 +2484,8 @@ get_unified_full_infrastructure_target() {
|
||||
# T-Beam keeps the observer as its ordinary release choice. TLora retains
|
||||
# both identities: its UART cannot fit alongside MQTT and ESP-NOW.
|
||||
case "${mqtt_base,,}" in
|
||||
tbeam_sx1262_repeater|tbeam_sx1276_repeater|\
|
||||
tbeam_sx1262_room_server|tbeam_sx1276_room_server|\
|
||||
tbeam_repeater|tbeam_sx1262_repeater|tbeam_sx1276_repeater|\
|
||||
tbeam_room_server|tbeam_sx1262_room_server|tbeam_sx1276_room_server|\
|
||||
lilygo_tlora_v2_1_1_6_repeater) return 1 ;;
|
||||
esac
|
||||
|
||||
@@ -3100,12 +3102,13 @@ requires_dram_limited_neighbors() {
|
||||
heltec_v2_repeater_lora_ota_no_external_sensors|\
|
||||
meshadventurer_sx1262_repeater_lora_ota_no_external_sensors|\
|
||||
meshadventurer_sx1268_repeater_lora_ota_no_external_sensors|\
|
||||
tbeam_repeater_lora_ota_no_external_sensors|\
|
||||
tbeam_sx1262_repeater_lora_ota_no_external_sensors|\
|
||||
tbeam_sx1276_repeater_lora_ota_no_external_sensors)
|
||||
return 0 ;;
|
||||
generic_e22_sx1262_repeater|generic_e22_sx1268_repeater|\
|
||||
heltec_v2_repeater|meshadventurer_sx1262_repeater|\
|
||||
meshadventurer_sx1268_repeater|tbeam_sx1262_repeater|\
|
||||
meshadventurer_sx1268_repeater|tbeam_repeater|tbeam_sx1262_repeater|\
|
||||
tbeam_sx1276_repeater)
|
||||
if [ "$ESP32_FULL_BUILD" = "1" ]; then return 0; fi ;;
|
||||
esac
|
||||
@@ -3123,6 +3126,7 @@ requires_dram_limited_neighbors() {
|
||||
|lilygo_tlora_v2_1_1_6_repeater_bridge_rs232 \
|
||||
|meshadventurer_sx1262_repeater_bridge_espnow \
|
||||
|meshadventurer_sx1268_repeater_bridge_espnow \
|
||||
|tbeam_repeater_bridge_espnow \
|
||||
|tbeam_sx1262_repeater_bridge_espnow \
|
||||
|tbeam_sx1276_repeater_bridge_espnow)
|
||||
return 0
|
||||
@@ -3132,7 +3136,7 @@ requires_dram_limited_neighbors() {
|
||||
case "${1,,}" in
|
||||
lilygo_tlora_v2_1_1_6_repeater_observer_mqtt_)
|
||||
return 0 ;;
|
||||
tbeam_sx1262_repeater_observer_mqtt|tbeam_sx1262_room_server_observer_mqtt|tbeam_sx1276_repeater_observer_mqtt|tbeam_sx1276_room_server_observer_mqtt|rak_3x72_repeater|tiny_relay_repeater|wio-e5-mini_repeater|wio-e5-repeater_bridge_rs232|wio-e5_repeater) return 0 ;;
|
||||
tbeam_repeater_observer_mqtt|tbeam_room_server_observer_mqtt|tbeam_sx1262_repeater_observer_mqtt|tbeam_sx1262_room_server_observer_mqtt|tbeam_sx1276_repeater_observer_mqtt|tbeam_sx1276_room_server_observer_mqtt|rak_3x72_repeater|tiny_relay_repeater|wio-e5-mini_repeater|wio-e5-repeater_bridge_rs232|wio-e5_repeater) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
@@ -3438,6 +3442,7 @@ is_esp32_partition_migration_full_target() {
|
||||
ebyte_eora-s3_repeater|ebyte_eora-s3_room_server|\
|
||||
generic_e22_sx1262_repeater|generic_e22_sx1268_repeater|\
|
||||
heltec_ct62_repeater|heltec_ct62_sensor|\
|
||||
lilygo_t3s3_repeater|lilygo_t3s3_room_server|\
|
||||
lilygo_t3s3_sx1262_repeater|lilygo_t3s3_sx1262_room_server|\
|
||||
lilygo_t3s3_sx1276_repeater|lilygo_t3s3_sx1276_room_server|\
|
||||
station_g2_repeater|station_g2_logging_repeater|station_g2_room_server|\
|
||||
@@ -3846,6 +3851,8 @@ apply_esp32_constrained_companion_size_profile() {
|
||||
station_g2_companion_radio_ble \
|
||||
|thinknode_m2_companion_radio_ble \
|
||||
|thinknode_m2_companion_radio_wifi \
|
||||
|lilygo_t3s3_companion_radio_ble \
|
||||
|lilygo_t3s3_companion_radio_ble_ps \
|
||||
|lilygo_t3s3_sx1262_companion_radio_ble \
|
||||
|lilygo_t3s3_sx1262_companion_radio_ble_ps \
|
||||
|lilygo_t3s3_sx1276_companion_radio_ble \
|
||||
@@ -3872,8 +3879,8 @@ apply_esp32_iram_advert_storage_profile() {
|
||||
lilygo_tlora_v2_1_1_6_repeater_observer_mqtt|lilygo_tlora_v2_1_1_6_repeater_observer_mqtt_|\
|
||||
lilygo_tlora_v2_1_1_6_room_server|lilygo_tlora_v2_1_1_6_room_server_|\
|
||||
lilygo_tlora_v2_1_1_6_room_server_observer_mqtt|lilygo_tlora_v2_1_1_6_room_server_observer_mqtt_|\
|
||||
tbeam_sx1262_repeater_observer_mqtt|tbeam_sx1276_repeater_observer_mqtt|\
|
||||
tbeam_sx1262_room_server_observer_mqtt|tbeam_sx1276_room_server_observer_mqtt)
|
||||
tbeam_repeater_observer_mqtt|tbeam_sx1262_repeater_observer_mqtt|tbeam_sx1276_repeater_observer_mqtt|\
|
||||
tbeam_room_server_observer_mqtt|tbeam_sx1262_room_server_observer_mqtt|tbeam_sx1276_room_server_observer_mqtt)
|
||||
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFLOOD_ADVERT_IRAM_WORD_STORAGE=1"
|
||||
;;
|
||||
esac
|
||||
@@ -3909,13 +3916,13 @@ apply_esp32_full_size_profile() {
|
||||
case "${env_name,,}" in
|
||||
lilygo_tlora_v2_1_1_6_room_server|lilygo_tlora_v2_1_1_6_room_server_|\
|
||||
lilygo_tlora_v2_1_1_6_room_server_observer_mqtt|lilygo_tlora_v2_1_1_6_room_server_observer_mqtt_|\
|
||||
tbeam_sx1262_room_server_observer_mqtt|tbeam_sx1276_room_server_observer_mqtt)
|
||||
tbeam_room_server_observer_mqtt|tbeam_sx1262_room_server_observer_mqtt|tbeam_sx1276_room_server_observer_mqtt)
|
||||
# Preserve all 32 Room posts in genuine byte-accessible RTC SLOW memory.
|
||||
# The bounded proof implementation serves the same maximum 4096 leaves
|
||||
# without retaining the legacy 16 KiB leaf cache alongside Room services.
|
||||
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DROOM_POSTS_RTC_SLOW_STORAGE=1 -DOTA_BOUNDED_SOURCE_PROOFS=1"
|
||||
;;
|
||||
tbeam_sx1262_repeater_observer_mqtt|tbeam_sx1276_repeater_observer_mqtt)
|
||||
tbeam_repeater_observer_mqtt|tbeam_sx1262_repeater_observer_mqtt|tbeam_sx1276_repeater_observer_mqtt)
|
||||
# MQTT/TLS plus OTA left only 3.3 KiB of static-region headroom with
|
||||
# 63 rules. Retain the complete rule engine with a 31-entry table.
|
||||
append_platformio_build_unflags "-DFLOOD_PACKET_FILTER_SLOTS=63"
|
||||
@@ -3929,6 +3936,7 @@ apply_esp32_full_size_profile() {
|
||||
lilygo_tlora_v2_1_1_6_repeater_bridge_espnow|\
|
||||
meshadventurer_sx1262_repeater_bridge_espnow|\
|
||||
meshadventurer_sx1268_repeater_bridge_espnow|\
|
||||
tbeam_repeater_bridge_espnow|\
|
||||
tbeam_sx1262_repeater_bridge_espnow|\
|
||||
tbeam_sx1276_repeater_bridge_espnow)
|
||||
if [ "${PACKET_LOGGING_OVERRIDE,,}" = "on" ]; then
|
||||
@@ -7132,7 +7140,7 @@ get_ordinary_full_priority() {
|
||||
case "${base,,}" in
|
||||
*_observer_mqtt) echo 20 ;;
|
||||
*_bridge_espnow) echo 10 ;;
|
||||
tbeam_sx1262_repeater|tbeam_sx1276_repeater) echo 0 ;;
|
||||
tbeam_repeater|tbeam_sx1262_repeater|tbeam_sx1276_repeater) echo 0 ;;
|
||||
*)
|
||||
# G2's deployed Full identity is the observer. Other audited plain
|
||||
# targets keep their own identity, with observer sources where needed.
|
||||
|
||||
@@ -578,6 +578,7 @@ def select_ordinary_full_records(records: list[dict]) -> list[dict]:
|
||||
"station_g2_repeater", "station_g2_room_server",
|
||||
"tbeam_sx1262_repeater", "tbeam_sx1276_repeater",
|
||||
"tbeam_sx1262_room_server", "tbeam_sx1276_room_server",
|
||||
"tbeam_repeater", "tbeam_room_server",
|
||||
}
|
||||
# Capacity exceptions may still need a dedicated bridge. Old plain
|
||||
# Meshadventurer images without the linked driver must not supersede it.
|
||||
|
||||
@@ -6,6 +6,18 @@ import sys
|
||||
from optional_display_profiles import resolved_defines, spec_for_defines
|
||||
|
||||
SPECS = (
|
||||
dict(key="autoLoRaRadio", capability="radio.autodetect.sx126x_sx127x",
|
||||
marker="meshcore.capability.radio.autodetect.sx126x_sx127x.v1",
|
||||
platform="ESP32_PLATFORM", board="ttgo-t-beam",
|
||||
target=r"Tbeam_(?:repeater(?:_bridge_espnow)?|room_server|kiss_modem|companion_radio_(?:ble|usb|wifi|full)(?:_ps)?)(?:_observer_mqtt)?",
|
||||
defines={"MESH_RADIO_AUTO_FAMILY": "1", "RADIO_CLASS": "UniversalLoRaRadio",
|
||||
"WRAPPER_CLASS": "UniversalLoRaRadio"}),
|
||||
dict(key="autoLoRaRadio", capability="radio.autodetect.sx126x_sx127x",
|
||||
marker="meshcore.capability.radio.autodetect.sx126x_sx127x.v1",
|
||||
platform="ESP32_PLATFORM", board="t3_s3_v1_x",
|
||||
target=r"LilyGo_T3S3_(?:repeater(?:_bridge_espnow)?|room_server|kiss_modem|terminal_chat|companion_radio_(?:ble|usb|wifi|full)(?:_ps)?)(?:_observer_mqtt)?",
|
||||
defines={"MESH_RADIO_AUTO_FAMILY": "1", "RADIO_CLASS": "UniversalLoRaRadio",
|
||||
"WRAPPER_CLASS": "UniversalLoRaRadio"}),
|
||||
dict(key="unifiedV4Display", capability="display.heltec_v4.unified",
|
||||
marker="meshcore.capability.display.heltec_v4.unified.v1",
|
||||
platform="ESP32_PLATFORM", board="heltec_v4",
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "LoRaRadioFamily.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
// SX1276/78 and RFM9x share this register layout. SX1272 (0x22) does not.
|
||||
inline bool isSX1276Version(uint8_t version) {
|
||||
return version == 0x12 || version == 0x13 || version == 0x11;
|
||||
}
|
||||
|
||||
// IO supplies reset(), readSX127Version(), ready(), readSX126Version(),
|
||||
// now(), and pause(). Identification never starts RX, CAD or transmission.
|
||||
template <typename IO>
|
||||
LoRaRadioFamily probeLoRaChip(IO& io, uint32_t timeout_ms = 250) {
|
||||
io.reset();
|
||||
const uint8_t version = io.readSX127Version();
|
||||
if (isSX1276Version(version) && io.readSX127Version() == version)
|
||||
return LoRaRadioFamily::SX127x;
|
||||
|
||||
// Discard the unrecognized command/status left on an SX126x by the first
|
||||
// read. A reset enters RC standby, so no speculative mode-setting is needed.
|
||||
io.reset();
|
||||
const uint32_t started = io.now();
|
||||
while (uint32_t(io.now() - started) < timeout_ms) {
|
||||
if (io.ready()) {
|
||||
char signature[6] = {};
|
||||
char confirm[6] = {};
|
||||
// SX1262 intentionally reports the SX1261 family signature in RadioLib.
|
||||
if (io.readSX126Version(signature, sizeof(signature))
|
||||
&& memcmp(signature, "SX1261", sizeof(signature)) == 0
|
||||
&& io.ready()
|
||||
&& io.readSX126Version(confirm, sizeof(confirm))
|
||||
&& memcmp(signature, confirm, sizeof(signature)) == 0)
|
||||
return LoRaRadioFamily::SX126x;
|
||||
}
|
||||
io.pause(1);
|
||||
}
|
||||
return LoRaRadioFamily::None;
|
||||
}
|
||||
|
||||
} // namespace mesh
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mesh {
|
||||
enum class LoRaRadioFamily : uint8_t { None, SX126x, SX127x };
|
||||
}
|
||||
@@ -7,6 +7,10 @@
|
||||
#include <nvs.h>
|
||||
//#include <RadioLib.h>
|
||||
|
||||
#if defined(MESH_RADIO_AUTO_FAMILY) && MESH_RADIO_AUTO_FAMILY
|
||||
extern bool prepareUniversalLoRaRadio();
|
||||
#endif
|
||||
|
||||
uint32_t deviceOnline = 0x00;
|
||||
|
||||
#if !defined(PORTABLE_MQTT_OBSERVER) || defined(TBEAM_SUPREME_SX1262)
|
||||
@@ -42,17 +46,28 @@ void TBeamBoard::begin() {
|
||||
digitalWrite(P_LORA_TX_LED, HIGH); //inverted pin for SX1276 - HIGH for off
|
||||
#endif
|
||||
|
||||
//radiotype_detect();
|
||||
// The radio rail must be powered before probing. Selection also supplies
|
||||
// the actual wake IRQ before regulator/tuning setup runs in the role.
|
||||
#if defined(MESH_RADIO_AUTO_FAMILY) && MESH_RADIO_AUTO_FAMILY
|
||||
prepareUniversalLoRaRadio();
|
||||
#endif
|
||||
|
||||
esp_reset_reason_t reason = esp_reset_reason();
|
||||
if (reason == ESP_RST_DEEPSLEEP) {
|
||||
uint64_t wakeup_source = esp_sleep_get_ext1_wakeup_status();
|
||||
if (wakeup_source & (1ULL << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep)
|
||||
#if defined(MESH_RADIO_AUTO_FAMILY) && MESH_RADIO_AUTO_FAMILY
|
||||
const uint32_t radio_irq = getIRQGpio();
|
||||
#else
|
||||
const uint32_t radio_irq = P_LORA_DIO_1;
|
||||
#endif
|
||||
if (radio_irq != static_cast<uint32_t>(-1)
|
||||
&& (wakeup_source & (1ULL << radio_irq))) {
|
||||
startup_reason = BD_STARTUP_RX_PACKET;
|
||||
}
|
||||
|
||||
mesh::esp32::releaseRtcGpioIfSupported((gpio_num_t)P_LORA_NSS);
|
||||
mesh::esp32::deinitRtcGpioIfSupported((gpio_num_t)P_LORA_DIO_1);
|
||||
if (radio_irq != static_cast<uint32_t>(-1))
|
||||
mesh::esp32::deinitRtcGpioIfSupported((gpio_num_t)radio_irq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include <RadioLib.h>
|
||||
#include <helpers/LoRaChipProbe.h>
|
||||
#include <helpers/UsbLogging.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
struct LoRaChipProbePins {
|
||||
uint32_t nss;
|
||||
uint32_t reset;
|
||||
uint32_t busy;
|
||||
};
|
||||
|
||||
class ESP32LoRaChipProbeIO {
|
||||
SPIClass& spi_;
|
||||
const LoRaChipProbePins& pins_;
|
||||
public:
|
||||
ESP32LoRaChipProbeIO(SPIClass& spi, const LoRaChipProbePins& pins)
|
||||
: spi_(spi), pins_(pins) {}
|
||||
uint32_t now() const { return millis(); }
|
||||
void pause(uint32_t ms) {
|
||||
#if MESH_USB_CONSOLE_COOPERATIVE
|
||||
serviceUsbLoggingPort();
|
||||
serviceUsbTerminalPort();
|
||||
#endif
|
||||
delay(ms);
|
||||
}
|
||||
void reset() {
|
||||
digitalWrite(pins_.nss, HIGH);
|
||||
pinMode(pins_.nss, OUTPUT);
|
||||
pinMode(pins_.busy, INPUT_PULLDOWN);
|
||||
digitalWrite(pins_.reset, HIGH);
|
||||
pinMode(pins_.reset, OUTPUT);
|
||||
digitalWrite(pins_.reset, LOW);
|
||||
pause(1);
|
||||
digitalWrite(pins_.reset, HIGH);
|
||||
pause(10);
|
||||
}
|
||||
bool ready() const { return digitalRead(pins_.busy) == LOW; }
|
||||
uint8_t readSX127Version() {
|
||||
spi_.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(pins_.nss, LOW);
|
||||
spi_.transfer(0x42); // SX127x RegVersion; read, not write.
|
||||
const uint8_t version = spi_.transfer(0);
|
||||
digitalWrite(pins_.nss, HIGH);
|
||||
spi_.endTransaction();
|
||||
return version;
|
||||
}
|
||||
bool readSX126Version(char* data, size_t length) {
|
||||
if (!ready()) return false;
|
||||
spi_.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(pins_.nss, LOW);
|
||||
spi_.transfer(RADIOLIB_SX126X_CMD_READ_REGISTER);
|
||||
spi_.transfer(RADIOLIB_SX126X_REG_VERSION_STRING >> 8);
|
||||
spi_.transfer(RADIOLIB_SX126X_REG_VERSION_STRING & 0xff);
|
||||
spi_.transfer(0); // command status precedes register contents.
|
||||
for (size_t i = 0; i < length; ++i) data[i] = spi_.transfer(0);
|
||||
digitalWrite(pins_.nss, HIGH);
|
||||
spi_.endTransaction();
|
||||
delayMicroseconds(1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Caller powers the radio and starts this board's SPI pins first. Leave NSS
|
||||
// deselected; the chosen chip's normal initialization performs its own reset.
|
||||
inline LoRaRadioFamily probeUniversalLoRaChip(SPIClass& spi,
|
||||
const LoRaChipProbePins& pins) {
|
||||
ESP32LoRaChipProbeIO io(spi, pins);
|
||||
const auto family = probeLoRaChip(io);
|
||||
if (family == LoRaRadioFamily::SX127x) pinMode(pins.busy, INPUT);
|
||||
return family;
|
||||
}
|
||||
|
||||
} // namespace mesh
|
||||
@@ -259,7 +259,11 @@ protected:
|
||||
// The T096 SX1262 bench test found RSSI valid and stable by 7 ms after RX
|
||||
// entry, including the 500 kHz/SF5 worst-case profile. Retain the
|
||||
// conservative 20 ms path for the other radio families.
|
||||
#if defined(USE_SX1262) || defined(USE_SX1268) || defined(USE_LLCC68)
|
||||
#if defined(MESH_RADIO_AUTO_FAMILY) && MESH_RADIO_AUTO_FAMILY
|
||||
// A universal image shares this implementation across both families. Keep
|
||||
// SX127x's settling margin even in TUs that also include the SX126x wrapper.
|
||||
static constexpr uint32_t NoiseFloorSettleMillis = 20UL;
|
||||
#elif defined(USE_SX1262) || defined(USE_SX1268) || defined(USE_LLCC68)
|
||||
static constexpr uint32_t NoiseFloorSettleMillis = 7UL;
|
||||
#else
|
||||
static constexpr uint32_t NoiseFloorSettleMillis = 20UL;
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#if defined(MESH_RADIO_AUTO_FAMILY) && MESH_RADIO_AUTO_FAMILY
|
||||
|
||||
#include "UniversalLoRaRadio.h"
|
||||
#include <new>
|
||||
|
||||
extern const char meshcore_capability_universal_lora_radio[];
|
||||
const char meshcore_capability_universal_lora_radio[] __attribute__((used)) =
|
||||
"meshcore.capability.radio.autodetect.sx126x_sx127x.v1";
|
||||
|
||||
UniversalLoRaRadio::UniversalLoRaRadio(Module& sx126_module, Module& sx127_module,
|
||||
mesh::MainBoard& board)
|
||||
: sx126_module_(sx126_module), sx127_module_(sx127_module), board_(board) {}
|
||||
|
||||
UniversalLoRaRadio::~UniversalLoRaRadio() {
|
||||
if (family_ == mesh::LoRaRadioFamily::SX126x) {
|
||||
static_cast<CustomSX1262Wrapper*>(backend_)->~CustomSX1262Wrapper();
|
||||
static_cast<CustomSX1262*>(physical_)->~CustomSX1262();
|
||||
} else if (family_ == mesh::LoRaRadioFamily::SX127x) {
|
||||
static_cast<SX127Backend*>(backend_)->~SX127Backend();
|
||||
static_cast<CustomSX1276*>(physical_)->~CustomSX1276();
|
||||
}
|
||||
}
|
||||
|
||||
bool UniversalLoRaRadio::selectFamily(mesh::LoRaRadioFamily family) {
|
||||
volatile const char* capability = meshcore_capability_universal_lora_radio;
|
||||
(void)*capability;
|
||||
// Selection never touches SPI. The board must positively identify the family
|
||||
// before calling this; a later hardware failure cannot rebind active IRQs.
|
||||
if (family != mesh::LoRaRadioFamily::SX126x
|
||||
&& family != mesh::LoRaRadioFamily::SX127x) return false;
|
||||
if (backend_) return family_ == family;
|
||||
if (family == mesh::LoRaRadioFamily::SX126x) {
|
||||
auto* chip = new (&chip_storage_) CustomSX1262(&sx126_module_);
|
||||
physical_ = chip;
|
||||
backend_ = new (&driver_storage_) CustomSX1262Wrapper(*chip, board_);
|
||||
} else {
|
||||
auto* chip = new (&chip_storage_) CustomSX1276(&sx127_module_);
|
||||
physical_ = chip;
|
||||
backend_ = new (&driver_storage_) SX127Backend(*chip, board_);
|
||||
}
|
||||
family_ = family;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UniversalLoRaRadio::stdInit(SPIClass* spi) {
|
||||
if (family_ == mesh::LoRaRadioFamily::SX126x)
|
||||
return static_cast<CustomSX1262*>(physical_)->std_init(spi);
|
||||
if (family_ == mesh::LoRaRadioFamily::SX127x)
|
||||
return static_cast<CustomSX1276*>(physical_)->std_init(spi);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* UniversalLoRaRadio::familyName() const {
|
||||
if (family_ == mesh::LoRaRadioFamily::SX126x) return "SX126x";
|
||||
if (family_ == mesh::LoRaRadioFamily::SX127x) return "SX127x";
|
||||
return "none";
|
||||
}
|
||||
|
||||
void UniversalLoRaRadio::powerOff() {
|
||||
if (family_ == mesh::LoRaRadioFamily::SX126x)
|
||||
static_cast<CustomSX1262Wrapper*>(backend_)->powerOff();
|
||||
else if (family_ == mesh::LoRaRadioFamily::SX127x)
|
||||
static_cast<SX127Backend*>(backend_)->powerOff();
|
||||
}
|
||||
|
||||
bool UniversalLoRaRadio::SX127Backend::validateProfile(
|
||||
const mesh::RadioProfileParams& params) const {
|
||||
// The common .cpp is compiled once for a universal image. Keep SX127x's
|
||||
// actual SF/range and protocol capabilities instead of its SX126x defaults.
|
||||
if (!mesh::RadioProfiles::valid(params, false)
|
||||
|| params.freq < 137.0f || params.freq > 1020.0f
|
||||
|| params.sf < 7 || params.bw > 500.0f) return false;
|
||||
if (params.protocol == mesh::RadioProfileProtocol::Meshtext && !supportsMeshtext()) return false;
|
||||
if (params.protocol == mesh::RadioProfileProtocol::Ethernet && !supportsEthernetTunnel()) return false;
|
||||
#if MESH_ENABLE_HOST_KISS
|
||||
if (params.protocol == mesh::RadioProfileProtocol::Kiss && !supportsHostKiss()) return false;
|
||||
#else
|
||||
if (params.protocol == mesh::RadioProfileProtocol::Kiss) return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UniversalLoRaRadio::SX127Backend::checkBeaconOutputPower(
|
||||
float frequency_mhz, int8_t power) const {
|
||||
(void)frequency_mhz;
|
||||
// Match SX127x::setOutputPower(): values below 2 dBm select RFO, not PA_BOOST.
|
||||
return static_cast<SX1276*>(_radio)->checkOutputPower(power, nullptr, power < 2)
|
||||
== RADIOLIB_ERR_NONE;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(MESH_RADIO_AUTO_FAMILY) && MESH_RADIO_AUTO_FAMILY
|
||||
|
||||
#include <type_traits>
|
||||
#include <helpers/LoRaRadioFamily.h>
|
||||
#include "RadioLibWrappers.h"
|
||||
#include "CustomSX1262Wrapper.h"
|
||||
#include "CustomSX1276Wrapper.h"
|
||||
|
||||
// Mesh and Dispatcher retain this address before setup(). Only the selected
|
||||
// backend is constructed, after the board powers and identifies its radio.
|
||||
// Existing wrappers continue to own IRQs, recovery, profiles and modem state.
|
||||
class UniversalLoRaRadio : public mesh::Radio {
|
||||
class SX127Backend : public CustomSX1276Wrapper {
|
||||
public:
|
||||
SX127Backend(CustomSX1276& radio, mesh::MainBoard& board)
|
||||
: CustomSX1276Wrapper(radio, board) {}
|
||||
bool validateProfile(const mesh::RadioProfileParams& params) const override;
|
||||
protected:
|
||||
bool checkBeaconOutputPower(float frequency_mhz, int8_t power) const override;
|
||||
};
|
||||
|
||||
using ChipStorage = typename std::aligned_union<0, CustomSX1262, CustomSX1276>::type;
|
||||
using DriverStorage = typename std::aligned_union<0, CustomSX1262Wrapper, SX127Backend>::type;
|
||||
ChipStorage chip_storage_;
|
||||
DriverStorage driver_storage_;
|
||||
Module& sx126_module_;
|
||||
Module& sx127_module_;
|
||||
mesh::MainBoard& board_;
|
||||
PhysicalLayer* physical_ = nullptr;
|
||||
RadioLibWrapper* backend_ = nullptr;
|
||||
mesh::LoRaRadioFamily family_ = mesh::LoRaRadioFamily::None;
|
||||
|
||||
public:
|
||||
// Compile both policies; the runtime capability still rejects RXPS on SX127x.
|
||||
static constexpr bool SupportsRxPowerSaving = true;
|
||||
UniversalLoRaRadio(Module& sx126_module, Module& sx127_module, mesh::MainBoard& board);
|
||||
~UniversalLoRaRadio();
|
||||
UniversalLoRaRadio(const UniversalLoRaRadio&) = delete;
|
||||
UniversalLoRaRadio& operator=(const UniversalLoRaRadio&) = delete;
|
||||
bool selectFamily(mesh::LoRaRadioFamily family);
|
||||
bool stdInit(SPIClass* spi);
|
||||
mesh::LoRaRadioFamily family() const { return family_; }
|
||||
PhysicalLayer* physicalLayer() { return physical_; }
|
||||
const PhysicalLayer* physicalLayer() const { return physical_; }
|
||||
const char* familyName() const;
|
||||
|
||||
// These small forwarding methods preserve the complete mesh::Radio contract.
|
||||
// An unidentified radio never transmits or reports successful reconfiguration.
|
||||
#define MESH_AUTO_LORA_RET(type, method, params, args, fallback) \
|
||||
type method params override { return backend_ ? backend_->method args : fallback; }
|
||||
#define MESH_AUTO_LORA_CONST(type, method, params, args, fallback) \
|
||||
type method params const override { return backend_ ? static_cast<const RadioLibWrapper*>(backend_)->method args : fallback; }
|
||||
#define MESH_AUTO_LORA_VOID(method, params, args) \
|
||||
void method params override { if (backend_) backend_->method args; }
|
||||
#define MESH_AUTO_LORA_EXTRA(type, method, params, args, fallback) \
|
||||
type method params { return backend_ ? backend_->method args : fallback; }
|
||||
#define MESH_AUTO_LORA_EXTRA_CONST(type, method, params, args, fallback) \
|
||||
type method params const { return backend_ ? static_cast<const RadioLibWrapper*>(backend_)->method args : fallback; }
|
||||
|
||||
MESH_AUTO_LORA_CONST(uint8_t, regulatorModes, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(mesh::power::RegulatorMode, defaultRegulatorMode, (), (), mesh::power::RegulatorMode::Default)
|
||||
MESH_AUTO_LORA_RET(bool, configureBootRegulator, (mesh::power::RegulatorMode mode), (mode), false)
|
||||
MESH_AUTO_LORA_CONST(mesh::power::RegulatorMode, activeRegulatorMode, (), (), mesh::power::RegulatorMode::Default)
|
||||
MESH_AUTO_LORA_CONST(bool, supportsCarrierWave, (), (), false)
|
||||
MESH_AUTO_LORA_RET(mesh::RadioParamApplyResult, setCarrierWave, (uint8_t profile, uint32_t duration_ms), (profile, duration_ms), mesh::RadioParamApplyResult::FAILED)
|
||||
MESH_AUTO_LORA_CONST(bool, isCarrierWaveActive, (), (), false)
|
||||
MESH_AUTO_LORA_CONST(uint8_t, carrierWaveProfile, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(uint32_t, carrierWaveRemainingMillis, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(bool, supportsMorseTx, (), (), false)
|
||||
MESH_AUTO_LORA_RET(mesh::MorseTxResult, startMorseTx, (float frequency_mhz, uint8_t wpm, const char* text), (frequency_mhz, wpm, text), mesh::MorseTxResult::Unsupported)
|
||||
MESH_AUTO_LORA_RET(mesh::MorseTxResult, stopMorseTx, (), (), mesh::MorseTxResult::Unsupported)
|
||||
MESH_AUTO_LORA_CONST(bool, isMorseTxActive, (), (), false)
|
||||
MESH_AUTO_LORA_CONST(float, morseTxFrequency, (), (), mesh::MorseTx::DefaultFrequencyMHz)
|
||||
MESH_AUTO_LORA_CONST(uint8_t, morseTxWpm, (), (), mesh::MorseTx::DefaultWpm)
|
||||
MESH_AUTO_LORA_CONST(uint32_t, morseTxRemainingMillis, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(bool, supportsMorseRx, (), (), false)
|
||||
MESH_AUTO_LORA_RET(mesh::MorseRxResult, startMorseRx, (float frequency_mhz, uint8_t wpm, uint32_t duration_ms), (frequency_mhz, wpm, duration_ms), mesh::MorseRxResult::Unsupported)
|
||||
MESH_AUTO_LORA_RET(mesh::MorseRxResult, stopMorseRx, (), (), mesh::MorseRxResult::Unsupported)
|
||||
MESH_AUTO_LORA_CONST(bool, isMorseRxActive, (), (), false)
|
||||
MESH_AUTO_LORA_CONST(bool, morseRxRecovering, (), (), false)
|
||||
MESH_AUTO_LORA_CONST(bool, morseRxLearning, (), (), false)
|
||||
MESH_AUTO_LORA_CONST(float, morseRxFrequency, (), (), mesh::MorseTx::DefaultFrequencyMHz)
|
||||
MESH_AUTO_LORA_CONST(float, morseRxBandwidthKHz, (), (), 0.0f)
|
||||
MESH_AUTO_LORA_CONST(uint32_t, morseRxRemainingMillis, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(uint32_t, morseCaptureGeneration, (), (), 0)
|
||||
bool morseRxDiagnostics(mesh::MorseRxDiagnostics& out) const override {
|
||||
if (backend_) return backend_->morseRxDiagnostics(out);
|
||||
out = {};
|
||||
return false;
|
||||
}
|
||||
MESH_AUTO_LORA_CONST(size_t, morseCaptureLength, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(bool, morseCaptureTruncated, (), (), false)
|
||||
MESH_AUTO_LORA_CONST(const char*, morseCaptureText, (), (), "")
|
||||
size_t readMorseCapture(size_t offset, char* out, size_t capacity) const override {
|
||||
if (backend_) return backend_->readMorseCapture(offset, out, capacity);
|
||||
if (out && capacity) out[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
MESH_AUTO_LORA_VOID(clearMorseCapture, (), ())
|
||||
#if defined(MESH_MORSE_HIL) && MESH_MORSE_HIL
|
||||
MESH_AUTO_LORA_CONST(size_t, morseTraceLength, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(uint32_t, morseTraceTotal, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(bool, morseTraceTruncated, (), (), false)
|
||||
MESH_AUTO_LORA_CONST(bool, readMorseTrace, (size_t offset, mesh::MorseRssiTraceEntry& out), (offset, out), false)
|
||||
#endif
|
||||
|
||||
MESH_AUTO_LORA_VOID(begin, (), ())
|
||||
MESH_AUTO_LORA_RET(mesh::RadioProfiles*, profiles, (), (), nullptr)
|
||||
MESH_AUTO_LORA_CONST(const mesh::RadioProfiles*, profiles, (), (), nullptr)
|
||||
#if MESH_RADIO_SWITCH_TUNING
|
||||
MESH_AUTO_LORA_CONST(mesh::RadioSwitchCapabilities, switchTuningCapabilities, (), (), mesh::RadioSwitchCapabilities{})
|
||||
MESH_AUTO_LORA_CONST(mesh::RadioSwitchTuning, switchTuning, (), (), mesh::RadioSwitchTuning{})
|
||||
MESH_AUTO_LORA_CONST(uint32_t, switchSpiHz, (), (), 0)
|
||||
MESH_AUTO_LORA_RET(bool, configureBootSwitchTuning, (const mesh::RadioSwitchTuning& tuning), (tuning), false)
|
||||
MESH_AUTO_LORA_RET(mesh::RadioParamApplyResult, trySetSwitchTuning,
|
||||
(const mesh::RadioSwitchTuning& tuning,
|
||||
bool (*persist)(void*, const mesh::RadioSwitchTuning&) = nullptr, void* context = nullptr),
|
||||
(tuning, persist, context), mesh::RadioParamApplyResult::FAILED)
|
||||
#endif
|
||||
MESH_AUTO_LORA_CONST(bool, validateProfile, (const mesh::RadioProfileParams& params), (params), false)
|
||||
MESH_AUTO_LORA_CONST(bool, supportsMeshtext, (), (), false)
|
||||
MESH_AUTO_LORA_CONST(bool, supportsEthernetTunnel, (), (), false)
|
||||
#if MESH_ENABLE_HOST_KISS
|
||||
MESH_AUTO_LORA_CONST(bool, supportsHostKiss, (), (), false)
|
||||
#endif
|
||||
#if MESH_ENABLE_TX_BEACONS
|
||||
MESH_AUTO_LORA_CONST(bool, validateBeaconPower, (float frequency_mhz, int8_t power), (frequency_mhz, power), false)
|
||||
MESH_AUTO_LORA_RET(mesh::RadioParamApplyResult, prepareBeaconTransmit, (const mesh::RadioProfileParams& params, int8_t power), (params, power), mesh::RadioParamApplyResult::FAILED)
|
||||
MESH_AUTO_LORA_RET(mesh::RadioParamApplyResult, restoreBeaconReceive, (), (), mesh::RadioParamApplyResult::FAILED)
|
||||
MESH_AUTO_LORA_CONST(bool, isBeaconRadioOwned, (), (), false)
|
||||
MESH_AUTO_LORA_RET(bool, isBeaconChannelBusy, (), (), true)
|
||||
MESH_AUTO_LORA_RET(uint32_t, getBeaconAirtime, (const mesh::RadioProfileParams& params, int length), (params, length), 0)
|
||||
#endif
|
||||
MESH_AUTO_LORA_CONST(uint8_t, receiveProfile, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(uint32_t, receiveProfileGeneration, (), (), 0)
|
||||
MESH_AUTO_LORA_RET(mesh::RadioParamApplyResult, prepareTransmitProfile, (uint8_t profile), (profile), mesh::RadioParamApplyResult::FAILED)
|
||||
MESH_AUTO_LORA_RET(mesh::RadioParamApplyResult, prepareTransmitProfile, (uint8_t profile, bool reply_rx_override), (profile, reply_rx_override), mesh::RadioParamApplyResult::FAILED)
|
||||
MESH_AUTO_LORA_CONST(uint16_t, profilePreamble, (uint8_t profile), (profile), 0)
|
||||
MESH_AUTO_LORA_RET(uint32_t, getProfileAirtime, (uint8_t profile, int len_bytes, uint8_t cr = 0), (profile, len_bytes, cr), 0)
|
||||
MESH_AUTO_LORA_RET(mesh::RadioParamApplyResult, trySetPrimaryParams, (const mesh::RadioProfileParams& params, bool temporary, const uint32_t* timings = nullptr), (params, temporary, timings), mesh::RadioParamApplyResult::FAILED)
|
||||
|
||||
MESH_AUTO_LORA_RET(int, recvRaw, (uint8_t* bytes, int size), (bytes, size), 0)
|
||||
MESH_AUTO_LORA_VOID(onReceiveProcessed, (), ())
|
||||
MESH_AUTO_LORA_RET(uint32_t, getEstAirtimeFor, (int len_bytes), (len_bytes), 0)
|
||||
MESH_AUTO_LORA_RET(float, packetScore, (float snr, int packet_len), (snr, packet_len), 0.0f)
|
||||
MESH_AUTO_LORA_RET(bool, startSendRaw, (const uint8_t* bytes, int length), (bytes, length), false)
|
||||
MESH_AUTO_LORA_RET(bool, setCodingRate, (uint8_t cr), (cr), false)
|
||||
MESH_AUTO_LORA_RET(mesh::RadioParamApplyResult, tryRestoreCodingRate, (uint8_t cr), (cr), mesh::RadioParamApplyResult::FAILED)
|
||||
MESH_AUTO_LORA_RET(bool, isSendComplete, (), (), false)
|
||||
MESH_AUTO_LORA_VOID(onSendFinished, (), ())
|
||||
MESH_AUTO_LORA_VOID(loop, (), ())
|
||||
MESH_AUTO_LORA_VOID(idle, (), ())
|
||||
MESH_AUTO_LORA_VOID(startRecv, (), ())
|
||||
MESH_AUTO_LORA_RET(bool, setTrackerSleep, (bool sleeping), (sleeping), false)
|
||||
MESH_AUTO_LORA_RET(bool, recoverRadio, (bool hard), (hard), false)
|
||||
|
||||
MESH_AUTO_LORA_CONST(int, getNoiseFloor, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(float, getNoiseFloorDbm, (), (), 0.0f)
|
||||
MESH_AUTO_LORA_CONST(float, getNoiseFloorDbm, (uint8_t profile), (profile), 0.0f)
|
||||
#if MESH_ENABLE_TELEMETRY_HISTORY
|
||||
MESH_AUTO_LORA_CONST(bool, getNoiseFloorReading, (uint8_t profile, float& dbm, uint32_t& published_at_ms), (profile, dbm, published_at_ms), false)
|
||||
MESH_AUTO_LORA_VOID(requestNoiseFloorMeasurement, (), ())
|
||||
#endif
|
||||
MESH_AUTO_LORA_CONST(float, getNoiseFloorCalibrationSecondsRemaining, (), (), 0.0f)
|
||||
MESH_AUTO_LORA_CONST(float, getNoiseFloorCalibrationSecondsRemaining, (uint8_t profile), (profile), 0.0f)
|
||||
MESH_AUTO_LORA_CONST(bool, isCalibratingNoiseFloor, (), (), false)
|
||||
MESH_AUTO_LORA_CONST(bool, getNoiseFloorWakeDelay, (uint32_t now, uint32_t& delay_ms), (now, delay_ms), false)
|
||||
MESH_AUTO_LORA_CONST(bool, getReceiveRetryDelay, (uint32_t now, uint32_t& delay_ms), (now, delay_ms), false)
|
||||
MESH_AUTO_LORA_CONST(bool, getProfileIdleDelay, (uint32_t& delay_ms), (delay_ms), false)
|
||||
MESH_AUTO_LORA_VOID(triggerNoiseFloorCalibrate, (int threshold), (threshold))
|
||||
MESH_AUTO_LORA_VOID(recalibrateNoiseFloor, (), ())
|
||||
MESH_AUTO_LORA_VOID(setCADEnabled, (bool enabled), (enabled))
|
||||
MESH_AUTO_LORA_EXTRA(bool, setCADScanTimeoutMillis, (uint32_t timeout_ms), (timeout_ms), false)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(uint32_t, getCADScanTimeoutMillis, (), (), 0)
|
||||
MESH_AUTO_LORA_VOID(resetAGC, (), ())
|
||||
MESH_AUTO_LORA_RET(bool, tryResetAGC, (), (), false)
|
||||
MESH_AUTO_LORA_CONST(uint32_t, getRecoveryCount, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(uint8_t, getRadioState, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(unsigned long, getLastRecvMillis, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(unsigned long, getLastRadioInterruptMillis, (), (), 0)
|
||||
MESH_AUTO_LORA_CONST(bool, isInRecvMode, (), (), false)
|
||||
MESH_AUTO_LORA_CONST(bool, supportsRxPowerSaving, (), (), false)
|
||||
MESH_AUTO_LORA_RET(bool, setRxPowerSaving, (bool enabled, uint32_t rx_us, uint32_t sleep_us), (enabled, rx_us, sleep_us), false)
|
||||
MESH_AUTO_LORA_CONST(bool, isRxPowerSavingContinuousFallback, (), (), false)
|
||||
MESH_AUTO_LORA_CONST(bool, supportsRxPowerSavingRfRxDisable, (), (), false)
|
||||
MESH_AUTO_LORA_RET(bool, setRxPowerSavingRfRxDisabled, (bool disabled), (disabled), false)
|
||||
MESH_AUTO_LORA_CONST(bool, isRxPowerSavingRfRxDisabled, (), (), false)
|
||||
MESH_AUTO_LORA_RET(mesh::RadioParamApplyResult, trySetParams, (float frequency, float bandwidth, uint8_t sf, uint8_t cr, const uint32_t* timings = nullptr), (frequency, bandwidth, sf, cr, timings), mesh::RadioParamApplyResult::FAILED)
|
||||
MESH_AUTO_LORA_RET(bool, isReceiving, (), (), false)
|
||||
MESH_AUTO_LORA_RET(bool, isReceivingPassive, (int interference_margin_db), (interference_margin_db), false)
|
||||
MESH_AUTO_LORA_CONST(float, getLastRSSI, (), (), 0.0f)
|
||||
MESH_AUTO_LORA_CONST(float, getLastSNR, (), (), 0.0f)
|
||||
MESH_AUTO_LORA_CONST(uint32_t, getPacketsRecvErrors, (), (), 0)
|
||||
|
||||
// Existing roles use these RadioLibWrapper helpers in addition to mesh::Radio.
|
||||
MESH_AUTO_LORA_EXTRA(mesh::RadioParamApplyResult, trySetRxPowerSaving, (bool enabled, uint32_t rx_us, uint32_t sleep_us), (enabled, rx_us, sleep_us), mesh::RadioParamApplyResult::FAILED)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(RxPowerSavingStatus, getRxPowerSavingStatus, (), (), RxPowerSavingStatus{})
|
||||
uint32_t rxPowerSavingTransitionUs() const {
|
||||
return backend_ ? backend_->rxPowerSavingTransitionUs() : rxPowerSavingDefaultTransitionUs();
|
||||
}
|
||||
void getRxPowerSavingTimings(uint32_t& rx_us, uint32_t& sleep_us) const {
|
||||
if (backend_) backend_->getRxPowerSavingTimings(rx_us, sleep_us);
|
||||
else { rx_us = 0; sleep_us = 0; }
|
||||
}
|
||||
MESH_AUTO_LORA_EXTRA(mesh::RadioParamApplyResult, trySetRxPowerSavingRfRxDisabled, (bool disabled), (disabled), mesh::RadioParamApplyResult::FAILED)
|
||||
MESH_AUTO_LORA_EXTRA(bool, isChannelActive, (), (), false)
|
||||
MESH_AUTO_LORA_EXTRA(bool, setParams, (float frequency, float bandwidth, uint8_t sf, uint8_t cr, const uint32_t* timings = nullptr), (frequency, bandwidth, sf, cr, timings), false)
|
||||
MESH_AUTO_LORA_EXTRA(uint32_t, getRngSeed, (), (), 0)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(bool, isTxPowerValid, (int8_t power), (power), false)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(bool, isTxPowerApplied, (int8_t power), (power), false)
|
||||
MESH_AUTO_LORA_EXTRA(bool, setTxPower, (int8_t power), (power), false)
|
||||
MESH_AUTO_LORA_EXTRA(mesh::RadioParamApplyResult, trySetTxPower, (int8_t power), (power), mesh::RadioParamApplyResult::FAILED)
|
||||
MESH_AUTO_LORA_EXTRA(float, getCurrentRSSI, (), (), NAN)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(uint8_t, getSpreadingFactor, (), (), 0)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(uint16_t, preambleLengthForParams, (uint8_t sf, float bandwidth), (sf, bandwidth), 0)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(uint16_t, currentPreambleLength, (), (), 0)
|
||||
MESH_AUTO_LORA_EXTRA(bool, updatePreamble, (uint8_t sf, float bandwidth), (sf, bandwidth), false)
|
||||
MESH_AUTO_LORA_EXTRA(PacketMillis, calcMaxPacketMillis, (uint8_t sf, float bandwidth, uint8_t cr, uint16_t preamble), (sf, bandwidth, cr, preamble), (PacketMillis{0, 0}))
|
||||
MESH_AUTO_LORA_EXTRA(int16_t, performChannelScan, (), (), RADIOLIB_ERR_UNSUPPORTED)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(uint32_t, getPacketsRecv, (), (), 0)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(uint32_t, getPacketsSent, (), (), 0)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(uint32_t, getRxPsWatchdogSoftCount, (), (), 0)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(uint32_t, getRxPsWatchdogHardCount, (), (), 0)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(bool, isWatchdogObserving, (), (), false)
|
||||
void resetStats() { if (backend_) backend_->resetStats(); }
|
||||
MESH_AUTO_LORA_EXTRA(bool, setRxBoostedGainMode, (bool enabled), (enabled), false)
|
||||
MESH_AUTO_LORA_EXTRA(mesh::RadioParamApplyResult, trySetRxBoostedGainMode, (bool enabled), (enabled), mesh::RadioParamApplyResult::FAILED)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(bool, supportsRxBoostedGainMode, (), (), false)
|
||||
MESH_AUTO_LORA_EXTRA_CONST(bool, getRxBoostedGainMode, (), (), false)
|
||||
MESH_AUTO_LORA_EXTRA(bool, configSideDetectors, (const uint8_t* spreading_factors, uint8_t count, float bandwidth), (spreading_factors, count, bandwidth), false)
|
||||
MESH_AUTO_LORA_EXTRA(mesh::RadioParamApplyResult, tryConfigSideDetectors, (const uint8_t* spreading_factors, uint8_t count, float bandwidth), (spreading_factors, count, bandwidth), mesh::RadioParamApplyResult::FAILED)
|
||||
void powerOff();
|
||||
|
||||
#undef MESH_AUTO_LORA_RET
|
||||
#undef MESH_AUTO_LORA_CONST
|
||||
#undef MESH_AUTO_LORA_VOID
|
||||
#undef MESH_AUTO_LORA_EXTRA
|
||||
#undef MESH_AUTO_LORA_EXTRA_CONST
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,224 @@
|
||||
; Startup-detected SX126x/SX127x radio. Legacy chip-specific targets retain
|
||||
; their original wiring, names, and OTA identities.
|
||||
|
||||
[LilyGo_T3S3]
|
||||
extends = esp32_base
|
||||
board = t3_s3_v1_x
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-I variants/lilygo_t3s3_universal
|
||||
-D LILYGO_T3S3
|
||||
-D P_LORA_DIO_1=33
|
||||
-D P_LORA_NSS=7
|
||||
-D P_LORA_RESET=8
|
||||
-D P_LORA_BUSY=34
|
||||
-D P_LORA_SCLK=5
|
||||
-D P_LORA_MISO=3
|
||||
-D P_LORA_MOSI=6
|
||||
-D P_LORA_TX_LED=37
|
||||
-D PIN_VBAT_READ=1
|
||||
-D PIN_USER_BTN=0
|
||||
-D PIN_BOARD_SDA=18
|
||||
-D PIN_BOARD_SCL=17
|
||||
-D PIN_OLED_RESET=-1
|
||||
-D SX126X_DIO2_AS_RF_SWITCH=true
|
||||
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
|
||||
-D SX126X_CURRENT_LIMIT=140
|
||||
-D USE_SX1262
|
||||
-D RADIO_CLASS=UniversalLoRaRadio
|
||||
-D WRAPPER_CLASS=UniversalLoRaRadio
|
||||
-D LORA_TX_POWER=20
|
||||
-D SX126X_RX_BOOSTED_GAIN=1
|
||||
-D USE_SX1276
|
||||
-D MESH_RADIO_AUTO_FAMILY=1
|
||||
-D SX127X_CURRENT_LIMIT=120
|
||||
-D P_LORA_DIO_0=9
|
||||
build_src_filter =
|
||||
${esp32_base.build_src_filter}
|
||||
+<../variants/lilygo_t3s3_universal>
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
adafruit/Adafruit SSD1306 @ ^2.5.13
|
||||
|
||||
[env:LilyGo_T3S3_repeater]
|
||||
extends = env:LilyGo_T3S3_sx1262_repeater
|
||||
build_flags =
|
||||
${LilyGo_T3S3.build_flags}
|
||||
-D LIGHTWEIGHT_WIFI_OTA=1 ; retain WebUI and the original dual-OTA partition map
|
||||
-D DISPLAY_CLASS=SSD1306Display
|
||||
-D ADVERT_NAME='"T3 S3 Repeater"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
build_src_filter =
|
||||
${LilyGo_T3S3.build_src_filter}
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_T3S3.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T3S3_repeater_bridge_espnow]
|
||||
extends = env:LilyGo_T3S3_sx1262_repeater_bridge_espnow
|
||||
build_flags =
|
||||
${LilyGo_T3S3.build_flags}
|
||||
-D LIGHTWEIGHT_WIFI_OTA=1 ; retain WebUI and the original dual-OTA partition map
|
||||
-D DISPLAY_CLASS=SSD1306Display
|
||||
-D ADVERT_NAME='"ESPNow Bridge"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_ESPNOW_BRIDGE=1
|
||||
build_src_filter =
|
||||
${LilyGo_T3S3.build_src_filter}
|
||||
+<helpers/bridges/ESPNowBridge.cpp>
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_T3S3.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T3S3_repeater_observer_mqtt]
|
||||
extends = env:LilyGo_T3S3_sx1262_repeater_observer_mqtt
|
||||
build_flags =
|
||||
${LilyGo_T3S3.build_flags}
|
||||
-D DISPLAY_CLASS=SSD1306Display
|
||||
-D ADVERT_NAME='"MQTT Observer"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
|
||||
-D ESP32_CPU_FREQ=160
|
||||
build_src_filter =
|
||||
${LilyGo_T3S3.build_src_filter}
|
||||
+<helpers/bridges/MQTTBridge.cpp>
|
||||
+<helpers/MQTTMessageBuilder.cpp>
|
||||
+<helpers/JWTHelper.cpp>
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_T3S3.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
elims/PsychicMqttClient@^0.2.4
|
||||
bblanchon/ArduinoJson @ 7.4.3
|
||||
arduino-libraries/NTPClient
|
||||
JChristensen/Timezone
|
||||
paulstoffregen/Time@1.6.1
|
||||
|
||||
[env:LilyGo_T3S3_room_server_observer_mqtt]
|
||||
extends = env:LilyGo_T3S3_sx1262_room_server_observer_mqtt
|
||||
build_flags =
|
||||
${LilyGo_T3S3.build_flags}
|
||||
-D DISPLAY_CLASS=SSD1306Display
|
||||
-D ADVERT_NAME='"T3 S3 Room Observer"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
-D CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
|
||||
-D ESP32_CPU_FREQ=160
|
||||
build_src_filter =
|
||||
${LilyGo_T3S3.build_src_filter}
|
||||
+<helpers/bridges/MQTTBridge.cpp>
|
||||
+<helpers/MQTTMessageBuilder.cpp>
|
||||
+<helpers/JWTHelper.cpp>
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<../examples/simple_room_server>
|
||||
lib_deps =
|
||||
${LilyGo_T3S3.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
elims/PsychicMqttClient@^0.2.4
|
||||
bblanchon/ArduinoJson @ 7.4.3
|
||||
arduino-libraries/NTPClient
|
||||
JChristensen/Timezone
|
||||
paulstoffregen/Time@1.6.1
|
||||
|
||||
[env:LilyGo_T3S3_terminal_chat]
|
||||
extends = env:LilyGo_T3S3_sx1262_terminal_chat
|
||||
build_flags =
|
||||
${LilyGo_T3S3.build_flags}
|
||||
-D MAX_CONTACTS=350
|
||||
-D MAX_GROUP_CHANNELS=1
|
||||
build_src_filter =
|
||||
${LilyGo_T3S3.build_src_filter}
|
||||
+<../examples/simple_secure_chat/main.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_T3S3.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
|
||||
[env:LilyGo_T3S3_room_server]
|
||||
extends = env:LilyGo_T3S3_sx1262_room_server
|
||||
build_flags =
|
||||
${LilyGo_T3S3.build_flags}
|
||||
-D DISPLAY_CLASS=SSD1306Display
|
||||
-D ADVERT_NAME='"T3 S3 Room"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
build_src_filter =
|
||||
${LilyGo_T3S3.build_src_filter}
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<../examples/simple_room_server>
|
||||
lib_deps =
|
||||
${LilyGo_T3S3.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:LilyGo_T3S3_companion_radio_usb]
|
||||
extends = env:LilyGo_T3S3_sx1262_companion_radio_usb
|
||||
build_flags =
|
||||
${LilyGo_T3S3.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D DISPLAY_CLASS=SSD1306Display
|
||||
-D MAX_CONTACTS=350
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D ENABLE_USB_INTERFACE
|
||||
build_src_filter =
|
||||
${LilyGo_T3S3.build_src_filter}
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_T3S3.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
|
||||
[env:LilyGo_T3S3_companion_radio_ble]
|
||||
extends = env:LilyGo_T3S3_sx1262_companion_radio_ble
|
||||
build_flags =
|
||||
${LilyGo_T3S3.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D DISPLAY_CLASS=SSD1306Display
|
||||
-D MAX_CONTACTS=350
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D BLE_PIN_CODE=123456
|
||||
-D BLE_DEBUG_LOGGING=1
|
||||
-D OFFLINE_QUEUE_SIZE=512
|
||||
build_src_filter =
|
||||
${LilyGo_T3S3.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_T3S3.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
|
||||
[env:LilyGo_T3S3_companion_radio_ble_ps]
|
||||
extends = env:LilyGo_T3S3_companion_radio_ble
|
||||
|
||||
[env:LilyGo_T3S3_kiss_modem]
|
||||
extends = env:LilyGo_T3S3_sx1262_kiss_modem
|
||||
build_src_filter =
|
||||
${LilyGo_T3S3.build_src_filter}
|
||||
+<../examples/kiss_modem/>
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <Arduino.h>
|
||||
#include "target.h"
|
||||
#include <helpers/radiolib/ESP32LoRaChipProbe.h>
|
||||
#include <helpers/radiolib/SX126xBufferedRadioHal.h>
|
||||
#include <helpers/radiolib/TunableRadioHal.h>
|
||||
|
||||
UniversalT3S3Board board;
|
||||
|
||||
static SPIClass spi;
|
||||
static SX126xBufferedRadioHal sx126x_hal(spi);
|
||||
static TunableRadioHal sx127x_hal(spi, 2000000);
|
||||
static Module sx126x_module(&sx126x_hal, P_LORA_NSS, P_LORA_DIO_1,
|
||||
P_LORA_RESET, P_LORA_BUSY);
|
||||
static Module sx127x_module(&sx127x_hal, P_LORA_NSS, P_LORA_DIO_0,
|
||||
P_LORA_RESET, P_LORA_DIO_1);
|
||||
UniversalLoRaRadio radio_driver(sx126x_module, sx127x_module, board);
|
||||
|
||||
ESP32RTCClock fallback_clock;
|
||||
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||
SensorManager sensors;
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
DISPLAY_CLASS display;
|
||||
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
|
||||
#endif
|
||||
|
||||
mesh::LoRaRadioFamily universalLoRaRadioFamily() {
|
||||
return radio_driver.family();
|
||||
}
|
||||
|
||||
bool prepareUniversalLoRaRadio() {
|
||||
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
|
||||
const mesh::LoRaChipProbePins pins{P_LORA_NSS, P_LORA_RESET, P_LORA_BUSY};
|
||||
return radio_driver.selectFamily(mesh::probeUniversalLoRaChip(spi, pins));
|
||||
}
|
||||
|
||||
bool radio_init() {
|
||||
fallback_clock.begin();
|
||||
rtc_clock.begin(Wire);
|
||||
return radio_driver.stdInit(&spi);
|
||||
}
|
||||
|
||||
mesh::LocalIdentity radio_new_identity() {
|
||||
auto* physical = radio_driver.physicalLayer();
|
||||
if (!physical) return mesh::LocalIdentity();
|
||||
RadioNoiseListener rng(*physical);
|
||||
return mesh::LocalIdentity(&rng);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <helpers/radiolib/UniversalLoRaRadio.h>
|
||||
#include <helpers/ESP32Board.h>
|
||||
#include <helpers/AutoDiscoverRTCClock.h>
|
||||
#include <helpers/SensorManager.h>
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include <helpers/ui/SSD1306Display.h>
|
||||
#include <helpers/ui/MomentaryButton.h>
|
||||
#endif
|
||||
|
||||
bool prepareUniversalLoRaRadio();
|
||||
mesh::LoRaRadioFamily universalLoRaRadioFamily();
|
||||
|
||||
class UniversalT3S3Board : public ESP32Board {
|
||||
public:
|
||||
void begin() {
|
||||
ESP32Board::begin();
|
||||
prepareUniversalLoRaRadio();
|
||||
}
|
||||
|
||||
uint32_t getIRQGpio() override {
|
||||
switch (universalLoRaRadioFamily()) {
|
||||
case mesh::LoRaRadioFamily::SX126x: return P_LORA_DIO_1;
|
||||
case mesh::LoRaRadioFamily::SX127x: return P_LORA_DIO_0;
|
||||
default: return static_cast<uint32_t>(-1);
|
||||
}
|
||||
}
|
||||
|
||||
const char* getManufacturerName() const override {
|
||||
switch (universalLoRaRadioFamily()) {
|
||||
case mesh::LoRaRadioFamily::SX126x: return "LilyGo T3 S3 SX126x";
|
||||
case mesh::LoRaRadioFamily::SX127x: return "LilyGo T3 S3 SX127x";
|
||||
default: return "LilyGo T3 S3 (radio undetected)";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
extern UniversalT3S3Board board;
|
||||
extern UniversalLoRaRadio radio_driver;
|
||||
extern AutoDiscoverRTCClock rtc_clock;
|
||||
extern SensorManager sensors;
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
extern DISPLAY_CLASS display;
|
||||
extern MomentaryButton user_btn;
|
||||
#endif
|
||||
|
||||
bool radio_init();
|
||||
mesh::LocalIdentity radio_new_identity();
|
||||
@@ -0,0 +1,194 @@
|
||||
; Startup-detected SX126x/SX127x radio. Legacy chip-specific targets retain
|
||||
; their original wiring, names, and OTA identities.
|
||||
|
||||
[LilyGo_TBeam]
|
||||
extends = esp32_base
|
||||
board = ttgo-t-beam
|
||||
build_unflags =
|
||||
-fexceptions
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-fno-exceptions
|
||||
-D PORTABLE_ESP32_ROM_NANO_FORMAT=1
|
||||
-I variants/lilygo_tbeam_universal
|
||||
-D TBEAM_SX1262
|
||||
-D P_LORA_DIO_0=26
|
||||
-D P_LORA_DIO_1=33
|
||||
-D P_LORA_BUSY=32
|
||||
-D P_LORA_NSS=18
|
||||
-D P_LORA_RESET=23
|
||||
-D P_LORA_SCLK=5
|
||||
-D P_LORA_MISO=19
|
||||
-D P_LORA_MOSI=27
|
||||
-D SX126X_DIO2_AS_RF_SWITCH=true
|
||||
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
|
||||
-D SX126X_CURRENT_LIMIT=140
|
||||
-D SX126X_RX_BOOSTED_GAIN=1
|
||||
-D USE_SX1262
|
||||
-D RADIO_CLASS=UniversalLoRaRadio
|
||||
-D WRAPPER_CLASS=UniversalLoRaRadio
|
||||
-D DISPLAY_CLASS=SSD1306Display
|
||||
-D LORA_TX_POWER=20
|
||||
-D P_LORA_TX_LED=4
|
||||
-D PIN_BOARD_SDA=21
|
||||
-D PIN_BOARD_SCL=22
|
||||
-D PIN_GPS_RX=12
|
||||
-D PIN_GPS_TX=34
|
||||
-D PIN_USER_BTN=38
|
||||
-D ENV_INCLUDE_GPS=1
|
||||
-D USE_SX1276
|
||||
-D MESH_RADIO_AUTO_FAMILY=1
|
||||
-D SX127X_CURRENT_LIMIT=120
|
||||
build_src_filter =
|
||||
${esp32_base.build_src_filter}
|
||||
+<../variants/lilygo_tbeam_universal>
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<helpers/esp32/TBeamBoard.cpp>
|
||||
+<helpers/sensors>
|
||||
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
lewisxhe/XPowersLib@^0.2.7
|
||||
adafruit/Adafruit SSD1306 @ ^2.5.13
|
||||
stevemarple/MicroNMEA @ ^2.0.6
|
||||
boschsensortec/BSEC Software Library @ ^1.8.1492
|
||||
|
||||
[env:Tbeam_companion_radio_ble]
|
||||
extends = env:Tbeam_SX1262_companion_radio_ble
|
||||
build_flags =
|
||||
${LilyGo_TBeam.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D MAX_CONTACTS=160
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D BLE_PIN_CODE=123456
|
||||
-D OFFLINE_QUEUE_SIZE=128
|
||||
build_src_filter =
|
||||
${LilyGo_TBeam.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_TBeam.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
|
||||
[env:Tbeam_companion_radio_ble_ps]
|
||||
extends = env:Tbeam_companion_radio_ble
|
||||
|
||||
[env:Tbeam_repeater]
|
||||
extends = env:Tbeam_SX1262_repeater
|
||||
build_flags =
|
||||
${LilyGo_TBeam.build_flags}
|
||||
-D ADVERT_NAME='"T-Beam Repeater"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D FLOOD_CHANNEL_SCOPE_SLOTS=31 ; classic ESP32 DRAM cannot fit the default 255 with LoRa OTA
|
||||
build_src_filter =
|
||||
${LilyGo_TBeam.build_src_filter}
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_TBeam.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:Tbeam_repeater_bridge_espnow]
|
||||
extends = env:Tbeam_SX1262_repeater_bridge_espnow
|
||||
build_flags =
|
||||
${LilyGo_TBeam.build_flags}
|
||||
-D ADVERT_NAME='"ESPNow Bridge"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D FLOOD_CHANNEL_SCOPE_SLOTS=31 ; classic ESP32 DRAM cannot fit the default 255 with ESP-NOW
|
||||
-D WITH_ESPNOW_BRIDGE=1
|
||||
-D DISABLE_LORA_OTA=1 ; ESP-NOW plus LoRa OTA overflows this board's internal DRAM
|
||||
build_src_filter =
|
||||
${LilyGo_TBeam.build_src_filter}
|
||||
+<helpers/bridges/ESPNowBridge.cpp>
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_TBeam.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:Tbeam_room_server]
|
||||
extends = env:Tbeam_SX1262_room_server
|
||||
build_flags =
|
||||
${LilyGo_TBeam.build_flags}
|
||||
-D ADVERT_NAME='"T-Beam Room"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
build_src_filter =
|
||||
${LilyGo_TBeam.build_src_filter}
|
||||
+<../examples/simple_room_server>
|
||||
lib_deps =
|
||||
${LilyGo_TBeam.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
|
||||
[env:Tbeam_kiss_modem]
|
||||
extends = env:Tbeam_SX1262_kiss_modem
|
||||
build_src_filter =
|
||||
${LilyGo_TBeam.build_src_filter}
|
||||
+<../examples/kiss_modem/>
|
||||
|
||||
[env:Tbeam_repeater_observer_mqtt]
|
||||
extends = env:Tbeam_SX1262_repeater_observer_mqtt
|
||||
build_flags =
|
||||
${LilyGo_TBeam.build_flags}
|
||||
-D ADVERT_NAME='"T-Beam MQTT Observer"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D FLOOD_CHANNEL_SCOPE_SLOTS=31 ; retain scope support within this observer's tight internal DRAM
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
|
||||
build_src_filter =
|
||||
${LilyGo_TBeam.build_src_filter}
|
||||
+<helpers/bridges/MQTTBridge.cpp>
|
||||
+<helpers/MQTTMessageBuilder.cpp>
|
||||
+<helpers/JWTHelper.cpp>
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
${LilyGo_TBeam.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
elims/PsychicMqttClient@^0.2.4
|
||||
bblanchon/ArduinoJson @ 7.4.3
|
||||
arduino-libraries/NTPClient
|
||||
JChristensen/Timezone
|
||||
paulstoffregen/Time@1.6.1
|
||||
|
||||
[env:Tbeam_room_server_observer_mqtt]
|
||||
extends = env:Tbeam_SX1262_room_server_observer_mqtt
|
||||
build_flags =
|
||||
${LilyGo_TBeam.build_flags}
|
||||
-D ADVERT_NAME='"T-Beam Room Observer"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
-D ROOM_PASSWORD='"hello"'
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
-D MQTT_DEBUG=1
|
||||
-D CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
|
||||
build_src_filter =
|
||||
${LilyGo_TBeam.build_src_filter}
|
||||
+<helpers/bridges/MQTTBridge.cpp>
|
||||
+<helpers/MQTTMessageBuilder.cpp>
|
||||
+<helpers/JWTHelper.cpp>
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
+<../examples/simple_room_server>
|
||||
lib_deps =
|
||||
${LilyGo_TBeam.lib_deps}
|
||||
${esp32_ota.lib_deps}
|
||||
elims/PsychicMqttClient@^0.2.4
|
||||
bblanchon/ArduinoJson @ 7.4.3
|
||||
arduino-libraries/NTPClient
|
||||
JChristensen/Timezone
|
||||
paulstoffregen/Time@1.6.1
|
||||
@@ -0,0 +1,57 @@
|
||||
#include <Arduino.h>
|
||||
#include "target.h"
|
||||
#include <helpers/radiolib/ESP32LoRaChipProbe.h>
|
||||
#include <helpers/radiolib/SX126xBufferedRadioHal.h>
|
||||
#include <helpers/radiolib/TunableRadioHal.h>
|
||||
|
||||
UniversalTBeamBoard board;
|
||||
|
||||
static SPIClass spi;
|
||||
static SX126xBufferedRadioHal sx126x_hal(spi);
|
||||
static TunableRadioHal sx127x_hal(spi, 2000000);
|
||||
static Module sx126x_module(&sx126x_hal, P_LORA_NSS, P_LORA_DIO_1,
|
||||
P_LORA_RESET, P_LORA_BUSY);
|
||||
static Module sx127x_module(&sx127x_hal, P_LORA_NSS, P_LORA_DIO_0,
|
||||
P_LORA_RESET, P_LORA_DIO_1);
|
||||
UniversalLoRaRadio radio_driver(sx126x_module, sx127x_module, board);
|
||||
|
||||
ESP32RTCClock fallback_clock;
|
||||
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||
|
||||
#if ENV_INCLUDE_GPS
|
||||
#include <helpers/sensors/MicroNMEALocationProvider.h>
|
||||
MicroNMEALocationProvider nmea(Serial1, &rtc_clock);
|
||||
EnvironmentSensorManager sensors(nmea);
|
||||
#else
|
||||
EnvironmentSensorManager sensors;
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
DISPLAY_CLASS display;
|
||||
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
|
||||
#endif
|
||||
|
||||
mesh::LoRaRadioFamily universalLoRaRadioFamily() {
|
||||
return radio_driver.family();
|
||||
}
|
||||
|
||||
bool prepareUniversalLoRaRadio() {
|
||||
// TBeamBoard calls this after enabling the PMU's radio rail. Probe before
|
||||
// regulator policy or any modem initialization can touch the wrong chip.
|
||||
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
|
||||
const mesh::LoRaChipProbePins pins{P_LORA_NSS, P_LORA_RESET, P_LORA_BUSY};
|
||||
return radio_driver.selectFamily(mesh::probeUniversalLoRaChip(spi, pins));
|
||||
}
|
||||
|
||||
bool radio_init() {
|
||||
fallback_clock.begin();
|
||||
rtc_clock.begin(Wire);
|
||||
return radio_driver.stdInit(&spi);
|
||||
}
|
||||
|
||||
mesh::LocalIdentity radio_new_identity() {
|
||||
auto* physical = radio_driver.physicalLayer();
|
||||
if (!physical) return mesh::LocalIdentity();
|
||||
RadioNoiseListener rng(*physical);
|
||||
return mesh::LocalIdentity(&rng);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <helpers/radiolib/UniversalLoRaRadio.h>
|
||||
#include <helpers/esp32/TBeamBoard.h>
|
||||
#include <helpers/AutoDiscoverRTCClock.h>
|
||||
#include <helpers/sensors/EnvironmentSensorManager.h>
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include <helpers/ui/SSD1306Display.h>
|
||||
#include <helpers/ui/MomentaryButton.h>
|
||||
#endif
|
||||
|
||||
bool prepareUniversalLoRaRadio();
|
||||
mesh::LoRaRadioFamily universalLoRaRadioFamily();
|
||||
|
||||
class UniversalTBeamBoard : public TBeamBoard {
|
||||
public:
|
||||
uint32_t getIRQGpio() override {
|
||||
switch (universalLoRaRadioFamily()) {
|
||||
case mesh::LoRaRadioFamily::SX126x: return P_LORA_DIO_1;
|
||||
case mesh::LoRaRadioFamily::SX127x: return P_LORA_DIO_0;
|
||||
default: return static_cast<uint32_t>(-1);
|
||||
}
|
||||
}
|
||||
|
||||
const char* getManufacturerName() const override {
|
||||
switch (universalLoRaRadioFamily()) {
|
||||
case mesh::LoRaRadioFamily::SX126x: return "LilyGo T-Beam SX126x";
|
||||
case mesh::LoRaRadioFamily::SX127x: return "LilyGo T-Beam SX127x";
|
||||
default: return "LilyGo T-Beam (radio undetected)";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
extern UniversalTBeamBoard board;
|
||||
extern UniversalLoRaRadio radio_driver;
|
||||
extern AutoDiscoverRTCClock rtc_clock;
|
||||
extern EnvironmentSensorManager sensors;
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
extern DISPLAY_CLASS display;
|
||||
extern MomentaryButton user_btn;
|
||||
#endif
|
||||
|
||||
bool radio_init();
|
||||
mesh::LocalIdentity radio_new_identity();
|
||||
Reference in new issue
Block a user