diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 8f938ce9e..4c570c856 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -9,12 +9,12 @@ plugins: lint: enabled: - prettier@3.5.3 - - trufflehog@3.88.18 + - trufflehog@3.88.20 - yamllint@1.37.0 - bandit@1.8.3 - checkov@3.2.394 - terrascan@1.19.9 - - trivy@0.60.0 + - trivy@0.61.0 - taplo@0.9.3 - ruff@0.11.2 - isort@6.0.1 diff --git a/bin/config.d/lora-MeshAdv-900M30S.yaml b/bin/config.d/lora-MeshAdv-900M30S.yaml index 113901d5e..5c148bf68 100644 --- a/bin/config.d/lora-MeshAdv-900M30S.yaml +++ b/bin/config.d/lora-MeshAdv-900M30S.yaml @@ -1,3 +1,5 @@ +# MeshAdv-Pi E22-900M30S +# https://github.com/chrismyers2000/MeshAdv-Pi-Hat Lora: Module: sx1262 CS: 21 @@ -9,4 +11,4 @@ Lora: DIO3_TCXO_VOLTAGE: true # Only for E22-900M33S: # Limit the output power to 8 dBm - # SX126X_MAX_POWER: 8 \ No newline at end of file + # SX126X_MAX_POWER: 8 diff --git a/bin/config.d/lora-MeshAdv-Mini-900M22S.yaml b/bin/config.d/lora-MeshAdv-Mini-900M22S.yaml new file mode 100644 index 000000000..554116b57 --- /dev/null +++ b/bin/config.d/lora-MeshAdv-Mini-900M22S.yaml @@ -0,0 +1,11 @@ +# MeshAdv Mini E22-900M22S +# https://github.com/chrismyers2000/MeshAdv-Mini +Lora: + Module: sx1262 # Ebyte E22-900M22S + CS: 8 + IRQ: 16 + Busy: 20 + Reset: 24 + TXen: 13 + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index 96c6b44c1..27117641e 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -128,11 +128,7 @@ bool EInkDisplay::connect() #ifdef PIN_EINK_EN // backlight power, HIGH is backlight on, LOW is off pinMode(PIN_EINK_EN, OUTPUT); -#ifdef ELECROW_ThinkNode_M1 digitalWrite(PIN_EINK_EN, LOW); -#else - digitalWrite(PIN_EINK_EN, HIGH); -#endif #endif #if defined(TTGO_T_ECHO) || defined(ELECROW_ThinkNode_M1) diff --git a/src/graphics/niche/Inputs/TwoButton.cpp b/src/graphics/niche/Inputs/TwoButton.cpp index 10d89ef41..b270d56cf 100644 --- a/src/graphics/niche/Inputs/TwoButton.cpp +++ b/src/graphics/niche/Inputs/TwoButton.cpp @@ -2,6 +2,7 @@ #include "./TwoButton.h" +#include "NodeDB.h" // For the helper function TwoButton::getUserButtonPin #include "PowerFSM.h" #include "sleep.h" @@ -57,14 +58,47 @@ void TwoButton::stop() detachInterrupt(buttons[1].pin); } +// Attempt to resolve a GPIO pin for the user button, honoring userPrefs.jsonc and device settings +// This helper method isn't used by the TweButton class itself, it could be moved elsewhere. +// Intention is to pass this value to TwoButton::setWiring in the setupNicheGraphics method. +uint8_t TwoButton::getUserButtonPin() +{ + uint8_t pin = 0xFF; // Unset + + // Use default pin for variant, if no better source +#ifdef BUTTON_PIN + pin = BUTTON_PIN; +#endif + + // From userPrefs.jsonc, if set +#ifdef USERPREFS_BUTTON_PIN + pin = USERPREFS_BUTTON_PIN; +#endif + + // From user's override in device settings, if set + if (config.device.button_gpio) + pin = config.device.button_gpio; + + return pin; +} + // Configures the wiring and logic of either button // Called when outlining your NicheGraphics implementation, in variant/nicheGraphics.cpp void TwoButton::setWiring(uint8_t whichButton, uint8_t pin, bool internalPullup) { + // Prevent the same GPIO being assigned to multiple buttons + // Allows an edge case when the user remaps hardware buttons using device settings, due to a broken user button + for (uint8_t i = 0; i < whichButton; i++) { + if (buttons[i].pin == pin) { + LOG_WARN("Attempted reuse of GPIO %d. Ignoring assignment whichButton=%d", pin, whichButton); + return; + } + } + assert(whichButton < 2); buttons[whichButton].pin = pin; - buttons[whichButton].activeLogic = LOW; - buttons[whichButton].mode = internalPullup ? INPUT_PULLUP : INPUT; // fix me + buttons[whichButton].activeLogic = LOW; // Unimplemented + buttons[whichButton].mode = internalPullup ? INPUT_PULLUP : INPUT; pinMode(buttons[whichButton].pin, buttons[whichButton].mode); } diff --git a/src/graphics/niche/Inputs/TwoButton.h b/src/graphics/niche/Inputs/TwoButton.h index 1e1576256..f1e18dd89 100644 --- a/src/graphics/niche/Inputs/TwoButton.h +++ b/src/graphics/niche/Inputs/TwoButton.h @@ -30,6 +30,8 @@ class TwoButton : protected concurrency::OSThread public: typedef std::function Callback; + static uint8_t getUserButtonPin(); // Resolve the GPIO, considering the various possible source of definition + static TwoButton *getInstance(); // Create or get the singleton instance void start(); // Start handling button input void stop(); // Stop handling button input (disconnect ISRs for sleep) @@ -62,7 +64,7 @@ class TwoButton : protected concurrency::OSThread public: // Per-button config uint8_t pin = 0xFF; // 0xFF: unset - bool activeLogic = LOW; // Active LOW by default. Todo: remove, unused + bool activeLogic = LOW; // Active LOW by default. Currently unimplemented. uint8_t mode = INPUT; // Whether to use internal pull up / pull down resistors uint32_t debounceLength = 50; // Minimum length for shortpress, in ms uint32_t longpressLength = 500; // How long after button down to fire longpress, in ms diff --git a/src/main.cpp b/src/main.cpp index ac58b3fa6..aacb9ae05 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1294,6 +1294,19 @@ extern meshtastic_DeviceMetadata getDeviceMetadata() deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_AMBIENTLIGHTING_CONFIG; #endif +// No bluetooth on these targets (yet): +// Pico W / 2W may get it at some point +// Portduino and ESP32-C6 are excluded because we don't have a working bluetooth stacks integrated yet. +#if defined(ARCH_RP2040) || defined(ARCH_PORTDUINO) || defined(ARCH_STM32WL) || defined(CONFIG_IDF_TARGET_ESP32C6) + deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_BLUETOOTH_CONFIG; +#endif + +#if defined(ARCH_NRF52) && !HAS_ETHERNET // nrf52 doesn't have network unless it's a RAK ethernet gateway currently + deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_NETWORK_CONFIG; // No network on nRF52 +#elif defined(ARCH_RP2040) && !HAS_WIFI && !HAS_ETHERNET + deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_NETWORK_CONFIG; // No network on RP2040 +#endif + #if !(MESHTASTIC_EXCLUDE_PKI) deviceMetadata.hasPKC = true; #endif diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 468192af1..32356e98e 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -690,7 +690,7 @@ void NodeDB::initConfigIntervals() config.display.screen_on_secs = default_screen_on_secs; -#if defined(T_WATCH_S3) || defined(T_DECK) || defined(MESH_TAB) || defined(RAK14014) || defined(ELECROW) +#if defined(T_WATCH_S3) || defined(T_DECK) || defined(UNPHONE) || defined(MESH_TAB) || defined(RAK14014) || defined(ELECROW) config.power.is_power_saving = true; config.display.screen_on_secs = 30; config.power.wait_bluetooth_secs = 30; diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index a7aea1c3e..4e074be71 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -11,6 +11,7 @@ inline const std::unordered_map configProducts = {{"MESHTOAD", "lora-usb-meshtoad-e22.yaml"}, {"MESHSTICK", "lora-meshstick-1262.yaml"}, {"MESHADV-PI", "lora-MeshAdv-900M30S.yaml"}, + {"MESHADV-MINI", "lora-MeshAdv-Mini-900M22S.yaml"}, {"POWERPI", "lora-MeshAdv-900M30S.yaml"}}; enum configNames { diff --git a/variants/ELECROW-ThinkNode-M1/nicheGraphics.h b/variants/ELECROW-ThinkNode-M1/nicheGraphics.h new file mode 100644 index 000000000..f68ac9edd --- /dev/null +++ b/variants/ELECROW-ThinkNode-M1/nicheGraphics.h @@ -0,0 +1,119 @@ +#pragma once + +#include "configuration.h" + +#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS + +// InkHUD-specific components +// --------------------------- +#include "graphics/niche/InkHUD/InkHUD.h" + +// Applets +#include "graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.h" +#include "graphics/niche/InkHUD/Applets/User/DM/DMApplet.h" +#include "graphics/niche/InkHUD/Applets/User/Heard/HeardApplet.h" +#include "graphics/niche/InkHUD/Applets/User/Positions/PositionsApplet.h" +#include "graphics/niche/InkHUD/Applets/User/RecentsList/RecentsListApplet.h" +#include "graphics/niche/InkHUD/Applets/User/ThreadedMessage/ThreadedMessageApplet.h" + +// Shared NicheGraphics components +// -------------------------------- +#include "graphics/niche/Drivers/Backlight/LatchingBacklight.h" +#include "graphics/niche/Drivers/EInk/GDEY0154D67.h" +#include "graphics/niche/Inputs/TwoButton.h" + +#include "graphics/niche/Fonts/FreeSans6pt7b.h" +#include "graphics/niche/Fonts/FreeSans6pt8bCyrillic.h" +#include + +void setupNicheGraphics() +{ + using namespace NicheGraphics; + + // SPI + // ----------------------------- + + // For NRF52 platforms, SPI pins are defined in variant.h, not passed to begin() + SPI1.begin(); + + // Driver + // ----------------------------- + + // Use E-Ink driver + Drivers::EInk *driver = new Drivers::GDEY0154D67; // Todo: confirm display model + driver->begin(&SPI1, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES); + + // InkHUD + // ---------------------------- + + InkHUD::InkHUD *inkhud = InkHUD::InkHUD::getInstance(); + + // Set the driver + inkhud->setDriver(driver); + + // Set how many FAST updates per FULL update + // Set how unhealthy additional FAST updates beyond this number are + // Todo: observe the display's performance in-person and adjust accordingly. + // Currently set to the values given by Elecrow for EInkDynamicDisplay. + inkhud->setDisplayResilience(10, 1.5); + + // Prepare fonts + InkHUD::Applet::fontLarge = InkHUD::AppletFont(FreeSans9pt7b); + InkHUD::Applet::fontSmall = InkHUD::AppletFont(FreeSans6pt7b); + /* + // Font localization demo: Cyrillic + InkHUD::Applet::fontSmall = InkHUD::AppletFont(FreeSans6pt8bCyrillic); + InkHUD::Applet::fontSmall.addSubstitutionsWin1251(); + */ + + // Customize default settings + inkhud->persistence->settings.userTiles.maxCount = 2; // Two applets side-by-side + inkhud->persistence->settings.rotation = 0; // To be confirmed? + inkhud->persistence->settings.optionalFeatures.batteryIcon = true; // Device definitely has a battery + + // Setup backlight + // Note: button mapping for this configured further down + Drivers::LatchingBacklight *backlight = Drivers::LatchingBacklight::getInstance(); + backlight->setPin(PIN_EINK_EN); + + // Pick applets + // Note: order of applets determines priority of "auto-show" feature + inkhud->addApplet("All Messages", new InkHUD::AllMessageApplet, true, true); // Activated, autoshown + inkhud->addApplet("DMs", new InkHUD::DMApplet); // Inactive + inkhud->addApplet("Channel 0", new InkHUD::ThreadedMessageApplet(0)); // Inactive + inkhud->addApplet("Channel 1", new InkHUD::ThreadedMessageApplet(1)); // Inactive + inkhud->addApplet("Positions", new InkHUD::PositionsApplet, true); // Activated + inkhud->addApplet("Recents List", new InkHUD::RecentsListApplet); // Inactive + inkhud->addApplet("Heard", new InkHUD::HeardApplet, true, false, 0); // Activated, no autoshow, default on tile 0 + + // Start running InkHUD + inkhud->begin(); + + // Buttons + // -------------------------- + + Inputs::TwoButton *buttons = Inputs::TwoButton::getInstance(); // Shared NicheGraphics component + + // As labeled on Elecrow diagram: https://www.elecrow.com/download/product/CIL12901M/ThinkNode-M1_User_Manual.pdf + constexpr uint8_t PAGE_TURN_BUTTON = 0; + constexpr uint8_t FUNCTION_BUTTON = 1; + + // Setup the main user button + buttons->setWiring(PAGE_TURN_BUTTON, PIN_BUTTON2); + buttons->setTiming(PAGE_TURN_BUTTON, 50, 500); // Todo: confirm 50ms is adequate debounce + buttons->setHandlerShortPress(PAGE_TURN_BUTTON, []() { InkHUD::InkHUD::getInstance()->shortpress(); }); + buttons->setHandlerLongPress(PAGE_TURN_BUTTON, []() { InkHUD::InkHUD::getInstance()->longpress(); }); + + // Setup the aux button + // Initial testing only: mapped to the backlight + // Todo: additional features + buttons->setWiring(FUNCTION_BUTTON, PIN_BUTTON1); + buttons->setTiming(FUNCTION_BUTTON, 50, 500); // 500ms before latch + buttons->setHandlerDown(FUNCTION_BUTTON, [backlight]() { backlight->peek(); }); + buttons->setHandlerLongPress(FUNCTION_BUTTON, [backlight]() { backlight->latch(); }); + buttons->setHandlerShortPress(FUNCTION_BUTTON, [backlight]() { backlight->off(); }); + + buttons->start(); +} + +#endif \ No newline at end of file diff --git a/variants/ELECROW-ThinkNode-M1/platformio.ini b/variants/ELECROW-ThinkNode-M1/platformio.ini index f37f6d310..86fbde398 100644 --- a/variants/ELECROW-ThinkNode-M1/platformio.ini +++ b/variants/ELECROW-ThinkNode-M1/platformio.ini @@ -10,6 +10,7 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/ELECROW-ThinkNode-M1 -DELECROW_ThinkNode_M1 -DGPS_POWER_TOGGLE -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" + -DUSE_EINK -DEINK_DISPLAY_MODEL=GxEPD2_154_D67 -DEINK_WIDTH=200 -DEINK_HEIGHT=200 @@ -26,4 +27,23 @@ lib_deps = https://github.com/meshtastic/GxEPD2/archive/33db3fa8ee6fc47d160bdb44f8f127c9a9203a10.zip lewisxhe/PCF8563_Library@^1.0.1 khoih-prog/nRF52_PWM@^1.0.1 -;upload_protocol = fs \ No newline at end of file +;upload_protocol = fs + +[env:thinknode_m1-inkhud] +extends = nrf52840_base, inkhud +board = ThinkNode-M1 +board_check = true +debug_tool = jlink +build_flags = + ${nrf52840_base.build_flags} + ${inkhud.build_flags} + -I variants/ELECROW-ThinkNode-M1 + -D ELECROW_ThinkNode_M1 + -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" +build_src_filter = + ${nrf52_base.build_src_filter} + ${inkhud.build_src_filter} +lib_deps = + ${inkhud.lib_deps} ; InkHUD libs first, so we get GFXRoot instead of AdafruitGFX + ${nrf52840_base.lib_deps} + lewisxhe/PCF8563_Library@^1.0.1 \ No newline at end of file diff --git a/variants/ELECROW-ThinkNode-M1/variant.h b/variants/ELECROW-ThinkNode-M1/variant.h index 3bfa360f6..fc2fddbdf 100644 --- a/variants/ELECROW-ThinkNode-M1/variant.h +++ b/variants/ELECROW-ThinkNode-M1/variant.h @@ -140,8 +140,6 @@ External serial flash WP25R1635FZUIL0 // Controls power for all peripherals (eink + GPS + LoRa + Sensor) #define PIN_POWER_EN (0 + 12) -#define USE_EINK - #define PIN_SPI1_MISO (32 + 7) #define PIN_SPI1_MOSI PIN_EINK_MOSI #define PIN_SPI1_SCK PIN_EINK_SCLK diff --git a/variants/heltec_vision_master_e213/nicheGraphics.h b/variants/heltec_vision_master_e213/nicheGraphics.h index 75e4423be..d6983bafe 100644 --- a/variants/heltec_vision_master_e213/nicheGraphics.h +++ b/variants/heltec_vision_master_e213/nicheGraphics.h @@ -95,7 +95,7 @@ void setupNicheGraphics() constexpr uint8_t AUX_BUTTON = 1; // Setup the main user button - buttons->setWiring(MAIN_BUTTON, BUTTON_PIN); + buttons->setWiring(MAIN_BUTTON, Inputs::TwoButton::getUserButtonPin()); buttons->setHandlerShortPress(MAIN_BUTTON, []() { InkHUD::InkHUD::getInstance()->shortpress(); }); buttons->setHandlerLongPress(MAIN_BUTTON, []() { InkHUD::InkHUD::getInstance()->longpress(); }); diff --git a/variants/heltec_vision_master_e290/nicheGraphics.h b/variants/heltec_vision_master_e290/nicheGraphics.h index 2674436b8..c2f26c7ff 100644 --- a/variants/heltec_vision_master_e290/nicheGraphics.h +++ b/variants/heltec_vision_master_e290/nicheGraphics.h @@ -19,7 +19,7 @@ Different NicheGraphics UIs and different hardware variants will each have their // InkHUD-specific components // --------------------------- -#include "graphics/niche/InkHUD/WindowManager.h" +#include "graphics/niche/InkHUD/InkHUD.h" // Applets #include "graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.h" @@ -113,7 +113,7 @@ void setupNicheGraphics() Inputs::TwoButton *buttons = Inputs::TwoButton::getInstance(); // A shared NicheGraphics component // Setup the main user button (0) - buttons->setWiring(0, BUTTON_PIN); + buttons->setWiring(0, Inputs::TwoButton::getUserButtonPin()); buttons->setHandlerShortPress(0, []() { InkHUD::InkHUD::getInstance()->shortpress(); }); buttons->setHandlerLongPress(0, []() { InkHUD::InkHUD::getInstance()->longpress(); }); diff --git a/variants/heltec_wireless_paper/nicheGraphics.h b/variants/heltec_wireless_paper/nicheGraphics.h index ece4225d0..5e938fa64 100644 --- a/variants/heltec_wireless_paper/nicheGraphics.h +++ b/variants/heltec_wireless_paper/nicheGraphics.h @@ -93,7 +93,7 @@ void setupNicheGraphics() constexpr uint8_t MAIN_BUTTON = 0; // Setup the main user button - buttons->setWiring(MAIN_BUTTON, BUTTON_PIN); + buttons->setWiring(MAIN_BUTTON, Inputs::TwoButton::getUserButtonPin()); buttons->setHandlerShortPress(MAIN_BUTTON, []() { InkHUD::InkHUD::getInstance()->shortpress(); }); buttons->setHandlerLongPress(MAIN_BUTTON, []() { InkHUD::InkHUD::getInstance()->longpress(); }); diff --git a/variants/t-echo/nicheGraphics.h b/variants/t-echo/nicheGraphics.h index e8a9232f1..f5dde6b19 100644 --- a/variants/t-echo/nicheGraphics.h +++ b/variants/t-echo/nicheGraphics.h @@ -104,7 +104,7 @@ void setupNicheGraphics() constexpr uint8_t TOUCH_BUTTON = 1; // Setup the main user button - buttons->setWiring(MAIN_BUTTON, BUTTON_PIN, LOW); + buttons->setWiring(MAIN_BUTTON, Inputs::TwoButton::getUserButtonPin()); buttons->setTiming(MAIN_BUTTON, 75, 500); buttons->setHandlerShortPress(MAIN_BUTTON, []() { InkHUD::InkHUD::getInstance()->shortpress(); }); buttons->setHandlerLongPress(MAIN_BUTTON, []() { InkHUD::InkHUD::getInstance()->longpress(); }); diff --git a/variants/unphone/platformio.ini b/variants/unphone/platformio.ini index 18efbb157..399d65b03 100644 --- a/variants/unphone/platformio.ini +++ b/variants/unphone/platformio.ini @@ -35,19 +35,19 @@ lib_deps = ${esp32s3_base.lib_deps} extends = env:unphone build_flags = ${env:unphone.build_flags} + -D CONFIG_DISABLE_HAL_LOCKS=1 -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1 -D MESHTASTIC_EXCLUDE_INPUTBROKER=1 - -D MESHTASTIC_EXCLUDE_BLUETOOTH=1 -D MESHTASTIC_EXCLUDE_WEBSERVER=1 -D MESHTASTIC_EXCLUDE_SERIAL=1 -D MESHTASTIC_EXCLUDE_SOCKETAPI=1 -D INPUTDRIVER_BUTTON_TYPE=21 - -D MAX_THREADS=40 -D HAS_SCREEN=0 -D HAS_TFT=1 -D HAS_SDCARD -D DISPLAY_SET_RESOLUTION - -D RAM_SIZE=3072 + -D RAM_SIZE=6144 + -D LV_CACHE_DEF_SIZE=2097152 -D LV_LVGL_H_INCLUDE_SIMPLE -D LV_CONF_INCLUDE_SIMPLE -D LV_COMP_CONF_INCLUDE_SIMPLE @@ -63,6 +63,7 @@ build_flags = -D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_UNPHONE.h\" -D VIEW_320x240 -D USE_PACKET_API + -D MAP_FULL_REDRAW lib_deps = ${env:unphone.lib_deps}