diff --git a/arch/nrf52/cpp_overrides/lfs_util.h b/arch/nrf52/cpp_overrides/lfs_util.h new file mode 100644 index 000000000..bf5a347b1 --- /dev/null +++ b/arch/nrf52/cpp_overrides/lfs_util.h @@ -0,0 +1,208 @@ +/* + * lfs utility functions + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ + +// MESHTASTIC/@geeksville note: This file is copied from the Adafruit nrf52 arduino lib. And we use a special -include in +// nrf52.ini to load it before EVERY file we do this hack because the default definitions for LFS_ASSERT are quite poor and we +// don't want to fork the adafruit lib (again) and send in a PR that they probably won't merge anyways. This file might break if +// they ever update lfs.util on their side, in which case we'll need to update this file to match their new version. The version +// this is a copy from is almost exactly +// https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/c25d93268a3b9c23e9a1ccfcaf9b208beca624ca/libraries/Adafruit_LittleFS/src/littlefs/lfs_util.h + +#ifndef LFS_UTIL_H +#define LFS_UTIL_H + +// Users can override lfs_util.h with their own configuration by defining +// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h). +// +// If LFS_CONFIG is used, none of the default utils will be emitted and must be +// provided by the config file. To start I would suggest copying lfs_util.h and +// modifying as needed. +#ifdef LFS_CONFIG +#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) +#define LFS_STRINGIZE2(x) #x +#include LFS_STRINGIZE(LFS_CONFIG) +#else + +// System includes +#include +#include +#include + +#ifndef LFS_NO_MALLOC +#include +#endif +#ifndef LFS_NO_ASSERT +#include +#endif + +#if !defined(LFS_NO_DEBUG) || !defined(LFS_NO_WARN) || !defined(LFS_NO_ERROR) +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// Macros, may be replaced by system specific wrappers. Arguments to these +// macros must not have side-effects as the macros can be removed for a smaller +// code footprint + +// Logging functions +#ifndef LFS_NO_DEBUG + +void logLegacy(const char *level, const char *fmt, ...); +#define LFS_DEBUG(fmt, ...) logLegacy("DEBUG", "lfs debug:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#else +#define LFS_DEBUG(fmt, ...) +#endif + +#ifndef LFS_NO_WARN +#define LFS_WARN(fmt, ...) logLegacy("WARN", "lfs warn:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#else +#define LFS_WARN(fmt, ...) +#endif + +#ifndef LFS_NO_ERROR +#define LFS_ERROR(fmt, ...) logLegacy("ERROR", "lfs error:%d: " fmt "\n", __LINE__, __VA_ARGS__) +#else +#define LFS_ERROR(fmt, ...) +#endif + +// Runtime assertions +#ifndef LFS_NO_ASSERT +#define LFS_ASSERT(test) assert(test) +#else +extern void lfs_assert(const char *reason); +#define LFS_ASSERT(test) \ + if (!(test)) \ + lfs_assert(#test) +#endif + +// Builtin functions, these may be replaced by more efficient +// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more +// expensive basic C implementation for debugging purposes + +// Min/max functions for unsigned 32-bit numbers +static inline uint32_t lfs_max(uint32_t a, uint32_t b) +{ + return (a > b) ? a : b; +} + +static inline uint32_t lfs_min(uint32_t a, uint32_t b) +{ + return (a < b) ? a : b; +} + +// Find the next smallest power of 2 less than or equal to a +static inline uint32_t lfs_npw2(uint32_t a) +{ +#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return 32 - __builtin_clz(a - 1); +#else + uint32_t r = 0; + uint32_t s; + a -= 1; + s = (a > 0xffff) << 4; + a >>= s; + r |= s; + s = (a > 0xff) << 3; + a >>= s; + r |= s; + s = (a > 0xf) << 2; + a >>= s; + r |= s; + s = (a > 0x3) << 1; + a >>= s; + r |= s; + return (r | (a >> 1)) + 1; +#endif +} + +// Count the number of trailing binary zeros in a +// lfs_ctz(0) may be undefined +static inline uint32_t lfs_ctz(uint32_t a) +{ +#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) + return __builtin_ctz(a); +#else + return lfs_npw2((a & -a) + 1) - 1; +#endif +} + +// Count the number of binary ones in a +static inline uint32_t lfs_popc(uint32_t a) +{ +#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return __builtin_popcount(a); +#else + a = a - ((a >> 1) & 0x55555555); + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); + return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; +#endif +} + +// Find the sequence comparison of a and b, this is the distance +// between a and b ignoring overflow +static inline int lfs_scmp(uint32_t a, uint32_t b) +{ + return (int)(unsigned)(a - b); +} + +// Convert from 32-bit little-endian to native order +static inline uint32_t lfs_fromle32(uint32_t a) +{ +#if !defined(LFS_NO_INTRINSICS) && ((defined(BYTE_ORDER) && BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return a; +#elif !defined(LFS_NO_INTRINSICS) && \ + ((defined(BYTE_ORDER) && BYTE_ORDER == ORDER_BIG_ENDIAN) || (defined(__BYTE_ORDER) && __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return __builtin_bswap32(a); +#else + return (((uint8_t *)&a)[0] << 0) | (((uint8_t *)&a)[1] << 8) | (((uint8_t *)&a)[2] << 16) | (((uint8_t *)&a)[3] << 24); +#endif +} + +// Convert to 32-bit little-endian from native order +static inline uint32_t lfs_tole32(uint32_t a) +{ + return lfs_fromle32(a); +} + +// Calculate CRC-32 with polynomial = 0x04c11db7 +void lfs_crc(uint32_t *crc, const void *buffer, size_t size); + +// Allocate memory, only used if buffers are not provided to littlefs +static inline void *lfs_malloc(size_t size) +{ +#ifndef LFS_NO_MALLOC + extern void *pvPortMalloc(size_t xWantedSize); + return pvPortMalloc(size); +#else + (void)size; + return NULL; +#endif +} + +// Deallocate memory, only used if buffers are not provided to littlefs +static inline void lfs_free(void *p) +{ +#ifndef LFS_NO_MALLOC + extern void vPortFree(void *pv); + vPortFree(p); +#else + (void)p; +#endif +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif +#endif \ No newline at end of file diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index 762c81d41..503da2aab 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -2,9 +2,13 @@ ; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files platform = platformio/nordicnrf52@^10.5.0 extends = arduino_base +platform_packages = + ; our custom Git version until they merge our PR + framework-arduinoadafruitnrf52 @ https://github.com/geeksville/Adafruit_nRF52_Arduino.git build_type = debug -build_flags = +build_flags = + -include arch/nrf52/cpp_overrides/lfs_util.h ${arduino_base.build_flags} -DSERIAL_BUFFER_SIZE=1024 -Wno-unused-variable diff --git a/arch/stm32/stm32.ini b/arch/stm32/stm32.ini index d6d14e2c9..050dbf7f0 100644 --- a/arch/stm32/stm32.ini +++ b/arch/stm32/stm32.ini @@ -12,6 +12,7 @@ build_flags = -flto -Isrc/platform/stm32wl -g -DMESHTASTIC_MINIMIZE_BUILD + -DMESHTASTIC_EXCLUDE_GPS -DDEBUG_MUTE ; -DVECT_TAB_OFFSET=0x08000000 -DconfigUSE_CMSIS_RTOS_V2=1 @@ -21,7 +22,7 @@ build_flags = -fdata-sections build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - - - - - - + ${arduino_base.build_src_filter} - - - - - - - - - - - - - - board_upload.offset_address = 0x08000000 upload_protocol = stlink @@ -33,4 +34,4 @@ lib_deps = lib_ignore = https://github.com/mathertel/OneButton@~2.6.1 - Wire + Wire \ No newline at end of file diff --git a/extra_scripts/disable_adafruit_usb.py b/extra_scripts/disable_adafruit_usb.py index fb391715c..596242184 100644 --- a/extra_scripts/disable_adafruit_usb.py +++ b/extra_scripts/disable_adafruit_usb.py @@ -5,16 +5,24 @@ Import("env") # NOTE: This is not currently used, but can serve as an example on how to write extra_scripts -print("Current CLI targets", COMMAND_LINE_TARGETS) -print("Current Build targets", BUILD_TARGETS) -print("CPP defs", env.get("CPPDEFINES")) +# print("Current CLI targets", COMMAND_LINE_TARGETS) +# print("Current Build targets", BUILD_TARGETS) +# print("CPP defs", env.get("CPPDEFINES")) +# print(env.Dump()) # Adafruit.py in the platformio build tree is a bit naive and always enables their USB stack for building. We don't want this. # So come in after that python script has run and disable it. This hack avoids us having to fork that big project and send in a PR # which might not be accepted. -@geeksville -env["CPPDEFINES"].remove("USBCON") -env["CPPDEFINES"].remove("USE_TINYUSB") +lib_builders = env.get("__PIO_LIB_BUILDERS", None) +if lib_builders is not None: + print("Disabling Adafruit USB stack") + for k in lib_builders: + if k.name == "Adafruit TinyUSB Library": + libenv = k.env + # print(f"{k.name }: { libenv.Dump() } ") + # libenv["CPPDEFINES"].remove("USBCON") + libenv["CPPDEFINES"].remove("USE_TINYUSB") # Custom actions when building program/firmware # env.AddPreAction("buildprog", callback...) diff --git a/monitor/filter_c3_exception_decoder.py b/monitor/filter_c3_exception_decoder.py index e59b0be2a..6d7b5370c 100644 --- a/monitor/filter_c3_exception_decoder.py +++ b/monitor/filter_c3_exception_decoder.py @@ -18,10 +18,7 @@ import subprocess import sys from platformio.project.exception import PlatformioException -from platformio.public import ( - DeviceMonitorFilterBase, - load_build_metadata, -) +from platformio.public import DeviceMonitorFilterBase, load_build_metadata # By design, __init__ is called inside miniterm and we can't pass context to it. # pylint: disable=attribute-defined-outside-init @@ -32,7 +29,7 @@ IS_WINDOWS = sys.platform.startswith("win") class Esp32C3ExceptionDecoder(DeviceMonitorFilterBase): NAME = "esp32_c3_exception_decoder" - PCADDR_PATTERN = re.compile(r'0x4[0-9a-f]{7}', re.IGNORECASE) + PCADDR_PATTERN = re.compile(r"0x4[0-9a-f]{7}", re.IGNORECASE) def __call__(self): self.buffer = "" @@ -75,14 +72,14 @@ See https://docs.platformio.org/page/projectconf/build_configurations.html % self.__class__.__name__ ) return False - + if not os.path.isfile(self.addr2line_path): sys.stderr.write( "%s: disabling, addr2line at %s does not exist\n" % (self.__class__.__name__, self.addr2line_path) ) return False - + return True except PlatformioException as e: sys.stderr.write( @@ -117,7 +114,7 @@ See https://docs.platformio.org/page/projectconf/build_configurations.html trace = self.get_backtrace(m) if len(trace) != "": - text = text[: last] + trace + text[last :] + text = text[:last] + trace + text[last:] last += len(trace) return text @@ -125,14 +122,10 @@ See https://docs.platformio.org/page/projectconf/build_configurations.html def get_backtrace(self, match): trace = "\n" enc = "mbcs" if IS_WINDOWS else "utf-8" - args = [self.addr2line_path, u"-fipC", u"-e", self.firmware_path] + args = [self.addr2line_path, "-fipC", "-e", self.firmware_path] try: addr = match.group() - output = ( - subprocess.check_output(args + [addr]) - .decode(enc) - .strip() - ) + output = subprocess.check_output(args + [addr]).decode(enc).strip() output = output.replace( "\n", "\n " ) # newlines happen with inlined methods diff --git a/protobufs b/protobufs index 0c052b5d2..8b5b2faf6 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 0c052b5d25fe8ed74c675178702f20a3fbc29afa +Subproject commit 8b5b2faf662b364754809f923271022f4f1492ed diff --git a/src/DebugConfiguration.cpp b/src/DebugConfiguration.cpp index d9ecd9fe3..d58856c4d 100644 --- a/src/DebugConfiguration.cpp +++ b/src/DebugConfiguration.cpp @@ -26,6 +26,16 @@ SOFTWARE.*/ #include "DebugConfiguration.h" +/// A C wrapper for LOG_DEBUG that can be used from arduino C libs that don't know about C++ or meshtastic +extern "C" void logLegacy(const char *level, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + if (console) + console->vprintf(level, fmt, args); + va_end(args); +} + #if HAS_NETWORKING Syslog::Syslog(UDP &client) @@ -169,4 +179,4 @@ inline bool Syslog::_sendLog(uint16_t pri, const char *appName, const char *mess return true; } -#endif +#endif \ No newline at end of file diff --git a/src/DebugConfiguration.h b/src/DebugConfiguration.h index 6f55dfa90..55453ea1e 100644 --- a/src/DebugConfiguration.h +++ b/src/DebugConfiguration.h @@ -62,6 +62,9 @@ #endif #endif +/// A C wrapper for LOG_DEBUG that can be used from arduino C libs that don't know about C++ or meshtastic +extern "C" void logLegacy(const char *level, const char *fmt, ...); + #define SYSLOG_NILVALUE "-" #define SYSLOG_CRIT 2 /* critical conditions */ diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index 3017ec085..f45319c0b 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -48,6 +48,15 @@ void OSFS::writeNBytes(uint16_t address, unsigned int num, const byte *input) } #endif +bool lfs_assert_failed = + false; // Note: we use this global on all platforms, though it can only be set true on nrf52 (in our modified lfs_util.h) + +extern "C" void lfs_assert(const char *reason) +{ + LOG_ERROR("LFS assert: %s\n", reason); + lfs_assert_failed = true; +} + /** * @brief Copies a file from one location to another. * @@ -199,7 +208,7 @@ std::vector getFiles(const char *dirname, uint8_t levels) * @param levels The number of levels of subdirectories to list. * @param del Whether or not to delete the contents of the directory after listing. */ -void listDir(const char *dirname, uint8_t levels, bool del = false) +void listDir(const char *dirname, uint8_t levels, bool del) { #ifdef FSCom #if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)) @@ -214,7 +223,9 @@ void listDir(const char *dirname, uint8_t levels, bool del = false) } File file = root.openNextFile(); - while (file) { + while ( + file && + file.name()[0]) { // This file.name() check is a workaround for a bug in the Adafruit LittleFS nrf52 glue (see issue 4395) if (file.isDirectory() && !String(file.name()).endsWith(".")) { if (levels) { #ifdef ARCH_ESP32 @@ -313,62 +324,6 @@ void rmDir(const char *dirname) #endif } -bool fsCheck() -{ -#if defined(ARCH_NRF52) - size_t write_size = 0; - size_t read_size = 0; - char buf[32] = {0}; - - Adafruit_LittleFS_Namespace::File file(FSCom); - const char *text = "meshtastic fs test"; - size_t text_length = strlen(text); - const char *filename = "/meshtastic.txt"; - - LOG_DEBUG("Try create file .\n"); - if (file.open(filename, FILE_O_WRITE)) { - write_size = file.write(text); - } else { - LOG_DEBUG("Open file failed .\n"); - goto FORMAT_FS; - } - - if (write_size != text_length) { - LOG_DEBUG("Text bytes do not match .\n"); - file.close(); - goto FORMAT_FS; - } - - file.close(); - - if (!file.open(filename, FILE_O_READ)) { - LOG_DEBUG("Open file failed .\n"); - goto FORMAT_FS; - } - - read_size = file.readBytes(buf, text_length); - if (read_size != text_length) { - LOG_DEBUG("Text bytes do not match .\n"); - file.close(); - goto FORMAT_FS; - } - - if (memcmp(buf, text, text_length) != 0) { - LOG_DEBUG("The written bytes do not match the read bytes .\n"); - file.close(); - goto FORMAT_FS; - } - return true; -FORMAT_FS: - LOG_DEBUG("Format FS ....\n"); - FSCom.format(); - FSCom.begin(); - return false; -#else - return true; -#endif -} - void fsInit() { #ifdef FSCom @@ -378,35 +333,6 @@ void fsInit() } #if defined(ARCH_ESP32) LOG_DEBUG("Filesystem files (%d/%d Bytes):\n", FSCom.usedBytes(), FSCom.totalBytes()); -#elif defined(ARCH_NRF52) - /* - * nRF52840 has a certain chance of automatic formatting failure. - * Try to create a file after initializing the file system. If the creation fails, - * it means that the file system is not working properly. Please format it manually again. - * To check the normality of the file system, you need to disable the LFS_NO_ASSERT assertion. - * Otherwise, the assertion will be entered at the moment of reading or opening, and the FS will not be formatted. - * */ - bool ret = false; - uint8_t retry = 3; - - while (retry--) { - ret = fsCheck(); - if (ret) { - LOG_DEBUG("File system check is OK.\n"); - break; - } - delay(10); - } - - // It may not be possible to reach this step. - // Add a loop here to prevent unpredictable situations from happening. - // Can add a screen to display error status later. - if (!ret) { - while (1) { - LOG_ERROR("The file system is damaged and cannot proceed to the next step.\n"); - delay(1000); - } - } #else LOG_DEBUG("Filesystem files:\n"); #endif diff --git a/src/FSCommon.h b/src/FSCommon.h index 3d485d1b1..254245b29 100644 --- a/src/FSCommon.h +++ b/src/FSCommon.h @@ -51,9 +51,13 @@ using namespace Adafruit_LittleFS_Namespace; #endif void fsInit(); +void fsListFiles(); bool copyFile(const char *from, const char *to); bool renameFile(const char *pathFrom, const char *pathTo); std::vector getFiles(const char *dirname, uint8_t levels); -void listDir(const char *dirname, uint8_t levels, bool del); +void listDir(const char *dirname, uint8_t levels, bool del = false); void rmDir(const char *dirname); -void setupSDCard(); \ No newline at end of file +void setupSDCard(); + +extern bool lfs_assert_failed; // Note: we use this global on all platforms, though it can only be set true on nrf52 (in our + // modified lfs_util.h) diff --git a/src/SafeFile.cpp b/src/SafeFile.cpp index 161a80870..c17d422bd 100644 --- a/src/SafeFile.cpp +++ b/src/SafeFile.cpp @@ -11,6 +11,9 @@ static File openFile(const char *filename, bool fullAtomic) String filenameTmp = filename; filenameTmp += ".tmp"; + // clear any previous LFS errors + lfs_assert_failed = false; + return FSCom.open(filenameTmp.c_str(), FILE_O_WRITE); } @@ -73,6 +76,9 @@ bool SafeFile::close() /// Read our (closed) tempfile back in and compare the hash bool SafeFile::testReadback() { + bool lfs_failed = lfs_assert_failed; + lfs_assert_failed = false; + String filenameTmp = filename; filenameTmp += ".tmp"; auto f2 = FSCom.open(filenameTmp.c_str(), FILE_O_READ); @@ -93,7 +99,7 @@ bool SafeFile::testReadback() return false; } - return true; + return !lfs_failed; } #endif \ No newline at end of file diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 82370937b..7d7de8700 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -810,6 +810,13 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime) powerState = newState; LOG_INFO("GPS power state moving from %s to %s\n", getGPSPowerStateString(oldState), getGPSPowerStateString(newState)); +#ifdef HELTEC_MESH_NODE_T114 + if ((oldState == GPS_OFF || oldState == GPS_HARDSLEEP) && (newState != GPS_OFF && newState != GPS_HARDSLEEP)) { + _serial_gps->begin(serialSpeeds[speedSelect]); + } else if ((newState == GPS_OFF || newState == GPS_HARDSLEEP) && (oldState != GPS_OFF && oldState != GPS_HARDSLEEP)) { + _serial_gps->end(); + } +#endif switch (newState) { case GPS_ACTIVE: case GPS_IDLE: @@ -1220,6 +1227,14 @@ GnssModel_t GPS::probe(int serialSpeed) return GNSS_MODEL_UC6580; } + clearBuffer(); + _serial_gps->write("$PDTINFO\r\n"); + delay(750); + if (getACK("UM600", 500) == GNSS_RESPONSE_OK) { + LOG_INFO("UM600 detected, using UC6580 Module\n"); + return GNSS_MODEL_UC6580; + } + // Get version information for ATGM336H clearBuffer(); _serial_gps->write("$PCAS06,1*1A\r\n"); @@ -1822,4 +1837,4 @@ void GPS::toggleGpsMode() enable(); } } -#endif // Exclude GPS +#endif // Exclude GPS \ No newline at end of file diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index 710baca98..070038672 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -6,6 +6,7 @@ #include static RTCQuality currentQuality = RTCQualityNone; +uint32_t lastSetFromPhoneNtpOrGps = 0; RTCQuality getRTCQuality() { @@ -121,6 +122,9 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate) if (shouldSet) { currentQuality = q; lastSetMsec = now; + if (currentQuality >= RTCQualityNTP) { + lastSetFromPhoneNtpOrGps = now; + } // This delta value works on all platforms timeStartMsec = now; diff --git a/src/gps/RTC.h b/src/gps/RTC.h index d31e85433..caa48dc06 100644 --- a/src/gps/RTC.h +++ b/src/gps/RTC.h @@ -24,6 +24,8 @@ enum RTCQuality { RTCQuality getRTCQuality(); +extern uint32_t lastSetFromPhoneNtpOrGps; + /// If we haven't yet set our RTC this boot, set it from a GPS derived time bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate = false); bool perhapsSetRTC(RTCQuality q, struct tm &t); diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index ea5ab9788..3a4db6ee0 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1591,6 +1591,9 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) dispdev->displayOn(); #ifdef USE_ST7789 + pinMode(VTFT_CTRL, OUTPUT); + digitalWrite(VTFT_CTRL, LOW); + ui->init(); #ifdef ESP_PLATFORM analogWrite(VTFT_LEDA, BRIGHTNESS_DEFAULT); #else @@ -1609,10 +1612,21 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) #endif LOG_INFO("Turning off screen\n"); dispdev->displayOff(); - #ifdef USE_ST7789 - pinMode(VTFT_LEDA, OUTPUT); - digitalWrite(VTFT_LEDA, !TFT_BACKLIGHT_ON); + SPI1.end(); +#if defined(ARCH_ESP32) + pinMode(VTFT_LEDA, ANALOG); + pinMode(VTFT_CTRL, ANALOG); + pinMode(ST7789_RESET, ANALOG); + pinMode(ST7789_RS, ANALOG); + pinMode(ST7789_NSS, ANALOG); +#else + nrf_gpio_cfg_default(VTFT_LEDA); + nrf_gpio_cfg_default(VTFT_CTRL); + nrf_gpio_cfg_default(ST7789_RESET); + nrf_gpio_cfg_default(ST7789_RS); + nrf_gpio_cfg_default(ST7789_NSS); +#endif #endif #ifdef T_WATCH_S3 diff --git a/src/main.cpp b/src/main.cpp index 1c4a64843..b6af60d2c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -319,6 +319,14 @@ void setup() digitalWrite(RESET_OLED, 1); #endif +#ifdef SENSOR_POWER_CTRL_PIN + pinMode(SENSOR_POWER_CTRL_PIN, OUTPUT); + digitalWrite(SENSOR_POWER_CTRL_PIN, SENSOR_POWER_ON); +#endif + +#ifdef SENSOR_GPS_CONFLICT + bool sensor_detected = false; +#endif #ifdef PERIPHERAL_WARMUP_MS // Some peripherals may require additional time to stabilize after power is connected // e.g. I2C on Heltec Vision Master @@ -458,6 +466,9 @@ void setup() LOG_INFO("No I2C devices found\n"); } else { LOG_INFO("%i I2C devices found\n", i2cCount); +#ifdef SENSOR_GPS_CONFLICT + sensor_detected = true; +#endif } #ifdef ARCH_ESP32 @@ -703,17 +714,24 @@ void setup() #if !MESHTASTIC_EXCLUDE_GPS // If we're taking on the repeater role, ignore GPS - if (HAS_GPS) { - if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER && - config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT) { - gps = GPS::createGps(); - if (gps) { - gpsStatus->observe(&gps->newStatus); - } else { - LOG_DEBUG("Running without GPS.\n"); +#ifdef SENSOR_GPS_CONFLICT + if (sensor_detected == false) { +#endif + if (HAS_GPS) { + if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER && + config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT) { + gps = GPS::createGps(); + if (gps) { + gpsStatus->observe(&gps->newStatus); + } else { + LOG_DEBUG("Running without GPS.\n"); + } } } +#ifdef SENSOR_GPS_CONFLICT } +#endif + #endif nodeStatus->observe(&nodeDB->newStatus); diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp index 604ac9dc4..3b137d4bd 100644 --- a/src/mesh/MeshModule.cpp +++ b/src/mesh/MeshModule.cpp @@ -55,7 +55,7 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod p->decoded.request_id = idFrom; p->channel = chIndex; if (err != meshtastic_Routing_Error_NONE) - LOG_ERROR("Alloc an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id); + LOG_WARN("Alloc an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id); return p; } diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 33d8b51ef..1caaaf39b 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -57,27 +57,6 @@ meshtastic_ChannelFile channelFile; meshtastic_OEMStore oemStore; static bool hasOemStore = false; -// These are not publically exposed - copied from InternalFileSystem.cpp -// #define FLASH_NRF52_PAGE_SIZE 4096 -// #define LFS_FLASH_TOTAL_SIZE (7*FLASH_NRF52_PAGE_SIZE) -// #define LFS_BLOCK_SIZE 128 - -/// List all files in the FS and test write and readback. -/// Useful for filesystem stress testing - normally stripped from build by the linker. -void flashTest() -{ - auto filesManifest = getFiles("/", 5); - - uint32_t totalSize = 0; - for (size_t i = 0; i < filesManifest.size(); i++) { - LOG_INFO("File %s (size %d)\n", filesManifest[i].file_name, filesManifest[i].size_bytes); - totalSize += filesManifest[i].size_bytes; - } - LOG_INFO("%d files (total size %u)\n", filesManifest.size(), totalSize); - // LOG_INFO("Filesystem block size %u, total bytes %u", LFS_FLASH_TOTAL_SIZE, LFS_BLOCK_SIZE); - nodeDB->saveToDisk(); -} - bool meshtastic_DeviceState_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field) { if (ostream) { @@ -145,6 +124,12 @@ NodeDB::NodeDB() // Include our owner in the node db under our nodenum meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getNodeNum()); + if (!config.has_security) { + config.has_security = true; + config.security.serial_enabled = config.device.serial_enabled; + config.security.bluetooth_logging_enabled = config.bluetooth.device_logging_enabled; + config.security.is_managed = config.device.is_managed; + } #if !(MESHTASTIC_EXCLUDE_PKI) // Calculate Curve25519 public and private keys printBytes("Old Pubkey", config.security.public_key.bytes, 32); @@ -155,10 +140,6 @@ NodeDB::NodeDB() crypto->setDHPrivateKey(config.security.private_key.bytes); } else { #if !(MESHTASTIC_EXCLUDE_PKI_KEYGEN) - config.has_security = true; - config.security.serial_enabled = config.device.serial_enabled; - config.security.bluetooth_logging_enabled = config.bluetooth.device_logging_enabled; - config.security.is_managed = config.device.is_managed; LOG_INFO("Generating new PKI keys\n"); crypto->generateKeyPair(config.security.public_key.bytes, config.security.private_key.bytes); config.security.public_key.size = 32; @@ -573,10 +554,21 @@ void NodeDB::cleanupMeshDB() { int newPos = 0, removed = 0; for (int i = 0; i < numMeshNodes; i++) { - if (meshNodes->at(i).has_user) + if (meshNodes->at(i).has_user) { + if (meshNodes->at(i).user.public_key.size > 0) { + for (int j = 0; j < numMeshNodes; j++) { + if (meshNodes->at(i).user.public_key.bytes[j] != 0) { + break; + } + if (j == 31) { + meshNodes->at(i).user.public_key.size = 0; + } + } + } meshNodes->at(newPos++) = meshNodes->at(i); - else + } else { removed++; + } } numMeshNodes -= removed; std::fill(devicestate.node_db_lite.begin() + numMeshNodes, devicestate.node_db_lite.begin() + numMeshNodes + removed, @@ -603,8 +595,16 @@ void NodeDB::installDefaultDeviceState() // Set default owner name pickNewNodeNum(); // based on macaddr now +#ifdef CONFIG_OWNER_LONG_NAME_USERPREFS + snprintf(owner.long_name, sizeof(owner.long_name), CONFIG_OWNER_LONG_NAME_USERPREFS); +#else snprintf(owner.long_name, sizeof(owner.long_name), "Meshtastic %02x%02x", ourMacAddr[4], ourMacAddr[5]); +#endif +#ifdef CONFIG_OWNER_SHORT_NAME_USERPREFS + snprintf(owner.short_name, sizeof(owner.short_name), CONFIG_OWNER_SHORT_NAME_USERPREFS); +#else snprintf(owner.short_name, sizeof(owner.short_name), "%02x%02x", ourMacAddr[4], ourMacAddr[5]); +#endif snprintf(owner.id, sizeof(owner.id), "!%08x", getNodeNum()); // Default node ID now based on nodenum memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr)); } @@ -649,11 +649,6 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t LoadFileResult state = LoadFileResult::OTHER_FAILURE; #ifdef FSCom - if (!FSCom.exists(filename)) { - LOG_INFO("File %s not found\n", filename); - return LoadFileResult::NOT_FOUND; - } - auto f = FSCom.open(filename, FILE_O_READ); if (f) { @@ -1182,4 +1177,4 @@ void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, co LOG_ERROR("A critical failure occurred, portduino is exiting..."); exit(2); #endif -} +} \ No newline at end of file diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 262d2d6a9..968b9d251 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -283,6 +283,9 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p) if (s.want_response) out += DEBUG_PORT.mt_sprintf(" WANTRESP"); + if (p->pki_encrypted) + out += DEBUG_PORT.mt_sprintf(" PKI"); + if (s.source != 0) out += DEBUG_PORT.mt_sprintf(" source=%08x", s.source); diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index c91ce50c5..0c9180eb5 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -4,6 +4,7 @@ #include "MeshTypes.h" #include "configuration.h" #include "mesh-pb-constants.h" +#include "modules/NodeInfoModule.h" // ReliableRouter::ReliableRouter() {} @@ -109,13 +110,24 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas LOG_DEBUG("Some other module has replied to this message, no need for a 2nd ack\n"); } else if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, p->hop_start, p->hop_limit); + } else if (p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag && p->channel == 0 && + (nodeDB->getMeshNode(p->from) != nullptr || nodeDB->getMeshNode(p->from)->user.public_key.size == 0)) { + // This looks like it might be a PKI packet from an unknown node, so send PKI_UNKNOWN_PUBKEY + sendAckNak(meshtastic_Routing_Error_PKI_UNKNOWN_PUBKEY, getFrom(p), p->id, channels.getPrimaryIndex(), + p->hop_start, p->hop_limit); } else { // Send a 'NO_CHANNEL' error on the primary channel if want_ack packet destined for us cannot be decoded sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex(), p->hop_start, p->hop_limit); } } - + if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && c && + c->error_reason == meshtastic_Routing_Error_PKI_UNKNOWN_PUBKEY) { + if (owner.public_key.size == 32) { + LOG_INFO("This seems like a remote PKI decrypt failure, so send a NodeInfo"); + nodeInfoModule->sendOurNodeInfo(p->from, false, p->channel, true); + } + } // We consider an ack to be either a !routing packet with a request ID or a routing packet with !error PacketId ackId = ((c && c->error_reason == meshtastic_Routing_Error_NONE) || !c) ? p->decoded.request_id : 0; diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 945f92bb7..a96773042 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -415,6 +415,8 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p) { concurrency::LockGuard g(cryptLock); + int16_t hash; + // If the packet is not yet encrypted, do so now if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded); @@ -460,31 +462,56 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p) // printBytes("plaintext", bytes, numbytes); ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it - auto hash = channels.setActiveByIndex(chIndex); - if (hash < 0) - // No suitable channel could be found for sending - return meshtastic_Routing_Error_NO_CHANNEL; - // Now that we are encrypting the packet channel should be the hash (no longer the index) - p->channel = hash; #if !(MESHTASTIC_EXCLUDE_PKI) meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(p->to); - if (!owner.is_licensed && p->to != NODENUM_BROADCAST && node != nullptr && node->user.public_key.size > 0 && - numbytes <= MAX_RHPACKETLEN - 8 && p->decoded.portnum != meshtastic_PortNum_TRACEROUTE_APP && + if (!owner.is_licensed && config.security.private_key.size == 32 && p->to != NODENUM_BROADCAST && node != nullptr && + node->user.public_key.size > 0 && p->decoded.portnum != meshtastic_PortNum_TRACEROUTE_APP && p->decoded.portnum != meshtastic_PortNum_NODEINFO_APP && p->decoded.portnum != meshtastic_PortNum_ROUTING_APP && p->decoded.portnum != meshtastic_PortNum_POSITION_APP) { LOG_DEBUG("Using PKI!\n"); if (numbytes + 8 > MAX_RHPACKETLEN) return meshtastic_Routing_Error_TOO_LARGE; + if (p->pki_encrypted && !memfll(p->public_key.bytes, 0, 32) && + memcmp(p->public_key.bytes, node->user.public_key.bytes, 32) != 0) { + LOG_WARN("Client public key for client differs from requested! Requested 0x%02x, but stored key begins 0x%02x\n", + *p->public_key.bytes, *node->user.public_key.bytes); + return meshtastic_Routing_Error_PKI_FAILED; + } crypto->encryptCurve25519(p->to, getFrom(p), p->id, numbytes, bytes, ScratchEncrypted); numbytes += 8; memcpy(p->encrypted.bytes, ScratchEncrypted, numbytes); p->channel = 0; + p->pki_encrypted = true; } else { + if (p->pki_encrypted == true) { + // Client specifically requested PKI encryption + return meshtastic_Routing_Error_PKI_FAILED; + } + hash = channels.setActiveByIndex(chIndex); + + // Now that we are encrypting the packet channel should be the hash (no longer the index) + p->channel = hash; + if (hash < 0) { + // No suitable channel could be found for sending + return meshtastic_Routing_Error_NO_CHANNEL; + } crypto->encryptPacket(getFrom(p), p->id, numbytes, bytes); memcpy(p->encrypted.bytes, bytes, numbytes); } #else + if (p->pki_encrypted == true) { + // Client specifically requested PKI encryption + return meshtastic_Routing_Error_PKI_FAILED; + } + hash = channels.setActiveByIndex(chIndex); + + // Now that we are encrypting the packet channel should be the hash (no longer the index) + p->channel = hash; + if (hash < 0) { + // No suitable channel could be found for sending + return meshtastic_Routing_Error_NO_CHANNEL; + } crypto->encryptPacket(getFrom(p), p->id, numbytes, bytes); memcpy(p->encrypted.bytes, bytes, numbytes); #endif diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 1d677e0d5..1f0621f9a 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -180,6 +180,13 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_SENSECAP_INDICATOR = 70, /* Seeed studio T1000-E tracker card. NRF52840 w/ LR1110 radio, GPS, button, buzzer, and sensors. */ meshtastic_HardwareModel_TRACKER_T1000_E = 71, + /* RAK3172 STM32WLE5 Module (https://store.rakwireless.com/products/wisduo-lpwan-module-rak3172) */ + meshtastic_HardwareModel_RAK3172 = 72, + /* Seeed Studio Wio-E5 (either mini or Dev kit) using STM32WL chip. */ + meshtastic_HardwareModel_WIO_E5 = 73, + /* RadioMaster 900 Bandit, https://www.radiomasterrc.com/products/bandit-expresslrs-rf-module + SSD1306 OLED and No GPS */ + meshtastic_HardwareModel_RADIOMASTER_900_BANDIT = 74, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ @@ -293,7 +300,11 @@ typedef enum _meshtastic_Routing_Error { meshtastic_Routing_Error_BAD_REQUEST = 32, /* The application layer service on the remote node received your request, but considered your request not authorized (i.e you did not send the request on the required bound channel) */ - meshtastic_Routing_Error_NOT_AUTHORIZED = 33 + meshtastic_Routing_Error_NOT_AUTHORIZED = 33, + /* The client specified a PKI transport, but the node was unable to send the packet using PKI (and did not send the message at all) */ + meshtastic_Routing_Error_PKI_FAILED = 34, + /* The receiving node does not have a Public Key to decode with */ + meshtastic_Routing_Error_PKI_UNKNOWN_PUBKEY = 35 } meshtastic_Routing_Error; /* The priority of this message for sending. @@ -986,8 +997,8 @@ extern "C" { #define _meshtastic_Position_AltSource_ARRAYSIZE ((meshtastic_Position_AltSource)(meshtastic_Position_AltSource_ALT_BAROMETRIC+1)) #define _meshtastic_Routing_Error_MIN meshtastic_Routing_Error_NONE -#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_NOT_AUTHORIZED -#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_NOT_AUTHORIZED+1)) +#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_PKI_UNKNOWN_PUBKEY +#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_PKI_UNKNOWN_PUBKEY+1)) #define _meshtastic_MeshPacket_Priority_MIN meshtastic_MeshPacket_Priority_UNSET #define _meshtastic_MeshPacket_Priority_MAX meshtastic_MeshPacket_Priority_MAX diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 43899ac9c..60681916f 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -63,7 +63,13 @@ typedef enum _meshtastic_TelemetrySensorType { /* DFRobot Lark Weather station (temperature, humidity, pressure, wind speed and direction) */ meshtastic_TelemetrySensorType_DFROBOT_LARK = 24, /* NAU7802 Scale Chip or compatible */ - meshtastic_TelemetrySensorType_NAU7802 = 25 + meshtastic_TelemetrySensorType_NAU7802 = 25, + /* BMP3XX High accuracy temperature and pressure */ + meshtastic_TelemetrySensorType_BMP3XX = 26, + /* ICM-20948 9-Axis digital motion processor */ + meshtastic_TelemetrySensorType_ICM20948 = 27, + /* MAX17048 1S lipo battery sensor (voltage, state of charge, time to go) */ + meshtastic_TelemetrySensorType_MAX17048 = 28 } meshtastic_TelemetrySensorType; /* Struct definitions */ @@ -237,8 +243,8 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET -#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_NAU7802 -#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_NAU7802+1)) +#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_MAX17048 +#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_MAX17048+1)) diff --git a/src/meshUtils.cpp b/src/meshUtils.cpp index 86d237129..99fcd2a57 100644 --- a/src/meshUtils.cpp +++ b/src/meshUtils.cpp @@ -64,4 +64,13 @@ void printBytes(const char *label, const uint8_t *p, size_t numbytes) for (size_t i = 0; i < numbytes; i++) LOG_DEBUG("%02x ", p[i]); LOG_DEBUG("\n"); +} + +bool memfll(const uint8_t *mem, uint8_t find, size_t numbytes) +{ + for (int i = 0; i < numbytes; i++) { + if (mem[i] != find) + return false; + } + return true; } \ No newline at end of file diff --git a/src/meshUtils.h b/src/meshUtils.h index e2d4188d7..ce063cb6a 100644 --- a/src/meshUtils.h +++ b/src/meshUtils.h @@ -14,4 +14,7 @@ template constexpr const T &clamp(const T &v, const T &lo, const T &hi char *strnstr(const char *s, const char *find, size_t slen); #endif -void printBytes(const char *label, const uint8_t *p, size_t numbytes); \ No newline at end of file +void printBytes(const char *label, const uint8_t *p, size_t numbytes); + +// is the memory region filled with a single character? +bool memfll(const uint8_t *mem, uint8_t find, size_t numbytes); \ No newline at end of file diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 62cf9d2a1..cb047a4dc 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -32,19 +32,22 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes return false; // Let others look at this message also if they want } -void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t channel) +void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t channel, bool _shorterTimeout) { // cancel any not yet sent (now stale) position packets if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal) service->cancelSending(prevPacketId); - + shorterTimeout = _shorterTimeout; meshtastic_MeshPacket *p = allocReply(); if (p) { // Check whether we didn't ignore it p->to = dest; p->decoded.want_response = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER && config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && wantReplies; - p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; + if (_shorterTimeout) + p->priority = meshtastic_MeshPacket_Priority_DEFAULT; + else + p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; if (channel > 0) { LOG_DEBUG("sending ourNodeInfo to channel %d\n", channel); p->channel = channel; @@ -53,6 +56,7 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha prevPacketId = p->id; service->sendToMesh(p); + shorterTimeout = false; } } @@ -65,10 +69,14 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply() } uint32_t now = millis(); // If we sent our NodeInfo less than 5 min. ago, don't send it again as it may be still underway. - if (lastSentToMesh && (now - lastSentToMesh) < (5 * 60 * 1000)) { + if (!shorterTimeout && lastSentToMesh && (now - lastSentToMesh) < (5 * 60 * 1000)) { LOG_DEBUG("Skip sending NodeInfo since we just sent it less than 5 minutes ago.\n"); ignoreRequest = true; // Mark it as ignored for MeshModule return NULL; + } else if (shorterTimeout && lastSentToMesh && (now - lastSentToMesh) < (60 * 1000)) { + LOG_DEBUG("Skip sending actively requested NodeInfo since we just sent it less than 60 seconds ago.\n"); + ignoreRequest = true; // Mark it as ignored for MeshModule + return NULL; } else { ignoreRequest = false; // Don't ignore requests anymore meshtastic_User &u = owner; diff --git a/src/modules/NodeInfoModule.h b/src/modules/NodeInfoModule.h index b10cccdf1..c1fb9ccce 100644 --- a/src/modules/NodeInfoModule.h +++ b/src/modules/NodeInfoModule.h @@ -20,7 +20,8 @@ class NodeInfoModule : public ProtobufModule, private concurren /** * Send our NodeInfo into the mesh */ - void sendOurNodeInfo(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false, uint8_t channel = 0); + void sendOurNodeInfo(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false, uint8_t channel = 0, + bool _shorterTimeout = false); protected: /** Called to handle a particular incoming message @@ -38,6 +39,7 @@ class NodeInfoModule : public ProtobufModule, private concurren private: uint32_t lastSentToMesh = 0; // Last time we sent our NodeInfo to the mesh + bool shorterTimeout = false; }; extern NodeInfoModule *nodeInfoModule; diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 5da918049..1618ba3ed 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -90,7 +90,6 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes // will always be an equivalent or lesser RTCQuality (RTCQualityNTP or RTCQualityNet). force = true; #endif - // Set from phone RTC Quality to RTCQualityNTP since it should be approximately so trySetRtc(p, isLocal, force); } @@ -126,14 +125,26 @@ void PositionModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic void PositionModule::trySetRtc(meshtastic_Position p, bool isLocal, bool forceUpdate) { + if (hasQualityTimesource() && !isLocal) { + LOG_DEBUG("Ignoring time from mesh because we have a GPS, RTC, or Phone/NTP time source in the past day\n"); + return; + } struct timeval tv; uint32_t secs = p.time; tv.tv_sec = secs; tv.tv_usec = 0; + perhapsSetRTC(isLocal ? RTCQualityNTP : RTCQualityFromNet, &tv, forceUpdate); } +bool PositionModule::hasQualityTimesource() +{ + bool setFromPhoneOrNtpToday = (millis() - lastSetFromPhoneNtpOrGps) <= (SEC_PER_DAY * 1000UL); + bool hasGpsOrRtc = (gps && gps->isConnected()) || (rtc_found.address != ScanI2C::ADDRESS_NONE.address); + return hasGpsOrRtc || setFromPhoneOrNtpToday; +} + meshtastic_MeshPacket *PositionModule::allocReply() { if (precision == 0) { diff --git a/src/modules/PositionModule.h b/src/modules/PositionModule.h index a5277aff6..c4ef66501 100644 --- a/src/modules/PositionModule.h +++ b/src/modules/PositionModule.h @@ -60,6 +60,7 @@ class PositionModule : public ProtobufModule, private concu void trySetRtc(meshtastic_Position p, bool isLocal, bool forceUpdate = false); uint32_t precision; void sendLostAndFoundText(); + bool hasQualityTimesource(); const uint32_t minimumTimeThreshold = Default::getConfiguredOrDefaultMsScaled(config.position.broadcast_smart_minimum_interval_secs, 30, numOnlineNodes); diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index 19f435908..1b997500a 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -228,6 +228,9 @@ void cpuDeepSleep(uint32_t msecToWake) // FIXME change polarity in hw so we can wake on ANY_HIGH instead - that would allow us to use all three buttons (instead // of just the first) gpio_pullup_en((gpio_num_t)BUTTON_PIN); +#ifdef ESP32S3_WAKE_TYPE + esp_sleep_enable_ext1_wakeup(gpioMask, ESP32S3_WAKE_TYPE); +#else #if SOC_PM_SUPPORT_EXT_WAKEUP #ifdef CONFIG_IDF_TARGET_ESP32 // ESP_EXT1_WAKEUP_ALL_LOW has been deprecated since esp-idf v5.4 for any other target. @@ -236,6 +239,8 @@ void cpuDeepSleep(uint32_t msecToWake) esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ANY_LOW); #endif #endif + +#endif // #end ESP32S3_WAKE_TYPE #endif // We want RTC peripherals to stay on diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 81a165f2d..1405ea4f3 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -198,8 +198,13 @@ void NRF52Bluetooth::shutdown() { // Shutdown bluetooth for minimum power draw LOG_INFO("Disable NRF52 bluetooth\n"); - if (connectionHandle != 0) { - Bluefruit.disconnect(connectionHandle); + uint8_t connection_num = Bluefruit.connected(); + if (connection_num) { + for (uint8_t i = 0; i < connection_num; i++) { + LOG_INFO("NRF52 bluetooth disconnecting handle %d\n", i); + Bluefruit.disconnect(i); + } + delay(100); // wait for ondisconnect; } Bluefruit.Advertising.stop(); } diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index a7d5d8c3d..b28640e65 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -251,6 +251,12 @@ void cpuDeepSleep(uint32_t msecToWake) nrf_gpio_cfg_default(WB_I2C1_SCL); nrf_gpio_cfg_default(WB_I2C1_SDA); #endif +#endif + +#ifdef HELTEC_MESH_NODE_T114 + nrf_gpio_cfg_default(PIN_GPS_PPS); + detachInterrupt(PIN_GPS_PPS); + detachInterrupt(PIN_BUTTON1); #endif // Sleepy trackers or sensors can low power "sleep" // Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event diff --git a/src/platform/stm32wl/architecture.h b/src/platform/stm32wl/architecture.h index 1c021903a..325a192a4 100644 --- a/src/platform/stm32wl/architecture.h +++ b/src/platform/stm32wl/architecture.h @@ -9,12 +9,18 @@ #ifndef HAS_RADIO #define HAS_RADIO 1 #endif +#ifndef HAS_TELEMETRY +#define HAS_TELEMETRY 1 +#endif // // set HW_VENDOR // - -#ifndef HW_VENDOR +#ifdef _VARIANT_WIOE5_ +#define HW_VENDOR meshtastic_HardwareModel_WIO_E5 +#elif defined(_VARIANT_RAK3172_) +#define HW_VENDOR meshtastic_HardwareModel_RAK3172 +#else #define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW #endif @@ -22,4 +28,4 @@ #define SX126X_CS 1000 #define SX126X_DIO1 1001 #define SX126X_RESET 1003 -#define SX126X_BUSY 1004 +#define SX126X_BUSY 1004 \ No newline at end of file diff --git a/src/sleep.cpp b/src/sleep.cpp index b4171002a..bf50d8ffa 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -278,6 +278,13 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) digitalWrite(LORA_CS, HIGH); gpio_hold_en((gpio_num_t)LORA_CS); } + +#if defined(I2C_SDA) + Wire.end(); + pinMode(I2C_SDA, ANALOG); + pinMode(I2C_SCL, ANALOG); +#endif + #endif #ifdef HAS_PMU diff --git a/userPrefs.h b/userPrefs.h index 5812fa0c8..4e80b579f 100644 --- a/userPrefs.h +++ b/userPrefs.h @@ -19,6 +19,9 @@ // #define CHANNEL_0_NAME_USERPREFS "DEFCONnect" // #define CHANNEL_0_PRECISION_USERPREFS 13 +// #define CONFIG_OWNER_LONG_NAME_USERPREFS "My Long Name" +// #define CONFIG_OWNER_SHORT_NAME_USERPREFS "MLN" + // #define SPLASH_TITLE_USERPREFS "DEFCONtastic" // #define icon_width 34 // #define icon_height 29 diff --git a/variants/heltec_capsule_sensor_v3/variant.h b/variants/heltec_capsule_sensor_v3/variant.h index 51c3cb6ad..d77571c27 100644 --- a/variants/heltec_capsule_sensor_v3/variant.h +++ b/variants/heltec_capsule_sensor_v3/variant.h @@ -40,3 +40,13 @@ #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +#define I2C_SDA 1 +#define I2C_SCL 2 +#define HAS_SCREEN 0 +#define SENSOR_POWER_CTRL_PIN 21 +#define SENSOR_POWER_ON 1 + +#define SENSOR_GPS_CONFLICT + +#define ESP32S3_WAKE_TYPE ESP_EXT1_WAKEUP_ANY_HIGH \ No newline at end of file diff --git a/variants/heltec_mesh_node_t114/variant.h b/variants/heltec_mesh_node_t114/variant.h index 8df59e394..f7a268148 100644 --- a/variants/heltec_mesh_node_t114/variant.h +++ b/variants/heltec_mesh_node_t114/variant.h @@ -146,7 +146,7 @@ No longer populated on PCB #define GPS_L76K -#define PIN_GPS_RESET (32 + 6) // An output to reset L76K GPS. As per datasheet, low for > 100ms will reset the L76K +// #define PIN_GPS_RESET (32 + 6) // An output to reset L76K GPS. As per datasheet, low for > 100ms will reset the L76K #define GPS_RESET_MODE LOW #define PIN_GPS_EN (21) #define GPS_EN_ACTIVE HIGH diff --git a/variants/rak2560/platformio.ini b/variants/rak2560/platformio.ini index 96c1bfa92..93c7acf71 100644 --- a/variants/rak2560/platformio.ini +++ b/variants/rak2560/platformio.ini @@ -6,6 +6,7 @@ board_check = true build_flags = ${nrf52840_base.build_flags} -Ivariants/rak2560 -D RAK_4631 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. + -DMESHTASTIC_EXCLUDE_GPS=1 -DHAS_RAKPROT=1 ; Define if RAk OneWireSerial is used (disables GPS) build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak2560> + + + lib_deps = diff --git a/variants/rak2560/variant.h b/variants/rak2560/variant.h index 0c1c9aed9..8e5d90553 100644 --- a/variants/rak2560/variant.h +++ b/variants/rak2560/variant.h @@ -227,7 +227,7 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG // #define GPS_TX_PIN PIN_SERIAL2_TX // #define PIN_GPS_EN PIN_3V3_EN // Disable GPS -#define MESHTASTIC_EXCLUDE_GPS 1 +// #define MESHTASTIC_EXCLUDE_GPS 1 // Define pin to enable GPS toggle (set GPIO to LOW) via user button triple press // RAK12002 RTC Module diff --git a/variants/wio-sdk-wm1110/platformio.ini b/variants/wio-sdk-wm1110/platformio.ini index 077356553..e77455bcf 100644 --- a/variants/wio-sdk-wm1110/platformio.ini +++ b/variants/wio-sdk-wm1110/platformio.ini @@ -3,29 +3,23 @@ extends = nrf52840_base board = wio-sdk-wm1110 +extra_scripts = + bin/platformio-custom.py + extra_scripts/disable_adafruit_usb.py + # Remove adafruit USB serial from the build (it is incompatible with using the ch340 serial chip on this board) build_unflags = ${nrf52840_base:build_unflags} -DUSBCON -DUSE_TINYUSB build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. + -DCFG_TUD_CDC=0 board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-sdk-wm1110> -lib_deps = - ${nrf52840_base.lib_deps} -debug_tool = jlink -;debug_tool = stlink -;debug_speed = 4000 -; No need to reflash if the binary hasn't changed -debug_load_mode = modified -; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -upload_protocol = nrfutil -;upload_protocol = stlink -; we prefer to stop in setup() because we are an 'ardiuno' app -debug_init_break = tbreak setup -; we need to turn off BLE/soft device if we are debugging otherwise it will watchdog reset us. -debug_extra_cmds = - echo Running .gdbinit script - commands 1 - set useSoftDevice = false - end +;debug_tool = jlink +debug_tool = stlink +; No need to reflash if the binary hasn't changed + +; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) +;upload_protocol = nrfutil +;upload_protocol = stlink \ No newline at end of file