diff --git a/.github/actions/build-variant/action.yml b/.github/actions/build-variant/action.yml
index 80d2a56bb..b3303d393 100644
--- a/.github/actions/build-variant/action.yml
+++ b/.github/actions/build-variant/action.yml
@@ -51,6 +51,7 @@ runs:
file: build.tar
target: build.tar
token: ${{ inputs.github_token }}
+ version: tags/v2.5.3
- name: Unpack web ui
if: inputs.include-web-ui == 'true'
diff --git a/.github/workflows/build_raspbian.yml b/.github/workflows/build_raspbian.yml
index 1fd8fad30..e857ae635 100644
--- a/.github/workflows/build_raspbian.yml
+++ b/.github/workflows/build_raspbian.yml
@@ -13,8 +13,8 @@ jobs:
- name: Install libbluetooth
shell: bash
run: |
- apt-get update -y --fix-missing
- apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
+ sudo apt-get update -y --fix-missing
+ sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
- name: Checkout code
uses: actions/checkout@v4
diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml
index efdbd2637..37164b758 100644
--- a/.github/workflows/main_matrix.yml
+++ b/.github/workflows/main_matrix.yml
@@ -203,6 +203,7 @@ jobs:
./device-*.sh
./device-*.bat
./littlefs-*.bin
+ ./littlefswebui-*.bin
./bleota*bin
./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30
diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini
index 99e8693dc..d75f86306 100644
--- a/arch/nrf52/nrf52.ini
+++ b/arch/nrf52/nrf52.ini
@@ -16,6 +16,7 @@ build_flags =
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
-DMESHTASTIC_EXCLUDE_AUDIO=1
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
+ -DMAX_NUM_NODES=80
build_src_filter =
${arduino_base.build_src_filter} - - - - - - - - - -
diff --git a/arch/rp2xx0/rp2040.ini b/arch/rp2xx0/rp2040.ini
index 17b5df618..57e5d7bc2 100644
--- a/arch/rp2xx0/rp2040.ini
+++ b/arch/rp2xx0/rp2040.ini
@@ -1,8 +1,8 @@
; Common settings for rp2040 Processor based targets
[rp2040_base]
-platform = https://github.com/maxgerhardt/platform-raspberrypi.git#v1.2.0-gcc12
+platform = https://github.com/maxgerhardt/platform-raspberrypi.git#a606be683748c73e9a0d46baf70163478d298f0f ; For arduino-pico 4.2.0
extends = arduino_base
-platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#4.0.3
+platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#4.2.1
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
@@ -23,4 +23,4 @@ lib_deps =
${arduino_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
- rweather/Crypto
\ No newline at end of file
+ rweather/Crypto
diff --git a/arch/rp2xx0/rp2350.ini b/arch/rp2xx0/rp2350.ini
index 33bb36ad1..58c5e5554 100644
--- a/arch/rp2xx0/rp2350.ini
+++ b/arch/rp2xx0/rp2350.ini
@@ -1,8 +1,8 @@
; Common settings for rp2040 Processor based targets
[rp2350_base]
-platform = https://github.com/maxgerhardt/platform-raspberrypi.git#9e55f6db5c56b9867c69fe473f388beea4546672
+platform = https://github.com/maxgerhardt/platform-raspberrypi.git#a606be683748c73e9a0d46baf70163478d298f0f ; For arduino-pico 4.2.0
extends = arduino_base
-platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#a6ab6e1f95bc1428d667d55ea7173c0744acc03c ; 4.0.2+
+platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#4.2.1
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
diff --git a/bin/base64_to_hex.py b/bin/base64_to_hex.py
new file mode 100644
index 000000000..07c559b9e
--- /dev/null
+++ b/bin/base64_to_hex.py
@@ -0,0 +1,33 @@
+import sys
+import base64
+
+def base64_to_hex_string(b64_string):
+ try:
+ # Decode the Base64 string to raw bytes
+ decoded_bytes = base64.b64decode(b64_string)
+ except Exception as e:
+ raise ValueError(f"Invalid Base64 input: {e}")
+
+ # Check if the decoded result is exactly 32 bytes
+ if len(decoded_bytes) != 32:
+ raise ValueError("Decoded Base64 input must be exactly 32 bytes.")
+
+ # Convert each byte to its hex representation
+ hex_values = [f"0x{byte:02x}" for byte in decoded_bytes]
+
+ # Join the formatted hex values with commas
+ formatted_output = "{ " + ", ".join(hex_values) + " };"
+ return formatted_output
+
+if __name__ == "__main__":
+ # Check if a Base64 string was provided in command line arguments
+ if len(sys.argv) != 2:
+ print("Usage: python script.py ")
+ sys.exit(1)
+
+ b64_string = sys.argv[1]
+ try:
+ formatted_hex = base64_to_hex_string(b64_string)
+ print(formatted_hex)
+ except ValueError as e:
+ print(e)
diff --git a/bin/build-esp32.sh b/bin/build-esp32.sh
index adb6ab12a..f8d808ced 100755
--- a/bin/build-esp32.sh
+++ b/bin/build-esp32.sh
@@ -35,6 +35,11 @@ cp $SRCBIN $OUTDIR/$basename-update.bin
echo "Building Filesystem for ESP32 targets"
pio run --environment $1 -t buildfs
+cp .pio/build/$1/littlefs.bin $OUTDIR/littlefswebui-$VERSION.bin
+# Remove webserver files from the filesystem and rebuild
+ls -l data/static # Diagnostic list of files
+rm -rf data/static
+pio run --environment $1 -t buildfs
cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR
diff --git a/protobufs b/protobufs
index af2fea10f..52688fdcc 160000
--- a/protobufs
+++ b/protobufs
@@ -1 +1 @@
-Subproject commit af2fea10fe2eba5857fb8e27975bbcea9c10af8e
+Subproject commit 52688fdccb8a40c23101cada3736b3b22c2b229e
diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp
index 0ea1309cc..238359952 100644
--- a/src/ButtonThread.cpp
+++ b/src/ButtonThread.cpp
@@ -1,4 +1,5 @@
#include "ButtonThread.h"
+#include "../userPrefs.h"
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_GPS
#include "GPS.h"
@@ -26,12 +27,12 @@ using namespace concurrency;
ButtonThread *buttonThread; // Declared extern in header
volatile ButtonThread::ButtonEventType ButtonThread::btnEvent = ButtonThread::BUTTON_EVENT_NONE;
-#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
+#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
OneButton ButtonThread::userButton; // Get reference to static member
#endif
ButtonThread::ButtonThread() : OSThread("Button")
{
-#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
+#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
#if defined(ARCH_PORTDUINO)
if (settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC) {
@@ -39,7 +40,12 @@ ButtonThread::ButtonThread() : OSThread("Button")
LOG_DEBUG("Use GPIO%02d for button", settingsMap[user]);
}
#elif defined(BUTTON_PIN)
- int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin
+#if !defined(USERPREFS_BUTTON_PIN)
+ int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin
+#endif
+#ifdef USERPREFS_BUTTON_PIN
+ int pin = config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN; // Resolved button pin
+#endif
#if defined(HELTEC_CAPSULE_SENSOR_V3)
this->userButton = OneButton(pin, false, false);
#elif defined(BUTTON_ACTIVE_LOW)
@@ -59,7 +65,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
#endif
#endif
-#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
+#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
userButton.attachClick(userButtonPressed);
userButton.setClickMs(BUTTON_CLICK_MS);
userButton.setPressMs(BUTTON_LONGPRESS_MS);
@@ -102,7 +108,7 @@ int32_t ButtonThread::runOnce()
// If the button is pressed we suppress CPU sleep until release
canSleep = true; // Assume we should not keep the board awake
-#if defined(BUTTON_PIN)
+#if defined(BUTTON_PIN) || defined(USERPREFS_BUTTON_PIN)
userButton.tick();
canSleep &= userButton.isIdle();
#elif defined(ARCH_PORTDUINO)
@@ -130,7 +136,12 @@ int32_t ButtonThread::runOnce()
return 50;
}
#ifdef BUTTON_PIN
+#if !defined(USERPREFS_BUTTON_PIN)
if (((config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN) !=
+#endif
+#if defined(USERPREFS_BUTTON_PIN)
+ if (((config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN) !=
+#endif
moduleConfig.canned_message.inputbroker_pin_press) ||
!(moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.rotary1_enabled) ||
!moduleConfig.canned_message.enabled) {
@@ -244,7 +255,12 @@ void ButtonThread::attachButtonInterrupts()
#elif defined(BUTTON_PIN)
// Interrupt for user button, during normal use. Improves responsiveness.
attachInterrupt(
+#if !defined(USERPREFS_BUTTON_PIN)
config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN,
+#endif
+#if defined(USERPREFS_BUTTON_PIN)
+ config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN,
+#endif
[]() {
ButtonThread::userButton.tick();
runASAP = true;
@@ -273,8 +289,13 @@ void ButtonThread::detachButtonInterrupts()
if (settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC)
detachInterrupt(settingsMap[user]);
#elif defined(BUTTON_PIN)
+#if !defined(USERPREFS_BUTTON_PIN)
detachInterrupt(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN);
#endif
+#if defined(USERPREFS_BUTTON_PIN)
+ detachInterrupt(config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN);
+#endif
+#endif
#ifdef BUTTON_PIN_ALT
detachInterrupt(BUTTON_PIN_ALT);
@@ -315,7 +336,7 @@ void ButtonThread::userButtonMultiPressed(void *callerThread)
// Non-static method, runs during callback. Grabs info while still valid
void ButtonThread::storeClickCount()
{
-#ifdef BUTTON_PIN
+#if defined(BUTTON_PIN) || defined(USERPREFS_BUTTON_PIN)
multipressClickCount = userButton.getNumberClicks();
#endif
}
diff --git a/src/ButtonThread.h b/src/ButtonThread.h
index 9cd7b3dac..a01a1718f 100644
--- a/src/ButtonThread.h
+++ b/src/ButtonThread.h
@@ -38,7 +38,7 @@ class ButtonThread : public concurrency::OSThread
void storeClickCount();
private:
-#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
+#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
static OneButton userButton; // Static - accessed from an interrupt
#endif
#ifdef BUTTON_PIN_ALT
diff --git a/src/Power.cpp b/src/Power.cpp
index d66214315..a354b74e2 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -251,7 +251,6 @@ class AnalogBatteryLevel : public HasBatteryLevel
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(HAS_PMU) && \
!MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
if (hasINA()) {
- LOG_DEBUG("Use INA on I2C addr 0x%x for device battery voltage", config.power.device_battery_ina_address);
return getINAVoltage();
}
#endif
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index bd0133740..fb7edcbfd 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -966,6 +966,16 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
display->drawXbm(x + (SCREEN_WIDTH - thumbs_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - thumbs_height) / 2 + 2 + 5, thumbs_width, thumbs_height,
thumbdown);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F60A") == 0 ||
+ strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F600") == 0 ||
+ strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F642") == 0 ||
+ strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F609") == 0 ||
+ strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F601") ==
+ 0) { // matches 5 different common smileys, so that the phone user doesn't have to remember which one is
+ // compatible
+ display->drawXbm(x + (SCREEN_WIDTH - smiley_width) / 2,
+ y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - smiley_height) / 2 + 2 + 5, smiley_width, smiley_height,
+ smiley);
} else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "❓") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - question_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - question_height) / 2 + 2 + 5, question_width, question_height,
@@ -2747,4 +2757,4 @@ int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg)
} // namespace graphics
#else
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
-#endif // HAS_SCREEN
\ No newline at end of file
+#endif // HAS_SCREEN
diff --git a/src/graphics/images.h b/src/graphics/images.h
index 2b0854a33..fb6b176fc 100644
--- a/src/graphics/images.h
+++ b/src/graphics/images.h
@@ -56,6 +56,16 @@ static unsigned char thumbdown[] PROGMEM = {
0x80, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00,
};
+#define smiley_height 30
+#define smiley_width 30
+static unsigned char smiley[] PROGMEM = {
+ 0x00, 0xfe, 0x0f, 0x00, 0x80, 0x01, 0x30, 0x00, 0x40, 0x00, 0xc0, 0x00, 0x20, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x02,
+ 0x08, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x10, 0x02, 0x0e, 0x0e, 0x10, 0x02, 0x09, 0x12, 0x10,
+ 0x01, 0x09, 0x12, 0x20, 0x01, 0x0f, 0x1e, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20,
+ 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x81, 0x00, 0x20, 0x20,
+ 0x82, 0x00, 0x20, 0x10, 0x02, 0x01, 0x10, 0x10, 0x04, 0x02, 0x08, 0x08, 0x04, 0xfc, 0x07, 0x08, 0x08, 0x00, 0x00, 0x04,
+ 0x10, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x01, 0x40, 0x00, 0xc0, 0x00, 0x80, 0x01, 0x30, 0x00, 0x00, 0xfe, 0x0f, 0x00};
+
#define question_height 25
#define question_width 25
static unsigned char question[] PROGMEM = {
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index 51469ddc0..55b8c0b4d 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -246,6 +246,31 @@ NodeDB::NodeDB()
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
config.position.gps_enabled = 0;
}
+#ifdef USERPREFS_FIXED_GPS
+ if (myNodeInfo.reboot_count == 1) { // Check if First boot ever or after Factory Reset.
+ meshtastic_Position fixedGPS = meshtastic_Position_init_default;
+#ifdef USERPREFS_FIXED_GPS_LAT
+ fixedGPS.latitude_i = (int32_t)(USERPREFS_FIXED_GPS_LAT * 1e7);
+ fixedGPS.has_latitude_i = true;
+#endif
+#ifdef USERPREFS_FIXED_GPS_LON
+ fixedGPS.longitude_i = (int32_t)(USERPREFS_FIXED_GPS_LON * 1e7);
+ fixedGPS.has_longitude_i = true;
+#endif
+#ifdef USERPREFS_FIXED_GPS_ALT
+ fixedGPS.altitude = USERPREFS_FIXED_GPS_ALT;
+ fixedGPS.has_altitude = true;
+#endif
+#if defined(USERPREFS_FIXED_GPS_LAT) && defined(USERPREFS_FIXED_GPS_LON)
+ fixedGPS.location_source = meshtastic_Position_LocSource_LOC_MANUAL;
+ config.has_position = true;
+ info->has_position = true;
+ info->position = TypeConversions::ConvertToPositionLite(fixedGPS);
+ nodeDB->setLocalPosition(fixedGPS);
+ config.position.fixed_position = true;
+#endif
+ }
+#endif
saveToDisk(saveWhat);
}
@@ -382,9 +407,30 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
config.lora.ignore_mqtt = false;
#endif
#ifdef USERPREFS_USE_ADMIN_KEY
- memcpy(config.security.admin_key[0].bytes, USERPREFS_ADMIN_KEY, 32);
- config.security.admin_key[0].size = 32;
- config.security.admin_key_count = 1;
+ // Initialize admin_key_count to zero
+ byte numAdminKeys = 0;
+
+ // Check if USERPREFS_ADMIN_KEY_0 is non-empty
+ if (sizeof(USERPREFS_ADMIN_KEY_0) > 0) {
+ memcpy(config.security.admin_key[numAdminKeys].bytes, USERPREFS_ADMIN_KEY_0, 32);
+ config.security.admin_key[numAdminKeys].size = 32;
+ numAdminKeys++;
+ }
+
+ // Check if USERPREFS_ADMIN_KEY_1 is non-empty
+ if (sizeof(USERPREFS_ADMIN_KEY_1) > 0) {
+ memcpy(config.security.admin_key[numAdminKeys].bytes, USERPREFS_ADMIN_KEY_1, 32);
+ config.security.admin_key[numAdminKeys].size = 32;
+ numAdminKeys++;
+ }
+
+ // Check if USERPREFS_ADMIN_KEY_2 is non-empty
+ if (sizeof(USERPREFS_ADMIN_KEY_2) > 0) {
+ memcpy(config.security.admin_key[config.security.admin_key_count].bytes, USERPREFS_ADMIN_KEY_2, 32);
+ config.security.admin_key[config.security.admin_key_count].size = 32;
+ numAdminKeys++;
+ }
+ config.security.admin_key_count = numAdminKeys;
#endif
if (shouldPreserveKey) {
config.security.private_key.size = 32;
@@ -438,8 +484,13 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
#else
bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
#endif
+#ifdef USERPREFS_FIXED_BLUETOOTH
+ config.bluetooth.fixed_pin = USERPREFS_FIXED_BLUETOOTH;
+ config.bluetooth.mode = meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN;
+#else
config.bluetooth.mode = hasScreen ? meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN
: meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN;
+#endif
// for backward compat, default position flags are ALT+MSL
config.position.position_flags =
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL |
@@ -793,8 +844,13 @@ void NodeDB::loadFromDisk()
0; // Mark the current device state as completely unusable, so that if we fail reading the entire file from
// disk we will still factoryReset to restore things.
+#ifdef ARCH_ESP32
+ if (FSCom.exists("/static/static"))
+ rmDir("/static/static"); // Remove bad static web files bundle from initial 2.5.13 release
+#endif
+
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
- auto state = loadProto(prefFileName, sizeof(meshtastic_DeviceState) + MAX_NUM_NODES * sizeof(meshtastic_NodeInfo),
+ auto state = loadProto(prefFileName, sizeof(meshtastic_DeviceState) + MAX_NUM_NODES_FS * sizeof(meshtastic_NodeInfo),
sizeof(meshtastic_DeviceState), &meshtastic_DeviceState_msg, &devicestate);
// See https://github.com/meshtastic/firmware/issues/4184#issuecomment-2269390786
@@ -813,6 +869,10 @@ void NodeDB::loadFromDisk()
meshNodes = &devicestate.node_db_lite;
numMeshNodes = devicestate.node_db_lite.size();
}
+ if (numMeshNodes > MAX_NUM_NODES) {
+ LOG_WARN("Node count %d exceeds MAX_NUM_NODES %d, truncating", numMeshNodes, MAX_NUM_NODES);
+ numMeshNodes = MAX_NUM_NODES;
+ }
meshNodes->resize(MAX_NUM_NODES);
state = loadProto(configFileName, meshtastic_LocalConfig_size, sizeof(meshtastic_LocalConfig), &meshtastic_LocalConfig_msg,
diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp
index f0d137e2c..53b66ff0a 100644
--- a/src/mesh/RadioInterface.cpp
+++ b/src/mesh/RadioInterface.cpp
@@ -601,8 +601,6 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
// LOG_DEBUG("Send queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)", rf95.txGood(), rf95.rxGood(), rf95.rxBad());
assert(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag); // It should have already been encoded by now
- lastTxStart = millis();
-
radioBuffer.header.from = p->from;
radioBuffer.header.to = p->to;
radioBuffer.header.id = p->id;
diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp
index a67114e12..d23f8ed62 100644
--- a/src/mesh/RadioLibInterface.cpp
+++ b/src/mesh/RadioLibInterface.cpp
@@ -278,7 +278,8 @@ void RadioLibInterface::onNotify(uint32_t notification)
startReceive(); // try receiving this packet, afterwards we'll be trying to transmit again
setTransmitDelay();
} else {
- // Send any outgoing packets we have ready
+ // Send any outgoing packets we have ready as fast as possible to keep the time between channel scan and
+ // actual transmission as short as possible
meshtastic_MeshPacket *txp = txQueue.dequeue();
assert(txp);
bool sent = startSend(txp);
@@ -470,7 +471,8 @@ void RadioLibInterface::setStandby()
/** start an immediate transmit */
bool RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
{
- printPacket("Start low level send", txp);
+ /* NOTE: Minimize the actions before startTransmit() to keep the time between
+ channel scan and actual transmit as low as possible to avoid collisions. */
if (disabled || !config.lora.tx_enabled) {
LOG_WARN("Drop Tx packet because LoRa Tx disabled");
packetPool.release(txp);
@@ -489,6 +491,9 @@ bool RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
completeSending();
powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); // Transmitter off now
startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode)
+ } else {
+ lastTxStart = millis();
+ printPacket("Started Tx", txp);
}
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register
diff --git a/src/mesh/generated/meshtastic/device_ui.pb.h b/src/mesh/generated/meshtastic/device_ui.pb.h
index 5c1e067ab..107aa8846 100644
--- a/src/mesh/generated/meshtastic/device_ui.pb.h
+++ b/src/mesh/generated/meshtastic/device_ui.pb.h
@@ -49,6 +49,8 @@ typedef enum _meshtastic_Language {
meshtastic_Language_DUTCH = 12,
/* Greek */
meshtastic_Language_GREEK = 13,
+ /* Norwegian */
+ meshtastic_Language_NORWEGIAN = 14,
/* Simplified Chinese (experimental) */
meshtastic_Language_SIMPLIFIED_CHINESE = 30,
/* Traditional Chinese (experimental) */
@@ -84,6 +86,7 @@ typedef struct _meshtastic_NodeHighlight {
char node_name[16];
} meshtastic_NodeHighlight;
+typedef PB_BYTES_ARRAY_T(16) meshtastic_DeviceUIConfig_calibration_data_t;
typedef struct _meshtastic_DeviceUIConfig {
/* A version integer used to invalidate saved files when we make incompatible changes. */
uint32_t version;
@@ -109,6 +112,8 @@ typedef struct _meshtastic_DeviceUIConfig {
/* Node list highlightening */
bool has_node_highlight;
meshtastic_NodeHighlight node_highlight;
+ /* 8 integers for screen calibration data */
+ meshtastic_DeviceUIConfig_calibration_data_t calibration_data;
} meshtastic_DeviceUIConfig;
@@ -132,10 +137,10 @@ extern "C" {
/* Initializer values for message structs */
-#define meshtastic_DeviceUIConfig_init_default {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_default, false, meshtastic_NodeHighlight_init_default}
+#define meshtastic_DeviceUIConfig_init_default {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_default, false, meshtastic_NodeHighlight_init_default, {0, {0}}}
#define meshtastic_NodeFilter_init_default {0, 0, 0, 0, 0, ""}
#define meshtastic_NodeHighlight_init_default {0, 0, 0, 0, ""}
-#define meshtastic_DeviceUIConfig_init_zero {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_zero, false, meshtastic_NodeHighlight_init_zero}
+#define meshtastic_DeviceUIConfig_init_zero {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_zero, false, meshtastic_NodeHighlight_init_zero, {0, {0}}}
#define meshtastic_NodeFilter_init_zero {0, 0, 0, 0, 0, ""}
#define meshtastic_NodeHighlight_init_zero {0, 0, 0, 0, ""}
@@ -164,6 +169,7 @@ extern "C" {
#define meshtastic_DeviceUIConfig_language_tag 11
#define meshtastic_DeviceUIConfig_node_filter_tag 12
#define meshtastic_DeviceUIConfig_node_highlight_tag 13
+#define meshtastic_DeviceUIConfig_calibration_data_tag 14
/* Struct field encoding specification for nanopb */
#define meshtastic_DeviceUIConfig_FIELDLIST(X, a) \
@@ -179,7 +185,8 @@ X(a, STATIC, SINGULAR, BOOL, banner_enabled, 9) \
X(a, STATIC, SINGULAR, UINT32, ring_tone_id, 10) \
X(a, STATIC, SINGULAR, UENUM, language, 11) \
X(a, STATIC, OPTIONAL, MESSAGE, node_filter, 12) \
-X(a, STATIC, OPTIONAL, MESSAGE, node_highlight, 13)
+X(a, STATIC, OPTIONAL, MESSAGE, node_highlight, 13) \
+X(a, STATIC, SINGULAR, BYTES, calibration_data, 14)
#define meshtastic_DeviceUIConfig_CALLBACK NULL
#define meshtastic_DeviceUIConfig_DEFAULT NULL
#define meshtastic_DeviceUIConfig_node_filter_MSGTYPE meshtastic_NodeFilter
@@ -215,7 +222,7 @@ extern const pb_msgdesc_t meshtastic_NodeHighlight_msg;
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_DEVICE_UI_PB_H_MAX_SIZE meshtastic_DeviceUIConfig_size
-#define meshtastic_DeviceUIConfig_size 99
+#define meshtastic_DeviceUIConfig_size 117
#define meshtastic_NodeFilter_size 36
#define meshtastic_NodeHighlight_size 25
diff --git a/src/mesh/mesh-pb-constants.h b/src/mesh/mesh-pb-constants.h
index f91c48560..039b36d8d 100644
--- a/src/mesh/mesh-pb-constants.h
+++ b/src/mesh/mesh-pb-constants.h
@@ -23,6 +23,8 @@
#define MAX_NUM_NODES 100
#endif
+#define MAX_NUM_NODES_FS 100
+
/// Max number of channels allowed
#define MAX_NUM_CHANNELS (member_size(meshtastic_ChannelFile, channels) / member_size(meshtastic_ChannelFile, channels[0]))
diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp
index faf5ce3de..911a47093 100644
--- a/src/mesh/wifi/WiFiAPClient.cpp
+++ b/src/mesh/wifi/WiFiAPClient.cpp
@@ -20,6 +20,8 @@
#include
#include
static void WiFiEvent(WiFiEvent_t event);
+#elif defined(ARCH_RP2040)
+#include
#endif
#ifndef DISABLE_NTP
@@ -59,19 +61,21 @@ static void onNetworkConnected()
// Start web server
LOG_INFO("Start WiFi network services");
-#ifdef ARCH_ESP32
// start mdns
if (!MDNS.begin("Meshtastic")) {
LOG_ERROR("Error setting up MDNS responder!");
} else {
- LOG_INFO("mDNS responder started");
LOG_INFO("mDNS Host: Meshtastic.local");
+#ifdef ARCH_ESP32
MDNS.addService("http", "tcp", 80);
MDNS.addService("https", "tcp", 443);
- }
-#else // ESP32 handles this in WiFiEvent
- LOG_INFO("Obtained IP address: %s", WiFi.localIP().toString().c_str());
+#elif defined(ARCH_RP2040)
+ // ARCH_RP2040 does not support HTTPS, create a "meshtastic" service
+ MDNS.addService("meshtastic", "tcp", 4403);
+ // ESP32 handles this in WiFiEvent
+ LOG_INFO("Obtained IP address: %s", WiFi.localIP().toString().c_str());
#endif
+ }
#ifndef DISABLE_NTP
LOG_INFO("Start NTP time client");
@@ -129,7 +133,7 @@ static int32_t reconnectWiFi()
// Make sure we clear old connection credentials
#ifdef ARCH_ESP32
WiFi.disconnect(false, true);
-#else
+#elif defined(ARCH_RP2040)
WiFi.disconnect(false);
#endif
LOG_INFO("Reconnecting to WiFi access point %s", wifiName);
@@ -193,7 +197,7 @@ void deinitWifi()
if (isWifiAvailable()) {
#ifdef ARCH_ESP32
WiFi.disconnect(true, false);
-#else
+#elif defined(ARCH_RP2040)
WiFi.disconnect(true);
#endif
WiFi.mode(WIFI_OFF);
@@ -229,15 +233,15 @@ bool initWifi()
if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_STATIC &&
config.network.ipv4_config.ip != 0) {
-#ifndef ARCH_RP2040
+#ifdef ARCH_ESP32
WiFi.config(config.network.ipv4_config.ip, config.network.ipv4_config.gateway, config.network.ipv4_config.subnet,
config.network.ipv4_config.dns);
-#else
+#elif defined(ARCH_RP2040)
WiFi.config(config.network.ipv4_config.ip, config.network.ipv4_config.dns, config.network.ipv4_config.gateway,
config.network.ipv4_config.subnet);
#endif
}
-#ifndef ARCH_RP2040
+#ifdef ARCH_ESP32
WiFi.onEvent(WiFiEvent);
WiFi.setAutoReconnect(true);
WiFi.setSleep(false);
diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp
index 5f1c1b284..6dca59570 100644
--- a/src/modules/AdminModule.cpp
+++ b/src/modules/AdminModule.cpp
@@ -526,6 +526,11 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
requiresReboot = false;
}
config.power = c.payload_variant.power;
+ if (c.payload_variant.power.on_battery_shutdown_after_secs > 0 &&
+ c.payload_variant.power.on_battery_shutdown_after_secs < 30) {
+ LOG_WARN("Tried to set on_battery_shutdown_after_secs too low, set to min 30 seconds");
+ config.power.on_battery_shutdown_after_secs = 30;
+ }
break;
case meshtastic_Config_network_tag:
LOG_INFO("Set config: WiFi");
diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp
index d88f275b9..3ec6ff690 100644
--- a/src/modules/ExternalNotificationModule.cpp
+++ b/src/modules/ExternalNotificationModule.cpp
@@ -119,12 +119,13 @@ int32_t ExternalNotificationModule::runOnce()
if (externalTurnedOn[1] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
millis()) {
- setExternalState(0, !getExternal(1));
+ setExternalState(1, !getExternal(1));
}
if (externalTurnedOn[2] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
millis()) {
- setExternalState(0, !getExternal(2));
+ LOG_DEBUG("EXTERNAL 2 %d compared to %d", externalTurnedOn[2]+moduleConfig.external_notification.output_ms, millis());
+ setExternalState(2, !getExternal(2));
}
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
red = (colorState & 4) ? brightnessValues[brightnessIndex] : 0; // Red enabled on colorState = 4,5,6,7
diff --git a/userPrefs.h b/userPrefs.h
index 58a44fef0..622a491c3 100644
--- a/userPrefs.h
+++ b/userPrefs.h
@@ -68,10 +68,39 @@ static unsigned char icon_bits[] = {
0x98, 0x3F, 0xF0, 0x23, 0x00, 0xFC, 0x0F, 0xE0, 0x7F, 0x00, 0xFC, 0x03, 0x80, 0xFF, 0x01, 0xFC, 0x00, 0x00, 0x3E, 0x00, 0x70,
0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00};
*/
+
+/*
+ * PKI Admin keys.
+ * If a Admin key is set with '{};'
+ * then it will be ignored, a PKI key must have a size of 32.
+ */
/*
#define USERPREFS_USE_ADMIN_KEY 1
-static unsigned char USERPREFS_ADMIN_KEY[] = {0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24, 0xdf, 0x13, 0xca, 0x5a, 0xa6,
- 0x0c, 0x0d, 0xec, 0x85, 0x5a, 0x4c, 0xf6, 0x1a, 0x96, 0x04, 0x1a,
- 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c};
+static unsigned char USERPREFS_ADMIN_KEY_0[] = {0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24, 0xdf, 0x13, 0xca, 0x5a, 0xa6,
+ 0x0c, 0x0d, 0xec, 0x85, 0x5a, 0x4c, 0xf6, 0x1a, 0x96, 0x04, 0x1a,
+ 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c};
+static unsigned char USERPREFS_ADMIN_KEY_1[] = {};
+static unsigned char USERPREFS_ADMIN_KEY_2[] = {};
*/
+
+/*
+ * USERPREF_FIXED_GPS_LAT and USERPREF_FIXED_GPS_LON must be set, USERPREF_FIXED_GPS_ALT is optional
+ *
+ * Fixed GPS is Eiffel Tower, Paris, France
+ */
+// #define USERPREFS_FIXED_GPS
+// #define USERPREFS_FIXED_GPS_LAT 48.85873920
+// #define USERPREFS_FIXED_GPS_LON 2.294508368
+// #define USERPREFS_FIXED_GPS_ALT 0
+
+/*
+ * Set Fixed Bluetooth paring code
+ */
+// #define USERPREFS_FIXED_BLUETOOTH 121212
+
+/*
+ * Will overwrite BUTTON_PIN if set
+ */
+// #define USERPREFS_BUTTON_PIN 36
+
#endif
\ No newline at end of file
diff --git a/variants/rak11310/platformio.ini b/variants/rak11310/platformio.ini
index c7b3504fe..923cedaa3 100644
--- a/variants/rak11310/platformio.ini
+++ b/variants/rak11310/platformio.ini
@@ -3,6 +3,7 @@ extends = rp2040_base
board = wiscore_rak11300
upload_protocol = picotool
# keep an old SDK to use less memory.
+platform = https://github.com/maxgerhardt/platform-raspberrypi.git#v1.2.0-gcc12
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.7.2
# add our variants files to the include and src paths
@@ -13,5 +14,5 @@ build_flags = ${rp2040_base.build_flags}
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
lib_deps =
${rp2040_base.lib_deps}
-debug_build_flags = ${rp2040_base.build_flags}
+debug_build_flags = ${rp2040_base.build_flags}, -g
debug_tool = cmsis-dap ; for e.g. Picotool
\ No newline at end of file
diff --git a/variants/rak_wismeshtap/platformio.ini b/variants/rak_wismeshtap/platformio.ini
index 461696d29..277fdbe24 100644
--- a/variants/rak_wismeshtap/platformio.ini
+++ b/variants/rak_wismeshtap/platformio.ini
@@ -9,7 +9,6 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/rak_wismeshtap -D RAK_4631
-DEINK_WIDTH=250
-DEINK_HEIGHT=122
-DMESHTASTIC_EXCLUDE_WIFI=1
- -DMESHTASTIC_EXCLUDE_WAYPOINT=1
-DMESHTASTIC_EXCLUDE_DETECTIONSENSOR=1
-DMESHTASTIC_EXCLUDE_STOREFORWARD=1
-DMESHTASTIC_EXCLUDE_POWER_TELEMETRY=1
diff --git a/variants/rp2040-lora/platformio.ini b/variants/rp2040-lora/platformio.ini
index 8499f6f3c..4c578fb2b 100644
--- a/variants/rp2040-lora/platformio.ini
+++ b/variants/rp2040-lora/platformio.ini
@@ -12,5 +12,5 @@ build_flags = ${rp2040_base.build_flags}
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
lib_deps =
${rp2040_base.lib_deps}
-debug_build_flags = ${rp2040_base.build_flags}
+debug_build_flags = ${rp2040_base.build_flags}, -g
debug_tool = cmsis-dap ; for e.g. Picotool
\ No newline at end of file
diff --git a/variants/rpipico/platformio.ini b/variants/rpipico/platformio.ini
index e4b9e479f..9c62ebcb5 100644
--- a/variants/rpipico/platformio.ini
+++ b/variants/rpipico/platformio.ini
@@ -12,5 +12,5 @@ build_flags = ${rp2040_base.build_flags}
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
lib_deps =
${rp2040_base.lib_deps}
-debug_build_flags = ${rp2040_base.build_flags}
+debug_build_flags = ${rp2040_base.build_flags}, -g
debug_tool = cmsis-dap ; for e.g. Picotool
\ No newline at end of file
diff --git a/variants/rpipico2/platformio.ini b/variants/rpipico2/platformio.ini
index a63414418..24714efd5 100644
--- a/variants/rpipico2/platformio.ini
+++ b/variants/rpipico2/platformio.ini
@@ -12,5 +12,5 @@ build_flags = ${rp2350_base.build_flags}
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
lib_deps =
${rp2350_base.lib_deps}
-debug_build_flags = ${rp2350_base.build_flags}
+debug_build_flags = ${rp2350_base.build_flags}, -g
debug_tool = cmsis-dap ; for e.g. Picotool
\ No newline at end of file
diff --git a/variants/rpipicow/platformio.ini b/variants/rpipicow/platformio.ini
index 2600b4b38..7a43ece3b 100644
--- a/variants/rpipicow/platformio.ini
+++ b/variants/rpipicow/platformio.ini
@@ -14,5 +14,5 @@ build_src_filter = ${rp2040_base.build_src_filter} +
lib_deps =
${rp2040_base.lib_deps}
${networking_base.lib_deps}
-debug_build_flags = ${rp2040_base.build_flags}
+debug_build_flags = ${rp2040_base.build_flags}, -g
debug_tool = cmsis-dap ; for e.g. Picotool
\ No newline at end of file
diff --git a/version.properties b/version.properties
index 91c1f4823..bed14bad5 100644
--- a/version.properties
+++ b/version.properties
@@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 5
-build = 12
+build = 14