diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 75b4bd6ea..040712e1d 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -1,6 +1,6 @@ version: 0.1 cli: - version: 1.22.7 + version: 1.22.8 plugins: sources: - id: trunk @@ -8,20 +8,20 @@ plugins: uri: https://github.com/trunk-io/plugins lint: enabled: - - trufflehog@3.83.2 + - trufflehog@3.83.6 - yamllint@1.35.1 - bandit@1.7.10 - - checkov@3.2.277 + - checkov@3.2.287 - terrascan@1.19.9 - trivy@0.56.2 #- trufflehog@3.63.2-rc0 - taplo@0.9.3 - - ruff@0.7.2 + - ruff@0.7.3 - isort@5.13.2 - markdownlint@0.42.0 - oxipng@9.1.2 - svgo@3.3.2 - - actionlint@1.7.3 + - actionlint@1.7.4 - flake8@7.1.1 - hadolint@2.12.0 - shfmt@3.6.0 diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index 382975e9f..1f17bc691 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -43,6 +43,7 @@ lib_deps = ${arduino_base.lib_deps} ${networking_base.lib_deps} ${environmental_base.lib_deps} + ${radiolib_base.lib_deps} https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2 h2zero/NimBLE-Arduino@^1.4.2 https://github.com/dbSuS/libpax.git#7bcd3fcab75037505be9b122ab2b24cc5176b587 diff --git a/arch/esp32/esp32c6.ini b/arch/esp32/esp32c6.ini index 53d7f92ec..3f8b1bdbe 100644 --- a/arch/esp32/esp32c6.ini +++ b/arch/esp32/esp32c6.ini @@ -23,6 +23,7 @@ lib_deps = ${arduino_base.lib_deps} ${networking_base.lib_deps} ${environmental_base.lib_deps} + ${radiolib_base.lib_deps} lewisxhe/XPowersLib@^0.2.6 https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f rweather/Crypto@^0.4.0 diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index 99b38900b..99e8693dc 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -15,12 +15,14 @@ build_flags = -Isrc/platform/nrf52 -DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818 -DMESHTASTIC_EXCLUDE_AUDIO=1 + -DMESHTASTIC_EXCLUDE_PAXCOUNTER=1 build_src_filter = ${arduino_base.build_src_filter} - - - - - - - - - - lib_deps= ${arduino_base.lib_deps} + ${radiolib_base.lib_deps} rweather/Crypto@^0.4.0 lib_ignore = diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini index 39d1c0b8c..04fd6db09 100644 --- a/arch/portduino/portduino.ini +++ b/arch/portduino/portduino.ini @@ -23,6 +23,7 @@ build_src_filter = lib_deps = ${env.lib_deps} ${networking_base.lib_deps} + ${radiolib_base.lib_deps} rweather/Crypto@^0.4.0 https://github.com/lovyan03/LovyanGFX.git#1401c28a47646fe00538d487adcb2eb3c72de805 diff --git a/arch/rp2xx0/rp2040.ini b/arch/rp2xx0/rp2040.ini index c004a3bec..17b5df618 100644 --- a/arch/rp2xx0/rp2040.ini +++ b/arch/rp2xx0/rp2040.ini @@ -22,4 +22,5 @@ lib_ignore = lib_deps = ${arduino_base.lib_deps} ${environmental_base.lib_deps} + ${radiolib_base.lib_deps} rweather/Crypto \ No newline at end of file diff --git a/arch/rp2xx0/rp2350.ini b/arch/rp2xx0/rp2350.ini index 7ef6332e3..33bb36ad1 100644 --- a/arch/rp2xx0/rp2350.ini +++ b/arch/rp2xx0/rp2350.ini @@ -21,4 +21,5 @@ lib_ignore = lib_deps = ${arduino_base.lib_deps} ${environmental_base.lib_deps} + ${radiolib_base.lib_deps} rweather/Crypto diff --git a/arch/stm32/stm32.ini b/arch/stm32/stm32.ini index 715e8aa73..7e211496d 100644 --- a/arch/stm32/stm32.ini +++ b/arch/stm32/stm32.ini @@ -30,8 +30,9 @@ upload_protocol = stlink lib_deps = ${env.lib_deps} charlesbaynham/OSFS@^1.2.3 + jgromes/RadioLib@7.0.2 https://github.com/caveman99/Crypto.git#f61ae26a53f7a2d0ba5511625b8bf8eff3a35d5e lib_ignore = - mathertel/OneButton@~2.6.1 + mathertel/OneButton@2.6.1 Wire \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 7057d574f..f7c73c190 100644 --- a/platformio.ini +++ b/platformio.ini @@ -29,7 +29,7 @@ default_envs = tbeam ;default_envs = rak4631 ;default_envs = rak4631_eth_gw ;default_envs = rak2560 -;default_envs = rak10701 +;default_envs = rak_wismeshtap ;default_envs = wio-e5 ;default_envs = radiomaster_900_bandit_nano ;default_envs = radiomaster_900_bandit_micro @@ -88,7 +88,6 @@ build_flags = -Wno-missing-field-initializers monitor_speed = 115200 monitor_filters = direct lib_deps = - jgromes/RadioLib@7.0.2 https://github.com/meshtastic/esp8266-oled-ssd1306.git#e16cee124fe26490cb14880c679321ad8ac89c95 mathertel/OneButton@2.6.1 https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 @@ -96,6 +95,7 @@ lib_deps = https://github.com/meshtastic/ArduinoThread.git#1ae8778c85d0a2a729f989e0b1e7d7c4dc84eef0 nanopb/Nanopb@0.4.9 erriez/ErriezCRC32@1.0.1 + ; Used for the code analysis in PIO Home / Inspect check_tool = cppcheck check_skip_packages = yes @@ -121,6 +121,10 @@ lib_deps = arduino-libraries/NTPClient@3.1.0 arcao/Syslog@2.0.0 +[radiolib_base] +lib_deps = + jgromes/RadioLib@7.1.0 + ; Common libs for environmental measurements in telemetry module ; (not included in native / portduino) [environmental_base] diff --git a/protobufs b/protobufs index 04f21f5c7..af2fea10f 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 04f21f5c7238b8e02f794d9282c4786752634b3c +Subproject commit af2fea10fe2eba5857fb8e27975bbcea9c10af8e 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 ab09cd08c..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 @@ -271,7 +270,7 @@ class AnalogBatteryLevel : public HasBatteryLevel config.power.adc_multiplier_override > 0 ? config.power.adc_multiplier_override : ADC_MULTIPLIER; // Do not call analogRead() often. const uint32_t min_read_interval = 5000; - if (!Throttle::isWithinTimespanMs(last_read_time_ms, min_read_interval)) { + if (!initial_read_done || !Throttle::isWithinTimespanMs(last_read_time_ms, min_read_interval)) { last_read_time_ms = millis(); uint32_t raw = 0; @@ -614,7 +613,7 @@ void Power::shutdown() #ifdef PIN_LED3 ledOff(PIN_LED3); #endif - doDeepSleep(DELAY_FOREVER, false); + doDeepSleep(DELAY_FOREVER, false, false); #endif } diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 7aa454d34..00dd6c942 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -55,9 +55,14 @@ static void sdsEnter() { LOG_DEBUG("State: SDS"); // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw - doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false); + doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false, false); } +static void lowBattSDSEnter() +{ + LOG_DEBUG("State: Lower batt SDS"); + doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false, true); +} extern Power *power; static void shutdownEnter() @@ -247,6 +252,7 @@ static void bootEnter() State stateSHUTDOWN(shutdownEnter, NULL, NULL, "SHUTDOWN"); State stateSDS(sdsEnter, NULL, NULL, "SDS"); +State stateLowBattSDS(lowBattSDSEnter, NULL, NULL, "SDS"); State stateLS(lsEnter, lsIdle, lsExit, "LS"); State stateNB(nbEnter, NULL, NULL, "NB"); State stateDARK(darkEnter, NULL, NULL, "DARK"); @@ -291,12 +297,12 @@ void PowerFSM_setup() "Press"); // Allow button to work while in serial API // Handle critically low power battery by forcing deep sleep - powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); - powerFSM.add_transition(&stateLS, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); - powerFSM.add_transition(&stateNB, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); - powerFSM.add_transition(&stateDARK, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); - powerFSM.add_transition(&stateON, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); - powerFSM.add_transition(&stateSERIAL, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); + powerFSM.add_transition(&stateBOOT, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); + powerFSM.add_transition(&stateLS, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); + powerFSM.add_transition(&stateNB, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); + powerFSM.add_transition(&stateDARK, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); + powerFSM.add_transition(&stateON, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); + powerFSM.add_transition(&stateSERIAL, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); // Handle being told to power off powerFSM.add_transition(&stateBOOT, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown"); diff --git a/src/input/TouchScreenBase.cpp b/src/input/TouchScreenBase.cpp index 03618b338..a63203362 100644 --- a/src/input/TouchScreenBase.cpp +++ b/src/input/TouchScreenBase.cpp @@ -1,6 +1,10 @@ #include "TouchScreenBase.h" #include "main.h" +#if defined(RAK14014) && !defined(MESHTASTIC_EXCLUDE_CANNEDMESSAGES) +#include "modules/CannedMessageModule.h" +#endif + #ifndef TIME_LONG_PRESS #define TIME_LONG_PRESS 400 #endif @@ -102,12 +106,30 @@ int32_t TouchScreenBase::runOnce() } _touchedOld = touched; +#if defined RAK14014 + // Speed up the processing speed of the keyboard in virtual keyboard mode + auto state = cannedMessageModule->getRunState(); + if (state == CANNED_MESSAGE_RUN_STATE_FREETEXT) { + if (_tapped) { + _tapped = false; + e.touchEvent = static_cast(TOUCH_ACTION_TAP); + LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y); + } + } else { + if (_tapped && (time_t(millis()) - _start) > TIME_LONG_PRESS - 50) { + _tapped = false; + e.touchEvent = static_cast(TOUCH_ACTION_TAP); + LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y); + } + } +#else // fire TAP event when no 2nd tap occured within time if (_tapped && (time_t(millis()) - _start) > TIME_LONG_PRESS - 50) { _tapped = false; e.touchEvent = static_cast(TOUCH_ACTION_TAP); LOG_DEBUG("action TAP(%d/%d)", _last_x, _last_y); } +#endif // fire LONG_PRESS event without the need for release if (touched && (time_t(millis()) - _start) > TIME_LONG_PRESS) { diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 9d7e4d8f6..dfc2ded22 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -30,6 +30,17 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) if (Router::cancelSending(p->from, p->id)) txRelayCanceled++; } + + /* If the original transmitter is doing retransmissions (hopStart equals hopLimit) for a reliable transmission, e.g., when + the ACK got lost, we will handle the packet again to make sure it gets an ACK to its packet. */ + bool isRepeated = p->hop_start > 0 && p->hop_start == p->hop_limit; + if (isRepeated) { + LOG_DEBUG("Repeated reliable tx"); + if (!perhapsRebroadcast(p) && isToUs(p) && p->want_ack) { + sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0); + } + } + return true; } @@ -42,14 +53,8 @@ bool FloodingRouter::isRebroadcaster() config.device.rebroadcast_mode != meshtastic_Config_DeviceConfig_RebroadcastMode_NONE; } -void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) +bool FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) { - bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0); - if (isAckorReply && !isToUs(p) && !isBroadcast(p->to)) { - // do not flood direct message that is ACKed or replied to - LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast"); - Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM - } if (!isToUs(p) && (p->hop_limit > 0) && !isFromUs(p)) { if (p->id != 0) { if (isRebroadcaster()) { @@ -68,6 +73,8 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas // Note: we are careful to resend using the original senders node id // We are careful not to call our hooked version of send() - because we don't want to check this again Router::send(tosend); + + return true; } else { LOG_DEBUG("No rebroadcast: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); } @@ -75,6 +82,21 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas LOG_DEBUG("Ignore 0 id broadcast"); } } + + return false; +} + +void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) +{ + bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0); + if (isAckorReply && !isToUs(p) && !isBroadcast(p->to)) { + // do not flood direct message that is ACKed or replied to + LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast"); + Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM + } + + perhapsRebroadcast(p); + // handle the packet as normal Router::sniffReceived(p, c); -} +} \ No newline at end of file diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index 25d674e6b..1b5c78c0f 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -28,6 +28,10 @@ class FloodingRouter : public Router { private: + /** Check if we should rebroadcast this packet, and do so if needed + * @return true if rebroadcasted */ + bool perhapsRebroadcast(const meshtastic_MeshPacket *p); + public: /** * Constructor diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 632f03456..7f051ae16 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -231,6 +231,9 @@ NodeDB::NodeDB() moduleConfig.telemetry.health_update_interval = Default::getConfiguredOrMinimumValue( moduleConfig.telemetry.health_update_interval, min_default_telemetry_interval_secs); } + // Ensure that the neighbor info update interval is coerced to the minimum + moduleConfig.neighbor_info.update_interval = + Default::getConfiguredOrMinimumValue(moduleConfig.neighbor_info.update_interval, min_neighbor_info_broadcast_secs); if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate))) saveWhat |= SEGMENT_DEVICESTATE; @@ -243,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); } @@ -435,8 +463,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 | @@ -473,7 +506,7 @@ void NodeDB::initConfigIntervals() config.display.screen_on_secs = default_screen_on_secs; -#if defined(T_WATCH_S3) || defined(T_DECK) +#if defined(T_WATCH_S3) || defined(T_DECK) || defined(RAK14014) config.power.is_power_saving = true; config.display.screen_on_secs = 30; config.power.wait_bluetooth_secs = 30; @@ -791,7 +824,7 @@ void NodeDB::loadFromDisk() // disk we will still factoryReset to restore things. // 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 @@ -810,6 +843,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, @@ -1228,12 +1265,12 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) int oldestBoringIndex = -1; for (int i = 1; i < numMeshNodes; i++) { // Simply the oldest non-favorite node - if (!meshNodes->at(i).is_favorite && meshNodes->at(i).last_heard < oldest) { + if (!meshNodes->at(i).is_favorite && !meshNodes->at(i).is_ignored && meshNodes->at(i).last_heard < oldest) { oldest = meshNodes->at(i).last_heard; oldestIndex = i; } // The oldest "boring" node - if (!meshNodes->at(i).is_favorite && meshNodes->at(i).user.public_key.size == 0 && + if (!meshNodes->at(i).is_favorite && !meshNodes->at(i).is_ignored && meshNodes->at(i).user.public_key.size == 0 && meshNodes->at(i).last_heard < oldestBoring) { oldestBoring = meshNodes->at(i).last_heard; oldestBoringIndex = i; diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 27df586d5..c663584c2 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -41,13 +41,6 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd seenRecently = false; } - /* If the original transmitter is doing retransmissions (hopStart equals hopLimit) for a reliable transmission, e.g., when the - ACK got lost, we will handle the packet again to make sure it gets an ACK/response to its packet. */ - if (seenRecently && p->hop_start > 0 && p->hop_start == p->hop_limit) { - LOG_DEBUG("Repeated reliable tx"); - seenRecently = false; - } - if (seenRecently) { // If it was seen with a next-hop not set to us and now it's NO_NEXT_HOP_PREFERENCE, and the relayer relayed already // before, it's a fallback to flooding. If we didn't already relay and the next-hop neither, consider it unseen because we diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index e01b90435..f42c0b59f 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -219,62 +219,70 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) } case STATE_SEND_METADATA: - LOG_DEBUG("Send Metadata"); + LOG_DEBUG("Send device metadata"); fromRadioScratch.which_payload_variant = meshtastic_FromRadio_metadata_tag; fromRadioScratch.metadata = getDeviceMetadata(); state = STATE_SEND_CHANNELS; break; case STATE_SEND_CHANNELS: - LOG_DEBUG("Send Channels"); fromRadioScratch.which_payload_variant = meshtastic_FromRadio_channel_tag; fromRadioScratch.channel = channels.getByIndex(config_state); config_state++; // Advance when we have sent all of our Channels if (config_state >= MAX_NUM_CHANNELS) { + LOG_DEBUG("Send channels %d", config_state); state = STATE_SEND_CONFIG; config_state = _meshtastic_AdminMessage_ConfigType_MIN + 1; } break; case STATE_SEND_CONFIG: - LOG_DEBUG("Send Radio config"); fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_tag; switch (config_state) { case meshtastic_Config_device_tag: + LOG_DEBUG("Send config: device"); fromRadioScratch.config.which_payload_variant = meshtastic_Config_device_tag; fromRadioScratch.config.payload_variant.device = config.device; break; case meshtastic_Config_position_tag: + LOG_DEBUG("Send config: position"); fromRadioScratch.config.which_payload_variant = meshtastic_Config_position_tag; fromRadioScratch.config.payload_variant.position = config.position; break; case meshtastic_Config_power_tag: + LOG_DEBUG("Send config: power"); fromRadioScratch.config.which_payload_variant = meshtastic_Config_power_tag; fromRadioScratch.config.payload_variant.power = config.power; fromRadioScratch.config.payload_variant.power.ls_secs = default_ls_secs; break; case meshtastic_Config_network_tag: + LOG_DEBUG("Send config: network"); fromRadioScratch.config.which_payload_variant = meshtastic_Config_network_tag; fromRadioScratch.config.payload_variant.network = config.network; break; case meshtastic_Config_display_tag: + LOG_DEBUG("Send config: display"); fromRadioScratch.config.which_payload_variant = meshtastic_Config_display_tag; fromRadioScratch.config.payload_variant.display = config.display; break; case meshtastic_Config_lora_tag: + LOG_DEBUG("Send config: lora"); fromRadioScratch.config.which_payload_variant = meshtastic_Config_lora_tag; fromRadioScratch.config.payload_variant.lora = config.lora; break; case meshtastic_Config_bluetooth_tag: + LOG_DEBUG("Send config: bluetooth"); fromRadioScratch.config.which_payload_variant = meshtastic_Config_bluetooth_tag; fromRadioScratch.config.payload_variant.bluetooth = config.bluetooth; break; case meshtastic_Config_security_tag: + LOG_DEBUG("Send config: security"); fromRadioScratch.config.which_payload_variant = meshtastic_Config_security_tag; fromRadioScratch.config.payload_variant.security = config.security; break; case meshtastic_Config_sessionkey_tag: + LOG_DEBUG("Send config: sessionkey"); fromRadioScratch.config.which_payload_variant = meshtastic_Config_sessionkey_tag; break; default: @@ -293,58 +301,70 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) break; case STATE_SEND_MODULECONFIG: - LOG_DEBUG("Send Module Config"); fromRadioScratch.which_payload_variant = meshtastic_FromRadio_moduleConfig_tag; switch (config_state) { case meshtastic_ModuleConfig_mqtt_tag: + LOG_DEBUG("Send module config: mqtt"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_mqtt_tag; fromRadioScratch.moduleConfig.payload_variant.mqtt = moduleConfig.mqtt; break; case meshtastic_ModuleConfig_serial_tag: + LOG_DEBUG("Send module config: serial"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_serial_tag; fromRadioScratch.moduleConfig.payload_variant.serial = moduleConfig.serial; break; case meshtastic_ModuleConfig_external_notification_tag: + LOG_DEBUG("Send module config: ext notification"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_external_notification_tag; fromRadioScratch.moduleConfig.payload_variant.external_notification = moduleConfig.external_notification; break; case meshtastic_ModuleConfig_store_forward_tag: + LOG_DEBUG("Send module config: store forward"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_store_forward_tag; fromRadioScratch.moduleConfig.payload_variant.store_forward = moduleConfig.store_forward; break; case meshtastic_ModuleConfig_range_test_tag: + LOG_DEBUG("Send module config: range test"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_range_test_tag; fromRadioScratch.moduleConfig.payload_variant.range_test = moduleConfig.range_test; break; case meshtastic_ModuleConfig_telemetry_tag: + LOG_DEBUG("Send module config: telemetry"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_telemetry_tag; fromRadioScratch.moduleConfig.payload_variant.telemetry = moduleConfig.telemetry; break; case meshtastic_ModuleConfig_canned_message_tag: + LOG_DEBUG("Send module config: canned message"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_canned_message_tag; fromRadioScratch.moduleConfig.payload_variant.canned_message = moduleConfig.canned_message; break; case meshtastic_ModuleConfig_audio_tag: + LOG_DEBUG("Send module config: audio"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_audio_tag; fromRadioScratch.moduleConfig.payload_variant.audio = moduleConfig.audio; break; case meshtastic_ModuleConfig_remote_hardware_tag: + LOG_DEBUG("Send module config: remote hardware"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_remote_hardware_tag; fromRadioScratch.moduleConfig.payload_variant.remote_hardware = moduleConfig.remote_hardware; break; case meshtastic_ModuleConfig_neighbor_info_tag: + LOG_DEBUG("Send module config: neighbor info"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_neighbor_info_tag; fromRadioScratch.moduleConfig.payload_variant.neighbor_info = moduleConfig.neighbor_info; break; case meshtastic_ModuleConfig_detection_sensor_tag: + LOG_DEBUG("Send module config: detection sensor"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag; fromRadioScratch.moduleConfig.payload_variant.detection_sensor = moduleConfig.detection_sensor; break; case meshtastic_ModuleConfig_ambient_lighting_tag: + LOG_DEBUG("Send module config: ambient lighting"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_ambient_lighting_tag; fromRadioScratch.moduleConfig.payload_variant.ambient_lighting = moduleConfig.ambient_lighting; break; case meshtastic_ModuleConfig_paxcounter_tag: + LOG_DEBUG("Send module config: paxcounter"); fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_paxcounter_tag; fromRadioScratch.moduleConfig.payload_variant.paxcounter = moduleConfig.paxcounter; break; @@ -444,7 +464,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) return numbytes; } - LOG_DEBUG("no FromRadio packet available"); + LOG_DEBUG("No FromRadio packet available"); return 0; } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 52e38ee66..cc33bd0a2 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -657,6 +657,13 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p) return; } + meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(p->from); + if (node != NULL && node->is_ignored) { + LOG_DEBUG("Ignore msg, 0x%x is ignored", p->from); + packetPool.release(p); + return; + } + if (p->from == NODENUM_BROADCAST) { LOG_DEBUG("Ignore msg from broadcast address"); packetPool.release(p); diff --git a/src/mesh/TypeConversions.cpp b/src/mesh/TypeConversions.cpp index 550f87021..5fc6b8a64 100644 --- a/src/mesh/TypeConversions.cpp +++ b/src/mesh/TypeConversions.cpp @@ -12,6 +12,7 @@ meshtastic_NodeInfo TypeConversions::ConvertToNodeInfo(const meshtastic_NodeInfo info.channel = lite->channel; info.via_mqtt = lite->via_mqtt; info.is_favorite = lite->is_favorite; + info.is_ignored = lite->is_ignored; if (lite->has_hops_away) { info.has_hops_away = true; diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index d802eb3da..bbf633ef5 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -180,6 +180,10 @@ typedef struct _meshtastic_AdminMessage { meshtastic_DeviceUIConfig get_ui_config_response; /* Tell the node to store UI data persistently. */ meshtastic_DeviceUIConfig store_ui_config; + /* Set specified node-num to be ignored on the NodeDB on the device */ + uint32_t set_ignored_node; + /* Set specified node-num to be un-ignored on the NodeDB on the device */ + uint32_t remove_ignored_node; /* Begins an edit transaction for config, module config, owner, and channel settings changes This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */ bool begin_edit_settings; @@ -279,6 +283,8 @@ extern "C" { #define meshtastic_AdminMessage_get_ui_config_request_tag 44 #define meshtastic_AdminMessage_get_ui_config_response_tag 45 #define meshtastic_AdminMessage_store_ui_config_tag 46 +#define meshtastic_AdminMessage_set_ignored_node_tag 47 +#define meshtastic_AdminMessage_remove_ignored_node_tag 48 #define meshtastic_AdminMessage_begin_edit_settings_tag 64 #define meshtastic_AdminMessage_commit_edit_settings_tag 65 #define meshtastic_AdminMessage_factory_reset_device_tag 94 @@ -329,6 +335,8 @@ X(a, STATIC, ONEOF, FIXED32, (payload_variant,set_time_only,set_time_only) X(a, STATIC, ONEOF, BOOL, (payload_variant,get_ui_config_request,get_ui_config_request), 44) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_ui_config_response,get_ui_config_response), 45) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,store_ui_config,store_ui_config), 46) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,set_ignored_node,set_ignored_node), 47) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_ignored_node,remove_ignored_node), 48) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, INT32, (payload_variant,factory_reset_device,factory_reset_device), 94) \ diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 3db39674e..dca5e5abb 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -87,8 +87,9 @@ typedef struct _meshtastic_NodeInfoLite { /* True if node is in our favorites list Persists between NodeDB internal clean ups */ bool is_favorite; - /* Last byte of the node number of the node that should be used as the next hop to reach this node. */ - uint8_t next_hop; + /* True if node is in our ignored list + Persists between NodeDB internal clean ups */ + bool is_ignored; } meshtastic_NodeInfoLite; /* This message is never sent over the wire, but it is used for serializing DB @@ -184,7 +185,7 @@ extern "C" { #define meshtastic_NodeInfoLite_via_mqtt_tag 8 #define meshtastic_NodeInfoLite_hops_away_tag 9 #define meshtastic_NodeInfoLite_is_favorite_tag 10 -#define meshtastic_NodeInfoLite_next_hop_tag 11 +#define meshtastic_NodeInfoLite_is_ignored_tag 11 #define meshtastic_DeviceState_my_node_tag 2 #define meshtastic_DeviceState_owner_tag 3 #define meshtastic_DeviceState_receive_queue_tag 5 @@ -230,7 +231,7 @@ X(a, STATIC, SINGULAR, UINT32, channel, 7) \ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ -X(a, STATIC, SINGULAR, UINT32, next_hop, 11) +X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_UserLite @@ -283,7 +284,7 @@ extern const pb_msgdesc_t meshtastic_ChannelFile_msg; /* meshtastic_DeviceState_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_ChannelFile_size #define meshtastic_ChannelFile_size 718 -#define meshtastic_NodeInfoLite_size 186 +#define meshtastic_NodeInfoLite_size 185 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 96 @@ -291,4 +292,4 @@ extern const pb_msgdesc_t meshtastic_ChannelFile_msg; } /* extern "C" */ #endif -#endif +#endif \ No newline at end of file diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 6289a0c11..da7fa0d78 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -801,6 +801,9 @@ typedef struct _meshtastic_NodeInfo { /* True if node is in our favorites list Persists between NodeDB internal clean ups */ bool is_favorite; + /* True if node is in our ignored list + Persists between NodeDB internal clean ups */ + bool is_ignored; } meshtastic_NodeInfo; typedef PB_BYTES_ARRAY_T(16) meshtastic_MyNodeInfo_device_id_t; @@ -1160,8 +1163,8 @@ extern "C" { #define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} #define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0} #define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0} -#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0} -#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0} +#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0} +#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0} #define meshtastic_MyNodeInfo_init_default {0, 0, 0, {0, {0}}, ""} #define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN} #define meshtastic_QueueStatus_init_default {0, 0, 0, 0} @@ -1185,8 +1188,8 @@ extern "C" { #define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} #define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0} #define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0} -#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0} -#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0} +#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0} +#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0} #define meshtastic_MyNodeInfo_init_zero {0, 0, 0, {0, {0}}, ""} #define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN} #define meshtastic_QueueStatus_init_zero {0, 0, 0, 0} @@ -1293,6 +1296,7 @@ extern "C" { #define meshtastic_NodeInfo_via_mqtt_tag 8 #define meshtastic_NodeInfo_hops_away_tag 9 #define meshtastic_NodeInfo_is_favorite_tag 10 +#define meshtastic_NodeInfo_is_ignored_tag 11 #define meshtastic_MyNodeInfo_my_node_num_tag 1 #define meshtastic_MyNodeInfo_reboot_count_tag 8 #define meshtastic_MyNodeInfo_min_app_version_tag 11 @@ -1493,7 +1497,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, device_metrics, 6) \ X(a, STATIC, SINGULAR, UINT32, channel, 7) \ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ -X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) +X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ +X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) #define meshtastic_NodeInfo_CALLBACK NULL #define meshtastic_NodeInfo_DEFAULT NULL #define meshtastic_NodeInfo_user_MSGTYPE meshtastic_User @@ -1732,7 +1737,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_MyNodeInfo_size 77 #define meshtastic_NeighborInfo_size 258 #define meshtastic_Neighbor_size 22 -#define meshtastic_NodeInfo_size 317 +#define meshtastic_NodeInfo_size 319 #define meshtastic_NodeRemoteHardwarePin_size 29 #define meshtastic_Position_size 144 #define meshtastic_QueueStatus_size 23 @@ -1746,4 +1751,4 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; } /* extern "C" */ #endif -#endif +#endif \ No newline at end of file diff --git a/src/mesh/mesh-pb-constants.h b/src/mesh/mesh-pb-constants.h index f91c48560..a055804d9 100644 --- a/src/mesh/mesh-pb-constants.h +++ b/src/mesh/mesh-pb-constants.h @@ -1,6 +1,7 @@ #pragma once #include +#include "architecture.h" #include "mesh/generated/meshtastic/admin.pb.h" #include "mesh/generated/meshtastic/deviceonly.pb.h" #include "mesh/generated/meshtastic/localonly.pb.h" @@ -20,8 +21,14 @@ /// max number of nodes allowed in the mesh #ifndef MAX_NUM_NODES +#ifdef ARCH_NRF52 +#define MAX_NUM_NODES 80 +#else #define MAX_NUM_NODES 100 #endif +#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/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 5401e1fdb..c81b6ede4 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -283,6 +283,28 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta } break; } + case meshtastic_AdminMessage_set_ignored_node_tag: { + LOG_INFO("Client received set_ignored_node command"); + meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->set_ignored_node); + if (node != NULL) { + node->is_ignored = true; + node->has_device_metrics = false; + node->has_position = false; + node->user.public_key.size = 0; + node->user.public_key.bytes[0] = 0; + saveChanges(SEGMENT_DEVICESTATE, false); + } + break; + } + case meshtastic_AdminMessage_remove_ignored_node_tag: { + LOG_INFO("Client received remove_ignored_node command"); + meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->remove_ignored_node); + if (node != NULL) { + node->is_ignored = false; + saveChanges(SEGMENT_DEVICESTATE, false); + } + break; + } case meshtastic_AdminMessage_set_fixed_position_tag: { LOG_INFO("Client received set_fixed_position command"); meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum()); @@ -504,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/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index bb3a314a2..37409b43b 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -325,7 +325,9 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) this->shift = !this->shift; } else if (keyTapped == "⌫") { +#ifndef RAK14014 this->highlight = keyTapped[0]; +#endif this->payload = 0x08; @@ -341,7 +343,9 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) validEvent = true; } else if (keyTapped == " ") { +#ifndef RAK14014 this->highlight = keyTapped[0]; +#endif this->payload = keyTapped[0]; @@ -361,7 +365,9 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) this->shift = false; } else if (keyTapped != "") { +#ifndef RAK14014 this->highlight = keyTapped[0]; +#endif this->payload = this->shift ? keyTapped[0] : std::tolower(keyTapped[0]); @@ -830,6 +836,11 @@ void CannedMessageModule::drawKeyboard(OLEDDisplay *display, OLEDDisplayUiState Letter updatedLetter = {letter.character, letter.width, xOffset, yOffset, cellWidth, cellHeight}; +#ifdef RAK14014 // Optimize the touch range of the virtual keyboard in the bottom row + if (outerIndex == outerSize - 1) { + updatedLetter.rectHeight = 240 - yOffset; + } +#endif this->keyboard[this->charSet][outerIndex][innerIndex] = updatedLetter; float characterOffset = ((cellWidth / 2) - (letter.width / 2)); diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h index e9dc2bda0..4427be144 100644 --- a/src/modules/CannedMessageModule.h +++ b/src/modules/CannedMessageModule.h @@ -68,6 +68,10 @@ class CannedMessageModule : public SinglePortModule, public Observabledecoded.payload.bytes[p->decoded.payload.size + 1] = '\0'; // Bell character p->decoded.payload.size++; } - LOG_INFO("Send message id=%d, dest=%x, msg=%.*s", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes); lastSentToMesh = millis(); - service->sendToMesh(p); + if (!channels.isDefaultChannel(0)) { + LOG_INFO("Send message id=%d, dest=%x, msg=%.*s", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes); + service->sendToMesh(p); + } else + LOG_ERROR("Message not allow on Public channel"); delete[] message; } @@ -140,14 +143,16 @@ void DetectionSensorModule::sendCurrentStateMessage(bool state) { char *message = new char[40]; sprintf(message, "%s state: %i", moduleConfig.detection_sensor.name, state); - meshtastic_MeshPacket *p = allocDataPacket(); p->want_ack = false; p->decoded.payload.size = strlen(message); memcpy(p->decoded.payload.bytes, message, p->decoded.payload.size); - LOG_INFO("Send message id=%d, dest=%x, msg=%.*s", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes); lastSentToMesh = millis(); - service->sendToMesh(p); + if (!channels.isDefaultChannel(0)) { + LOG_INFO("Send message id=%d, dest=%x, msg=%.*s", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes); + service->sendToMesh(p); + } else + LOG_ERROR("Message not allow on Public channel"); delete[] message; } @@ -156,4 +161,4 @@ bool DetectionSensorModule::hasDetectionEvent() bool currentState = digitalRead(moduleConfig.detection_sensor.monitor_pin); // LOG_DEBUG("Detection Sensor Module: Current state: %i", currentState); return (moduleConfig.detection_sensor.detection_trigger_type & 1) ? currentState : !currentState; -} \ No newline at end of file +} diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index f80d3eb67..fc15aabb6 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -364,7 +364,7 @@ int32_t PositionModule::runOnce() sleepOnNextExecution = false; uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(config.position.position_broadcast_secs); LOG_DEBUG("Sleep for %ims, then awaking to send position again", nightyNightMs); - doDeepSleep(nightyNightMs, false); + doDeepSleep(nightyNightMs, false, false); } meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum()); diff --git a/src/modules/PowerStressModule.cpp b/src/modules/PowerStressModule.cpp index 80b14c756..d487fe6fc 100644 --- a/src/modules/PowerStressModule.cpp +++ b/src/modules/PowerStressModule.cpp @@ -111,7 +111,7 @@ int32_t PowerStressModule::runOnce() setBluetoothEnable(true); break; case meshtastic_PowerStressMessage_Opcode_CPU_DEEPSLEEP: - doDeepSleep(sleep_msec, true); + doDeepSleep(sleep_msec, true, true); break; case meshtastic_PowerStressMessage_Opcode_CPU_FULLON: { uint32_t start_msec = millis(); diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index c18944ebd..4ef68d4b7 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -74,7 +74,7 @@ int32_t EnvironmentTelemetryModule::runOnce() uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval, default_telemetry_broadcast_interval_secs); LOG_DEBUG("Sleep for %ims, then awake to send metrics again", nightyNightMs); - doDeepSleep(nightyNightMs, true); + doDeepSleep(nightyNightMs, true, false); } uint32_t result = UINT32_MAX; diff --git a/src/modules/Telemetry/HealthTelemetry.cpp b/src/modules/Telemetry/HealthTelemetry.cpp index 7cacdc6c1..22534e9f5 100644 --- a/src/modules/Telemetry/HealthTelemetry.cpp +++ b/src/modules/Telemetry/HealthTelemetry.cpp @@ -40,7 +40,7 @@ int32_t HealthTelemetryModule::runOnce() uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.health_update_interval, default_telemetry_broadcast_interval_secs); LOG_DEBUG("Sleep for %ims, then awake to send metrics again", nightyNightMs); - doDeepSleep(nightyNightMs, true); + doDeepSleep(nightyNightMs, true, false); } uint32_t result = UINT32_MAX; diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index 409585f44..367643849 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -28,7 +28,7 @@ int32_t PowerTelemetryModule::runOnce() uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval, default_telemetry_broadcast_interval_secs); LOG_DEBUG("Sleep for %ims, then awake to send metrics again", nightyNightMs); - doDeepSleep(nightyNightMs, true); + doDeepSleep(nightyNightMs, true, false); } uint32_t result = UINT32_MAX; diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 76607f6d2..0e2710940 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -580,6 +580,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp_encrypted, const meshtastic_Me LOG_DEBUG("portnum %i message", env->packet->decoded.portnum); } else { LOG_DEBUG("nothing, pkt not decrypted"); + mqttPool.release(env); return; // Don't upload a still-encrypted PKI packet if not encryption_enabled } @@ -768,4 +769,4 @@ bool MQTT::isPrivateIpAddress(const char address[]) int octet2Num = atoi(octet2); return octet2Num >= 16 && octet2Num <= 31; -} +} \ No newline at end of file diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index ba3050e9a..1a274aa28 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -170,8 +170,6 @@ #define HW_VENDOR meshtastic_HardwareModel_HELTEC_VISION_MASTER_E213 #elif defined(HELTEC_VISION_MASTER_E290) #define HW_VENDOR meshtastic_HardwareModel_HELTEC_VISION_MASTER_E290 -#elif defined(HELTEC_MESH_NODE_T114) -#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_NODE_T114 #elif defined(SENSECAP_INDICATOR) #define HW_VENDOR meshtastic_HardwareModel_SENSECAP_INDICATOR #elif defined(SEEED_XIAO_S3) diff --git a/src/sleep.cpp b/src/sleep.cpp index a50f7aac3..05597cdfa 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -187,7 +187,7 @@ static void waitEnterSleep(bool skipPreflight = false) notifySleep.notifyObservers(NULL); } -void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) +void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false, bool skipSaveNodeDb = false) { if (INCLUDE_vTaskSuspend && (msecToWake == portMAX_DELAY)) { LOG_INFO("Enter deep sleep forever"); @@ -219,7 +219,9 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) screen->doDeepSleep(); // datasheet says this will draw only 10ua - nodeDB->saveToDisk(); + if (!skipSaveNodeDb) { + nodeDB->saveToDisk(); + } #ifdef PIN_POWER_EN pinMode(PIN_POWER_EN, INPUT); // power off peripherals diff --git a/src/sleep.h b/src/sleep.h index 6ac420769..8d3cb17e8 100644 --- a/src/sleep.h +++ b/src/sleep.h @@ -4,7 +4,7 @@ #include "Observer.h" #include "configuration.h" -void doDeepSleep(uint32_t msecToWake, bool skipPreflight), cpuDeepSleep(uint32_t msecToWake); +void doDeepSleep(uint32_t msecToWake, bool skipPreflight, bool skipSaveNodeDb), cpuDeepSleep(uint32_t msecToWake); #ifdef ARCH_ESP32 #include "esp_sleep.h" diff --git a/userPrefs.h b/userPrefs.h index 58a44fef0..c105e6b52 100644 --- a/userPrefs.h +++ b/userPrefs.h @@ -74,4 +74,25 @@ static unsigned char USERPREFS_ADMIN_KEY[] = {0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24 0x0c, 0x0d, 0xec, 0x85, 0x5a, 0x4c, 0xf6, 0x1a, 0x96, 0x04, 0x1a, 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c}; */ + +/* + * 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/rak10701/platformio.ini b/variants/rak_wismeshtap/platformio.ini similarity index 72% rename from variants/rak10701/platformio.ini rename to variants/rak_wismeshtap/platformio.ini index 4c9bf3b20..461696d29 100644 --- a/variants/rak10701/platformio.ini +++ b/variants/rak_wismeshtap/platformio.ini @@ -1,15 +1,20 @@ ; The very slick RAK wireless RAK10701 Field Tester device. Note you will have to flash to Arduino bootloader to use this firmware. Be aware touch is not currently working. -[env:rak10701] +[env:rak_wismeshtap] extends = nrf52840_base -board_level = extra board = wiscore_rak4631 -build_flags = ${nrf52840_base.build_flags} -Ivariants/rak10701 -D RAK_4631 +build_flags = ${nrf52840_base.build_flags} -Ivariants/rak_wismeshtap -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. -DEINK_DISPLAY_MODEL=GxEPD2_213_BN -DEINK_WIDTH=250 -DEINK_HEIGHT=122 -build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak10701> + + + + -DMESHTASTIC_EXCLUDE_WIFI=1 + -DMESHTASTIC_EXCLUDE_WAYPOINT=1 + -DMESHTASTIC_EXCLUDE_DETECTIONSENSOR=1 + -DMESHTASTIC_EXCLUDE_STOREFORWARD=1 + -DMESHTASTIC_EXCLUDE_POWER_TELEMETRY=1 + -DMESHTASTIC_EXCLUDE_ATAK=1 +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak_wismeshtap> + + + lib_deps = ${nrf52840_base.lib_deps} ${networking_base.lib_deps} @@ -21,4 +26,4 @@ lib_deps = beegee-tokyo/RAK14014-FT6336U @ 1.0.1 debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -;upload_protocol = jlink \ No newline at end of file +;upload_protocol = jlink diff --git a/variants/rak10701/variant.cpp b/variants/rak_wismeshtap/variant.cpp similarity index 100% rename from variants/rak10701/variant.cpp rename to variants/rak_wismeshtap/variant.cpp diff --git a/variants/rak10701/variant.h b/variants/rak_wismeshtap/variant.h similarity index 99% rename from variants/rak10701/variant.h rename to variants/rak_wismeshtap/variant.h index c263796ee..19eb841fe 100644 --- a/variants/rak10701/variant.h +++ b/variants/rak_wismeshtap/variant.h @@ -243,7 +243,7 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG // Therefore must be 1 to keep peripherals powered // Power is on the controllable 3V3_S rail // #define PIN_GPS_RESET (34) -#define PIN_GPS_EN PIN_3V3_EN +// #define PIN_GPS_EN PIN_3V3_EN #define PIN_GPS_PPS (17) // Pulse per second input from the GPS #define GPS_RX_PIN PIN_SERIAL1_RX 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