From f4463154cff38e0f9718f8ee1f247e4911bec0f0 Mon Sep 17 00:00:00 2001 From: Rob Loranger Date: Fri, 20 Jun 2025 14:20:42 -0700 Subject: [PATCH 01/39] allows manual BLE pin even when device has display also updates remaining variants to use default of 123456 instead of 0 for random pin --- examples/companion_radio/MyMesh.cpp | 4 ++-- variants/heltec_v2/platformio.ini | 2 +- variants/heltec_v3/platformio.ini | 2 +- variants/nano_g2_ultra/platformio.ini | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 034f0206..da7150a1 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -613,10 +613,10 @@ void MyMesh::begin(bool has_display) { _prefs.cr = constrain(_prefs.cr, 5, 8); _prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, 1, MAX_LORA_TX_POWER); -#ifdef BLE_PIN_CODE +#ifdef BLE_PIN_CODE // 123456 by default if (_prefs.ble_pin == 0) { #ifdef DISPLAY_CLASS - if (has_display) { + if (has_display && BLE_PIN_CODE == 123456) { StdRNG rng; _active_ble_pin = rng.nextInt(100000, 999999); // random pin each session } else { diff --git a/variants/heltec_v2/platformio.ini b/variants/heltec_v2/platformio.ini index 562b309d..43bc43ad 100644 --- a/variants/heltec_v2/platformio.ini +++ b/variants/heltec_v2/platformio.ini @@ -96,7 +96,7 @@ build_flags = -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 - -D BLE_PIN_CODE=0 + -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 ; -D MESH_PACKET_LOGGING=1 diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index e8818fdd..41015477 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -107,7 +107,7 @@ build_flags = -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 -D DISPLAY_CLASS=SSD1306Display - -D BLE_PIN_CODE=0 ; dynamic, random PIN + -D BLE_PIN_CODE=123456 ; dynamic, random PIN -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 ; -D MESH_PACKET_LOGGING=1 diff --git a/variants/nano_g2_ultra/platformio.ini b/variants/nano_g2_ultra/platformio.ini index 20928bdf..c2bb1f23 100644 --- a/variants/nano_g2_ultra/platformio.ini +++ b/variants/nano_g2_ultra/platformio.ini @@ -36,7 +36,7 @@ build_flags = -I src/helpers/ui -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 - -D BLE_PIN_CODE=0 + -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 -D DISPLAY_CLASS=SH1106Display From e417c43c30b0eb270a8c647c92d2053164111194 Mon Sep 17 00:00:00 2001 From: JQ Date: Fri, 27 Jun 2025 22:57:49 -0700 Subject: [PATCH 02/39] wireless paper board support --- src/helpers/HeltecV3Board.h | 6 +- src/helpers/ui/E213Display.cpp | 116 ++++++++++++++++++ src/helpers/ui/E213Display.h | 37 ++++++ variants/heltec_wireless_paper/platformio.ini | 84 +++++++++++++ variants/heltec_wireless_paper/target.cpp | 44 +++++++ variants/heltec_wireless_paper/target.h | 27 ++++ 6 files changed, 312 insertions(+), 2 deletions(-) create mode 100644 src/helpers/ui/E213Display.cpp create mode 100644 src/helpers/ui/E213Display.h create mode 100644 variants/heltec_wireless_paper/platformio.ini create mode 100644 variants/heltec_wireless_paper/target.cpp create mode 100644 variants/heltec_wireless_paper/target.h diff --git a/src/helpers/HeltecV3Board.h b/src/helpers/HeltecV3Board.h index 57015a04..b71514cc 100644 --- a/src/helpers/HeltecV3Board.h +++ b/src/helpers/HeltecV3Board.h @@ -4,7 +4,7 @@ #include // LoRa radio module pins for Heltec V3 -// Also for Heltec Wireless Tracker +// Also for Heltec Wireless Tracker/Paper #define P_LORA_DIO_1 14 #define P_LORA_NSS 8 #define P_LORA_RESET RADIOLIB_NC @@ -14,7 +14,9 @@ #define P_LORA_MOSI 10 // built-ins -#define PIN_VBAT_READ 1 +#ifndef PIN_VBAT_READ // set in platformio.ini for boards like Heltec Wireless Paper (20) + #define PIN_VBAT_READ 1 +#endif #ifndef PIN_ADC_CTRL // set in platformio.ini for Heltec Wireless Tracker (2) #define PIN_ADC_CTRL 37 #endif diff --git a/src/helpers/ui/E213Display.cpp b/src/helpers/ui/E213Display.cpp new file mode 100644 index 00000000..5ec30b00 --- /dev/null +++ b/src/helpers/ui/E213Display.cpp @@ -0,0 +1,116 @@ +#include "E213Display.h" +#include "../../MeshCore.h" + +bool E213Display::begin() { + if (_init) return true; + + powerOn(); + display.begin(); + + // Set to landscape mode rotated 180 degrees + display.setRotation(3); + + _init = true; + _isOn = true; + + clear(); + display.fastmodeOn(); // Enable fast mode for quicker (partial) updates + + return true; +} + +void E213Display::powerOn() { + #ifdef PIN_VEXT_EN + pinMode(PIN_VEXT_EN, OUTPUT); + digitalWrite(PIN_VEXT_EN, LOW); // Active low + delay(50); // Allow power to stabilize + #endif +} + +void E213Display::powerOff() { + #ifdef PIN_VEXT_EN + digitalWrite(PIN_VEXT_EN, HIGH); // Turn off power + #endif +} + +void E213Display::turnOn() { + if (!_init) begin(); + powerOn(); + _isOn = true; +} + +void E213Display::turnOff() { + powerOff(); + _isOn = false; +} + +void E213Display::clear() { + display.clear(); +} + +void E213Display::startFrame(Color bkg) { + // Fill screen with white first to ensure clean background + display.fillRect(0, 0, width(), height(), WHITE); + if (bkg == LIGHT) { + // Fill with black if light background requested (inverted for e-ink) + display.fillRect(0, 0, width(), height(), BLACK); + } +} + +void E213Display::setTextSize(int sz) { + // The library handles text size internally + display.setTextSize(sz); +} + +void E213Display::setColor(Color c) { + // implemented in individual display methods +} + +void E213Display::setCursor(int x, int y) { + display.setCursor(x, y); +} + +void E213Display::print(const char* str) { + display.print(str); +} + +void E213Display::fillRect(int x, int y, int w, int h) { + display.fillRect(x, y, w, h, BLACK); +} + +void E213Display::drawRect(int x, int y, int w, int h) { + display.drawRect(x, y, w, h, BLACK); +} + +void E213Display::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { + // Width in bytes for bitmap processing + uint16_t widthInBytes = (w + 7) / 8; + + // Process the bitmap row by row + for (int by = 0; by < h; by++) { + // Scan across the row bit by bit + for (int bx = 0; bx < w; bx++) { + // Get the current bit using MSB ordering (like GxEPDDisplay) + uint16_t byteOffset = (by * widthInBytes) + (bx / 8); + uint8_t bitMask = 0x80 >> (bx & 7); + bool bitSet = bits[byteOffset] & bitMask; + + // If the bit is set, draw the pixel + if (bitSet) { + display.drawPixel(x + bx, y + by, BLACK); + } + } + } +} + +uint16_t E213Display::getTextWidth(const char* str) { + int16_t x1, y1; + uint16_t w, h; + display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h); + return w; +} + +void E213Display::endFrame() { + display.update(); +} + diff --git a/src/helpers/ui/E213Display.h b/src/helpers/ui/E213Display.h new file mode 100644 index 00000000..d568b45f --- /dev/null +++ b/src/helpers/ui/E213Display.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include "DisplayDriver.h" + +// Display driver for E213 e-ink display +class E213Display : public DisplayDriver { + EInkDisplay_VisionMasterE213 display; + bool _init = false; + bool _isOn = false; + +public: + E213Display() : DisplayDriver(250, 122) { + } + + bool begin(); + bool isOn() override { return _isOn; } + void turnOn() override; + void turnOff() override; + void clear() override; + void startFrame(Color bkg = DARK) override; + void setTextSize(int sz) override; + void setColor(Color c) override; + void setCursor(int x, int y) override; + void print(const char* str) override; + void fillRect(int x, int y, int w, int h) override; + void drawRect(int x, int y, int w, int h) override; + void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override; + uint16_t getTextWidth(const char* str) override; + void endFrame() override; + +private: + void powerOn(); + void powerOff(); +}; \ No newline at end of file diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini new file mode 100644 index 00000000..0b9ac38e --- /dev/null +++ b/variants/heltec_wireless_paper/platformio.ini @@ -0,0 +1,84 @@ +[Heltec_Wireless_Paper_base] +extends = esp32_base +board = esp32-s3-devkitc-1 +build_flags = + ${esp32_base.build_flags} + -I variants/heltec_wireless_paper + -D HELTEC_WIRELESS_PAPER + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D P_LORA_TX_LED=18 + ; -D PIN_BOARD_SDA=17 + ; -D PIN_BOARD_SCL=18 + -D PIN_USER_BTN=0 + -D PIN_VEXT_EN=45 + -D PIN_VBAT_READ=20 + -D PIN_ADC_CTRL=19 + -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 DISP_CS=4 + -D DISP_BUSY=7 + -D DISP_DC=5 + -D DISP_RST=6 + -D DISP_SCLK=3 + -D DISP_MOSI=2 + -D ARDUINO_heltec_wifi_lora_32_V3 + -D WIRELESS_PAPER +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/heltec_wireless_paper> +lib_deps = + ${esp32_base.lib_deps} + todd-herbert/heltec-eink-modules @ 4.5.0 + +[env:Heltec_Wireless_Paper_companion_radio_ble] +extends = Heltec_Wireless_Paper_base +build_flags = + ${Heltec_Wireless_Paper_base.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D DISPLAY_CLASS=E213Display + -D BLE_PIN_CODE=0 ; dynamic, random PIN + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 +build_src_filter = ${Heltec_Wireless_Paper_base.build_src_filter} + + + + + +<../examples/companion_radio> +lib_deps = + ${Heltec_Wireless_Paper_base.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Heltec_Wireless_Paper_repeater] +extends = Heltec_Wireless_Paper_base +build_flags = + ${Heltec_Wireless_Paper_base.build_flags} + -D DISPLAY_CLASS=E213Display + -D ADVERT_NAME='"Heltec WP Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 +build_src_filter = ${Heltec_Wireless_Paper_base.build_src_filter} + + + +<../examples/simple_repeater> +lib_deps = + ${Heltec_Wireless_Paper_base.lib_deps} + ${esp32_ota.lib_deps} + +[env:Heltec_Wireless_Paper_room_server] +extends = Heltec_Wireless_Paper_base +build_flags = + ${Heltec_Wireless_Paper_base.build_flags} + -D DISPLAY_CLASS=E213Display + -D ADVERT_NAME='"Heltec WP Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +build_src_filter = ${Heltec_Wireless_Paper_base.build_src_filter} + + + +<../examples/simple_room_server> +lib_deps = + ${Heltec_Wireless_Paper_base.lib_deps} + ${esp32_ota.lib_deps} \ No newline at end of file diff --git a/variants/heltec_wireless_paper/target.cpp b/variants/heltec_wireless_paper/target.cpp new file mode 100644 index 00000000..b2808689 --- /dev/null +++ b/variants/heltec_wireless_paper/target.cpp @@ -0,0 +1,44 @@ +#include +#include "target.h" + +HeltecV3Board board; + +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); + +SensorManager sensors; + +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + +bool radio_init() { + fallback_clock.begin(); + rtc_clock.begin(Wire); + 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(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} \ No newline at end of file diff --git a/variants/heltec_wireless_paper/target.h b/variants/heltec_wireless_paper/target.h new file mode 100644 index 00000000..e3130308 --- /dev/null +++ b/variants/heltec_wireless_paper/target.h @@ -0,0 +1,27 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#ifdef DISPLAY_CLASS + #include +#endif + +extern HeltecV3Board board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern SensorManager sensors; + +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + +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(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); \ No newline at end of file From ff3e888dfd7ad139ff77be492faf7bbf44a7d0a1 Mon Sep 17 00:00:00 2001 From: JQ Date: Fri, 27 Jun 2025 23:30:52 -0700 Subject: [PATCH 03/39] formatting --- src/helpers/ui/E213Display.cpp | 38 +++++++++++------------ src/helpers/ui/E213Display.h | 14 ++++----- variants/heltec_wireless_paper/target.cpp | 7 +++-- variants/heltec_wireless_paper/target.h | 10 +++--- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/helpers/ui/E213Display.cpp b/src/helpers/ui/E213Display.cpp index 5ec30b00..92bf37fb 100644 --- a/src/helpers/ui/E213Display.cpp +++ b/src/helpers/ui/E213Display.cpp @@ -1,36 +1,37 @@ #include "E213Display.h" + #include "../../MeshCore.h" bool E213Display::begin() { if (_init) return true; - + powerOn(); display.begin(); - + // Set to landscape mode rotated 180 degrees display.setRotation(3); - + _init = true; _isOn = true; - + clear(); display.fastmodeOn(); // Enable fast mode for quicker (partial) updates - + return true; } void E213Display::powerOn() { - #ifdef PIN_VEXT_EN - pinMode(PIN_VEXT_EN, OUTPUT); - digitalWrite(PIN_VEXT_EN, LOW); // Active low - delay(50); // Allow power to stabilize - #endif +#ifdef PIN_VEXT_EN + pinMode(PIN_VEXT_EN, OUTPUT); + digitalWrite(PIN_VEXT_EN, LOW); // Active low + delay(50); // Allow power to stabilize +#endif } void E213Display::powerOff() { - #ifdef PIN_VEXT_EN - digitalWrite(PIN_VEXT_EN, HIGH); // Turn off power - #endif +#ifdef PIN_VEXT_EN + digitalWrite(PIN_VEXT_EN, HIGH); // Turn off power +#endif } void E213Display::turnOn() { @@ -70,7 +71,7 @@ void E213Display::setCursor(int x, int y) { display.setCursor(x, y); } -void E213Display::print(const char* str) { +void E213Display::print(const char *str) { display.print(str); } @@ -82,10 +83,10 @@ void E213Display::drawRect(int x, int y, int w, int h) { display.drawRect(x, y, w, h, BLACK); } -void E213Display::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { +void E213Display::drawXbm(int x, int y, const uint8_t *bits, int w, int h) { // Width in bytes for bitmap processing uint16_t widthInBytes = (w + 7) / 8; - + // Process the bitmap row by row for (int by = 0; by < h; by++) { // Scan across the row bit by bit @@ -94,7 +95,7 @@ void E213Display::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { uint16_t byteOffset = (by * widthInBytes) + (bx / 8); uint8_t bitMask = 0x80 >> (bx & 7); bool bitSet = bits[byteOffset] & bitMask; - + // If the bit is set, draw the pixel if (bitSet) { display.drawPixel(x + bx, y + by, BLACK); @@ -103,7 +104,7 @@ void E213Display::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { } } -uint16_t E213Display::getTextWidth(const char* str) { +uint16_t E213Display::getTextWidth(const char *str) { int16_t x1, y1; uint16_t w, h; display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h); @@ -113,4 +114,3 @@ uint16_t E213Display::getTextWidth(const char* str) { void E213Display::endFrame() { display.update(); } - diff --git a/src/helpers/ui/E213Display.h b/src/helpers/ui/E213Display.h index d568b45f..330a2b6d 100644 --- a/src/helpers/ui/E213Display.h +++ b/src/helpers/ui/E213Display.h @@ -1,9 +1,10 @@ #pragma once +#include "DisplayDriver.h" + #include #include #include -#include "DisplayDriver.h" // Display driver for E213 e-ink display class E213Display : public DisplayDriver { @@ -12,8 +13,7 @@ class E213Display : public DisplayDriver { bool _isOn = false; public: - E213Display() : DisplayDriver(250, 122) { - } + E213Display() : DisplayDriver(250, 122) {} bool begin(); bool isOn() override { return _isOn; } @@ -24,13 +24,13 @@ public: void setTextSize(int sz) override; void setColor(Color c) override; void setCursor(int x, int y) override; - void print(const char* str) override; + void print(const char *str) override; void fillRect(int x, int y, int w, int h) override; void drawRect(int x, int y, int w, int h) override; - void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override; - uint16_t getTextWidth(const char* str) override; + void drawXbm(int x, int y, const uint8_t *bits, int w, int h) override; + uint16_t getTextWidth(const char *str) override; void endFrame() override; - + private: void powerOn(); void powerOff(); diff --git a/variants/heltec_wireless_paper/target.cpp b/variants/heltec_wireless_paper/target.cpp index b2808689..65eaab04 100644 --- a/variants/heltec_wireless_paper/target.cpp +++ b/variants/heltec_wireless_paper/target.cpp @@ -1,6 +1,7 @@ -#include #include "target.h" +#include + HeltecV3Board board; static SPIClass spi; @@ -14,7 +15,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; #ifdef DISPLAY_CLASS - DISPLAY_CLASS display; +DISPLAY_CLASS display; #endif bool radio_init() { @@ -40,5 +41,5 @@ void radio_set_tx_power(uint8_t dbm) { mesh::LocalIdentity radio_new_identity() { RadioNoiseListener rng(radio); - return mesh::LocalIdentity(&rng); // create new random identity + return mesh::LocalIdentity(&rng); // create new random identity } \ No newline at end of file diff --git a/variants/heltec_wireless_paper/target.h b/variants/heltec_wireless_paper/target.h index e3130308..f06eead3 100644 --- a/variants/heltec_wireless_paper/target.h +++ b/variants/heltec_wireless_paper/target.h @@ -2,13 +2,13 @@ #define RADIOLIB_STATIC_ONLY 1 #include -#include -#include -#include #include +#include +#include +#include #include #ifdef DISPLAY_CLASS - #include +#include #endif extern HeltecV3Board board; @@ -17,7 +17,7 @@ extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; #ifdef DISPLAY_CLASS - extern DISPLAY_CLASS display; +extern DISPLAY_CLASS display; #endif bool radio_init(); From ddbf27c245fd27aa346f996f8f1477b99030790f Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Sun, 29 Jun 2025 15:16:02 +0200 Subject: [PATCH 04/39] change fixed preamble to match the new 16 --- src/helpers/CustomLR1110Wrapper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/CustomLR1110Wrapper.h b/src/helpers/CustomLR1110Wrapper.h index 7e2ffa2d..947bb51d 100644 --- a/src/helpers/CustomLR1110Wrapper.h +++ b/src/helpers/CustomLR1110Wrapper.h @@ -17,7 +17,7 @@ public: void onSendFinished() override { RadioLibWrapper::onSendFinished(); - _radio->setPreambleLength(8); // overcomes weird issues with small and big pkts + _radio->setPreambleLength(16); // overcomes weird issues with small and big pkts } float getLastRSSI() const override { return ((CustomLR1110 *)_radio)->getRSSI(); } From 1bfa3d338c8821590e9132117604612bb41cf560 Mon Sep 17 00:00:00 2001 From: seagull9000 Date: Mon, 30 Jun 2025 09:48:18 +1200 Subject: [PATCH 05/39] Refactor radiolib for Heltec Wireless Tracker Made changes and tested transmission and reception. Note: TX to T1000E would not work direct, but always went through a repeater. TX to two Thinknode M1's went through direct.. --- variants/heltec_tracker/target.cpp | 33 +++--------------------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/variants/heltec_tracker/target.cpp b/variants/heltec_tracker/target.cpp index 042c7c0d..f41702c5 100644 --- a/variants/heltec_tracker/target.cpp +++ b/variants/heltec_tracker/target.cpp @@ -23,43 +23,16 @@ HWTSensorManager sensors = HWTSensorManager(nmea); DISPLAY_CLASS display(&board.periph_power); // peripheral power pin is shared #endif -#ifndef LORA_CR - #define LORA_CR 5 -#endif - bool radio_init() { fallback_clock.begin(); rtc_clock.begin(Wire); -#ifdef SX126X_DIO3_TCXO_VOLTAGE - float tcxo = SX126X_DIO3_TCXO_VOLTAGE; -#else - float tcxo = 1.6f; -#endif - #if defined(P_LORA_SCLK) - spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); -#endif - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); - if (status != RADIOLIB_ERR_NONE) { - Serial.print("ERROR: radio init failed: "); - Serial.println(status); - return false; // fail - } - - radio.setCRC(1); - -#ifdef SX126X_CURRENT_LIMIT - radio.setCurrentLimit(SX126X_CURRENT_LIMIT); -#endif -#ifdef SX126X_DIO2_AS_RF_SWITCH - radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); -#endif -#ifdef SX126X_RX_BOOSTED_GAIN - radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); + return radio.std_init(&spi); +#else + return radio.std_init(); #endif - return true; // success } uint32_t radio_get_rng_seed() { From c56da5e6aa9708ee711bac37b53bc54ddb80956e Mon Sep 17 00:00:00 2001 From: taco Date: Mon, 30 Jun 2025 08:51:18 +1000 Subject: [PATCH 06/39] refactor: lilgo_t3s3 with CustomSX1262::std_init() --- variants/lilygo_t3s3/target.cpp | 39 +++------------------------------ 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/variants/lilygo_t3s3/target.cpp b/variants/lilygo_t3s3/target.cpp index 7fa45e54..b7c4542c 100644 --- a/variants/lilygo_t3s3/target.cpp +++ b/variants/lilygo_t3s3/target.cpp @@ -3,13 +3,8 @@ ESP32Board board; -#if defined(P_LORA_SCLK) - static SPIClass spi; - RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); -#else - RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); -#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; @@ -28,35 +23,7 @@ bool radio_init() { fallback_clock.begin(); rtc_clock.begin(Wire); -#ifdef SX126X_DIO3_TCXO_VOLTAGE - float tcxo = SX126X_DIO3_TCXO_VOLTAGE; -#else - float tcxo = 1.6f; -#endif - -#if defined(P_LORA_SCLK) - spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); -#endif - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); - if (status != RADIOLIB_ERR_NONE) { - Serial.print("ERROR: radio init failed: "); - Serial.println(status); - return false; // fail - } - - radio.setCRC(1); - -#ifdef SX126X_CURRENT_LIMIT - radio.setCurrentLimit(SX126X_CURRENT_LIMIT); -#endif -#ifdef SX126X_DIO2_AS_RF_SWITCH - radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); -#endif -#ifdef SX126X_RX_BOOSTED_GAIN - radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); -#endif - - return true; // success + return radio.std_init(&spi); } uint32_t radio_get_rng_seed() { From 4541380632a791dd7e2de70ea1c1e36f2f9d85a9 Mon Sep 17 00:00:00 2001 From: jankowski-t Date: Mon, 30 Jun 2025 03:46:18 +0200 Subject: [PATCH 07/39] Support MeshAdventurer Added support for MeshAdventurer, including radio, display, button, GPS, voltage reading --- src/helpers/MeshadventurerBoard.h | 81 +++++++++ variants/meshadventurer/platformio.ini | 234 +++++++++++++++++++++++++ variants/meshadventurer/target.cpp | 152 ++++++++++++++++ variants/meshadventurer/target.h | 46 +++++ variants/meshadventurer/variant.h | 44 +++++ 5 files changed, 557 insertions(+) create mode 100644 src/helpers/MeshadventurerBoard.h create mode 100644 variants/meshadventurer/platformio.ini create mode 100644 variants/meshadventurer/target.cpp create mode 100644 variants/meshadventurer/target.h create mode 100644 variants/meshadventurer/variant.h diff --git a/src/helpers/MeshadventurerBoard.h b/src/helpers/MeshadventurerBoard.h new file mode 100644 index 00000000..65e11102 --- /dev/null +++ b/src/helpers/MeshadventurerBoard.h @@ -0,0 +1,81 @@ +#pragma once + +#include + +// LoRa radio module pins for Meshadventurer +#define P_LORA_DIO_1 33 +#define P_LORA_NSS 18 +#define P_LORA_RESET 23 +#define P_LORA_BUSY 32 +#define P_LORA_SCLK 5 +#define P_LORA_MISO 19 +#define P_LORA_MOSI 27 + +#define PIN_VBAT_READ 35 + +#include "ESP32Board.h" + +#include + +class MeshadventurerBoard : public ESP32Board { + +public: + void begin() { + ESP32Board::begin(); + + esp_reset_reason_t reason = esp_reset_reason(); + if (reason == ESP_RST_DEEPSLEEP) { + long wakeup_source = esp_sleep_get_ext1_wakeup_status(); + if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep) + startup_reason = BD_STARTUP_RX_PACKET; + } + + rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS); + rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1); + } + } + + void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) { + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + + // Make sure the DIO1 and NSS GPIOs are held on required levels during deep sleep + rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY); + rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1); + + rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS); + + if (pin_wake_btn < 0) { + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet + } else { + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn + } + + if (secs > 0) { + esp_sleep_enable_timer_wakeup(secs * 1000000); + } + + // Finally set ESP32 into sleep + esp_deep_sleep_start(); // CPU halts here and never returns! + } + + void powerOff() override { + // TODO: re-enable this when there is a definite wake-up source pin: + // enterDeepSleep(0); + } + + uint16_t getBattMilliVolts() override { + analogReadResolution(12); + + uint32_t raw = 0; + for (int i = 0; i < 4; i++) { + raw += analogReadMilliVolts(PIN_VBAT_READ); + } + raw = raw / 4; + + return (2 * raw); + } + + const char* getManufacturerName() const override { + return "Meshadventurer"; + } +}; diff --git a/variants/meshadventurer/platformio.ini b/variants/meshadventurer/platformio.ini new file mode 100644 index 00000000..5fea4103 --- /dev/null +++ b/variants/meshadventurer/platformio.ini @@ -0,0 +1,234 @@ +[Meshadventurer] +extends = esp32_base +board = esp32doit-devkit-v1 +board_build.partitions = min_spiffs.csv ; get around 4mb flash limit +build_flags = + ${esp32_base.build_flags} + -I variants/meshadventurer + -D MESHADVENTURER + -D P_LORA_TX_LED=2 + -D PIN_VBAT_READ=35 + -D PIN_USER_BTN_ANA=39 + -D P_LORA_DIO_1=33 + -D P_LORA_NSS=18 + -D P_LORA_RESET=23 + -D P_LORA_BUSY=32 + -D P_LORA_SCLK=5 + -D P_LORA_MOSI=27 + -D P_LORA_MISO=19 + -D SX126X_TXEN=13 + -D SX126X_RXEN=14 + -D PIN_BOARD_SDA=21 + -D PIN_BOARD_SCL=22 + -D SX126X_DIO2_AS_RF_SWITCH=false + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_RX_BOOSTED_GAIN=1 + -D PIN_GPS_RX=12 + -D PIN_GPS_TX=15 + -D DISPLAY_CLASS=SSD1306Display +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/meshadventurer> +lib_deps = + ${esp32_base.lib_deps} + stevemarple/MicroNMEA @ ^2.0.6 + adafruit/Adafruit SSD1306 @ ^2.5.13 + +[env:Meshadventurer_sx1262_repeater] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_repeater/main.cpp> + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Meshadventurer Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + ${esp32_ota.lib_deps} + +[env:Meshadventurer_sx1268_repeater] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_repeater/main.cpp> + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Meshadventurer Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + ${esp32_ota.lib_deps} + +[env:Meshadventurer_sx1262_companion_radio_usb] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/companion_radio> + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1262_companion_radio_ble] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/companion_radio> + + + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1262_terminal_chat] +extends = Meshadventurer +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> + + +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1262_room_server] +extends = Meshadventurer +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Meshadventurer Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_room_server> + + +lib_deps = + ${Meshadventurer.lib_deps} + ${esp32_ota.lib_deps} + +[env:Meshadventurer_sx1268_companion_radio_usb] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/companion_radio> + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1268_companion_radio_ble] +extends = Meshadventurer +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/companion_radio> + + + + +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1268_terminal_chat] +extends = Meshadventurer +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> + + +lib_deps = + ${Meshadventurer.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Meshadventurer_sx1268_room_server] +extends = Meshadventurer +build_flags = + ${Meshadventurer.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Meshadventurer Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Meshadventurer.build_src_filter} + +<../examples/simple_room_server> + + +lib_deps = + ${Meshadventurer.lib_deps} + ${esp32_ota.lib_deps} \ No newline at end of file diff --git a/variants/meshadventurer/target.cpp b/variants/meshadventurer/target.cpp new file mode 100644 index 00000000..43e171c0 --- /dev/null +++ b/variants/meshadventurer/target.cpp @@ -0,0 +1,152 @@ +#include +#include "target.h" + +#include + +MeshadventurerBoard board; + +#if defined(P_LORA_SCLK) + static SPIClass spi; + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); +#else + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); +#endif + +WRAPPER_CLASS radio_driver(radio, board); + +ESP32RTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); +MASensorManager sensors = MASensorManager(nmea); + +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + +#ifndef LORA_CR + #define LORA_CR 5 +#endif + +bool radio_init() { + fallback_clock.begin(); + rtc_clock.begin(Wire); + +#ifdef SX126X_DIO3_TCXO_VOLTAGE + float tcxo = SX126X_DIO3_TCXO_VOLTAGE; +#else + float tcxo = 1.6f; +#endif + +#if defined(P_LORA_SCLK) + spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); +#endif + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + radio.setCRC(1); + +#if defined(SX126X_RXEN) && defined(SX126X_TXEN) + radio.setRfSwitchPins(SX126X_RXEN, SX126X_TXEN); +#endif + +#ifdef SX126X_CURRENT_LIMIT + radio.setCurrentLimit(SX126X_CURRENT_LIMIT); +#endif +#ifdef SX126X_DIO2_AS_RF_SWITCH + radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); +#endif +#ifdef SX126X_RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); +#endif + + return true; // success +} + +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(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} + +void MASensorManager::start_gps() { + if(!gps_active) { + MESH_DEBUG_PRINTLN("starting GPS"); + gps_active = true; + } +} + +void MASensorManager::stop_gps() { + if(gps_active) { + MESH_DEBUG_PRINTLN("stopping GPS"); + gps_active = false; + } +} + +bool MASensorManager::begin() { + Serial1.setPins(PIN_GPS_RX, PIN_GPS_TX); + Serial1.begin(9600); + delay(500); + return true; +} + +bool MASensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { + if(requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? + telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); + } + return true; +} + +void MASensorManager::loop() { + static long next_gps_update = 0; + _location->loop(); + if(millis() > next_gps_update && gps_active) { + if(_location->isValid()) { + node_lat = ((double)_location->getLatitude()) / 1000000.; + node_lon = ((double)_location->getLongitude()) / 1000000.; + node_altitude = ((double)_location->getAltitude()) / 1000.0; + MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); + } + next_gps_update = millis() + 1000; + } +} + +int MASensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch) + +const char* MASensorManager::getSettingName(int i) const { + return i == 0 ? "gps" : NULL; +} +const char* MASensorManager::getSettingValue(int i) const { + if(i == 0) { + return gps_active ? "1" : "0"; + } + return NULL; +} +bool MASensorManager::setSettingValue(const char* name, const char* value) { + if(strcmp(name, "gps") == 0) { + if(strcmp(value, "0") == 0) { + stop_gps(); + } else { + start_gps(); + } + return true; + } + return false; // not supported +} diff --git a/variants/meshadventurer/target.h b/variants/meshadventurer/target.h new file mode 100644 index 00000000..0e0235ba --- /dev/null +++ b/variants/meshadventurer/target.h @@ -0,0 +1,46 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DISPLAY_CLASS + #include +#endif + +class MASensorManager : public SensorManager { + bool gps_active = false; + LocationProvider * _location; + + void start_gps(); + void stop_gps(); +public: + MASensorManager(LocationProvider &location): _location(&location) { } + bool begin() override; + bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + void loop() override; + int getNumSettings() const override; + const char* getSettingName(int i) const override; + const char* getSettingValue(int i) const override; + bool setSettingValue(const char* name, const char* value) override; +}; + +extern MeshadventurerBoard board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern MASensorManager sensors; + +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; +#endif + +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(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/meshadventurer/variant.h b/variants/meshadventurer/variant.h new file mode 100644 index 00000000..356a3e17 --- /dev/null +++ b/variants/meshadventurer/variant.h @@ -0,0 +1,44 @@ +// For OLED LCD +#define I2C_SDA 21 +#define I2C_SCL 22 + +// For GPS, 'undef's not needed +#define GPS_TX_PIN 15 +#define GPS_RX_PIN 12 +#define PIN_GPS_EN 4 +#define GPS_POWER_TOGGLE // Moved definition from platformio.ini to here + +#define BUTTON_PIN 39 // The middle button GPIO on the T-Beam +#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage +#define ADC_CHANNEL ADC1_GPIO35_CHANNEL +#define ADC_MULTIPLIER 2 +#define EXT_PWR_DETECT 4 // Pin to detect connected external power source for LILYGO® TTGO T-Energy T18 and other DIY boards +#define EXT_NOTIFY_OUT 12 // Overridden default pin to use for Ext Notify Module (#975). +#define LED_PIN 2 // add status LED (compatible with core-pcb and DIY targets) + +// Radio +#define USE_SX1262 // E22-900M30S uses SX1262 +#define USE_SX1268 // E22-400M30S uses SX1268 +#define SX126X_MAX_POWER 22 // Outputting 22dBm from SX1262 results in ~30dBm E22-900M30S output (module only uses last stage of the YP2233W PA) +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 // E22 series TCXO reference voltage is 1.8V + +#define SX126X_CS 18 // EBYTE module's NSS pin +#define SX126X_SCK 5 // EBYTE module's SCK pin +#define SX126X_MOSI 27 // EBYTE module's MOSI pin +#define SX126X_MISO 19 // EBYTE module's MISO pin +#define SX126X_RESET 23 // EBYTE module's NRST pin +#define SX126X_BUSY 32 // EBYTE module's BUSY pin +#define SX126X_DIO1 33 // EBYTE module's DIO1 pin + +// The E22's TXEN pin is connected to MCU pin, E22's RXEN pin is connected to MCU pin (allows for ramping up PA before transmission +// Don't define DIO2_AS_RF_SWITCH because we only use DIO2 or an MCU pin mutually exclusively to connect to E22's TXEN (to prevent +// a short if they are both connected at the same time and there's a slight non-neglibible delay and/or voltage difference between +// DIO2 and TXEN). +#define SX126X_TXEN 13 // Schematic connects EBYTE module's TXEN pin to MCU +#define SX126X_RXEN 14 // Schematic connects EBYTE module's RXEN pin to MCU + +#define LORA_CS SX126X_CS // Compatibility with variant file configuration structure +#define LORA_SCK SX126X_SCK // Compatibility with variant file configuration structure +#define LORA_MOSI SX126X_MOSI // Compatibility with variant file configuration structure +#define LORA_MISO SX126X_MISO // Compatibility with variant file configuration structure +#define LORA_DIO1 SX126X_DIO1 // Compatibility with variant file configuration structure From c91356016bbcf0366bd0478af9c6f33a00cc2a2d Mon Sep 17 00:00:00 2001 From: jankowski-t Date: Mon, 30 Jun 2025 05:40:07 +0200 Subject: [PATCH 08/39] Fixed MeshAdventurer repeater build failing Update build_src_filter in platformio.ini --- variants/meshadventurer/platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/variants/meshadventurer/platformio.ini b/variants/meshadventurer/platformio.ini index 5fea4103..f8995e18 100644 --- a/variants/meshadventurer/platformio.ini +++ b/variants/meshadventurer/platformio.ini @@ -36,7 +36,7 @@ lib_deps = [env:Meshadventurer_sx1262_repeater] extends = Meshadventurer build_src_filter = ${Meshadventurer.build_src_filter} - +<../examples/simple_repeater/main.cpp> + +<../examples/simple_repeater> + build_flags = ${Meshadventurer.build_flags} @@ -57,7 +57,7 @@ lib_deps = [env:Meshadventurer_sx1268_repeater] extends = Meshadventurer build_src_filter = ${Meshadventurer.build_src_filter} - +<../examples/simple_repeater/main.cpp> + +<../examples/simple_repeater> + build_flags = ${Meshadventurer.build_flags} From 8c80c10d2a0bc1dff1853252610154eae0192635 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 30 Jun 2025 18:57:24 +1000 Subject: [PATCH 09/39] * CustomLR1110::getTimeOnAir(), copied from sx1262 --- src/helpers/CustomLR1110.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/helpers/CustomLR1110.h b/src/helpers/CustomLR1110.h index 3451aac1..d431dac1 100644 --- a/src/helpers/CustomLR1110.h +++ b/src/helpers/CustomLR1110.h @@ -9,6 +9,35 @@ class CustomLR1110 : public LR1110 { public: CustomLR1110(Module *mod) : LR1110(mod) { } + RadioLibTime_t getTimeOnAir(size_t len) override { + uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << this->spreadingFactor) / (this->bandwidthKhz * 10) ; + uint8_t sfCoeff1_x4 = 17; // (4.25 * 4) + uint8_t sfCoeff2 = 8; + if(this->spreadingFactor == 5 || this->spreadingFactor == 6) { + sfCoeff1_x4 = 25; // 6.25 * 4 + sfCoeff2 = 0; + } + uint8_t sfDivisor = 4*this->spreadingFactor; + if(symbolLength_us >= 16000) { + sfDivisor = 4*(this->spreadingFactor - 2); + } + const int8_t bitsPerCrc = 16; + const int8_t N_symbol_header = this->headerType == RADIOLIB_SX126X_LORA_HEADER_EXPLICIT ? 20 : 0; + + // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8) + int16_t bitCount = (int16_t) 8 * len + this->crcTypeLoRa * bitsPerCrc - 4 * this->spreadingFactor + sfCoeff2 + N_symbol_header; + if(bitCount < 0) { + bitCount = 0; + } + // add (sfDivisor) - 1 to the numerator to give integer CEIL(...) + uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor); + + // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit + uint32_t nSymbol_x4 = (this->preambleLengthLoRa + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * (this->codingRate + 4) * 4; + + return((symbolLength_us * nSymbol_x4) / 4); + } + bool isReceiving() { uint16_t irq = getIrqStatus(); bool detected = ((irq & LR1110_IRQ_HEADER_VALID) || (irq & LR1110_IRQ_HAS_PREAMBLE)); From 3dc4607d8960437e4349b9b785eb66cf55610fb1 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 30 Jun 2025 23:18:16 +1000 Subject: [PATCH 10/39] * PAYLOAD_TYPE_PATH: reserving upper 4 bits if 'extra_type' field, for future use --- src/Mesh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mesh.cpp b/src/Mesh.cpp index a6b06c07..87f99878 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -135,7 +135,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) { int k = 0; uint8_t path_len = data[k++]; uint8_t* path = &data[k]; k += path_len; - uint8_t extra_type = data[k++]; + uint8_t extra_type = data[k++] & 0x0F; // upper 4 bits reserved for future use uint8_t* extra = &data[k]; uint8_t extra_len = len - k; // remainder of packet (may be padded with zeroes!) if (onPeerPathRecv(pkt, j, secret, path, path_len, extra_type, extra, extra_len)) { From 6f94c8148a54c6f31d85303e973e64d8686e7285 Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Tue, 1 Jul 2025 01:56:34 +0300 Subject: [PATCH 11/39] Add Minewsemi ME25LS01 variant --- boards/minewsemi_me25ls01.json | 59 +++++ src/helpers/nrf52/MinewsemiME25LS01Board.cpp | 92 ++++++++ src/helpers/nrf52/MinewsemiME25LS01Board.h | 112 ++++++++++ .../minewsemi_me25ls01/NullDisplayDriver.h | 24 ++ variants/minewsemi_me25ls01/platformio.ini | 184 +++++++++++++++ variants/minewsemi_me25ls01/target.cpp | 209 ++++++++++++++++++ variants/minewsemi_me25ls01/target.h | 46 ++++ variants/minewsemi_me25ls01/variant.cpp | 98 ++++++++ variants/minewsemi_me25ls01/variant.h | 147 ++++++++++++ 9 files changed, 971 insertions(+) create mode 100644 boards/minewsemi_me25ls01.json create mode 100644 src/helpers/nrf52/MinewsemiME25LS01Board.cpp create mode 100644 src/helpers/nrf52/MinewsemiME25LS01Board.h create mode 100644 variants/minewsemi_me25ls01/NullDisplayDriver.h create mode 100644 variants/minewsemi_me25ls01/platformio.ini create mode 100644 variants/minewsemi_me25ls01/target.cpp create mode 100644 variants/minewsemi_me25ls01/target.h create mode 100644 variants/minewsemi_me25ls01/variant.cpp create mode 100644 variants/minewsemi_me25ls01/variant.h diff --git a/boards/minewsemi_me25ls01.json b/boards/minewsemi_me25ls01.json new file mode 100644 index 00000000..4c943158 --- /dev/null +++ b/boards/minewsemi_me25ls01.json @@ -0,0 +1,59 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v7.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_WIO_WM1110 -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + ["0x239A", "0x8029"], + ["0x239A", "0x0029"], + ["0x239A", "0x002A"], + ["0x239A", "0x802A"] + ], + "usb_product": "me25ls01-BOOT", + "mcu": "nrf52840", + "variant": "minewsemi_me25ls01", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "7.3.0", + "sd_fwid": "0x0123" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": ["bluetooth"], + "debug": { + "jlink_device": "nRF52840_xxAA", + "svd_path": "nrf52840.svd", + "openocd_target": "nrf52.cfg" + }, + "frameworks": ["arduino"], + "name": "Minewsemi ME25LS01", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "speed": 115200, + "protocol": "nrfutil", + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "stlink", + "cmsis-dap", + "blackmagic" + ], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://en.minewsemi.com/lora-module/lr1110-nrf52840-me25LS01", + "vendor": "MINEWSEMI" +} diff --git a/src/helpers/nrf52/MinewsemiME25LS01Board.cpp b/src/helpers/nrf52/MinewsemiME25LS01Board.cpp new file mode 100644 index 00000000..f402a0fd --- /dev/null +++ b/src/helpers/nrf52/MinewsemiME25LS01Board.cpp @@ -0,0 +1,92 @@ +#include +#include "MinewsemiME25LS01Board.h" +#include + +#include + +void MinewsemiME25LS01Board::begin() { + // for future use, sub-classes SHOULD call this from their begin() + startup_reason = BD_STARTUP_NORMAL; + btn_prev_state = HIGH; + + sd_power_mode_set(NRF_POWER_MODE_LOWPWR); + +#ifdef BUTTON_PIN + // pinMode(BATTERY_PIN, INPUT); + pinMode(BUTTON_PIN, INPUT); + pinMode(LED_PIN, OUTPUT); +#endif + +#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) + Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); +#endif + + Wire.begin(); + +#ifdef P_LORA_TX_LED + pinMode(P_LORA_TX_LED, OUTPUT); + digitalWrite(P_LORA_TX_LED, LOW); +#endif + + delay(10); // give sx1262 some time to power up +} + +#if 0 +static BLEDfu bledfu; + +static void connect_callback(uint16_t conn_handle) { + (void)conn_handle; + MESH_DEBUG_PRINTLN("BLE client connected"); +} + +static void disconnect_callback(uint16_t conn_handle, uint8_t reason) { + (void)conn_handle; + (void)reason; + + MESH_DEBUG_PRINTLN("BLE client disconnected"); +} + + +bool TrackerT1000eBoard::startOTAUpdate(const char* id, char reply[]) { + // Config the peripheral connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16); + + Bluefruit.begin(1, 0); + // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 + Bluefruit.setTxPower(4); + // Set the BLE device name + Bluefruit.setName("T1000E_OTA"); + + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + + // To be consistent OTA DFU should be added first if it exists + bledfu.begin(); + + // Set up and start advertising + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addName(); + + /* Start Advertising + - Enable auto advertising if disconnected + - Interval: fast mode = 20 ms, slow mode = 152.5 ms + - Timeout for fast mode is 30 seconds + - Start(timeout) with timeout = 0 will advertise forever (until connected) + + For recommended advertising interval + https://developer.apple.com/library/content/qa/qa1931/_index.html + */ + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + + strcpy(reply, "OK - started"); + return true; +} +#endif \ No newline at end of file diff --git a/src/helpers/nrf52/MinewsemiME25LS01Board.h b/src/helpers/nrf52/MinewsemiME25LS01Board.h new file mode 100644 index 00000000..4b8c8293 --- /dev/null +++ b/src/helpers/nrf52/MinewsemiME25LS01Board.h @@ -0,0 +1,112 @@ +#pragma once + +#include +#include + +// LoRa and SPI pins + +#define P_LORA_DIO_1 (32 + 12) // P1.12 +#define P_LORA_NSS (32 + 13) // P1.13 +#define P_LORA_RESET (32 + 11) // P1.11 +#define P_LORA_BUSY (32 + 10) // P1.10 +#define P_LORA_SCLK (32 + 15) // P1.15 +#define P_LORA_MISO (0 + 29) // P0.29 +#define P_LORA_MOSI (0 + 2) // P0.2 + +#define LR11X0_DIO_AS_RF_SWITCH true +#define LR11X0_DIO3_TCXO_VOLTAGE 1.6 + +// built-ins +//#define PIN_VBAT_READ 5 +//#define ADC_MULTIPLIER (3 * 1.73 * 1000) + +class MinewsemiME25LS01Board : public mesh::MainBoard { +protected: + uint8_t startup_reason; + uint8_t btn_prev_state; + +public: + void begin(); + + uint16_t getBattMilliVolts() override { + #ifdef BATTERY_PIN + #ifdef PIN_3V3_EN + digitalWrite(PIN_3V3_EN, HIGH); + #endif + analogReference(AR_INTERNAL_3_0); + analogReadResolution(12); + delay(10); + float volts = (analogRead(BATTERY_PIN) * ADC_MULTIPLIER * AREF_VOLTAGE) / 4096; + #ifdef PIN_3V3_EN + digitalWrite(PIN_3V3_EN, LOW); + #endif + + analogReference(AR_DEFAULT); // put back to default + analogReadResolution(10); + + return volts * 1000; + #else + return 0; + #endif + } + + uint8_t getStartupReason() const override { return startup_reason; } + + const char* getManufacturerName() const override { + return "m25ls01"; + } + + int buttonStateChanged() { + #ifdef BUTTON_PIN + uint8_t v = digitalRead(BUTTON_PIN); + if (v != btn_prev_state) { + btn_prev_state = v; + return (v == LOW) ? 1 : -1; + } + #endif + return 0; + } + + void powerOff() override { + #ifdef HAS_GPS + digitalWrite(GPS_VRTC_EN, LOW); + digitalWrite(GPS_RESET, LOW); + digitalWrite(GPS_SLEEP_INT, LOW); + digitalWrite(GPS_RTC_INT, LOW); + pinMode(GPS_RESETB, OUTPUT); + digitalWrite(GPS_RESETB, LOW); + #endif + + #ifdef BUZZER_EN + digitalWrite(BUZZER_EN, LOW); + #endif + + #ifdef PIN_3V3_EN + digitalWrite(PIN_3V3_EN, LOW); + #endif + + #ifdef LED_PIN + digitalWrite(LED_PIN, LOW); + #endif + #ifdef BUTTON_PIN + nrf_gpio_cfg_sense_input(digitalPinToInterrupt(BUTTON_PIN), NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_HIGH); + #endif + sd_power_system_off(); + } + + #if defined(P_LORA_TX_LED) + void onBeforeTransmit() override { + digitalWrite(P_LORA_TX_LED, HIGH);// turn TX LED on + } + void onAfterTransmit() override { + digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off + } +#endif + + + void reboot() override { + NVIC_SystemReset(); + } + +// bool startOTAUpdate(const char* id, char reply[]) override; +}; \ No newline at end of file diff --git a/variants/minewsemi_me25ls01/NullDisplayDriver.h b/variants/minewsemi_me25ls01/NullDisplayDriver.h new file mode 100644 index 00000000..38bf93f1 --- /dev/null +++ b/variants/minewsemi_me25ls01/NullDisplayDriver.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +class NullDisplayDriver : public DisplayDriver { +public: + NullDisplayDriver() : DisplayDriver(128, 64) { } + bool begin() { return false; } // not present + + bool isOn() override { return false; } + void turnOn() override { } + void turnOff() override { } + void clear() override { } + void startFrame(Color bkg = DARK) override { } + void setTextSize(int sz) override { } + void setColor(Color c) override { } + void setCursor(int x, int y) override { } + void print(const char* str) override { } + void fillRect(int x, int y, int w, int h) override { } + void drawRect(int x, int y, int w, int h) override { } + void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override { } + uint16_t getTextWidth(const char* str) override { return 0; } + void endFrame() { } +}; diff --git a/variants/minewsemi_me25ls01/platformio.ini b/variants/minewsemi_me25ls01/platformio.ini new file mode 100644 index 00000000..4775e289 --- /dev/null +++ b/variants/minewsemi_me25ls01/platformio.ini @@ -0,0 +1,184 @@ +; ----------------- NRF52 me25ls01--------------------- +[nrf52840_me25ls01] +extends = nrf52_base +platform_packages = framework-arduinoadafruitnrf52 +build_flags = ${nrf52_base.build_flags} + -I src/helpers/nrf52 + -I lib/nrf52/s140_nrf52_7.3.0_API/include + -I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52 +lib_ignore = + BluetoothOTA + lvgl + lib5b4 +lib_deps = + ${nrf52_base.lib_deps} + rweather/Crypto @ ^0.4.0 + +[me25ls01] +extends = nrf52840_me25ls01 +board = minewsemi_me25ls01 +board_build.ldscript = boards/nrf52840_s140_v7.ld +build_flags = ${nrf52840_me25ls01.build_flags} + -I variants/minewsemi_me25ls01 + -D me25ls01 + -D PIN_USER_BTN=27 + -D USER_BTN_PRESSED=HIGH + -D PIN_STATUS_LED=39 + -D P_LORA_TX_LED=22 + -D RADIO_CLASS=CustomLR1110 + -D WRAPPER_CLASS=CustomLR1110Wrapper + -D LORA_TX_POWER=22 + -D ENV_INCLUDE_GPS=0 + -D ENV_INCLUDE_AHTX0=1 + -D ENV_INCLUDE_BME280=1 + -D ENV_INCLUDE_INA3221=1 + -D ENV_INCLUDE_INA219=1 +build_src_filter = ${nrf52840_me25ls01.build_src_filter} + + + + + +<../variants/minewsemi_me25ls01> + + +debug_tool = jlink +upload_protocol = nrfutil +lib_deps = ${nrf52840_me25ls01.lib_deps} + densaugeo/base64 @ ~1.4.0 + stevemarple/MicroNMEA @ ^2.0.6 + end2endzone/NonBlockingRTTTL@^1.3.0 + adafruit/Adafruit SSD1306 @ ^2.5.13 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 + +[env:Minewsemi_me25ls01_companion_radio_ble] +extends = me25ls01 +build_flags = ${me25ls01.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 + -D OFFLINE_QUEUE_SIZE=256 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D DISPLAY_CLASS=NullDisplayDriver + ;-D PIN_BUZZER=25 + ;-D PIN_BUZZER_EN=37 +build_src_filter = ${me25ls01.build_src_filter} + + + ;+ + +<../examples/companion_radio/*.cpp> +lib_deps = ${me25ls01.lib_deps} + adafruit/RTClib @ ^2.1.3 + + +[env:Minewsemi_me25ls01_repeater] +extends = me25ls01 +build_flags = ${me25ls01.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 + -D OFFLINE_QUEUE_SIZE=256 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D ADVERT_NAME='"ME25LS01 Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 + -D DISPLAY_CLASS=NullDisplayDriver +build_src_filter = ${me25ls01.build_src_filter} + ;+ + ;+ + ;+<../examples/companion_radio/*.cpp> + +<../examples/simple_repeater> +lib_deps = ${me25ls01.lib_deps} + adafruit/RTClib @ ^2.1.3 + + + +[env:Minewsemi_me25ls01_room_server] +extends = me25ls01 +build_flags = ${me25ls01.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 + -D OFFLINE_QUEUE_SIZE=256 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D ADVERT_NAME='"ME25LS01 Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' + -D MAX_NEIGHBOURS=8 + -D DISPLAY_CLASS=NullDisplayDriver +build_src_filter = ${me25ls01.build_src_filter} + ;+ + ;+ + ;+<../examples/companion_radio/*.cpp> + ;+<../examples/simple_repeater> + +<../examples/simple_room_server> +lib_deps = ${me25ls01.lib_deps} + adafruit/RTClib @ ^2.1.3 + +[env:Minewsemi_me25ls01_terminal_chat] +extends = me25ls01 +build_flags = ${me25ls01.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 + -D OFFLINE_QUEUE_SIZE=256 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D ADVERT_NAME='"ME25LS01 Chat"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' + -D MAX_NEIGHBOURS=8 + -D DISPLAY_CLASS=NullDisplayDriver +build_src_filter = ${me25ls01.build_src_filter} + ;+ + ;+ + ;+<../examples/companion_radio/*.cpp> + ;+<../examples/simple_repeater> + ;+<../examples/simple_room_server> + +<../examples/simple_secure_chat/main.cpp> +lib_deps = ${me25ls01.lib_deps} + adafruit/RTClib @ ^2.1.3 + +[env:Minewsemi_me25ls01_companion_radio_usb] +extends = me25ls01 +build_flags = ${me25ls01.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + ;-D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 + -D OFFLINE_QUEUE_SIZE=256 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D DISPLAY_CLASS=NullDisplayDriver +build_src_filter = ${me25ls01.build_src_filter} + + + ;+ + ;+ + ;+<../examples/companion_radio/*.cpp> + ;+<../examples/simple_repeater> + ;+<../examples/simple_room_server> + +<../examples/companion_radio> +lib_deps = ${me25ls01.lib_deps} + adafruit/RTClib @ ^2.1.3 + diff --git a/variants/minewsemi_me25ls01/target.cpp b/variants/minewsemi_me25ls01/target.cpp new file mode 100644 index 00000000..b6b1b585 --- /dev/null +++ b/variants/minewsemi_me25ls01/target.cpp @@ -0,0 +1,209 @@ +#include +//#include "t1000e_sensors.h" +#include "target.h" +#include + +MinewsemiME25LS01Board board; + +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); + +VolatileRTCClock rtc_clock; +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); +//T1000SensorManager sensors = T1000SensorManager(nmea); +me25ls01SensorManager sensors = me25ls01SensorManager(nmea); + +#ifdef DISPLAY_CLASS + NullDisplayDriver display; +#endif + +#ifndef LORA_CR + #define LORA_CR 5 +#endif + +#ifdef RF_SWITCH_TABLE +static const uint32_t rfswitch_dios[Module::RFSWITCH_MAX_PINS] = { + RADIOLIB_LR11X0_DIO5, + RADIOLIB_LR11X0_DIO6, + RADIOLIB_LR11X0_DIO7, + RADIOLIB_LR11X0_DIO8, + RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 DIO7 DIO8 + { LR11x0::MODE_STBY, {LOW, LOW, LOW, LOW }}, + { LR11x0::MODE_RX, {HIGH, LOW, LOW, HIGH }}, + { LR11x0::MODE_TX, {HIGH, HIGH, LOW, HIGH }}, + { LR11x0::MODE_TX_HP, {LOW, HIGH, LOW, HIGH }}, + { LR11x0::MODE_TX_HF, {LOW, LOW, LOW, LOW }}, + { LR11x0::MODE_GNSS, {LOW, LOW, HIGH, LOW }}, + { LR11x0::MODE_WIFI, {LOW, LOW, LOW, LOW }}, + END_OF_MODE_TABLE, +}; +#endif + +bool radio_init() { + //rtc_clock.begin(Wire); + +#ifdef LR11X0_DIO3_TCXO_VOLTAGE + float tcxo = LR11X0_DIO3_TCXO_VOLTAGE; +#else + float tcxo = 1.6f; +#endif + + SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); + SPI.begin(); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + radio.setCRC(1); + +#ifdef RF_SWITCH_TABLE + radio.setRfSwitchTable(rfswitch_dios, rfswitch_table); +#endif +#ifdef RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(RX_BOOSTED_GAIN); +#endif + + return true; // success +} + +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(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} + +void me25ls01SensorManager::start_gps() { + gps_active = false; + //_nmea->begin(); + // this init sequence should be better + // comes from seeed examples and deals with all gps pins + // pinMode(GPS_EN, OUTPUT); + // digitalWrite(GPS_EN, HIGH); + // delay(10); + // pinMode(GPS_VRTC_EN, OUTPUT); + // digitalWrite(GPS_VRTC_EN, HIGH); + // delay(10); + + // pinMode(GPS_RESET, OUTPUT); + // digitalWrite(GPS_RESET, HIGH); + // delay(10); + // digitalWrite(GPS_RESET, LOW); + + // pinMode(GPS_SLEEP_INT, OUTPUT); + // digitalWrite(GPS_SLEEP_INT, HIGH); + // pinMode(GPS_RTC_INT, OUTPUT); + // digitalWrite(GPS_RTC_INT, LOW); + // pinMode(GPS_RESETB, INPUT_PULLUP); +} + +void me25ls01SensorManager::sleep_gps() { + gps_active = false; + // digitalWrite(GPS_VRTC_EN, HIGH); + // digitalWrite(GPS_EN, LOW); + // digitalWrite(GPS_RESET, HIGH); + // digitalWrite(GPS_SLEEP_INT, HIGH); + // digitalWrite(GPS_RTC_INT, LOW); + // pinMode(GPS_RESETB, OUTPUT); + // digitalWrite(GPS_RESETB, LOW); + //_nmea->stop(); +} + +void me25ls01SensorManager::stop_gps() { + gps_active = false; + // digitalWrite(GPS_VRTC_EN, LOW); + // digitalWrite(GPS_EN, LOW); + // digitalWrite(GPS_RESET, HIGH); + // digitalWrite(GPS_SLEEP_INT, HIGH); + // digitalWrite(GPS_RTC_INT, LOW); + // pinMode(GPS_RESETB, OUTPUT); + // digitalWrite(GPS_RESETB, LOW); + // //_nmea->stop(); +} + + +bool me25ls01SensorManager::begin() { + // init GPS + Serial1.begin(115200); + + // make sure gps pin are off + // digitalWrite(GPS_VRTC_EN, LOW); + // digitalWrite(GPS_RESET, LOW); + // digitalWrite(GPS_SLEEP_INT, LOW); + // digitalWrite(GPS_RTC_INT, LOW); + // pinMode(GPS_RESETB, OUTPUT); + // digitalWrite(GPS_RESETB, LOW); + + return true; +} + +bool me25ls01SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { + if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? + //telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); + } + if (requester_permissions & TELEM_PERM_ENVIRONMENT) { + //telemetry.addLuminosity(TELEM_CHANNEL_SELF, t1000e_get_light()); + //telemetry.addTemperature(TELEM_CHANNEL_SELF, t1000e_get_temperature()); + } + return true; +} + +void me25ls01SensorManager::loop() { + static long next_gps_update = 0; + + //_nmea->loop(); + + // if (millis() > next_gps_update) { + // if (_nmea->isValid()) { + // node_lat = ((double)_nmea->getLatitude())/1000000.; + // node_lon = ((double)_nmea->getLongitude())/1000000.; + // node_altitude = ((double)_nmea->getAltitude()) / 1000.0; + // //Serial.printf("lat %f lon %f\r\n", _lat, _lon); + // } + // next_gps_update = millis() + 1000; + //} +} + +int me25ls01SensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch) + +const char* me25ls01SensorManager::getSettingName(int i) const { + return i == 0 ? "gps" : NULL; +} +const char* me25ls01SensorManager::getSettingValue(int i) const { + if (i == 0) { + return gps_active ? "1" : "0"; + } + return NULL; +} +bool me25ls01SensorManager::setSettingValue(const char* name, const char* value) { + if (strcmp(name, "gps") == 0) { + // if (strcmp(value, "0") == 0) { + // sleep_gps(); // sleep for faster fix ! + // } else { + // start_gps(); + // } + return true; + } + return false; // not supported +} diff --git a/variants/minewsemi_me25ls01/target.h b/variants/minewsemi_me25ls01/target.h new file mode 100644 index 00000000..e5354a10 --- /dev/null +++ b/variants/minewsemi_me25ls01/target.h @@ -0,0 +1,46 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#include +#ifdef DISPLAY_CLASS + #include "NullDisplayDriver.h" +#endif + +class me25ls01SensorManager: public SensorManager { + bool gps_active = false; + LocationProvider * _nmea; + + void start_gps(); + void sleep_gps(); + void stop_gps(); +public: + me25ls01SensorManager(LocationProvider &nmea): _nmea(&nmea) { } + bool begin() override; + bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + void loop() override; + int getNumSettings() const override; + const char* getSettingName(int i) const override; + const char* getSettingValue(int i) const override; + bool setSettingValue(const char* name, const char* value) override; +}; + +#ifdef DISPLAY_CLASS + extern NullDisplayDriver display; +#endif + +extern MinewsemiME25LS01Board board; +extern WRAPPER_CLASS radio_driver; +extern VolatileRTCClock rtc_clock; +extern me25ls01SensorManager 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(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/minewsemi_me25ls01/variant.cpp b/variants/minewsemi_me25ls01/variant.cpp new file mode 100644 index 00000000..5440e600 --- /dev/null +++ b/variants/minewsemi_me25ls01/variant.cpp @@ -0,0 +1,98 @@ +/* + * variant.cpp + * Copyright (C) 2023 Seeed K.K. + * MIT License + */ + +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[PINS_COUNT + 1] = +{ + 0, // P0.00 + 1, // P0.01 + 2, // P0.02, AIN0 BATTERY_PIN + 3, // P0.03 + 4, // P0.04, SENSOR_EN + 5, // P0.05, EXT_PWR_DETEC + 6, // P0.06, PIN_BUTTON1 + 7, // P0.07, LORA_BUSY + 8, // P0.08, GPS_VRTC_EN + 9, // P0.09 + 10, // P0.10 + 11, // P0.11, PIN_SPI_SCK + 12, // P0.12, PIN_SPI_NSS + 13, // P0.13, PIN_SERIAL1_TX + 14, // P0.14, PIN_SERIAL1_RX + 15, // P0.15, GPS_RTC_INT + 16, // P0.16, PIN_SERIAL2_TX + 17, // P0.17, PIN_SERIAL2_RX + 18, // P0.18 + 19, // P0.19 + 20, // P0.20 + 21, // P0.21 + 22, // P0.22 + 23, // P0.23 + 24, // P0.24, LED_GREEN + 25, // P0.25, BUZZER_PIN + 26, // P0.26, PIN_WIRE_SDA + 27, // P0.27, PIN_WIRE_SCL + 28, // P0.28 + 29, // P0.29, AIN5, LUX_SENSOR + 30, // P0.30 + 31, // P0.31, AIN7, TEMP_SENSOR + 32, // P1.00 + 33, // P1.01, LORA_DIO_1 + 34, // P1.02 + 35, // P1.03, EXT_CHRG_DETECT + 36, // P1.04 + 37, // P1.05, LR1110_EN + 38, // P1.06, 3V3_EN PWR TO SENSORS + 39, // P1.07, PIN_3V3_ACC_EN + 40, // P1.08, PIN_SPI_MISO + 41, // P1.09, PIN_SPI_MOSI + 42, // P1.10, LORA_RESET + 43, // P1.11, GPS_EN + 44, // P1.12, GPS_SLEEP_INT + 45, // P1.13 + 46, // P1.14, GPS_RESETB + 47, // P1.15, PIN_GPS_RESET + 255, // NRFX_SPIM_PIN_NOT_USED +}; + +void initVariant() +{ + // All pins output HIGH by default. + // https://github.com/Seeed-Studio/Adafruit_nRF52_Arduino/blob/fab7d30a997a1dfeef9d1d59bfb549adda73815a/cores/nRF5/wiring.c#L65-L69 + + pinMode(BATTERY_PIN, INPUT); + pinMode(EXT_CHRG_DETECT, INPUT); + pinMode(EXT_PWR_DETECT, INPUT); + // pinMode(GPS_RESETB, INPUT); + pinMode(PIN_BUTTON1, INPUT); + + pinMode(PIN_3V3_EN, OUTPUT); + pinMode(PIN_3V3_ACC_EN, OUTPUT); + // pinMode(BUZZER_EN, OUTPUT); + // pinMode(SENSOR_EN, OUTPUT); + // pinMode(GPS_EN, OUTPUT); + // pinMode(GPS_RESET, OUTPUT); + // pinMode(GPS_VRTC_EN, OUTPUT); + // pinMode(GPS_SLEEP_INT, OUTPUT); + // pinMode(GPS_RTC_INT, OUTPUT); + pinMode(LED_PIN, OUTPUT); + pinMode(P_LORA_TX_LED, OUTPUT); + + // digitalWrite(PIN_3V3_EN, LOW); + // digitalWrite(PIN_3V3_ACC_EN, LOW); + // digitalWrite(BUZZER_EN, LOW); + // digitalWrite(SENSOR_EN, LOW); + // digitalWrite(GPS_EN, LOW); + // digitalWrite(GPS_RESET, LOW); + // digitalWrite(GPS_VRTC_EN, LOW); + // digitalWrite(GPS_SLEEP_INT, HIGH); + // digitalWrite(GPS_RTC_INT, LOW); + digitalWrite(LED_PIN, HIGH); + digitalWrite(P_LORA_TX_LED, LOW); +} diff --git a/variants/minewsemi_me25ls01/variant.h b/variants/minewsemi_me25ls01/variant.h new file mode 100644 index 00000000..d085a4b9 --- /dev/null +++ b/variants/minewsemi_me25ls01/variant.h @@ -0,0 +1,147 @@ +/* + * variant.h + * Copyright (C) 2023 Seeed K.K. + * MIT License + */ + +#pragma once + +#include "WVariant.h" + +//////////////////////////////////////////////////////////////////////////////// +// Low frequency clock source + +#define USE_LFXO // 32.768 kHz crystal oscillator +#define VARIANT_MCK (64000000ul) +// #define USE_LFRC // 32.768 kHz RC oscillator + +//////////////////////////////////////////////////////////////////////////////// +// Power + +#define NRF_APM // detect usb power +#define PIN_3V3_EN (32 + 5) // P1.6 Power to Sensors +#define PIN_3V3_ACC_EN -1 + +#define BATTERY_PIN (-1) // P0.2/AIN0 +#define BATTERY_IMMUTABLE +#define ADC_MULTIPLIER (2.0F) + +#define EXT_CHRG_DETECT (-1) // P1.3 +#define EXT_PWR_DETECT (-1) // P0.5 + +#define ADC_RESOLUTION (14) +#define BATTERY_SENSE_RES (12) + +#define AREF_VOLTAGE (3.0) + +//////////////////////////////////////////////////////////////////////////////// +// Number of pins + +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (6) +#define NUM_ANALOG_OUTPUTS (0) + +//////////////////////////////////////////////////////////////////////////////// +// UART pin definition + +#define PIN_SERIAL1_RX (14) // P0.14 - checked +#define PIN_SERIAL1_TX (13) // P0.13 - checked + +#define PIN_SERIAL2_RX (17) // P0.17 - checked +#define PIN_SERIAL2_TX (16) // P0.16 - checked + +//////////////////////////////////////////////////////////////////////////////// +// I2C pin definition + +#define HAS_WIRE (1) // checked +#define WIRE_INTERFACES_COUNT (1) // checked + +#define PIN_WIRE_SDA (15) // P0.26 - checked +#define PIN_WIRE_SCL (17) // P0.27 - checked +#define I2C_NO_RESCAN +// #define HAS_QMA6100P +// #define QMA_6100P_INT_PIN (-1) // P1.2 + +//////////////////////////////////////////////////////////////////////////////// +// SPI pin definition + +#define SPI_INTERFACES_COUNT (1) + +#define PIN_SPI_MISO (0 + 29) // P0.29 +#define PIN_SPI_MOSI (0 + 2) // P0.2 +#define PIN_SPI_SCK (32 + 15) // P1.15 +#define PIN_SPI_NSS (32 + 13) // P1.13 + +//////////////////////////////////////////////////////////////////////////////// +// Builtin LEDs + +#define LED_BUILTIN (-1) +#define LED_RED (32 + 5) // P1.5 +#define LED_BLUE (32 + 7) // P1.7 +#define LED_PIN LED_BLUE +#define P_LORA_TX_LED LED_RED + +#define LED_STATE_ON HIGH + +//////////////////////////////////////////////////////////////////////////////// +// Builtin buttons + +#define PIN_BUTTON1 (0 + 27) // P0.6 +#define BUTTON_PIN PIN_BUTTON1 + +//////////////////////////////////////////////////////////////////////////////// +// LR1110 + +#define LORA_DIO_1 (32 + 12) // P1.12 +#define LORA_DIO_2 (32 + 10) // P1.10 +#define LORA_NSS (PIN_SPI_NSS) // P1.13 +#define LORA_RESET (32 + 11) // P1.11 +#define LORA_BUSY (32 + 10) // P1.10 +#define LORA_SCLK (PIN_SPI_SCK) // P1.15 +#define LORA_MISO (PIN_SPI_MISO) // P0.29 +#define LORA_MOSI (PIN_SPI_MOSI) // P0.2 +#define LORA_CS PIN_SPI_NSS // P1.13 + +#define LR11X0_DIO_AS_RF_SWITCH true +#define LR11X0_DIO3_TCXO_VOLTAGE 1.6 + +#define LR1110_IRQ_PIN LORA_DIO_1 +#define LR1110_NRESET_PIN LORA_RESET +#define LR1110_BUSY_PIN LORA_DIO_2 +#define LR1110_SPI_NSS_PIN LORA_CS +#define LR1110_SPI_SCK_PIN LORA_SCLK +#define LR1110_SPI_MOSI_PIN LORA_MOSI +#define LR1110_SPI_MISO_PIN LORA_MISO +//////////////////////////////////////////////////////////////////////////////// +// GPS + +//#define HAS_GPS 0 +#define GPS_RX_PIN PIN_SERIAL1_RX +#define GPS_TX_PIN PIN_SERIAL1_TX + +#define GPS_EN (-1) // P1.11 +#define GPS_RESET (-1) // P1.15 + +#define GPS_VRTC_EN (-1) // P0.8 +#define GPS_SLEEP_INT (-1) // P1.12 +#define GPS_RTC_INT (-1) // P0.15 +#define GPS_RESETB (-1) // P1.14 + +//////////////////////////////////////////////////////////////////////////////// +// Temp+Lux Sensor + +#define SENSOR_EN (-1) // P0.4 +#define TEMP_SENSOR (-1) // P0.31/AIN7 +#define LUX_SENSOR (-1) // P0.29/AIN5 + +//////////////////////////////////////////////////////////////////////////////// +// Accelerometer (I2C addr : ??? ) + +#define PIN_3V3_ACC_EN (-1) // P1.7 + +//////////////////////////////////////////////////////////////////////////////// +// Buzzer + +#define BUZZER_EN (-1) // P1.5 +#define BUZZER_PIN (0 + 25) // P0.25 \ No newline at end of file From b80d99edd1726d4a602fb9d9f91e0e79bb6b1313 Mon Sep 17 00:00:00 2001 From: Florent de Lamotte Date: Tue, 1 Jul 2025 15:42:54 +0200 Subject: [PATCH 12/39] t1000e: set preamble to 16 at init --- variants/t1000-e/target.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/t1000-e/target.cpp b/variants/t1000-e/target.cpp index 49ae26eb..f6fb1f04 100644 --- a/variants/t1000-e/target.cpp +++ b/variants/t1000-e/target.cpp @@ -54,7 +54,7 @@ bool radio_init() { SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); SPI.begin(); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); Serial.println(status); From af2628bb00ec8306b15520438c23c0bc39608257 Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Wed, 2 Jul 2025 12:27:39 +0300 Subject: [PATCH 13/39] Use EnvironmentSensorManager in Minewsemi variant --- variants/minewsemi_me25ls01/target.cpp | 129 ++---------------------- variants/minewsemi_me25ls01/target.h | 21 +--- variants/minewsemi_me25ls01/variant.cpp | 6 -- variants/minewsemi_me25ls01/variant.h | 6 -- 4 files changed, 11 insertions(+), 151 deletions(-) diff --git a/variants/minewsemi_me25ls01/target.cpp b/variants/minewsemi_me25ls01/target.cpp index b6b1b585..13306762 100644 --- a/variants/minewsemi_me25ls01/target.cpp +++ b/variants/minewsemi_me25ls01/target.cpp @@ -1,7 +1,5 @@ #include -//#include "t1000e_sensors.h" #include "target.h" -#include MinewsemiME25LS01Board board; @@ -10,9 +8,14 @@ RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BU WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock rtc_clock; -MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); -//T1000SensorManager sensors = T1000SensorManager(nmea); -me25ls01SensorManager sensors = me25ls01SensorManager(nmea); +extern EnvironmentSensorManager sensors; +#if ENV_INCLUDE_GPS + #include + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); + EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); +#else + EnvironmentSensorManager sensors; +#endif #ifdef DISPLAY_CLASS NullDisplayDriver display; @@ -92,118 +95,4 @@ void radio_set_tx_power(uint8_t dbm) { mesh::LocalIdentity radio_new_identity() { RadioNoiseListener rng(radio); return mesh::LocalIdentity(&rng); // create new random identity -} - -void me25ls01SensorManager::start_gps() { - gps_active = false; - //_nmea->begin(); - // this init sequence should be better - // comes from seeed examples and deals with all gps pins - // pinMode(GPS_EN, OUTPUT); - // digitalWrite(GPS_EN, HIGH); - // delay(10); - // pinMode(GPS_VRTC_EN, OUTPUT); - // digitalWrite(GPS_VRTC_EN, HIGH); - // delay(10); - - // pinMode(GPS_RESET, OUTPUT); - // digitalWrite(GPS_RESET, HIGH); - // delay(10); - // digitalWrite(GPS_RESET, LOW); - - // pinMode(GPS_SLEEP_INT, OUTPUT); - // digitalWrite(GPS_SLEEP_INT, HIGH); - // pinMode(GPS_RTC_INT, OUTPUT); - // digitalWrite(GPS_RTC_INT, LOW); - // pinMode(GPS_RESETB, INPUT_PULLUP); -} - -void me25ls01SensorManager::sleep_gps() { - gps_active = false; - // digitalWrite(GPS_VRTC_EN, HIGH); - // digitalWrite(GPS_EN, LOW); - // digitalWrite(GPS_RESET, HIGH); - // digitalWrite(GPS_SLEEP_INT, HIGH); - // digitalWrite(GPS_RTC_INT, LOW); - // pinMode(GPS_RESETB, OUTPUT); - // digitalWrite(GPS_RESETB, LOW); - //_nmea->stop(); -} - -void me25ls01SensorManager::stop_gps() { - gps_active = false; - // digitalWrite(GPS_VRTC_EN, LOW); - // digitalWrite(GPS_EN, LOW); - // digitalWrite(GPS_RESET, HIGH); - // digitalWrite(GPS_SLEEP_INT, HIGH); - // digitalWrite(GPS_RTC_INT, LOW); - // pinMode(GPS_RESETB, OUTPUT); - // digitalWrite(GPS_RESETB, LOW); - // //_nmea->stop(); -} - - -bool me25ls01SensorManager::begin() { - // init GPS - Serial1.begin(115200); - - // make sure gps pin are off - // digitalWrite(GPS_VRTC_EN, LOW); - // digitalWrite(GPS_RESET, LOW); - // digitalWrite(GPS_SLEEP_INT, LOW); - // digitalWrite(GPS_RTC_INT, LOW); - // pinMode(GPS_RESETB, OUTPUT); - // digitalWrite(GPS_RESETB, LOW); - - return true; -} - -bool me25ls01SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { - if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? - //telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); - } - if (requester_permissions & TELEM_PERM_ENVIRONMENT) { - //telemetry.addLuminosity(TELEM_CHANNEL_SELF, t1000e_get_light()); - //telemetry.addTemperature(TELEM_CHANNEL_SELF, t1000e_get_temperature()); - } - return true; -} - -void me25ls01SensorManager::loop() { - static long next_gps_update = 0; - - //_nmea->loop(); - - // if (millis() > next_gps_update) { - // if (_nmea->isValid()) { - // node_lat = ((double)_nmea->getLatitude())/1000000.; - // node_lon = ((double)_nmea->getLongitude())/1000000.; - // node_altitude = ((double)_nmea->getAltitude()) / 1000.0; - // //Serial.printf("lat %f lon %f\r\n", _lat, _lon); - // } - // next_gps_update = millis() + 1000; - //} -} - -int me25ls01SensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch) - -const char* me25ls01SensorManager::getSettingName(int i) const { - return i == 0 ? "gps" : NULL; -} -const char* me25ls01SensorManager::getSettingValue(int i) const { - if (i == 0) { - return gps_active ? "1" : "0"; - } - return NULL; -} -bool me25ls01SensorManager::setSettingValue(const char* name, const char* value) { - if (strcmp(name, "gps") == 0) { - // if (strcmp(value, "0") == 0) { - // sleep_gps(); // sleep for faster fix ! - // } else { - // start_gps(); - // } - return true; - } - return false; // not supported -} +} \ No newline at end of file diff --git a/variants/minewsemi_me25ls01/target.h b/variants/minewsemi_me25ls01/target.h index e5354a10..aad55757 100644 --- a/variants/minewsemi_me25ls01/target.h +++ b/variants/minewsemi_me25ls01/target.h @@ -8,28 +8,11 @@ #include #include #include +#include #ifdef DISPLAY_CLASS #include "NullDisplayDriver.h" #endif -class me25ls01SensorManager: public SensorManager { - bool gps_active = false; - LocationProvider * _nmea; - - void start_gps(); - void sleep_gps(); - void stop_gps(); -public: - me25ls01SensorManager(LocationProvider &nmea): _nmea(&nmea) { } - bool begin() override; - bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; - void loop() override; - int getNumSettings() const override; - const char* getSettingName(int i) const override; - const char* getSettingValue(int i) const override; - bool setSettingValue(const char* name, const char* value) override; -}; - #ifdef DISPLAY_CLASS extern NullDisplayDriver display; #endif @@ -37,7 +20,7 @@ public: extern MinewsemiME25LS01Board board; extern WRAPPER_CLASS radio_driver; extern VolatileRTCClock rtc_clock; -extern me25ls01SensorManager sensors; +extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); diff --git a/variants/minewsemi_me25ls01/variant.cpp b/variants/minewsemi_me25ls01/variant.cpp index 5440e600..a6b6eaab 100644 --- a/variants/minewsemi_me25ls01/variant.cpp +++ b/variants/minewsemi_me25ls01/variant.cpp @@ -1,9 +1,3 @@ -/* - * variant.cpp - * Copyright (C) 2023 Seeed K.K. - * MIT License - */ - #include "variant.h" #include "wiring_constants.h" #include "wiring_digital.h" diff --git a/variants/minewsemi_me25ls01/variant.h b/variants/minewsemi_me25ls01/variant.h index d085a4b9..de57a65e 100644 --- a/variants/minewsemi_me25ls01/variant.h +++ b/variants/minewsemi_me25ls01/variant.h @@ -1,9 +1,3 @@ -/* - * variant.h - * Copyright (C) 2023 Seeed K.K. - * MIT License - */ - #pragma once #include "WVariant.h" From 483b31665c31fc25cf8b9b43c34024fb6a591562 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Wed, 2 Jul 2025 21:11:07 +1000 Subject: [PATCH 14/39] * ver bump to v1.7.2 --- examples/companion_radio/MyMesh.h | 4 ++-- examples/simple_repeater/main.cpp | 4 ++-- examples/simple_room_server/main.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 891a390e..247a9b3d 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -10,11 +10,11 @@ #define FIRMWARE_VER_CODE 6 #ifndef FIRMWARE_BUILD_DATE -#define FIRMWARE_BUILD_DATE "29 Jun 2025" +#define FIRMWARE_BUILD_DATE "2 Jul 2025" #endif #ifndef FIRMWARE_VERSION -#define FIRMWARE_VERSION "v1.7.1" +#define FIRMWARE_VERSION "v1.7.2" #endif #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 8b797991..71c9f24a 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -22,11 +22,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "29 Jun 2025" + #define FIRMWARE_BUILD_DATE "2 Jul 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.7.1" + #define FIRMWARE_VERSION "v1.7.2" #endif #ifndef LORA_FREQ diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index 3d6cf80b..c394f3e5 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -22,11 +22,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "29 Jun 2025" + #define FIRMWARE_BUILD_DATE "2 Jul 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.7.1" + #define FIRMWARE_VERSION "v1.7.2" #endif #ifndef LORA_FREQ From 3832836eb24093133b86609cb0d677f8d0c5d8c8 Mon Sep 17 00:00:00 2001 From: recrof Date: Wed, 2 Jul 2025 16:42:35 +0200 Subject: [PATCH 15/39] EnvironmentSensorManager: add support for SHTC3 and LPS22HB --- .../sensors/EnvironmentSensorManager.cpp | 78 +++++++++++++++---- .../sensors/EnvironmentSensorManager.h | 2 + 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index b672cdd4..f0480a87 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -24,6 +24,14 @@ static Adafruit_BME280 BME280; static Adafruit_BMP280 BMP280; #endif +#if ENV_INCLUDE_SHTC3 +#include +static Adafruit_SHTC3 SHTC3; +#endif + +#if ENV_INCLUDE_LPS22HB +#include +#endif #if ENV_INCLUDE_INA3221 #define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address @@ -76,28 +84,48 @@ bool EnvironmentSensorManager::begin() { } #endif + #if ENV_INCLUDE_SHTC3 + if (SHTC3.begin()) { + MESH_DEBUG_PRINTLN("Found sensor: SHTC3"); + SHTC3_initialized = true; + } else { + SHTC3_initialized = false; + MESH_DEBUG_PRINTLN("SHTC3 was not found at I2C address %02X", 0x70); + } + #endif + + #if ENV_INCLUDE_LPS22HB + if (BARO.begin()) { + MESH_DEBUG_PRINTLN("Found sensor: LPS22HB"); + LPS22HB_initialized = true; + } else { + LPS22HB_initialized = false; + MESH_DEBUG_PRINTLN("LPS22HB was not found at I2C address %02X", 0x5C); + } + #endif + #if ENV_INCLUDE_INA3221 if (INA3221.begin(TELEM_INA3221_ADDRESS, &Wire)) { - MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS); - MESH_DEBUG_PRINTLN("%04X %04X", INA3221.getDieID(), INA3221.getManufacturerID()); + MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS); + MESH_DEBUG_PRINTLN("%04X %04X", INA3221.getDieID(), INA3221.getManufacturerID()); - for(int i = 0; i < 3; i++) { - INA3221.setShuntResistance(i, TELEM_INA3221_SHUNT_VALUE); - } - INA3221_initialized = true; + for(int i = 0; i < 3; i++) { + INA3221.setShuntResistance(i, TELEM_INA3221_SHUNT_VALUE); + } + INA3221_initialized = true; } else { - INA3221_initialized = false; - MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); + INA3221_initialized = false; + MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); } #endif #if ENV_INCLUDE_INA219 if (INA219.begin(&Wire)) { - MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", TELEM_INA219_ADDRESS); - INA219_initialized = true; + MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", TELEM_INA219_ADDRESS); + INA219_initialized = true; } else { - INA219_initialized = false; - MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); + INA219_initialized = false; + MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); } #endif @@ -139,6 +167,24 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen } #endif + #if ENV_INCLUDE_SHTC3 + if (SHTC3_initialized) { + sensors_event_t humidity, temp; + SHTC3.getEvent(&humidity, &temp); + + telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity); + } + #endif + + #if ENV_INCLUDE_LPS22HB + if (LPS22HB_initialized) { + telemetry.addTemperature(TELEM_CHANNEL_SELF, BARO.readTemperature()); + telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BARO.readPressure()); + telemetry.addAltitude(TELEM_CHANNEL_SELF, BARO.readAltitude()); + } + #endif + #if ENV_INCLUDE_INA3221 if (INA3221_initialized) { for(int i = 0; i < TELEM_INA3221_NUM_CHANNELS; i++) { @@ -157,10 +203,10 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen #if ENV_INCLUDE_INA219 if (INA219_initialized) { - telemetry.addVoltage(next_available_channel, INA219.getBusVoltage_V()); - telemetry.addCurrent(next_available_channel, INA219.getCurrent_mA() / 1000); - telemetry.addPower(next_available_channel, INA219.getPower_mW() / 1000); - next_available_channel++; + telemetry.addVoltage(next_available_channel, INA219.getBusVoltage_V()); + telemetry.addCurrent(next_available_channel, INA219.getCurrent_mA() / 1000); + telemetry.addPower(next_available_channel, INA219.getPower_mW() / 1000); + next_available_channel++; } #endif diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 76bffc48..f7804431 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -13,6 +13,8 @@ protected: bool BMP280_initialized = false; bool INA3221_initialized = false; bool INA219_initialized = false; + bool SHTC3_initialized = false; + bool LPS22HB_initialized = false; bool gps_detected = false; bool gps_active = false; From 539f99a90f0b9ff32034e8aa3dbce95d4b7791af Mon Sep 17 00:00:00 2001 From: recrof Date: Wed, 2 Jul 2025 16:50:47 +0200 Subject: [PATCH 16/39] removed unsupported(?) readAltitude --- src/helpers/sensors/EnvironmentSensorManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index f0480a87..a424c46b 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -181,7 +181,6 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen if (LPS22HB_initialized) { telemetry.addTemperature(TELEM_CHANNEL_SELF, BARO.readTemperature()); telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BARO.readPressure()); - telemetry.addAltitude(TELEM_CHANNEL_SELF, BARO.readAltitude()); } #endif From dcb7ffa92ee470896380eb191730c4a45b983716 Mon Sep 17 00:00:00 2001 From: JQ Date: Wed, 2 Jul 2025 08:32:36 -0700 Subject: [PATCH 17/39] fixing radio include order for heltec paper --- variants/heltec_wireless_paper/target.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/variants/heltec_wireless_paper/target.h b/variants/heltec_wireless_paper/target.h index f06eead3..7d901c01 100644 --- a/variants/heltec_wireless_paper/target.h +++ b/variants/heltec_wireless_paper/target.h @@ -2,10 +2,10 @@ #define RADIOLIB_STATIC_ONLY 1 #include -#include -#include -#include #include +#include +#include +#include #include #ifdef DISPLAY_CLASS #include From ad2e015a5b35a5f9e4a0aa7584111f728897555a Mon Sep 17 00:00:00 2001 From: Rob Loranger Date: Wed, 2 Jul 2025 10:24:45 -0700 Subject: [PATCH 18/39] move rak usr btn to companions repeaters do not typically have user buttons and there is only one analog pin available on most, if not all, base boards. so this allows repeaters to add custom peripherals or alternate battery signals --- variants/rak4631/platformio.ini | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 9391f99b..86879ed7 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -6,8 +6,6 @@ board_check = true build_flags = ${nrf52840_base.build_flags} -I variants/rak4631 -D RAK_4631 - -D PIN_USER_BTN=9 - -D PIN_USER_BTN_ANA=31 -D PIN_BOARD_SCL=14 -D PIN_BOARD_SDA=13 -D PIN_OLED_RESET=-1 @@ -84,6 +82,8 @@ build_src_filter = ${rak4631.build_src_filter} extends = rak4631 build_flags = ${rak4631.build_flags} + -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 @@ -100,6 +100,8 @@ lib_deps = extends = rak4631 build_flags = ${rak4631.build_flags} + -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 @@ -120,6 +122,8 @@ lib_deps = extends = rak4631 build_flags = ${rak4631.build_flags} + -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 @@ -145,6 +149,8 @@ lib_deps = extends = rak4631 build_flags = ${rak4631.build_flags} + -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=1 ; -D MESH_PACKET_LOGGING=1 From 6440bcaf48ddfb37d0f281928127f565d064c5c2 Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Thu, 3 Jul 2025 00:07:50 +0300 Subject: [PATCH 19/39] Clean up pins in variant.h --- variants/minewsemi_me25ls01/variant.cpp | 64 ++++++++----------------- variants/minewsemi_me25ls01/variant.h | 60 ++++------------------- 2 files changed, 31 insertions(+), 93 deletions(-) diff --git a/variants/minewsemi_me25ls01/variant.cpp b/variants/minewsemi_me25ls01/variant.cpp index a6b6eaab..15f30d14 100644 --- a/variants/minewsemi_me25ls01/variant.cpp +++ b/variants/minewsemi_me25ls01/variant.cpp @@ -6,44 +6,44 @@ const uint32_t g_ADigitalPinMap[PINS_COUNT + 1] = { 0, // P0.00 1, // P0.01 - 2, // P0.02, AIN0 BATTERY_PIN + 2, // P0.02 3, // P0.03 - 4, // P0.04, SENSOR_EN - 5, // P0.05, EXT_PWR_DETEC - 6, // P0.06, PIN_BUTTON1 - 7, // P0.07, LORA_BUSY - 8, // P0.08, GPS_VRTC_EN + 4, // P0.04 + 5, // P0.05 + 6, // P0.06 + 7, // P0.07 + 8, // P0.08 9, // P0.09 10, // P0.10 - 11, // P0.11, PIN_SPI_SCK - 12, // P0.12, PIN_SPI_NSS + 11, // P0.11 + 12, // P0.12 13, // P0.13, PIN_SERIAL1_TX 14, // P0.14, PIN_SERIAL1_RX - 15, // P0.15, GPS_RTC_INT - 16, // P0.16, PIN_SERIAL2_TX - 17, // P0.17, PIN_SERIAL2_RX + 15, // P0.15, PIN_SERIAL2_RX + 16, // P0.16, PIN_WIRE_SCL + 17, // P0.17, PIN_SERIAL2_TX 18, // P0.18 19, // P0.19 20, // P0.20 - 21, // P0.21 + 21, // P0.21, PIN_WIRE_SDA 22, // P0.22 23, // P0.23 - 24, // P0.24, LED_GREEN - 25, // P0.25, BUZZER_PIN - 26, // P0.26, PIN_WIRE_SDA - 27, // P0.27, PIN_WIRE_SCL + 24, // P0.24, + 25, // P0.25, + 26, // P0.26, + 27, // P0.27, 28, // P0.28 - 29, // P0.29, AIN5, LUX_SENSOR + 29, // P0.29, 30, // P0.30 - 31, // P0.31, AIN7, TEMP_SENSOR + 31, // P0.31, 32, // P1.00 33, // P1.01, LORA_DIO_1 34, // P1.02 - 35, // P1.03, EXT_CHRG_DETECT + 35, // P1.03, 36, // P1.04 37, // P1.05, LR1110_EN - 38, // P1.06, 3V3_EN PWR TO SENSORS - 39, // P1.07, PIN_3V3_ACC_EN + 38, // P1.06, + 39, // P1.07, 40, // P1.08, PIN_SPI_MISO 41, // P1.09, PIN_SPI_MOSI 42, // P1.10, LORA_RESET @@ -57,36 +57,14 @@ const uint32_t g_ADigitalPinMap[PINS_COUNT + 1] = void initVariant() { - // All pins output HIGH by default. - // https://github.com/Seeed-Studio/Adafruit_nRF52_Arduino/blob/fab7d30a997a1dfeef9d1d59bfb549adda73815a/cores/nRF5/wiring.c#L65-L69 - pinMode(BATTERY_PIN, INPUT); - pinMode(EXT_CHRG_DETECT, INPUT); - pinMode(EXT_PWR_DETECT, INPUT); - // pinMode(GPS_RESETB, INPUT); pinMode(PIN_BUTTON1, INPUT); pinMode(PIN_3V3_EN, OUTPUT); pinMode(PIN_3V3_ACC_EN, OUTPUT); - // pinMode(BUZZER_EN, OUTPUT); - // pinMode(SENSOR_EN, OUTPUT); - // pinMode(GPS_EN, OUTPUT); - // pinMode(GPS_RESET, OUTPUT); - // pinMode(GPS_VRTC_EN, OUTPUT); - // pinMode(GPS_SLEEP_INT, OUTPUT); - // pinMode(GPS_RTC_INT, OUTPUT); pinMode(LED_PIN, OUTPUT); pinMode(P_LORA_TX_LED, OUTPUT); - // digitalWrite(PIN_3V3_EN, LOW); - // digitalWrite(PIN_3V3_ACC_EN, LOW); - // digitalWrite(BUZZER_EN, LOW); - // digitalWrite(SENSOR_EN, LOW); - // digitalWrite(GPS_EN, LOW); - // digitalWrite(GPS_RESET, LOW); - // digitalWrite(GPS_VRTC_EN, LOW); - // digitalWrite(GPS_SLEEP_INT, HIGH); - // digitalWrite(GPS_RTC_INT, LOW); digitalWrite(LED_PIN, HIGH); digitalWrite(P_LORA_TX_LED, LOW); } diff --git a/variants/minewsemi_me25ls01/variant.h b/variants/minewsemi_me25ls01/variant.h index de57a65e..bbf15ff6 100644 --- a/variants/minewsemi_me25ls01/variant.h +++ b/variants/minewsemi_me25ls01/variant.h @@ -9,10 +9,7 @@ #define VARIANT_MCK (64000000ul) // #define USE_LFRC // 32.768 kHz RC oscillator -//////////////////////////////////////////////////////////////////////////////// // Power - -#define NRF_APM // detect usb power #define PIN_3V3_EN (32 + 5) // P1.6 Power to Sensors #define PIN_3V3_ACC_EN -1 @@ -20,46 +17,33 @@ #define BATTERY_IMMUTABLE #define ADC_MULTIPLIER (2.0F) -#define EXT_CHRG_DETECT (-1) // P1.3 -#define EXT_PWR_DETECT (-1) // P0.5 - #define ADC_RESOLUTION (14) #define BATTERY_SENSE_RES (12) #define AREF_VOLTAGE (3.0) -//////////////////////////////////////////////////////////////////////////////// // Number of pins - #define PINS_COUNT (48) #define NUM_DIGITAL_PINS (48) #define NUM_ANALOG_INPUTS (6) #define NUM_ANALOG_OUTPUTS (0) -//////////////////////////////////////////////////////////////////////////////// // UART pin definition +#define PIN_SERIAL1_RX (14) // P0.14 +#define PIN_SERIAL1_TX (13) // P0.13 -#define PIN_SERIAL1_RX (14) // P0.14 - checked -#define PIN_SERIAL1_TX (13) // P0.13 - checked +#define PIN_SERIAL2_RX (15) // P0.15 +#define PIN_SERIAL2_TX (17) // P0.17 -#define PIN_SERIAL2_RX (17) // P0.17 - checked -#define PIN_SERIAL2_TX (16) // P0.16 - checked - -//////////////////////////////////////////////////////////////////////////////// // I2C pin definition +#define HAS_WIRE (1) +#define WIRE_INTERFACES_COUNT (1) -#define HAS_WIRE (1) // checked -#define WIRE_INTERFACES_COUNT (1) // checked - -#define PIN_WIRE_SDA (15) // P0.26 - checked -#define PIN_WIRE_SCL (17) // P0.27 - checked +#define PIN_WIRE_SDA (21) // P0.21 +#define PIN_WIRE_SCL (16) // P0.16 #define I2C_NO_RESCAN -// #define HAS_QMA6100P -// #define QMA_6100P_INT_PIN (-1) // P1.2 -//////////////////////////////////////////////////////////////////////////////// // SPI pin definition - #define SPI_INTERFACES_COUNT (1) #define PIN_SPI_MISO (0 + 29) // P0.29 @@ -67,9 +51,7 @@ #define PIN_SPI_SCK (32 + 15) // P1.15 #define PIN_SPI_NSS (32 + 13) // P1.13 -//////////////////////////////////////////////////////////////////////////////// // Builtin LEDs - #define LED_BUILTIN (-1) #define LED_RED (32 + 5) // P1.5 #define LED_BLUE (32 + 7) // P1.7 @@ -78,15 +60,12 @@ #define LED_STATE_ON HIGH -//////////////////////////////////////////////////////////////////////////////// // Builtin buttons #define PIN_BUTTON1 (0 + 27) // P0.6 #define BUTTON_PIN PIN_BUTTON1 -//////////////////////////////////////////////////////////////////////////////// // LR1110 - #define LORA_DIO_1 (32 + 12) // P1.12 #define LORA_DIO_2 (32 + 10) // P1.10 #define LORA_NSS (PIN_SPI_NSS) // P1.13 @@ -107,10 +86,9 @@ #define LR1110_SPI_SCK_PIN LORA_SCLK #define LR1110_SPI_MOSI_PIN LORA_MOSI #define LR1110_SPI_MISO_PIN LORA_MISO -//////////////////////////////////////////////////////////////////////////////// -// GPS -//#define HAS_GPS 0 +// GPS +#define HAS_GPS 0 #define GPS_RX_PIN PIN_SERIAL1_RX #define GPS_TX_PIN PIN_SERIAL1_TX @@ -121,21 +99,3 @@ #define GPS_SLEEP_INT (-1) // P1.12 #define GPS_RTC_INT (-1) // P0.15 #define GPS_RESETB (-1) // P1.14 - -//////////////////////////////////////////////////////////////////////////////// -// Temp+Lux Sensor - -#define SENSOR_EN (-1) // P0.4 -#define TEMP_SENSOR (-1) // P0.31/AIN7 -#define LUX_SENSOR (-1) // P0.29/AIN5 - -//////////////////////////////////////////////////////////////////////////////// -// Accelerometer (I2C addr : ??? ) - -#define PIN_3V3_ACC_EN (-1) // P1.7 - -//////////////////////////////////////////////////////////////////////////////// -// Buzzer - -#define BUZZER_EN (-1) // P1.5 -#define BUZZER_PIN (0 + 25) // P0.25 \ No newline at end of file From ca422bbafbebea98083d08fadf58902a77363fc3 Mon Sep 17 00:00:00 2001 From: JQ Date: Wed, 2 Jul 2025 14:37:11 -0700 Subject: [PATCH 20/39] fix ble pin --- variants/heltec_wireless_paper/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini index 0b9ac38e..513ba4b9 100644 --- a/variants/heltec_wireless_paper/platformio.ini +++ b/variants/heltec_wireless_paper/platformio.ini @@ -40,7 +40,7 @@ build_flags = -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 -D DISPLAY_CLASS=E213Display - -D BLE_PIN_CODE=0 ; dynamic, random PIN + -D BLE_PIN_CODE=123456 ; dynamic, random PIN -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 build_src_filter = ${Heltec_Wireless_Paper_base.build_src_filter} From ec98d5f8a51dc497259610a4038ac25a35dbe112 Mon Sep 17 00:00:00 2001 From: Lloyd Date: Wed, 2 Jul 2025 23:41:31 +0100 Subject: [PATCH 21/39] BLE: Remove ScanResponse.addName() to fix re-advertising after disconnect Removed the call to Bluefruit.ScanResponse.addName() in startAdv(), as it was preventing BLE from reliably restarting advertising after a disconnect. Hypothesis: adding the device name to the scan response exceeds internal buffer limits or causes a conflict with advertising timing, leading to the BLE stack silently failing to re-advertise. Tested successfully (on T-1000) without this line, advertising now resumes correctly after disconnection (on Iphone) --- src/helpers/nrf52/SerialBLEInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/nrf52/SerialBLEInterface.cpp b/src/helpers/nrf52/SerialBLEInterface.cpp index f43a3767..c6c99d5b 100644 --- a/src/helpers/nrf52/SerialBLEInterface.cpp +++ b/src/helpers/nrf52/SerialBLEInterface.cpp @@ -27,7 +27,7 @@ void SerialBLEInterface::startAdv() { // Secondary Scan Response packet (optional) // Since there is no room for 'Name' in Advertising packet - Bluefruit.ScanResponse.addName(); + // Bluefruit.ScanResponse.addName(); /* Start Advertising * - Enable auto advertising if disconnected From d23378cff692f0be9ca4245104978536d8729f63 Mon Sep 17 00:00:00 2001 From: WattleFoxxo Date: Thu, 3 Jul 2025 11:42:53 +1000 Subject: [PATCH 22/39] Add XIAO RP2040 support --- src/helpers/rp2040/XiaoRP2040Board.cpp | 30 +++++++ src/helpers/rp2040/XiaoRP2040Board.h | 75 ++++++++++++++++++ variants/xiao_rp2040/platformio.ini | 104 +++++++++++++++++++++++++ variants/xiao_rp2040/target.cpp | 71 +++++++++++++++++ variants/xiao_rp2040/target.h | 21 +++++ 5 files changed, 301 insertions(+) create mode 100644 src/helpers/rp2040/XiaoRP2040Board.cpp create mode 100644 src/helpers/rp2040/XiaoRP2040Board.h create mode 100644 variants/xiao_rp2040/platformio.ini create mode 100644 variants/xiao_rp2040/target.cpp create mode 100644 variants/xiao_rp2040/target.h diff --git a/src/helpers/rp2040/XiaoRP2040Board.cpp b/src/helpers/rp2040/XiaoRP2040Board.cpp new file mode 100644 index 00000000..bb439706 --- /dev/null +++ b/src/helpers/rp2040/XiaoRP2040Board.cpp @@ -0,0 +1,30 @@ +#include "XiaoRP2040Board.h" + +#include +#include + +void XiaoRP2040Board::begin() { + // for future use, sub-classes SHOULD call this from their begin() + startup_reason = BD_STARTUP_NORMAL; + +#ifdef P_LORA_TX_LED + pinMode(P_LORA_TX_LED, OUTPUT); +#endif + +#ifdef PIN_VBAT_READ + pinMode(PIN_VBAT_READ, INPUT); +#endif + +#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) + Wire.setSDA(PIN_BOARD_SDA); + Wire.setSCL(PIN_BOARD_SCL); +#endif + + Wire.begin(); + + delay(10); // give sx1262 some time to power up +} + +bool XiaoRP2040Board::startOTAUpdate(const char *id, char reply[]) { + return false; +} diff --git a/src/helpers/rp2040/XiaoRP2040Board.h b/src/helpers/rp2040/XiaoRP2040Board.h new file mode 100644 index 00000000..c9353906 --- /dev/null +++ b/src/helpers/rp2040/XiaoRP2040Board.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +// LoRa radio module pins for the Xiao RP2040 +// https://wiki.seeedstudio.com/XIAO-RP2040/ + +#define P_LORA_DIO_1 27 // D1 +#define P_LORA_NSS 6 // D4 +#define P_LORA_RESET 28 // D2 +#define P_LORA_BUSY 29 // D3 +#define P_LORA_TX_LED 17 + +#define SX126X_RXEN 7 // D5 +#define SX126X_TXEN -1 + +#define SX126X_DIO2_AS_RF_SWITCH true +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +/* + * This board has no built-in way to read battery voltage. + * Nevertheless it's very easy to make it work, you only require two 1% resistors. + * If your using the WIO SX1262 Addon for xaio, make sure you dont connect D0! + * + * BAT+ -----+ + * | + * VSYS --+ -/\/\/\/\- --+ + * 200k | + * +-- D0 + * | + * GND --+ -/\/\/\/\- --+ + * | 100k + * BAT- -----+ + */ +#define PIN_VBAT_READ 26 // D0 +#define BATTERY_SAMPLES 8 +#define ADC_MULTIPLIER (3.0f * 3.3f * 1000) + +class XiaoRP2040Board : public mesh::MainBoard { +protected: + uint8_t startup_reason; + +public: + void begin(); + uint8_t getStartupReason() const override { return startup_reason; } + +#ifdef P_LORA_TX_LED + void onBeforeTransmit() override { digitalWrite(P_LORA_TX_LED, HIGH); } + void onAfterTransmit() override { digitalWrite(P_LORA_TX_LED, LOW); } +#endif + + + uint16_t getBattMilliVolts() override { +#if defined(PIN_VBAT_READ) && defined(ADC_MULTIPLIER) + analogReadResolution(12); + + uint32_t raw = 0; + for (int i = 0; i < BATTERY_SAMPLES; i++) { + raw += analogRead(PIN_VBAT_READ); + } + raw = raw / BATTERY_SAMPLES; + + return (ADC_MULTIPLIER * raw) / 4096; +#else + return 0; +#endif + } + + const char *getManufacturerName() const override { return "Xiao RP2040"; } + + void reboot() override { rp2040.reboot(); } + + bool startOTAUpdate(const char *id, char reply[]) override; +}; diff --git a/variants/xiao_rp2040/platformio.ini b/variants/xiao_rp2040/platformio.ini new file mode 100644 index 00000000..960fdbba --- /dev/null +++ b/variants/xiao_rp2040/platformio.ini @@ -0,0 +1,104 @@ +[Xiao_rp2040] +extends = rp2040_base + +board = seeed_xiao_rp2040 +board_build.filesystem_size = 0.5m + +build_flags = ${rp2040_base.build_flags} + -I variants/xiao_rp2040 + -D SX126X_CURRENT_LIMIT=140 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D SX126X_RX_BOOSTED_GAIN=1 +; Debug options + ; -D DEBUG_RP2040_WIRE=1 + ; -D DEBUG_RP2040_SPI=1 + ; -D DEBUG_RP2040_CORE=1 + ; -D RADIOLIB_DEBUG_SPI=1 + ; -D DEBUG_RP2040_PORT=Serial + +build_src_filter = ${rp2040_base.build_src_filter} + + + +<../variants/xiao_rp2040> + +lib_deps = ${rp2040_base.lib_deps} + +[env:Xiao_rp2040_Repeater] +extends = Xiao_rp2040 +build_flags = ${Xiao_rp2040.build_flags} + -D ADVERT_NAME='"Xiao Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 +build_src_filter = ${Xiao_rp2040.build_src_filter} + +<../examples/simple_repeater> + +[env:Xiao_rp2040_room_server] +extends = Xiao_rp2040 +build_flags = ${Xiao_rp2040.build_flags} + -D ADVERT_NAME='"Xiao Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Xiao_rp2040.build_src_filter} + +<../examples/simple_room_server> + +[env:Xiao_rp2040_companion_radio_usb] +extends = Xiao_rp2040 +build_flags = ${Xiao_rp2040.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 +; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 +build_src_filter = ${Xiao_rp2040.build_src_filter} + +<../examples/companion_radio> +lib_deps = ${Xiao_rp2040.lib_deps} + densaugeo/base64 @ ~1.4.0 + +; [env:Xiao_rp2040_companion_radio_ble] +; extends = Xiao_rp2040 +; build_flags = ${Xiao_rp2040.build_flags} +; -D MAX_CONTACTS=100 +; -D MAX_GROUP_CHANNELS=8 +; -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 +; ; -D MESH_PACKET_LOGGING=1 +; ; -D MESH_DEBUG=1 +; build_src_filter = ${Xiao_rp2040.build_src_filter} +; +<../examples/companion_radio> +; lib_deps = ${Xiao_rp2040.lib_deps} +; densaugeo/base64 @ ~1.4.0 + +; [env:Xiao_rp2040_companion_radio_wifi] +; extends = Xiao_rp2040 +; build_flags = ${Xiao_rp2040.build_flags} +; -D MAX_CONTACTS=100 +; -D MAX_GROUP_CHANNELS=8 +; -D WIFI_DEBUG_LOGGING=1 +; -D WIFI_SSID='"myssid"' +; -D WIFI_PWD='"mypwd"' +; ; -D MESH_PACKET_LOGGING=1 +; ; -D MESH_DEBUG=1 +; build_src_filter = ${Xiao_rp2040.build_src_filter} +; +<../examples/companion_radio> +; lib_deps = ${Xiao_rp2040.lib_deps} +; densaugeo/base64 @ ~1.4.0 + +[env:Xiao_rp2040_terminal_chat] +extends = Xiao_rp2040 +build_flags = ${Xiao_rp2040.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Xiao_rp2040.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> +lib_deps = ${Xiao_rp2040.lib_deps} + densaugeo/base64 @ ~1.4.0 diff --git a/variants/xiao_rp2040/target.cpp b/variants/xiao_rp2040/target.cpp new file mode 100644 index 00000000..a801aae8 --- /dev/null +++ b/variants/xiao_rp2040/target.cpp @@ -0,0 +1,71 @@ +#include "target.h" + +#include +#include + +XiaoRP2040Board board; + +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); + +WRAPPER_CLASS radio_driver(radio, board); + +VolatileRTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +SensorManager sensors; + +#ifndef LORA_CR +#define LORA_CR 5 +#endif + +bool radio_init() { + rtc_clock.begin(Wire); + +#ifdef SX126X_DIO3_TCXO_VOLTAGE + float tcxo = SX126X_DIO3_TCXO_VOLTAGE; +#else + float tcxo = 1.6f; +#endif + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + radio.setCRC(1); + +#ifdef SX126X_CURRENT_LIMIT + radio.setCurrentLimit(SX126X_CURRENT_LIMIT); +#endif + +#ifdef SX126X_DIO2_AS_RF_SWITCH + radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); +#endif + +#ifdef SX126X_RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); +#endif + + return true; // success +} + +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(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/xiao_rp2040/target.h b/variants/xiao_rp2040/target.h new file mode 100644 index 00000000..6a3c192b --- /dev/null +++ b/variants/xiao_rp2040/target.h @@ -0,0 +1,21 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 + +#include +#include +#include +#include +#include +#include + +extern XiaoRP2040Board board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern SensorManager 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(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); From 90656e7d06ecf53f320149f1b9ce98e4a02cdf08 Mon Sep 17 00:00:00 2001 From: Rob Loranger Date: Thu, 3 Jul 2025 09:18:26 -0700 Subject: [PATCH 23/39] clean up xiao nrf52 move variant specific code out of src/helpers redefine RXEN for alternate radio pinout --- .../nrf52 => variants/xiao_nrf52}/XiaoNrf52Board.cpp | 0 .../helpers/nrf52 => variants/xiao_nrf52}/XiaoNrf52Board.h | 7 +++---- variants/xiao_nrf52/platformio.ini | 3 +-- variants/xiao_nrf52/target.h | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) rename {src/helpers/nrf52 => variants/xiao_nrf52}/XiaoNrf52Board.cpp (100%) rename {src/helpers/nrf52 => variants/xiao_nrf52}/XiaoNrf52Board.h (92%) diff --git a/src/helpers/nrf52/XiaoNrf52Board.cpp b/variants/xiao_nrf52/XiaoNrf52Board.cpp similarity index 100% rename from src/helpers/nrf52/XiaoNrf52Board.cpp rename to variants/xiao_nrf52/XiaoNrf52Board.cpp diff --git a/src/helpers/nrf52/XiaoNrf52Board.h b/variants/xiao_nrf52/XiaoNrf52Board.h similarity index 92% rename from src/helpers/nrf52/XiaoNrf52Board.h rename to variants/xiao_nrf52/XiaoNrf52Board.h index e6c8e7f7..60b9f5bb 100644 --- a/src/helpers/nrf52/XiaoNrf52Board.h +++ b/variants/xiao_nrf52/XiaoNrf52Board.h @@ -5,20 +5,19 @@ #ifdef XIAO_NRF52 -// LoRa radio module pins for Seeed Xiao-nrf52 +// redefine lora pins if using the S3 variant of SX1262 board #ifdef SX1262_XIAO_S3_VARIANT #undef P_LORA_DIO_1 #undef P_LORA_BUSY #undef P_LORA_RESET #undef P_LORA_NSS + #undef SX126X_RXEN #define P_LORA_DIO_1 D0 #define P_LORA_BUSY D1 #define P_LORA_RESET D2 #define P_LORA_NSS D3 + #define SX126X_RXEN D4 #endif -//#define SX126X_POWER_EN 37 - - class XiaoNrf52Board : public mesh::MainBoard { protected: diff --git a/variants/xiao_nrf52/platformio.ini b/variants/xiao_nrf52/platformio.ini index c4934e04..bba3e632 100644 --- a/variants/xiao_nrf52/platformio.ini +++ b/variants/xiao_nrf52/platformio.ini @@ -50,8 +50,7 @@ build_flags = ${nrf52840_xiao.build_flags} -D ENV_INCLUDE_INA219=1 build_src_filter = ${nrf52840_xiao.build_src_filter} + - + - + + + +<../variants/xiao_nrf52> debug_tool = jlink upload_protocol = nrfutil diff --git a/variants/xiao_nrf52/target.h b/variants/xiao_nrf52/target.h index eb299006..c8c6a42a 100644 --- a/variants/xiao_nrf52/target.h +++ b/variants/xiao_nrf52/target.h @@ -3,7 +3,7 @@ #define RADIOLIB_STATIC_ONLY 1 #include #include -#include +#include #include #include #include From 74818d0594b9b5e45e5ffa9b264080497ba76439 Mon Sep 17 00:00:00 2001 From: taco Date: Fri, 4 Jul 2025 13:55:39 +1000 Subject: [PATCH 24/39] fix: change GPS pins Pin 45 and 46 are strapping pins on ESP32-S3, which can lead to unintended consequences on boot. I have amended the pins and added an enable pin as well. --- variants/heltec_v3/platformio.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index c39e9c76..c3bb27b7 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -23,9 +23,9 @@ build_flags = -D ENV_INCLUDE_INA3221=1 -D ENV_INCLUDE_INA219=1 -D ENV_INCLUDE_GPS=1 - -D PIN_GPS_RX=45 - -D PIN_GPS_TX=46 - -D PIN_GPS_EN=-1 + -D PIN_GPS_RX=47 + -D PIN_GPS_TX=48 + -D PIN_GPS_EN=46 build_src_filter = ${esp32_base.build_src_filter} +<../variants/heltec_v3> + From 2bb7e6dad4e1e622577edb4febbc9bdf10a3eb0a Mon Sep 17 00:00:00 2001 From: taco Date: Fri, 4 Jul 2025 14:12:57 +1000 Subject: [PATCH 25/39] fix: heltec v3: change gps enable pin --- variants/heltec_v3/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index c3bb27b7..a4b6bf6f 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -25,7 +25,7 @@ build_flags = -D ENV_INCLUDE_GPS=1 -D PIN_GPS_RX=47 -D PIN_GPS_TX=48 - -D PIN_GPS_EN=46 + -D PIN_GPS_EN=26 build_src_filter = ${esp32_base.build_src_filter} +<../variants/heltec_v3> + From 3d70a0d02cc877c6bba1620696f352c1968e8edd Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Fri, 4 Jul 2025 21:33:07 +1000 Subject: [PATCH 26/39] * added RADIOLIB_EXLUDE_'s for faster builds --- platformio.ini | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/platformio.ini b/platformio.ini index 90e7cfb0..d20508a8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -29,6 +29,20 @@ build_flags = -w -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1 -D LORA_SF=11 -D ENABLE_PRIVATE_KEY_IMPORT=1 ; NOTE: comment these out for more secure firmware -D ENABLE_PRIVATE_KEY_EXPORT=1 + -D RADIOLIB_EXCLUDE_CC1101=1 + -D RADIOLIB_EXCLUDE_RF69=1 + -D RADIOLIB_EXCLUDE_SX1231=1 + -D RADIOLIB_EXCLUDE_SI443X=1 + -D RADIOLIB_EXCLUDE_RFM2X=1 + -D RADIOLIB_EXCLUDE_SX128X=1 + -D RADIOLIB_EXCLUDE_AFSK=1 + -D RADIOLIB_EXCLUDE_AX25=1 + -D RADIOLIB_EXCLUDE_HELLSCHREIBER=1 + -D RADIOLIB_EXCLUDE_MORSE=1 + -D RADIOLIB_EXCLUDE_APRS=1 + -D RADIOLIB_EXCLUDE_BELL=1 + -D RADIOLIB_EXCLUDE_RTTY=1 + -D RADIOLIB_EXCLUDE_SSTV=1 build_src_filter = +<*.cpp> + From 294138804151046a6798f472933df607ebd1b4c1 Mon Sep 17 00:00:00 2001 From: recrof Date: Fri, 4 Jul 2025 15:03:25 +0200 Subject: [PATCH 27/39] initial support for Seeed Studio SenseCap Solar board --- boards/seeed_sensecap_solar.json | 60 +++++++++++++ .../sensecap_solar/SenseCapSolarBoard.cpp | 81 ++++++++++++++++++ variants/sensecap_solar/SenseCapSolarBoard.h | 42 +++++++++ variants/sensecap_solar/platformio.ini | 75 ++++++++++++++++ variants/sensecap_solar/target.cpp | 39 +++++++++ variants/sensecap_solar/target.h | 21 +++++ variants/sensecap_solar/variant.cpp | 69 +++++++++++++++ variants/sensecap_solar/variant.h | 85 +++++++++++++++++++ 8 files changed, 472 insertions(+) create mode 100644 boards/seeed_sensecap_solar.json create mode 100644 variants/sensecap_solar/SenseCapSolarBoard.cpp create mode 100644 variants/sensecap_solar/SenseCapSolarBoard.h create mode 100644 variants/sensecap_solar/platformio.ini create mode 100644 variants/sensecap_solar/target.cpp create mode 100644 variants/sensecap_solar/target.h create mode 100644 variants/sensecap_solar/variant.cpp create mode 100644 variants/sensecap_solar/variant.h diff --git a/boards/seeed_sensecap_solar.json b/boards/seeed_sensecap_solar.json new file mode 100644 index 00000000..d6630d82 --- /dev/null +++ b/boards/seeed_sensecap_solar.json @@ -0,0 +1,60 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v7.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_Seeed_XIAO_nRF52840 -DNRF52840_XXAA -DSEEED_XIAO_NRF52840 ", + "f_cpu": "64000000L", + "hwids": [ + [ "0x2886", "0x0059" ] + ], + "mcu": "nrf52840", + "variant": "Seeed_XIAO_nRF52840", + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "7.3.0", + "sd_fwid": "0x0123" + }, + "bsp": { + "name": "adafruit" + }, + "bootloader": { + "settings_addr": "0xFF000" + }, + "usb_product": "XIAO nRF52840" + }, + "connectivity": [ + "bluetooth" + ], + "debug": { + "jlink_device": "nRF52840_xxAA", + "openocd_target": "nrf52.cfg", + "svd_path": "nrf52840.svd" + }, + "frameworks": [ + "arduino" + ], + "name": "Seeed Studio XIAO nRF52840", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "protocol": "nrfutil", + "speed": 115200, + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "cmsis-dap", + "sam-ba", + "blackmagic" + ], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://wiki.seeedstudio.com/meshtastic_solar_node/", + "vendor": "Seeed Studio" +} \ No newline at end of file diff --git a/variants/sensecap_solar/SenseCapSolarBoard.cpp b/variants/sensecap_solar/SenseCapSolarBoard.cpp new file mode 100644 index 00000000..eb903f59 --- /dev/null +++ b/variants/sensecap_solar/SenseCapSolarBoard.cpp @@ -0,0 +1,81 @@ +#include +#include "SenseCapSolarBoard.h" + +#include +#include + +static BLEDfu bledfu; + +static void connect_callback(uint16_t conn_handle) { + (void)conn_handle; + MESH_DEBUG_PRINTLN("BLE client connected"); +} + +static void disconnect_callback(uint16_t conn_handle, uint8_t reason) { + (void)conn_handle; + (void)reason; + + MESH_DEBUG_PRINTLN("BLE client disconnected"); +} + +void SenseCapSolarBoard::begin() { + // for future use, sub-classes SHOULD call this from their begin() + startup_reason = BD_STARTUP_NORMAL; + +#if defined(PIN_WIRE_SDA) && defined(PIN_WIRE_SCL) + Wire.setPins(PIN_WIRE_SDA, PIN_WIRE_SCL); +#endif + + Wire.begin(); + +#ifdef P_LORA_TX_LED + pinMode(P_LORA_TX_LED, OUTPUT); + digitalWrite(P_LORA_TX_LED, HIGH); +#endif + + delay(10); // give sx1262 some time to power up +} + +bool SenseCapSolarBoard::startOTAUpdate(const char* id, char reply[]) { + // Config the peripheral connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16); + + Bluefruit.begin(1, 0); + // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 + Bluefruit.setTxPower(4); + // Set the BLE device name + Bluefruit.setName("SENSECAP_SOLAR_OTA"); + + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + + // To be consistent OTA DFU should be added first if it exists + bledfu.begin(); + + // Set up and start advertising + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addName(); + + /* Start Advertising + - Enable auto advertising if disconnected + - Interval: fast mode = 20 ms, slow mode = 152.5 ms + - Timeout for fast mode is 30 seconds + - Start(timeout) with timeout = 0 will advertise forever (until connected) + + For recommended advertising interval + https://developer.apple.com/library/content/qa/qa1931/_index.html + */ + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + + strcpy(reply, "OK - started"); + + return true; +} diff --git a/variants/sensecap_solar/SenseCapSolarBoard.h b/variants/sensecap_solar/SenseCapSolarBoard.h new file mode 100644 index 00000000..b0956644 --- /dev/null +++ b/variants/sensecap_solar/SenseCapSolarBoard.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +class SenseCapSolarBoard : public mesh::MainBoard { +protected: + uint8_t startup_reason; + +public: + void begin(); + uint8_t getStartupReason() const override { return startup_reason; } + +#if defined(P_LORA_TX_LED) + void onBeforeTransmit() override { + digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on + } + void onAfterTransmit() override { + digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off + } +#endif + + uint16_t getBattMilliVolts() override { + digitalWrite(VBAT_ENABLE, LOW); + int adcvalue = 0; + analogReadResolution(12); + analogReference(AR_INTERNAL_3_0); + delay(10); + adcvalue = analogRead(BATTERY_PIN); + return (adcvalue * ADC_MULTIPLIER * AREF_VOLTAGE) / 4.096; + } + + const char* getManufacturerName() const override { + return "Seeed SenseCap Solar"; + } + + void reboot() override { + NVIC_SystemReset(); + } + + bool startOTAUpdate(const char* id, char reply[]) override; +}; diff --git a/variants/sensecap_solar/platformio.ini b/variants/sensecap_solar/platformio.ini new file mode 100644 index 00000000..281f6688 --- /dev/null +++ b/variants/sensecap_solar/platformio.ini @@ -0,0 +1,75 @@ +[SenseCap_Solar] +extends = nrf52_base +board = seeed_sensecap_solar +board_build.ldscript = boards/nrf52840_s140_v7.ld +build_flags = ${nrf52_base.build_flags} + -I lib/nrf52/s140_nrf52_7.3.0_API/include + -I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52 + -I variants/sensecap_solar + -I src/helpers/nrf52 + -D NRF52_PLATFORM=1 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D P_LORA_TX_LED=12 + -D P_LORA_DIO_1=1 + -D P_LORA_RESET=2 + -D P_LORA_BUSY=3 + -D P_LORA_NSS=4 + -D LORA_TX_POWER=22 + -D SX126X_RXEN=5 + -D SX126X_TXEN=RADIOLIB_NC + -D SX126X_DIO2_AS_RF_SWITCH=1 + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_CURRENT_LIMIT=140 + -D SX126X_RX_BOOSTED_GAIN=1 + -D ENV_INCLUDE_AHTX0=1 + -D ENV_INCLUDE_BME280=1 + -D ENV_INCLUDE_BMP280=1 + -D ENV_INCLUDE_SHTC3=1 + -D ENV_INCLUDE_LPS22HB=1 + -D ENV_INCLUDE_INA3221=1 + -D ENV_INCLUDE_INA219=1 +build_src_filter = ${nrf52_base.build_src_filter} + + + + + + + +<../variants/SenseCap_Solar> +debug_tool = jlink +upload_protocol = nrfutil +lib_deps = + ${nrf52_base.lib_deps} + rweather/Crypto @ ^0.4.0 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 + adafruit/Adafruit BMP280 Library @ ^2.6.8 + adafruit/Adafruit SHTC3 Library @ ^1.0.1 + arduino-libraries/Arduino_LPS22HB @ ^1.0.2 + +[env:SenseCap_Solar_repeater] +extends = SenseCap_Solar +build_flags = + ${SenseCap_Solar.build_flags} + -D ADVERT_NAME='"SenseCap_Solar Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${SenseCap_Solar.build_src_filter} + +<../examples/simple_repeater/main.cpp> + +[env:SenseCap_Solar_room_server] +extends = SenseCap_Solar +build_flags = + ${SenseCap_Solar.build_flags} + -D ADVERT_NAME='"SenseCap_Solar Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${SenseCap_Solar.build_src_filter} + +<../examples/simple_room_server/main.cpp> \ No newline at end of file diff --git a/variants/sensecap_solar/target.cpp b/variants/sensecap_solar/target.cpp new file mode 100644 index 00000000..6bd7d31a --- /dev/null +++ b/variants/sensecap_solar/target.cpp @@ -0,0 +1,39 @@ +#include +#include "target.h" +#include + +SenseCapSolarBoard board; + +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); + +VolatileRTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +EnvironmentSensorManager sensors; + +bool radio_init() { + rtc_clock.begin(Wire); + + 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(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/sensecap_solar/target.h b/variants/sensecap_solar/target.h new file mode 100644 index 00000000..63506951 --- /dev/null +++ b/variants/sensecap_solar/target.h @@ -0,0 +1,21 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#include + +extern SenseCapSolarBoard 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(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/sensecap_solar/variant.cpp b/variants/sensecap_solar/variant.cpp new file mode 100644 index 00000000..2b3ca305 --- /dev/null +++ b/variants/sensecap_solar/variant.cpp @@ -0,0 +1,69 @@ +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" +#include "nrf.h" + +const uint32_t g_ADigitalPinMap[] = { + // D0 .. D10 - Peripheral control pins + 2, // D0 P0.02 (A0) GNSS_WAKEUP + 3, // D1 P0.03 (A1) LORA_DIO1 + 28, // D2 P0.28 (A2) LORA_RESET + 29, // D3 P0.29 (A3) LORA_BUSY + 4, // D4 P0.04 (A4/SDA) LORA_CS + 5, // D5 P0.05 (A5/SCL) LORA_SW + 43, // D6 P1.11 (UART_TX) GNSS_TX + 44, // D7 P1.12 (UART_RX) GNSS_RX + 45, // D8 P1.13 (SPI_SCK) LORA_SCK + 46, // D9 P1.14 (SPI_MISO) LORA_MISO + 47, // D10 P1.15 (SPI_MOSI) LORA_MOSI + + // D11-D12 - LED outputs + 15, // D11 P0.15 User LED + 19, // D12 P0.19 Breathing LED + + // D13 - User input + 33, // D13 P1.01 User Button + + // D14-D15 - Grove/NFC interface + 9, // D14 P0.09 NFC1/GROVE_D1 + 10, // D15 P0.10 NFC2/GROVE_D0 + + // D16 - Power management + // 31, // D16 P0.31 VBAT_ADC (Battery voltage) + 31, // D16 P0.31 VBAT_ADC (Battery voltage) + // D17 - GNSS control + 35, // D17 P1.03 GNSS_RESET + + 37, // D18 P1.05 GNSS_ENABLE + 14, // D19 P0.14 BAT_READ + 39, // D20 P1.07 USER_BUTTON + + // + 21, // D21 P0.21 (QSPI_SCK) + 25, // D22 P0.25 (QSPI_CSN) + 20, // D23 P0.20 (QSPI_SIO_0 DI) + 24, // D24 P0.24 (QSPI_SIO_1 DO) + 22, // D25 P0.22 (QSPI_SIO_2 WP) + 23, // D26 P0.23 (QSPI_SIO_3 HOLD) +}; + +void initVariant() { + pinMode(GPS_EN, OUTPUT); + digitalWrite(GPS_EN, LOW); + + pinMode(BATTERY_PIN, INPUT); + pinMode(VBAT_ENABLE, OUTPUT); + digitalWrite(VBAT_ENABLE, LOW); + + pinMode(PIN_QSPI_CS, OUTPUT); + digitalWrite(PIN_QSPI_CS, HIGH); + + pinMode(LED_GREEN, OUTPUT); + digitalWrite(LED_GREEN, LOW); + + pinMode(LED_BLUE, OUTPUT); + digitalWrite(LED_BLUE, LOW); + + pinMode(GPS_EN, OUTPUT); + digitalWrite(GPS_EN, HIGH); +} diff --git a/variants/sensecap_solar/variant.h b/variants/sensecap_solar/variant.h new file mode 100644 index 00000000..76494f48 --- /dev/null +++ b/variants/sensecap_solar/variant.h @@ -0,0 +1,85 @@ +#ifndef _SEEED_SENSECAP_SOLAR_H_ +#define _SEEED_SENSECAP_SOLAR_H_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#define PINS_COUNT (33) +#define NUM_DIGITAL_PINS (33) +#define NUM_ANALOG_INPUTS (8) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED (12) +#define LED_PWR (PINS_COUNT) + +#define LED_BUILTIN (PIN_LED) + +#define LED_RED (PINS_COUNT) +#define LED_GREEN (12) +#define LED_BLUE (11) + +#define LED_STATE_ON (1) // State when LED is litted + +// Buttons +#define PIN_BUTTON1 (13) +#define PIN_BUTTON2 (20) + +#define VBAT_ENABLE (19) // Output LOW to enable reading of the BAT voltage. + +// Analog pins +#define BATTERY_PIN (16) // Read the BAT voltage. +#define AREF_VOLTAGE (3.0F) +#define ADC_MULTIPLIER (3.0F) // 1M, 512k divider bridge +#define ADC_RESOLUTION (12) + +// Serial interfaces +#define PIN_SERIAL1_RX (7) +#define PIN_SERIAL1_TX (6) + +// SPI Interfaces +#define SPI_INTERFACES_COUNT (1) + +#define PIN_SPI_MISO (9) +#define PIN_SPI_MOSI (10) +#define PIN_SPI_SCK (8) + +// Lora SPI is on SPI0 +#define P_LORA_SCLK PIN_SPI_SCK +#define P_LORA_MISO PIN_SPI_MISO +#define P_LORA_MOSI PIN_SPI_MOSI + +// Wire Interfaces +#define WIRE_INTERFACES_COUNT (1) + +#define PIN_WIRE_SDA (14) +#define PIN_WIRE_SCL (15) + +// GPS L76KB +#define GPS_BAUDRATE 9600 +#define GPS_THREAD_INTERVAL 50 +#define PIN_GPS_TX PIN_SERIAL1_RX +#define PIN_GPS_RX PIN_SERIAL1_TX +#define PIN_GPS_STANDBY (0) +#define GPS_EN (18) + +// QSPI Pins +#define PIN_QSPI_SCK (21) +#define PIN_QSPI_CS (22) +#define PIN_QSPI_IO0 (23) +#define PIN_QSPI_IO1 (24) +#define PIN_QSPI_IO2 (25) +#define PIN_QSPI_IO3 (26) + +#define EXTERNAL_FLASH_DEVICES P25Q16H +#define EXTERNAL_FLASH_USE_QSPI + +#endif \ No newline at end of file From 71255e00f173f7552a210ac96a508e6898dd2902 Mon Sep 17 00:00:00 2001 From: Florent de Lamotte Date: Fri, 4 Jul 2025 15:42:56 +0200 Subject: [PATCH 28/39] stm32 targets: set preamble to 16 --- variants/rak3x72/target.cpp | 2 +- variants/wio-e5-dev/target.cpp | 2 +- variants/wio-e5-mini/target.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/variants/rak3x72/target.cpp b/variants/rak3x72/target.cpp index d7070eae..446783aa 100644 --- a/variants/rak3x72/target.cpp +++ b/variants/rak3x72/target.cpp @@ -38,7 +38,7 @@ bool radio_init() { radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, STM32WL_TCXO_VOLTAGE, 0); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, STM32WL_TCXO_VOLTAGE, 0); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/variants/wio-e5-dev/target.cpp b/variants/wio-e5-dev/target.cpp index 8ccbe384..42e900e4 100644 --- a/variants/wio-e5-dev/target.cpp +++ b/variants/wio-e5-dev/target.cpp @@ -35,7 +35,7 @@ bool radio_init() { radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, 1.7, 0); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, 1.7, 0); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/variants/wio-e5-mini/target.cpp b/variants/wio-e5-mini/target.cpp index 6c045dd5..0e2358b8 100644 --- a/variants/wio-e5-mini/target.cpp +++ b/variants/wio-e5-mini/target.cpp @@ -33,7 +33,7 @@ bool radio_init() { radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, 1.7, 0); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, 1.7, 0); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); From fa481e832b4360593f2a1a8340e2f59944940882 Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Fri, 4 Jul 2025 16:40:19 +0200 Subject: [PATCH 29/39] LR's corrected calculation override (instead of SX) and minor changes according to radiolib's wiki --- src/helpers/CustomLR1110.h | 76 ++++++++++++++++++++++++------------- variants/t1000-e/target.cpp | 3 +- 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/helpers/CustomLR1110.h b/src/helpers/CustomLR1110.h index d431dac1..e82f48f5 100644 --- a/src/helpers/CustomLR1110.h +++ b/src/helpers/CustomLR1110.h @@ -10,34 +10,58 @@ class CustomLR1110 : public LR1110 { CustomLR1110(Module *mod) : LR1110(mod) { } RadioLibTime_t getTimeOnAir(size_t len) override { - uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << this->spreadingFactor) / (this->bandwidthKhz * 10) ; - uint8_t sfCoeff1_x4 = 17; // (4.25 * 4) - uint8_t sfCoeff2 = 8; - if(this->spreadingFactor == 5 || this->spreadingFactor == 6) { - sfCoeff1_x4 = 25; // 6.25 * 4 - sfCoeff2 = 0; - } - uint8_t sfDivisor = 4*this->spreadingFactor; - if(symbolLength_us >= 16000) { - sfDivisor = 4*(this->spreadingFactor - 2); - } - const int8_t bitsPerCrc = 16; - const int8_t N_symbol_header = this->headerType == RADIOLIB_SX126X_LORA_HEADER_EXPLICIT ? 20 : 0; - - // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8) - int16_t bitCount = (int16_t) 8 * len + this->crcTypeLoRa * bitsPerCrc - 4 * this->spreadingFactor + sfCoeff2 + N_symbol_header; - if(bitCount < 0) { - bitCount = 0; - } - // add (sfDivisor) - 1 to the numerator to give integer CEIL(...) - uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor); - - // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit - uint32_t nSymbol_x4 = (this->preambleLengthLoRa + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * (this->codingRate + 4) * 4; - - return((symbolLength_us * nSymbol_x4) / 4); + // calculate number of symbols + float N_symbol = 0; + if(this->codingRate <= RADIOLIB_LR11X0_LORA_CR_4_8_SHORT) { + // legacy coding rate - nice and simple + // get SF coefficients + float coeff1 = 0; + int16_t coeff2 = 0; + int16_t coeff3 = 0; + if(this->spreadingFactor < 7) { + // SF5, SF6 + coeff1 = 6.25; + coeff2 = 4*this->spreadingFactor; + coeff3 = 4*this->spreadingFactor; + } else if(this->spreadingFactor < 11) { + // SF7. SF8, SF9, SF10 + coeff1 = 4.25; + coeff2 = 4*this->spreadingFactor + 8; + coeff3 = 4*this->spreadingFactor; + } else { + // SF11, SF12 + coeff1 = 4.25; + coeff2 = 4*this->spreadingFactor + 8; + coeff3 = 4*(this->spreadingFactor - 2); } + // get CRC length + int16_t N_bitCRC = 16; + if(this->crcTypeLoRa == RADIOLIB_LR11X0_LORA_CRC_DISABLED) { + N_bitCRC = 0; + } + + // get header length + int16_t N_symbolHeader = 20; + if(this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) { + N_symbolHeader = 0; + } + + // calculate number of LoRa preamble symbols - NO! Lora preamble is already in symbols + // uint32_t N_symbolPreamble = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4)); + + // calculate the number of symbols - nope + // N_symbol = (float)N_symbolPreamble + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRate + 4); + // calculate the number of symbols - using only preamblelora because it's already in symbols + N_symbol = (float)preambleLengthLoRa + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(this->codingRate + 4); + } else { + // long interleaving - not needed for this modem + } + + // get time-on-air in us + return(((uint32_t(1) << this->spreadingFactor) / this->bandwidthKhz) * N_symbol * 1000.0f); +} + bool isReceiving() { uint16_t irq = getIrqStatus(); bool detected = ((irq & LR1110_IRQ_HEADER_VALID) || (irq & LR1110_IRQ_HAS_PREAMBLE)); diff --git a/variants/t1000-e/target.cpp b/variants/t1000-e/target.cpp index f6fb1f04..06509c4f 100644 --- a/variants/t1000-e/target.cpp +++ b/variants/t1000-e/target.cpp @@ -61,7 +61,8 @@ bool radio_init() { return false; // fail } - radio.setCRC(1); + radio.setCRC(2); + radio.explicitHeader(); #ifdef RF_SWITCH_TABLE radio.setRfSwitchTable(rfswitch_dios, rfswitch_table); From aa3c702ffdbe06fce30735813488484d00cb4f71 Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Fri, 4 Jul 2025 19:27:11 +0300 Subject: [PATCH 30/39] Read battery voltage on Minewsemi ME25LS01 --- src/helpers/nrf52/MinewsemiME25LS01Board.cpp | 11 ++--- src/helpers/nrf52/MinewsemiME25LS01Board.h | 50 +++++--------------- variants/minewsemi_me25ls01/platformio.ini | 19 -------- variants/minewsemi_me25ls01/variant.cpp | 6 +-- variants/minewsemi_me25ls01/variant.h | 9 +--- 5 files changed, 22 insertions(+), 73 deletions(-) diff --git a/src/helpers/nrf52/MinewsemiME25LS01Board.cpp b/src/helpers/nrf52/MinewsemiME25LS01Board.cpp index f402a0fd..c41a6bc0 100644 --- a/src/helpers/nrf52/MinewsemiME25LS01Board.cpp +++ b/src/helpers/nrf52/MinewsemiME25LS01Board.cpp @@ -8,11 +8,12 @@ void MinewsemiME25LS01Board::begin() { // for future use, sub-classes SHOULD call this from their begin() startup_reason = BD_STARTUP_NORMAL; btn_prev_state = HIGH; + + pinMode(PIN_VBAT_READ, INPUT); sd_power_mode_set(NRF_POWER_MODE_LOWPWR); #ifdef BUTTON_PIN - // pinMode(BATTERY_PIN, INPUT); pinMode(BUTTON_PIN, INPUT); pinMode(LED_PIN, OUTPUT); #endif @@ -31,7 +32,6 @@ void MinewsemiME25LS01Board::begin() { delay(10); // give sx1262 some time to power up } -#if 0 static BLEDfu bledfu; static void connect_callback(uint16_t conn_handle) { @@ -47,7 +47,7 @@ static void disconnect_callback(uint16_t conn_handle, uint8_t reason) { } -bool TrackerT1000eBoard::startOTAUpdate(const char* id, char reply[]) { +bool MinewsemiME25LS01Board::startOTAUpdate(const char* id, char reply[]) { // Config the peripheral connection with maximum bandwidth // more SRAM required by SoftDevice // Note: All config***() function must be called before begin() @@ -58,7 +58,7 @@ bool TrackerT1000eBoard::startOTAUpdate(const char* id, char reply[]) { // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 Bluefruit.setTxPower(4); // Set the BLE device name - Bluefruit.setName("T1000E_OTA"); + Bluefruit.setName("Minewsemi_OTA"); Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); @@ -88,5 +88,4 @@ bool TrackerT1000eBoard::startOTAUpdate(const char* id, char reply[]) { strcpy(reply, "OK - started"); return true; -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/helpers/nrf52/MinewsemiME25LS01Board.h b/src/helpers/nrf52/MinewsemiME25LS01Board.h index 4b8c8293..777606a6 100644 --- a/src/helpers/nrf52/MinewsemiME25LS01Board.h +++ b/src/helpers/nrf52/MinewsemiME25LS01Board.h @@ -16,9 +16,9 @@ #define LR11X0_DIO_AS_RF_SWITCH true #define LR11X0_DIO3_TCXO_VOLTAGE 1.6 -// built-ins -//#define PIN_VBAT_READ 5 -//#define ADC_MULTIPLIER (3 * 1.73 * 1000) +#define PIN_VBAT_READ BATTERY_PIN +#define ADC_MULTIPLIER (1.815f) // dependent on voltage divider resistors. TODO: more accurate battery tracking + class MinewsemiME25LS01Board : public mesh::MainBoard { protected: @@ -28,43 +28,23 @@ protected: public: void begin(); +#define BATTERY_SAMPLES 8 + uint16_t getBattMilliVolts() override { - #ifdef BATTERY_PIN - #ifdef PIN_3V3_EN - digitalWrite(PIN_3V3_EN, HIGH); - #endif - analogReference(AR_INTERNAL_3_0); analogReadResolution(12); - delay(10); - float volts = (analogRead(BATTERY_PIN) * ADC_MULTIPLIER * AREF_VOLTAGE) / 4096; - #ifdef PIN_3V3_EN - digitalWrite(PIN_3V3_EN, LOW); - #endif - analogReference(AR_DEFAULT); // put back to default - analogReadResolution(10); - - return volts * 1000; - #else - return 0; - #endif + uint32_t raw = 0; + for (int i = 0; i < BATTERY_SAMPLES; i++) { + raw += analogRead(PIN_VBAT_READ); + } + raw = raw / BATTERY_SAMPLES; + return (ADC_MULTIPLIER * raw); } uint8_t getStartupReason() const override { return startup_reason; } const char* getManufacturerName() const override { - return "m25ls01"; - } - - int buttonStateChanged() { - #ifdef BUTTON_PIN - uint8_t v = digitalRead(BUTTON_PIN); - if (v != btn_prev_state) { - btn_prev_state = v; - return (v == LOW) ? 1 : -1; - } - #endif - return 0; + return "Minewsemi"; } void powerOff() override { @@ -81,10 +61,6 @@ public: digitalWrite(BUZZER_EN, LOW); #endif - #ifdef PIN_3V3_EN - digitalWrite(PIN_3V3_EN, LOW); - #endif - #ifdef LED_PIN digitalWrite(LED_PIN, LOW); #endif @@ -108,5 +84,5 @@ public: NVIC_SystemReset(); } -// bool startOTAUpdate(const char* id, char reply[]) override; + bool startOTAUpdate(const char* id, char reply[]) override; }; \ No newline at end of file diff --git a/variants/minewsemi_me25ls01/platformio.ini b/variants/minewsemi_me25ls01/platformio.ini index 4775e289..302e695f 100644 --- a/variants/minewsemi_me25ls01/platformio.ini +++ b/variants/minewsemi_me25ls01/platformio.ini @@ -8,7 +8,6 @@ build_flags = ${nrf52_base.build_flags} -I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52 lib_ignore = BluetoothOTA - lvgl lib5b4 lib_deps = ${nrf52_base.lib_deps} @@ -67,7 +66,6 @@ build_flags = ${me25ls01.build_flags} ;-D PIN_BUZZER_EN=37 build_src_filter = ${me25ls01.build_src_filter} + - ;+ +<../examples/companion_radio/*.cpp> lib_deps = ${me25ls01.lib_deps} adafruit/RTClib @ ^2.1.3 @@ -92,9 +90,6 @@ build_flags = ${me25ls01.build_flags} -D MAX_NEIGHBOURS=8 -D DISPLAY_CLASS=NullDisplayDriver build_src_filter = ${me25ls01.build_src_filter} - ;+ - ;+ - ;+<../examples/companion_radio/*.cpp> +<../examples/simple_repeater> lib_deps = ${me25ls01.lib_deps} adafruit/RTClib @ ^2.1.3 @@ -121,10 +116,6 @@ build_flags = ${me25ls01.build_flags} -D MAX_NEIGHBOURS=8 -D DISPLAY_CLASS=NullDisplayDriver build_src_filter = ${me25ls01.build_src_filter} - ;+ - ;+ - ;+<../examples/companion_radio/*.cpp> - ;+<../examples/simple_repeater> +<../examples/simple_room_server> lib_deps = ${me25ls01.lib_deps} adafruit/RTClib @ ^2.1.3 @@ -149,11 +140,6 @@ build_flags = ${me25ls01.build_flags} -D MAX_NEIGHBOURS=8 -D DISPLAY_CLASS=NullDisplayDriver build_src_filter = ${me25ls01.build_src_filter} - ;+ - ;+ - ;+<../examples/companion_radio/*.cpp> - ;+<../examples/simple_repeater> - ;+<../examples/simple_room_server> +<../examples/simple_secure_chat/main.cpp> lib_deps = ${me25ls01.lib_deps} adafruit/RTClib @ ^2.1.3 @@ -173,11 +159,6 @@ build_flags = ${me25ls01.build_flags} -D DISPLAY_CLASS=NullDisplayDriver build_src_filter = ${me25ls01.build_src_filter} + - ;+ - ;+ - ;+<../examples/companion_radio/*.cpp> - ;+<../examples/simple_repeater> - ;+<../examples/simple_room_server> +<../examples/companion_radio> lib_deps = ${me25ls01.lib_deps} adafruit/RTClib @ ^2.1.3 diff --git a/variants/minewsemi_me25ls01/variant.cpp b/variants/minewsemi_me25ls01/variant.cpp index 15f30d14..5dbac9d3 100644 --- a/variants/minewsemi_me25ls01/variant.cpp +++ b/variants/minewsemi_me25ls01/variant.cpp @@ -35,7 +35,7 @@ const uint32_t g_ADigitalPinMap[PINS_COUNT + 1] = 28, // P0.28 29, // P0.29, 30, // P0.30 - 31, // P0.31, + 31, // P0.31, BATTERY_PIN 32, // P1.00 33, // P1.01, LORA_DIO_1 34, // P1.02 @@ -60,8 +60,8 @@ void initVariant() pinMode(BATTERY_PIN, INPUT); pinMode(PIN_BUTTON1, INPUT); - pinMode(PIN_3V3_EN, OUTPUT); - pinMode(PIN_3V3_ACC_EN, OUTPUT); + // pinMode(PIN_3V3_EN, OUTPUT); + // pinMode(PIN_3V3_ACC_EN, OUTPUT); pinMode(LED_PIN, OUTPUT); pinMode(P_LORA_TX_LED, OUTPUT); diff --git a/variants/minewsemi_me25ls01/variant.h b/variants/minewsemi_me25ls01/variant.h index bbf15ff6..a8bbbe3a 100644 --- a/variants/minewsemi_me25ls01/variant.h +++ b/variants/minewsemi_me25ls01/variant.h @@ -2,26 +2,19 @@ #include "WVariant.h" -//////////////////////////////////////////////////////////////////////////////// // Low frequency clock source - #define USE_LFXO // 32.768 kHz crystal oscillator #define VARIANT_MCK (64000000ul) // #define USE_LFRC // 32.768 kHz RC oscillator // Power -#define PIN_3V3_EN (32 + 5) // P1.6 Power to Sensors -#define PIN_3V3_ACC_EN -1 - -#define BATTERY_PIN (-1) // P0.2/AIN0 +#define BATTERY_PIN (31) #define BATTERY_IMMUTABLE #define ADC_MULTIPLIER (2.0F) #define ADC_RESOLUTION (14) #define BATTERY_SENSE_RES (12) -#define AREF_VOLTAGE (3.0) - // Number of pins #define PINS_COUNT (48) #define NUM_DIGITAL_PINS (48) From d32fa5c00476013f3a12183277a15aaa5d6795e9 Mon Sep 17 00:00:00 2001 From: Lloyd Date: Fri, 4 Jul 2025 21:07:55 +0100 Subject: [PATCH 31/39] Manually restart BLE advertising after disconnect to prevent stack freeze MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced use of `restartOnDisconnect(true)` with explicit (existing) manual re-advertising logic. This avoids Bluetooth stack instability caused by overlapping advertising state, Changes: - Added explicit `Bluefruit.Advertising.stop()` and data clears in `startAdv()` - Disabled automatic restart with `restartOnDisconnect(false)` - Re-advertising now fully handled in `checkRecvFrame()` loop Tested on: iPhone, Android, Windows, and Chrome – confirmed stable reconnects and name visibility. --- src/helpers/nrf52/SerialBLEInterface.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/helpers/nrf52/SerialBLEInterface.cpp b/src/helpers/nrf52/SerialBLEInterface.cpp index c6c99d5b..af5b425e 100644 --- a/src/helpers/nrf52/SerialBLEInterface.cpp +++ b/src/helpers/nrf52/SerialBLEInterface.cpp @@ -18,6 +18,10 @@ void SerialBLEInterface::begin(const char* device_name, uint32_t pin_code) { } void SerialBLEInterface::startAdv() { + Bluefruit.Advertising.stop(); // always clean restart + Bluefruit.Advertising.clearData(); // clear advertising data + Bluefruit.ScanResponse.clearData(); // clear scan response data + // Advertising packet Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); Bluefruit.Advertising.addTxPower(); @@ -27,7 +31,7 @@ void SerialBLEInterface::startAdv() { // Secondary Scan Response packet (optional) // Since there is no room for 'Name' in Advertising packet - // Bluefruit.ScanResponse.addName(); + Bluefruit.ScanResponse.addName(); /* Start Advertising * - Enable auto advertising if disconnected @@ -38,7 +42,7 @@ void SerialBLEInterface::startAdv() { * For recommended advertising interval * https://developer.apple.com/library/content/qa/qa1931/_index.html */ - Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.restartOnDisconnect(false); // don't restart automatically as already beeing done in checkRecvFrame() Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds From 013787556d8572486fa1268ff163f58ca2d4e308 Mon Sep 17 00:00:00 2001 From: Tobias Schwarz Date: Sat, 5 Jul 2025 16:08:49 +0200 Subject: [PATCH 32/39] add room server role for TBeam SX1262 --- variants/lilygo_tbeam_SX1262/platformio.ini | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/variants/lilygo_tbeam_SX1262/platformio.ini b/variants/lilygo_tbeam_SX1262/platformio.ini index 8bf2c5ab..eac899f0 100644 --- a/variants/lilygo_tbeam_SX1262/platformio.ini +++ b/variants/lilygo_tbeam_SX1262/platformio.ini @@ -69,4 +69,21 @@ build_src_filter = ${LilyGo_TBeam_SX1262.build_src_filter} +<../examples/simple_repeater> lib_deps = ${LilyGo_TBeam_SX1262.lib_deps} - ${esp32_ota.lib_deps} \ No newline at end of file + ${esp32_ota.lib_deps} + +[env:Tbeam_SX1262_room_server] +extends = LilyGo_TBeam_SX1262 +build_flags = + ${LilyGo_TBeam_SX1262.build_flags} + -D ADVERT_NAME='"Tbeam SX1262 Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${LilyGo_TBeam_SX1262.build_src_filter} + +<../examples/simple_room_server> +lib_deps = + ${LilyGo_TBeam_SX1262.lib_deps} + ${esp32_ota.lib_deps} From 7ea6a9851362546ee181123b810935cc4d26dac6 Mon Sep 17 00:00:00 2001 From: liamcottle Date: Sun, 6 Jul 2025 14:07:56 +1200 Subject: [PATCH 33/39] dont show cli data replies on display --- examples/companion_radio/MyMesh.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 879200b7..c141f9d6 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -315,17 +315,24 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe i += tlen; addToOfflineQueue(out_frame, i); + // we only want to show text messages on display, not cli data + bool should_display = txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_SIGNED_PLAIN; + if (_serial->isConnected()) { uint8_t frame[1]; frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); } else { #ifdef DISPLAY_CLASS - ui_task.soundBuzzer(UIEventType::contactMessage); + if(should_display){ + ui_task.soundBuzzer(UIEventType::contactMessage); + } #endif } #ifdef DISPLAY_CLASS - ui_task.newMsg(path_len, from.name, text, offline_queue_len); + if(should_display){ + ui_task.newMsg(path_len, from.name, text, offline_queue_len); + } #endif } From 0914056a09244b850f43595d27303e9d5ecf500f Mon Sep 17 00:00:00 2001 From: liamcottle Date: Sun, 6 Jul 2025 14:16:43 +1200 Subject: [PATCH 34/39] tidy logic for devices with display --- examples/companion_radio/MyMesh.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index c141f9d6..6ddc19d6 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -315,23 +315,20 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe i += tlen; addToOfflineQueue(out_frame, i); - // we only want to show text messages on display, not cli data - bool should_display = txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_SIGNED_PLAIN; - if (_serial->isConnected()) { uint8_t frame[1]; frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); - } else { + } + #ifdef DISPLAY_CLASS - if(should_display){ + // we only want to show text messages on display, not cli data + bool should_display = txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_SIGNED_PLAIN; + if (should_display) { + ui_task.newMsg(path_len, from.name, text, offline_queue_len); + if (!_serial->isConnected()) { ui_task.soundBuzzer(UIEventType::contactMessage); } -#endif - } -#ifdef DISPLAY_CLASS - if(should_display){ - ui_task.newMsg(path_len, from.name, text, offline_queue_len); } #endif } From e47755c8e977007cdd6bb37afeef7f3890a65916 Mon Sep 17 00:00:00 2001 From: recrof Date: Sun, 6 Jul 2025 15:22:51 +0200 Subject: [PATCH 35/39] Seeed SenseCap Solar: invert leds --- variants/sensecap_solar/SenseCapSolarBoard.cpp | 2 +- variants/sensecap_solar/SenseCapSolarBoard.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/variants/sensecap_solar/SenseCapSolarBoard.cpp b/variants/sensecap_solar/SenseCapSolarBoard.cpp index eb903f59..d6c044d1 100644 --- a/variants/sensecap_solar/SenseCapSolarBoard.cpp +++ b/variants/sensecap_solar/SenseCapSolarBoard.cpp @@ -30,7 +30,7 @@ void SenseCapSolarBoard::begin() { #ifdef P_LORA_TX_LED pinMode(P_LORA_TX_LED, OUTPUT); - digitalWrite(P_LORA_TX_LED, HIGH); + digitalWrite(P_LORA_TX_LED, LOW); #endif delay(10); // give sx1262 some time to power up diff --git a/variants/sensecap_solar/SenseCapSolarBoard.h b/variants/sensecap_solar/SenseCapSolarBoard.h index b0956644..b1e5f8f1 100644 --- a/variants/sensecap_solar/SenseCapSolarBoard.h +++ b/variants/sensecap_solar/SenseCapSolarBoard.h @@ -13,10 +13,10 @@ public: #if defined(P_LORA_TX_LED) void onBeforeTransmit() override { - digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on + digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED on } void onAfterTransmit() override { - digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off + digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off } #endif From 5ec89dff5b8fbcb0d9ca9951c8555da322e37cf5 Mon Sep 17 00:00:00 2001 From: Jelle Kalf Date: Sun, 6 Jul 2025 19:52:12 +0200 Subject: [PATCH 36/39] Xiao ESP32 C3: * Fixed pins for mainstream wio sx1262 * Moved previous sx1262 support to _custom version * companion firmware added --- variants/xiao_c3/platformio.ini | 86 +++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/variants/xiao_c3/platformio.ini b/variants/xiao_c3/platformio.ini index 55baf2b8..3643c612 100644 --- a/variants/xiao_c3/platformio.ini +++ b/variants/xiao_c3/platformio.ini @@ -1,6 +1,28 @@ [Xiao_esp32_C3] extends = esp32_base board = seeed_xiao_esp32c3 +build_flags = + ${esp32_base.build_flags} + -I variants/xiao_c3 + -D ESP32_CPU_FREQ=80 + ; -D LORA_TX_BOOST_PIN=D3 + ; -D P_LORA_TX_LED=D5 + -D PIN_VBAT_READ=D0 + -D P_LORA_DIO_1=D1 + -D P_LORA_NSS=D4 + -D P_LORA_RESET=RADIOLIB_NC + -D P_LORA_BUSY=D3 + -D PIN_BOARD_SDA=D6 + -D PIN_BOARD_SCL=D7 + -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_CURRENT_LIMIT=140 +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/xiao_c3> + +[Xiao_esp32_C3_custom] +extends = esp32_base +board = seeed_xiao_esp32c3 build_flags = ${esp32_base.build_flags} -I variants/xiao_c3 @@ -60,3 +82,67 @@ build_flags = lib_deps = ${Xiao_esp32_C3.lib_deps} ${esp32_ota.lib_deps} + +[env:Xiao_C3_sx1262_companion_radio_ble] +extends = Xiao_esp32_C3 +build_src_filter = ${Xiao_esp32_C3.build_src_filter} + +<../examples/companion_radio> + + +build_flags = + ${Xiao_esp32_C3.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D SX126X_RX_BOOSTED_GAIN=1 + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 + -D OFFLINE_QUEUE_SIZE=256 + ; -D BLE_DEBUG_LOGGING=1 + ; -D MESH_PACKET_LOGGING=1 + ; -D MESH_DEBUG=1 +lib_deps = + ${Xiao_esp32_C3.lib_deps} + ${esp32_ota.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Xiao_C3_Repeater_sx1262_custom] +extends = Xiao_esp32_C3_custom +build_src_filter = ${Xiao_esp32_C3.build_src_filter} + +<../examples/simple_repeater/main.cpp> +build_flags = + ${Xiao_esp32_C3.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D SX126X_RX_BOOSTED_GAIN=1 + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Xiao Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${Xiao_esp32_C3.lib_deps} + ${esp32_ota.lib_deps} + +[env:Xiao_C3_Repeater_sx1268_custom] +extends = Xiao_esp32_C3_custom +build_src_filter = ${Xiao_esp32_C3.build_src_filter} + +<../examples/simple_repeater/main.cpp> +build_flags = + ${Xiao_esp32_C3.build_flags} + -D RADIO_CLASS=CustomSX1268 + -D WRAPPER_CLASS=CustomSX1268Wrapper + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"Xiao Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 + ; -D MESH_PACKET_LOGGING=1 + ; -D MESH_DEBUG=1 +lib_deps = + ${Xiao_esp32_C3.lib_deps} + ${esp32_ota.lib_deps} \ No newline at end of file From 67f9204e88e3583797323384a30d846cdf8a3790 Mon Sep 17 00:00:00 2001 From: liamcottle Date: Mon, 7 Jul 2025 16:36:55 +1200 Subject: [PATCH 37/39] refactor nrf52 ble to use callbacks --- src/helpers/nrf52/SerialBLEInterface.cpp | 105 +++++++++++++---------- src/helpers/nrf52/SerialBLEInterface.h | 13 ++- 2 files changed, 64 insertions(+), 54 deletions(-) diff --git a/src/helpers/nrf52/SerialBLEInterface.cpp b/src/helpers/nrf52/SerialBLEInterface.cpp index af5b425e..a8c11d97 100644 --- a/src/helpers/nrf52/SerialBLEInterface.cpp +++ b/src/helpers/nrf52/SerialBLEInterface.cpp @@ -1,6 +1,27 @@ #include "SerialBLEInterface.h" +static SerialBLEInterface* instance; + +void SerialBLEInterface::onConnect(uint16_t connection_handle) { + BLE_DEBUG_PRINTLN("SerialBLEInterface: connected"); + if(instance){ + instance->_isDeviceConnected = true; + // no need to stop advertising on connect, as the ble stack does this automatically + } +} + +void SerialBLEInterface::onDisconnect(uint16_t connection_handle, uint8_t reason) { + BLE_DEBUG_PRINTLN("SerialBLEInterface: disconnected reason=%d", reason); + if(instance){ + instance->_isDeviceConnected = false; + instance->startAdv(); + } +} + void SerialBLEInterface::begin(const char* device_name, uint32_t pin_code) { + + instance = this; + char charpin[20]; sprintf(charpin, "%d", pin_code); @@ -13,12 +34,28 @@ void SerialBLEInterface::begin(const char* device_name, uint32_t pin_code) { Bluefruit.Security.setMITM(true); Bluefruit.Security.setPIN(charpin); + Bluefruit.Periph.setConnectCallback(onConnect); + Bluefruit.Periph.setDisconnectCallback(onDisconnect); + // To be consistent OTA DFU should be added first if it exists //bledfu.begin(); + + // Configure and start the BLE Uart service + bleuart.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); + bleuart.begin(); + } void SerialBLEInterface::startAdv() { - Bluefruit.Advertising.stop(); // always clean restart + + BLE_DEBUG_PRINTLN("SerialBLEInterface: starting advertising"); + + // clean restart if already advertising + if(Bluefruit.Advertising.isRunning()){ + BLE_DEBUG_PRINTLN("SerialBLEInterface: already advertising, stopping to allow clean restart"); + Bluefruit.Advertising.stop(); + } + Bluefruit.Advertising.clearData(); // clear advertising data Bluefruit.ScanResponse.clearData(); // clear scan response data @@ -42,10 +79,25 @@ void SerialBLEInterface::startAdv() { * For recommended advertising interval * https://developer.apple.com/library/content/qa/qa1931/_index.html */ - Bluefruit.Advertising.restartOnDisconnect(false); // don't restart automatically as already beeing done in checkRecvFrame() + Bluefruit.Advertising.restartOnDisconnect(false); // don't restart automatically as we handle it in onDisconnect Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode - Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + +} + +void SerialBLEInterface::stopAdv() { + + BLE_DEBUG_PRINTLN("SerialBLEInterface: stopping advertising"); + + // we only want to stop advertising if it's running, otherwise an invalid state error is logged by ble stack + if(!Bluefruit.Advertising.isRunning()){ + return; + } + + // stop advertising + Bluefruit.Advertising.stop(); + } // ---------- public methods @@ -56,25 +108,14 @@ void SerialBLEInterface::enable() { _isEnabled = true; clearBuffers(); - // Configure and start the BLE Uart service - bleuart.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); - bleuart.begin(); - // Start advertising startAdv(); - - checkAdvRestart = false; } void SerialBLEInterface::disable() { _isEnabled = false; - BLE_DEBUG_PRINTLN("SerialBLEInterface::disable"); - - Bluefruit.Advertising.stop(); - - oldDeviceConnected = deviceConnected = false; - checkAdvRestart = false; + stopAdv(); } size_t SerialBLEInterface::writeFrame(const uint8_t src[], size_t len) { @@ -83,7 +124,7 @@ size_t SerialBLEInterface::writeFrame(const uint8_t src[], size_t len) { return 0; } - if (deviceConnected && len > 0) { + if (_isDeviceConnected && len > 0) { if (send_queue_len >= FRAME_QUEUE_SIZE) { BLE_DEBUG_PRINTLN("writeFrame(), send_queue is full!"); return 0; @@ -119,44 +160,14 @@ size_t SerialBLEInterface::checkRecvFrame(uint8_t dest[]) { } else { int len = bleuart.available(); if (len > 0) { - deviceConnected = true; // should probably use the callback to monitor cx bleuart.readBytes(dest, len); BLE_DEBUG_PRINTLN("readBytes: sz=%d, hdr=%d", len, (uint32_t) dest[0]); return len; } } - - if (Bluefruit.connected() == 0) deviceConnected = false; - - if (deviceConnected != oldDeviceConnected) { - if (!deviceConnected) { // disconnecting - clearBuffers(); - - BLE_DEBUG_PRINTLN("SerialBLEInterface -> disconnecting..."); - delay(500); // give the bluetooth stack the chance to get things ready - - checkAdvRestart = true; - } else { - BLE_DEBUG_PRINTLN("SerialBLEInterface -> stopping advertising"); - BLE_DEBUG_PRINTLN("SerialBLEInterface -> connecting..."); - // connecting - // do stuff here on connecting - Bluefruit.Advertising.stop(); - checkAdvRestart = false; - } - oldDeviceConnected = deviceConnected; - } - - if (checkAdvRestart) { - if (Bluefruit.connected() == 0) { - BLE_DEBUG_PRINTLN("SerialBLEInterface -> re-starting advertising"); - startAdv(); - } - checkAdvRestart = false; - } return 0; } bool SerialBLEInterface::isConnected() const { - return deviceConnected; //pServer != NULL && pServer->getConnectedCount() > 0; + return _isDeviceConnected; } diff --git a/src/helpers/nrf52/SerialBLEInterface.h b/src/helpers/nrf52/SerialBLEInterface.h index d5555f56..12a4f46a 100644 --- a/src/helpers/nrf52/SerialBLEInterface.h +++ b/src/helpers/nrf52/SerialBLEInterface.h @@ -5,10 +5,8 @@ class SerialBLEInterface : public BaseSerialInterface { BLEUart bleuart; - bool deviceConnected; - bool oldDeviceConnected; - bool checkAdvRestart; bool _isEnabled; + bool _isDeviceConnected; unsigned long _last_write; struct Frame { @@ -21,18 +19,19 @@ class SerialBLEInterface : public BaseSerialInterface { Frame send_queue[FRAME_QUEUE_SIZE]; void clearBuffers() { send_queue_len = 0; } - void startAdv(); + static void onConnect(uint16_t connection_handle); + static void onDisconnect(uint16_t connection_handle, uint8_t reason); public: SerialBLEInterface() { - deviceConnected = false; - oldDeviceConnected = false; - checkAdvRestart = false; _isEnabled = false; + _isDeviceConnected = false; _last_write = 0; send_queue_len = 0; } + void startAdv(); + void stopAdv(); void begin(const char* device_name, uint32_t pin_code); // BaseSerialInterface methods From d30412bf65e603c3d5a1da01ba2253ee03919624 Mon Sep 17 00:00:00 2001 From: Florent de Lamotte Date: Mon, 7 Jul 2025 10:41:29 +0200 Subject: [PATCH 38/39] xiao_c3: small fixups --- variants/xiao_c3/platformio.ini | 51 +++++++++++++++++---------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/variants/xiao_c3/platformio.ini b/variants/xiao_c3/platformio.ini index 3643c612..b5bf1e16 100644 --- a/variants/xiao_c3/platformio.ini +++ b/variants/xiao_c3/platformio.ini @@ -5,15 +5,14 @@ build_flags = ${esp32_base.build_flags} -I variants/xiao_c3 -D ESP32_CPU_FREQ=80 - ; -D LORA_TX_BOOST_PIN=D3 - ; -D P_LORA_TX_LED=D5 -D PIN_VBAT_READ=D0 -D P_LORA_DIO_1=D1 -D P_LORA_NSS=D4 - -D P_LORA_RESET=RADIOLIB_NC + -D P_LORA_RESET=D2 -D P_LORA_BUSY=D3 -D PIN_BOARD_SDA=D6 -D PIN_BOARD_SCL=D7 + -D SX126X_RXEN=D5 -D SX126X_DIO2_AS_RF_SWITCH=true -D SX126X_DIO3_TCXO_VOLTAGE=1.8 -D SX126X_CURRENT_LIMIT=140 @@ -52,7 +51,7 @@ build_flags = -D WRAPPER_CLASS=CustomSX1262Wrapper -D SX126X_RX_BOOSTED_GAIN=1 -D LORA_TX_POWER=22 - -D ADVERT_NAME='"Xiao Repeater"' + -D ADVERT_NAME='"Xiao C3 Repeater"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 -D ADMIN_PASSWORD='"password"' @@ -63,27 +62,7 @@ lib_deps = ${Xiao_esp32_C3.lib_deps} ${esp32_ota.lib_deps} -[env:Xiao_C3_Repeater_sx1268] -extends = Xiao_esp32_C3 -build_src_filter = ${Xiao_esp32_C3.build_src_filter} - +<../examples/simple_repeater/main.cpp> -build_flags = - ${Xiao_esp32_C3.build_flags} - -D RADIO_CLASS=CustomSX1268 - -D WRAPPER_CLASS=CustomSX1268Wrapper - -D LORA_TX_POWER=22 - -D ADVERT_NAME='"Xiao Repeater"' - -D ADVERT_LAT=0.0 - -D ADVERT_LON=0.0 - -D ADMIN_PASSWORD='"password"' - -D MAX_NEIGHBOURS=8 - ; -D MESH_PACKET_LOGGING=1 - ; -D MESH_DEBUG=1 -lib_deps = - ${Xiao_esp32_C3.lib_deps} - ${esp32_ota.lib_deps} - -[env:Xiao_C3_sx1262_companion_radio_ble] +[env:Xiao_C3_companion_radio_ble] extends = Xiao_esp32_C3 build_src_filter = ${Xiao_esp32_C3.build_src_filter} +<../examples/companion_radio> @@ -106,6 +85,28 @@ lib_deps = ${esp32_ota.lib_deps} densaugeo/base64 @ ~1.4.0 +[env:Xiao_C3_companion_radio_usb] +extends = Xiao_esp32_C3 +build_src_filter = ${Xiao_esp32_C3.build_src_filter} + +<../examples/companion_radio> + + +build_flags = + ${Xiao_esp32_C3.build_flags} + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D SX126X_RX_BOOSTED_GAIN=1 + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D OFFLINE_QUEUE_SIZE=256 + ; -D BLE_DEBUG_LOGGING=1 + ; -D MESH_PACKET_LOGGING=1 + ; -D MESH_DEBUG=1 +lib_deps = + ${Xiao_esp32_C3.lib_deps} + ${esp32_ota.lib_deps} + densaugeo/base64 @ ~1.4.0 + [env:Xiao_C3_Repeater_sx1262_custom] extends = Xiao_esp32_C3_custom build_src_filter = ${Xiao_esp32_C3.build_src_filter} From 00ebb090e76f1836b38ed48b4e29041e23849b46 Mon Sep 17 00:00:00 2001 From: jankowski-t Date: Mon, 7 Jul 2025 18:33:31 +0200 Subject: [PATCH 39/39] Migrate Meshadventurer to std_init() --- variants/meshadventurer/target.cpp | 43 ++++-------------------------- 1 file changed, 5 insertions(+), 38 deletions(-) diff --git a/variants/meshadventurer/target.cpp b/variants/meshadventurer/target.cpp index 43e171c0..a1d6dcad 100644 --- a/variants/meshadventurer/target.cpp +++ b/variants/meshadventurer/target.cpp @@ -5,13 +5,8 @@ MeshadventurerBoard board; -#if defined(P_LORA_SCLK) - static SPIClass spi; - RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); -#else - RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); -#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; @@ -30,40 +25,12 @@ MASensorManager sensors = MASensorManager(nmea); bool radio_init() { fallback_clock.begin(); rtc_clock.begin(Wire); - -#ifdef SX126X_DIO3_TCXO_VOLTAGE - float tcxo = SX126X_DIO3_TCXO_VOLTAGE; -#else - float tcxo = 1.6f; -#endif #if defined(P_LORA_SCLK) - spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); + return radio.std_init(&spi); +#else + return radio.std_init(); #endif - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); - if (status != RADIOLIB_ERR_NONE) { - Serial.print("ERROR: radio init failed: "); - Serial.println(status); - return false; // fail - } - - radio.setCRC(1); - -#if defined(SX126X_RXEN) && defined(SX126X_TXEN) - radio.setRfSwitchPins(SX126X_RXEN, SX126X_TXEN); -#endif - -#ifdef SX126X_CURRENT_LIMIT - radio.setCurrentLimit(SX126X_CURRENT_LIMIT); -#endif -#ifdef SX126X_DIO2_AS_RF_SWITCH - radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); -#endif -#ifdef SX126X_RX_BOOSTED_GAIN - radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); -#endif - - return true; // success } uint32_t radio_get_rng_seed() {