From 5195815df017e67ce6ee599367f2cd4ce52b5bed Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Thu, 29 May 2025 23:21:09 +1200 Subject: [PATCH 01/21] Parse own short name in LogoApplet (#6913) --- src/graphics/niche/InkHUD/Applets/System/Logo/LogoApplet.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/graphics/niche/InkHUD/Applets/System/Logo/LogoApplet.cpp b/src/graphics/niche/InkHUD/Applets/System/Logo/LogoApplet.cpp index 89bdb0bc7..fa85deab3 100644 --- a/src/graphics/niche/InkHUD/Applets/System/Logo/LogoApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/System/Logo/LogoApplet.cpp @@ -111,9 +111,10 @@ void InkHUD::LogoApplet::onShutdown() // Prepare for the powered-off screen now // We can change these values because the initial "shutting down" screen has already rendered at this point + meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); textLeft = ""; textRight = ""; - textTitle = owner.short_name; + textTitle = parseShortName(ourNode); fontTitle = fontLarge; // This is then drawn by InkHUD::Events::onShutdown, with a blocking FULL update, after InkHUD's flash write is complete From e31cd0bc773901df844192d3edcdd42ce57f262e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 06:27:36 -0500 Subject: [PATCH 02/21] chore(deps): update meshtastic/device-ui digest to 3dfcc97 (#6912) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index d7504e6c5..e5d36d862 100644 --- a/platformio.ini +++ b/platformio.ini @@ -108,7 +108,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/e63b219e78e9655be10745b4037cefd2c608d258.zip + https://github.com/meshtastic/device-ui/archive/3dfcc973cdfec8b34719510952e160bbfb57d9df.zip ; Common libs for environmental measurements in telemetry module [environmental_base] From c0c2ec195f53b3f2e51dc71df73957631af83a09 Mon Sep 17 00:00:00 2001 From: dylanli Date: Thu, 29 May 2025 19:33:22 +0800 Subject: [PATCH 03/21] add support for seeed wio tracker L1 (#6907) * add support for seeed wio tracker l1 * add support in nrf52 arch * fix ADC problem and comments incorrect * fix gps wakeup pin * fix gps pin --- boards/seeed_wio_tracker_L1.json | 54 ++++++ src/configuration.h | 6 +- src/platform/nrf52/architecture.h | 2 + variants/seeed_wio_tracker_L1/platformio.ini | 13 ++ variants/seeed_wio_tracker_L1/variant.cpp | 97 ++++++++++ variants/seeed_wio_tracker_L1/variant.h | 185 +++++++++++++++++++ 6 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 boards/seeed_wio_tracker_L1.json create mode 100644 variants/seeed_wio_tracker_L1/platformio.ini create mode 100644 variants/seeed_wio_tracker_L1/variant.cpp create mode 100644 variants/seeed_wio_tracker_L1/variant.h diff --git a/boards/seeed_wio_tracker_L1.json b/boards/seeed_wio_tracker_L1.json new file mode 100644 index 000000000..7c7bc62fa --- /dev/null +++ b/boards/seeed_wio_tracker_L1.json @@ -0,0 +1,54 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v7.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_MDBT50Q_RX -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [["0x2886", "0x1668"]], + "usb_product": "TRACKER L1", + "mcu": "nrf52840", + "variant": "seeed_wio_tracker_L1", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "7.3.0", + "sd_fwid": "0x0123" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": ["bluetooth"], + "debug": { + "jlink_device": "nRF52840_xxAA", + "svd_path": "nrf52840.svd", + "openocd_target": "nrf52840-mdk-rs" + }, + "frameworks": ["arduino"], + "name": "seeed_wio_tracker_L1", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "speed": 115200, + "protocol": "nrfutil", + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "stlink", + "cmsis-dap", + "blackmagic" + ], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://www.seeedstudio.com/Wio-Tracker-L1-p-6477.html", + "vendor": "Seeed Studio" +} diff --git a/src/configuration.h b/src/configuration.h index 0c23e677d..32d99295e 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -99,8 +99,12 @@ along with this program. If not, see . // ----------------------------------------------------------------------------- // OLED & Input // ----------------------------------------------------------------------------- - +#if defined(SEEED_WIO_TRACKER_L1) +#define SSD1306_ADDRESS 0x3D +#define USE_SH1106 +#else #define SSD1306_ADDRESS 0x3C +#endif #define ST7567_ADDRESS 0x3F // The SH1106 controller is almost, but not quite, the same as SSD1306 diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index 9d1d48f1c..eea3aee45 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -85,6 +85,8 @@ #define HW_VENDOR meshtastic_HardwareModel_SEEED_SOLAR_NODE #elif defined(HELTEC_MESH_POCKET) #define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_POCKET +#elif defined(SEEED_WIO_TRACKER_L1) +#define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1 #else #define HW_VENDOR meshtastic_HardwareModel_NRF52_UNKNOWN #endif diff --git a/variants/seeed_wio_tracker_L1/platformio.ini b/variants/seeed_wio_tracker_L1/platformio.ini new file mode 100644 index 000000000..3c4653d7e --- /dev/null +++ b/variants/seeed_wio_tracker_L1/platformio.ini @@ -0,0 +1,13 @@ +[env:seeed_wio_tracker_L1] +board = seeed_wio_tracker_L1 +extends = nrf52840_base +;board_level = extra +build_flags = ${nrf52840_base.build_flags} + -I $PROJECT_DIR/variants/seeed_wio_tracker_L1 + -D SEEED_WIO_TRACKER_L1 + -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/seeed_wio_tracker_L1> +lib_deps = + ${nrf52840_base.lib_deps} +debug_tool = jlink diff --git a/variants/seeed_wio_tracker_L1/variant.cpp b/variants/seeed_wio_tracker_L1/variant.cpp new file mode 100644 index 000000000..3ff5688bb --- /dev/null +++ b/variants/seeed_wio_tracker_L1/variant.cpp @@ -0,0 +1,97 @@ +/* + * variant.cpp - Digital pin mapping for TRACKER L1 + * + * This file defines the pin mapping array that maps logical digital pins (D0-D17) + * to physical GPIO ports/pins on the Nordic nRF52 series microcontroller. + * + * Board: [Seeed Studio WIO TRACKER L1] + * Hardware Features: + * - LoRa module (CS/SCK/MISO/MOSI control pins) + * - GNSS module (TX/RX/Reset/Wakeup) + * - User LEDs (D11-D12) + * - User button (D13) + * - Grove/NFC interface (D14-D15) + * - Battery voltage monitoring (D16) + * + * Created [20250521] + * By [Dylan] + */ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +/** + * @brief Digital pin to GPIO port/pin mapping table + * + * Format: Logical Pin (Dx) -> nRF Port.Pin (Px.xx) + * + */ + +extern "C" { +const uint32_t g_ADigitalPinMap[] = { + // D0 .. D10 - Peripheral control pins + 41, // D0 P1.09 GNSS_WAKEUP + 7, // D1 P0.07 LORA_DIO1 + 39, // D2 P1,07 LORA_RESET + 42, // D3 P1.10 LORA_BUSY + 46, // D4 P1.14 (A4/SDA) LORA_CS + 40, // D5 P1.08 (A5/SCL) LORA_SW + 27, // D6 P0.27 (UART_TX) GNSS_TX + 26, // D7 P0.26 (UART_RX) GNSS_RX + 30, // D8 P0.30 (SPI_SCK) LORA_SCK + 3, // D9 P0.3 (SPI_MISO) LORA_MISO + 28, // D10 P0.28 (SPI_MOSI) LORA_MOSI + + // D11-D12 - LED outputs + 33, // D11 P1.1 User LED + // Buzzzer + 32, // D12 P1.0 Buzzer + + // D13 - User input + 8, // D13 P0.08 User Button + + // D14-D15 - Grove interface + 6, // D14 P0.06 OLED SDA + 5, // D15 P0.05 OLED SCL + + // D16 - Battery voltage ADC input + 31, // D16 P0.31 VBAT_ADC + // GROVE + 0, // D17 P0.00 GROVESDA + 1, // D18 P0.01 GROVESCL + + // FLASH + 21, // D19 P0.21 (QSPI_SCK) + 25, // D20 P0.25 (QSPI_CSN) + 20, // D21 P0.20 (QSPI_SIO_0 DI) + 24, // D22 P0.24 (QSPI_SIO_1 DO) + 22, // D23 P0.22 (QSPI_SIO_2 WP) + 23, // D24 P0.23 (QSPI_SIO_3 HOLD) + + + 36, // D25 TB_UP + 12, // D26 TB_DOWN + 11, // D27 TB_LEFT + 35, // D28 TB_RIGHT + 37, // D29 TB_PRESS + 4, // D30 BAT_CTL +}; +} + +void initVariant() +{ + pinMode(PIN_QSPI_CS, OUTPUT); + digitalWrite(PIN_QSPI_CS, HIGH); + // This setup is crucial for ensuring low power consumption and proper initialization of the hardware components. + // VBAT_ENABLE + pinMode(BAT_READ, OUTPUT); + digitalWrite(BAT_READ, HIGH); + + pinMode(PIN_LED1, OUTPUT); + digitalWrite(PIN_LED1, LOW); + pinMode(PIN_LED2, OUTPUT); + digitalWrite(PIN_LED2, LOW); + pinMode(PIN_LED2, OUTPUT); +} \ No newline at end of file diff --git a/variants/seeed_wio_tracker_L1/variant.h b/variants/seeed_wio_tracker_L1/variant.h new file mode 100644 index 000000000..23c788480 --- /dev/null +++ b/variants/seeed_wio_tracker_L1/variant.h @@ -0,0 +1,185 @@ +#ifndef _SEEED_TRACKER_L1_H_ +#define _SEEED_TRACKER_L1_H_ +#include "WVariant.h" +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Clock Configuration +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#define VARIANT_MCK (64000000ul) // Master clock frequency +#define USE_LFXO // 32.768kHz crystal for LFCLK + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Pin Capacity Definitions +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#define PINS_COUNT (33u) // Total GPIO pins +#define NUM_DIGITAL_PINS (33u) // Digital I/O pins +#define NUM_ANALOG_INPUTS (8u) // Analog inputs (A0-A5 + VBAT + AREF) +#define NUM_ANALOG_OUTPUTS (0u) + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// LED Configuration +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// LEDs +// LEDs +#define PIN_LED1 (11) // LED P1.15 +#define PIN_LED2 (12) // + +#define LED_BUILTIN PIN_LED1 +#define LED_CONN PIN_LED2 + +#define LED_GREEN PIN_LED1 +#define LED_BLUE PIN_LED2 +// #define LED_PIN PIN_LED2 +#define LED_STATE_ON 1 // State when LED is litted +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Button Configuration +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#define BUTTON_PIN D13 // This is the Program Button +// #define BUTTON_NEED_PULLUP 1 +#define BUTTON_ACTIVE_LOW true +#define BUTTON_ACTIVE_PULLUP false + +#define BUTTON_PIN_TOUCH 13 // Touch button +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Digital Pin Mapping (D0-D10) +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#define D0 0 // P1.06 GNSS_WAKEUP/IO0 +#define D1 1 // P0.07 LORA_DIO1 +#define D2 2 // P1.07 LORA_RESET +#define D3 3 // P1.10 LORA_BUSY +#define D4 4 // P1.14 LORA_CS +#define D5 5 // P1.08 LORA_SW +#define D6 6 // P0.27 GNSS_TX +#define D7 7 // P0.26 GNSS_RX +#define D8 8 // P0.30 SPI_SCK +#define D9 9 // P0.03 SPI_MISO +#define D10 10 // P0.28 SPI_MOSI +#define D12 12 // P1.00 Buzzer +#define D13 13 // P0.08 User Button +#define D14 14 // P0.05 OLED SCL +#define D15 15 // P0.06 OLED SDA +#define D16 16 // P0.31 VBAT_ADC +#define D17 17 // P0.00 GROVE SDA +#define D18 18 // P0.01 GROVE_SCL +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Analog Pin Definitions +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#define PIN_A0 0 // P0.02 Analog Input 0 +#define PIN_A1 1 // P0.03 Analog Input 1 +#define PIN_A2 2 // P0.28 Analog Input 2 +#define PIN_A3 3 // P0.29 Analog Input 3 +#define PIN_A4 4 // P0.04 Analog Input 4 +#define PIN_A5 5 // P0.05 Analog Input 5 +#define PIN_VBAT D16 // P0.31 Battery voltage sense +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Communication Interfaces +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// I2C Configuration +#define HAS_WIRE 1 +#define PIN_WIRE_SDA D14 // P0.09 +#define PIN_WIRE_SCL D15 // P0.10 +#define WIRE_INTERFACES_COUNT 1 +#define I2C_NO_RESCAN + +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; + +#define HAS_SCREEN 1 +#define USE_SSD1306 1 + +// SPI Configuration (SX1262) + +#define SPI_INTERFACES_COUNT 1 +#define PIN_SPI_MISO 9 // P0.03 (D9) +#define PIN_SPI_MOSI 10 // P0.28 (D10) +#define PIN_SPI_SCK 8 // P0.30 (D8) + +// SX1262 LoRa Module Pins +#define USE_SX1262 +#define SX126X_CS D4 // Chip select +#define SX126X_DIO1 D1 // Digital IO 1 (Interrupt) +#define SX126X_BUSY D3 // Busy status +#define SX126X_RESET D2 // Reset control +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 // TCXO supply voltage +#define SX126X_RXEN D5 // RX enable control +#define SX126X_TXEN RADIOLIB_NC +#define SX126X_DIO2_AS_RF_SWITCH // This Line is really necessary for SX1262 to work with RF switch or will loss TX power +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Power Management +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +#define BAT_READ \ + 30 // D30 = P0.04 Reads battery voltage from divider on signal board. +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#define ADC_MULTIPLIER 2.0 +#define BATTERY_PIN PIN_VBAT // PIN_A7 +#define AREF_VOLTAGE 3.6 +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// GPS L76KB +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#define GPS_L76K +#ifdef GPS_L76K +#define PIN_GPS_RX D6 // P0.26 +#define PIN_GPS_TX D7 +#define HAS_GPS 1 +#define GPS_BAUDRATE 9600 +#define GPS_THREAD_INTERVAL 50 +#define PIN_SERIAL1_RX PIN_GPS_TX +#define PIN_SERIAL1_TX PIN_GPS_RX + +#define GPS_RX_PIN PIN_GPS_TX +#define GPS_TX_PIN PIN_GPS_RX +#define PIN_GPS_STANDBY D0 + +// #define GPS_DEBUG +// #define GPS_EN D18 // P1.05 +#endif + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// On-board QSPI Flash +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// On-board QSPI Flash +#define PIN_QSPI_SCK (21) +#define PIN_QSPI_CS (22) +#define PIN_QSPI_IO0 (23) +#define PIN_QSPI_IO1 (24) +#define PIN_QSPI_IO2 (25) +#define PIN_QSPI_IO3 (26) + +#define EXTERNAL_FLASH_DEVICES P25Q16H +#define EXTERNAL_FLASH_USE_QSPI + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Buzzer +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Buzzer + +#define PIN_BUZZER D12 // P1.00, pwm output + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// joystick +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +#define CANNED_MESSAGE_MODULE_ENABLE 1 + +// trackball +#define HAS_TRACKBALL 1 +#define TB_UP 25 +#define TB_DOWN 26 +#define TB_LEFT 27 +#define TB_RIGHT 28 +#define TB_PRESS 29 +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// Compatibility Definitions +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +#ifdef __cplusplus +extern "C" { +#endif +// Serial port placeholders + +#define PIN_SERIAL2_RX (-1) +#define PIN_SERIAL2_TX (-1) +#ifdef __cplusplus +} +#endif + +#endif // _SEEED_SOLAR_NODE_H_ \ No newline at end of file From 7849a3d29119be7abef060bc99d7048997f13d03 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 29 May 2025 06:35:18 -0500 Subject: [PATCH 04/21] Trunk --- variants/seeed_wio_tracker_L1/variant.cpp | 3 +-- variants/seeed_wio_tracker_L1/variant.h | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/variants/seeed_wio_tracker_L1/variant.cpp b/variants/seeed_wio_tracker_L1/variant.cpp index 3ff5688bb..6c34d63e6 100644 --- a/variants/seeed_wio_tracker_L1/variant.cpp +++ b/variants/seeed_wio_tracker_L1/variant.cpp @@ -70,13 +70,12 @@ const uint32_t g_ADigitalPinMap[] = { 22, // D23 P0.22 (QSPI_SIO_2 WP) 23, // D24 P0.23 (QSPI_SIO_3 HOLD) - 36, // D25 TB_UP 12, // D26 TB_DOWN 11, // D27 TB_LEFT 35, // D28 TB_RIGHT 37, // D29 TB_PRESS - 4, // D30 BAT_CTL + 4, // D30 BAT_CTL }; } diff --git a/variants/seeed_wio_tracker_L1/variant.h b/variants/seeed_wio_tracker_L1/variant.h index 23c788480..b257fd9b6 100644 --- a/variants/seeed_wio_tracker_L1/variant.h +++ b/variants/seeed_wio_tracker_L1/variant.h @@ -107,10 +107,9 @@ static const uint8_t SCL = PIN_WIRE_SCL; // Power Management // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -#define BAT_READ \ - 30 // D30 = P0.04 Reads battery voltage from divider on signal board. +#define BAT_READ 30 // D30 = P0.04 Reads battery voltage from divider on signal board. #define BATTERY_SENSE_RESOLUTION_BITS 12 -#define ADC_MULTIPLIER 2.0 +#define ADC_MULTIPLIER 2.0 #define BATTERY_PIN PIN_VBAT // PIN_A7 #define AREF_VOLTAGE 3.6 // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ From f972b62d89420abdac781113747b2c40ac873b41 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 09:06:52 -0500 Subject: [PATCH 05/21] Upgrade trunk to 1.24.0 (#6915) Co-authored-by: sachaw <11172820+sachaw@users.noreply.github.com> --- .trunk/trunk.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 162fdfd2d..3a02034a6 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -1,6 +1,6 @@ version: 0.1 cli: - version: 1.22.15 + version: 1.24.0 plugins: sources: - id: trunk @@ -9,7 +9,7 @@ plugins: lint: enabled: - checkov@3.2.435 - - renovate@40.32.7 + - renovate@40.33.8 - prettier@3.5.3 - trufflehog@3.88.34 - yamllint@1.37.1 From cb9429e83e06b29679b5c85272b62615ce583bed Mon Sep 17 00:00:00 2001 From: dmarman Date: Thu, 29 May 2025 16:09:33 +0200 Subject: [PATCH 06/21] Added full support for LTR390UV readings of UV and Lux (#6872) * Added full support for LTR390UV readings of UV and Lux * Trunk formatting * Added full support for LTR390UV readings of UV and Lux * Trunk formatting * fix library check and unnecessary bit resolution change * fixed log info messages and removed unused dependency * Hopefully fixes git mess * fix variable scope and getMetrics returns * set metrics flags bavk to false in case something wrong happens while reading LTR390UV mode --------- Co-authored-by: Domingo Co-authored-by: Ben Meadors --- platformio.ini | 4 +- .../Telemetry/EnvironmentTelemetry.cpp | 18 +++++ .../Telemetry/Sensor/LTR390UVSensor.cpp | 73 +++++++++++++++++++ src/modules/Telemetry/Sensor/LTR390UVSensor.h | 25 +++++++ 4 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 src/modules/Telemetry/Sensor/LTR390UVSensor.cpp create mode 100644 src/modules/Telemetry/Sensor/LTR390UVSensor.h diff --git a/platformio.ini b/platformio.ini index e5d36d862..125dfb573 100644 --- a/platformio.ini +++ b/platformio.ini @@ -161,6 +161,8 @@ lib_deps = sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2 # renovate: datasource=custom.pio depName=SparkFun 9DoF IMU Breakout ICM 20948 packageName=sparkfun/library/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@1.3.2 + # renovate: datasource=custom.pio depName=Adafruit LTR390 Library packageName=adafruit/library/Adafruit LTR390 Library + adafruit/Adafruit LTR390 Library@1.1.2 # renovate: datasource=custom.pio depName=Adafruit PCT2075 packageName=adafruit/Adafruit PCT2075 adafruit/Adafruit PCT2075@1.0.5 @@ -190,4 +192,4 @@ lib_deps = # renovate: datasource=custom.pio depName=Bosch BME68x packageName=boschsensortec/library/BME68x Sensor Library boschsensortec/BME68x Sensor Library@1.3.40408 # renovate: datasource=git-refs depName=meshtastic-DFRobot_LarkWeatherStation packageName=https://github.com/meshtastic/DFRobot_LarkWeatherStation gitBranch=master - https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip + https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip \ No newline at end of file diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 51f076552..6d29fecb2 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -52,6 +52,13 @@ BMP280Sensor bmp280Sensor; NullSensor bme280Sensor; #endif +#if __has_include() +#include "Sensor/LTR390UVSensor.h" +LTR390UVSensor ltr390uvSensor; +#else +NullSensor ltr390uvSensor; +#endif + #if __has_include() #include "Sensor/BME680Sensor.h" BME680Sensor bme680Sensor; @@ -231,6 +238,8 @@ int32_t EnvironmentTelemetryModule::runOnce() #endif if (bme280Sensor.hasSensor()) result = bme280Sensor.runOnce(); + if (ltr390uvSensor.hasSensor()) + result = ltr390uvSensor.runOnce(); if (bmp3xxSensor.hasSensor()) result = bmp3xxSensor.runOnce(); if (bme680Sensor.hasSensor()) @@ -524,6 +533,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m valid = valid && bme280Sensor.getMetrics(m); hasSensor = true; } + if (ltr390uvSensor.hasSensor()) { + valid = valid && ltr390uvSensor.getMetrics(m); + hasSensor = true; + } if (bmp3xxSensor.hasSensor()) { valid = valid && bmp3xxSensor.getMetrics(m); hasSensor = true; @@ -752,6 +765,11 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule if (result != AdminMessageHandleResult::NOT_HANDLED) return result; } + if (ltr390uvSensor.hasSensor()) { + result = ltr390uvSensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } if (bmp3xxSensor.hasSensor()) { result = bmp3xxSensor.handleAdminMessage(mp, request, response); if (result != AdminMessageHandleResult::NOT_HANDLED) diff --git a/src/modules/Telemetry/Sensor/LTR390UVSensor.cpp b/src/modules/Telemetry/Sensor/LTR390UVSensor.cpp new file mode 100644 index 000000000..fb84700c4 --- /dev/null +++ b/src/modules/Telemetry/Sensor/LTR390UVSensor.cpp @@ -0,0 +1,73 @@ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "LTR390UVSensor.h" +#include "TelemetrySensor.h" +#include + +LTR390UVSensor::LTR390UVSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_LTR390UV, "LTR390UV") {} + +int32_t LTR390UVSensor::runOnce() +{ + LOG_INFO("Init sensor: %s", sensorName); + if (!hasSensor()) { + return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + } + + status = ltr390uv.begin(nodeTelemetrySensorsMap[sensorType].second); + ltr390uv.setMode(LTR390_MODE_UVS); + ltr390uv.setGain(LTR390_GAIN_18); // Datasheet default + ltr390uv.setResolution(LTR390_RESOLUTION_20BIT); // Datasheet default + + return initI2CSensor(); +} + +void LTR390UVSensor::setup() {} + +bool LTR390UVSensor::getMetrics(meshtastic_Telemetry *measurement) +{ + LOG_DEBUG("LTR390UV getMetrics"); + + // Because the sensor does not measure Lux and UV at the same time, we need to read them in two passes. + if (ltr390uv.newDataAvailable()) { + measurement->variant.environment_metrics.has_lux = true; + measurement->variant.environment_metrics.has_uv_lux = true; + + if (ltr390uv.getMode() == LTR390_MODE_ALS) { + lastLuxReading = 0.6 * ltr390uv.readALS() / (1 * 4); // Datasheet page 23 for gain x1 and 20bit resolution + LOG_DEBUG("LTR390UV Lux reading: %f", lastLuxReading); + + measurement->variant.environment_metrics.lux = lastLuxReading; + measurement->variant.environment_metrics.uv_lux = lastUVReading; + + ltr390uv.setGain( + LTR390_GAIN_18); // Recommended for UVI - x18. Do not change, 2300 UV Sensitivity only specified for x18 gain + ltr390uv.setMode(LTR390_MODE_UVS); + + return true; + + } else if (ltr390uv.getMode() == LTR390_MODE_UVS) { + lastUVReading = ltr390uv.readUVS() / + 2300.f; // Datasheet page 23 and page 6, only characterisation for gain x18 and 20bit resolution + LOG_DEBUG("LTR390UV UV reading: %f", lastUVReading); + + measurement->variant.environment_metrics.lux = lastLuxReading; + measurement->variant.environment_metrics.uv_lux = lastUVReading; + + ltr390uv.setGain( + LTR390_GAIN_1); // x1 gain will already max out the sensor at direct sunlight, so no need to increase it + ltr390uv.setMode(LTR390_MODE_ALS); + + return true; + } + } + + // In case we fail to read the sensor mode, set the has_lux and has_uv_lux back to false + measurement->variant.environment_metrics.has_lux = false; + measurement->variant.environment_metrics.has_uv_lux = false; + + return false; +} +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/LTR390UVSensor.h b/src/modules/Telemetry/Sensor/LTR390UVSensor.h new file mode 100644 index 000000000..40206bce8 --- /dev/null +++ b/src/modules/Telemetry/Sensor/LTR390UVSensor.h @@ -0,0 +1,25 @@ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include + +class LTR390UVSensor : public TelemetrySensor +{ + private: + Adafruit_LTR390 ltr390uv = Adafruit_LTR390(); + float lastLuxReading = 0; + float lastUVReading = 0; + + protected: + virtual void setup() override; + + public: + LTR390UVSensor(); + virtual int32_t runOnce() override; + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; +}; + +#endif \ No newline at end of file From ba535433543f40b0e15280c7beb9e0afabe56142 Mon Sep 17 00:00:00 2001 From: Quency-D <55523105+Quency-D@users.noreply.github.com> Date: Thu, 29 May 2025 22:10:25 +0800 Subject: [PATCH 07/21] Add a new screen for heltec_wireless_paper. (#6894) Co-authored-by: Ben Meadors --- src/graphics/EInkDisplay2.cpp | 64 +++- src/graphics/EInkDisplay2.h | 6 +- src/graphics/EInkMultiWrapper.h | 327 ++++++++++++++++++ src/graphics/niche/Drivers/EInk/E0213A367.cpp | 126 +++++++ src/graphics/niche/Drivers/EInk/E0213A367.h | 44 +++ .../heltec_wireless_paper/nicheGraphics.h | 57 ++- variants/heltec_wireless_paper/platformio.ini | 6 +- 7 files changed, 624 insertions(+), 6 deletions(-) create mode 100644 src/graphics/EInkMultiWrapper.h create mode 100644 src/graphics/niche/Drivers/EInk/E0213A367.cpp create mode 100644 src/graphics/niche/Drivers/EInk/E0213A367.h diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index 5a2749482..b518299f7 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -174,7 +174,7 @@ bool EInkDisplay::connect() } } -#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) || \ +#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \ defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \ defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER) { @@ -228,6 +228,68 @@ bool EInkDisplay::connect() auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, *spi1); adafruitDisplay = new GxEPD2_BW(*lowLevel); + // Init GxEPD2 + adafruitDisplay->init(); + adafruitDisplay->setRotation(3); + } +#elif defined(HELTEC_WIRELESS_PAPER) + { + uint8_t model; + pinMode(PIN_EINK_SCLK, OUTPUT); + pinMode(PIN_EINK_DC, OUTPUT); + pinMode(PIN_EINK_CS, OUTPUT); + pinMode(PIN_EINK_RES, OUTPUT); + + //rest e-ink + digitalWrite(PIN_EINK_RES, LOW); + delay(20); + digitalWrite(PIN_EINK_RES, HIGH); + delay(20); + + digitalWrite(PIN_EINK_DC, LOW); + digitalWrite(PIN_EINK_CS, LOW); + + // write cmd + uint8_t cmd = 0x2F; + pinMode(PIN_EINK_MOSI, OUTPUT); + digitalWrite(PIN_EINK_SCLK, LOW); + for (int i = 0; i < 8; i++) + { + digitalWrite(PIN_EINK_MOSI, (cmd & 0x80) ? HIGH : LOW); + cmd <<= 1; + digitalWrite(PIN_EINK_SCLK, HIGH); + delayMicroseconds(1); + digitalWrite(PIN_EINK_SCLK, LOW); + delayMicroseconds(1); + } + delay(10); + + digitalWrite(PIN_EINK_DC, HIGH); + pinMode(PIN_EINK_MOSI, INPUT_PULLUP); + + // read chip ID + uint8_t chipId = 0; + for (int8_t b = 7; b >= 0; b--) + { + digitalWrite(PIN_EINK_SCLK, LOW); + delayMicroseconds(1); + digitalWrite(PIN_EINK_SCLK, HIGH); + delayMicroseconds(1); + if (digitalRead(PIN_EINK_MOSI)) chipId |= (1 << b); + } + digitalWrite(PIN_EINK_CS, HIGH); + LOG_INFO("eink chipId: %02X", chipId); + model = ((chipId&0x03) !=0x01) ? 1 : 2; + + // Start HSPI + hspi = new SPIClass(HSPI); + hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS + // VExt already enabled in setup() + // RTC GPIO hold disabled in setup() + + // Create GxEPD2 objects + adafruitDisplay = new EInkMultiWrapper(model, PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, *hspi); + // Init GxEPD2 adafruitDisplay->init(); adafruitDisplay->setRotation(3); diff --git a/src/graphics/EInkDisplay2.h b/src/graphics/EInkDisplay2.h index 93be197b0..965a3307a 100644 --- a/src/graphics/EInkDisplay2.h +++ b/src/graphics/EInkDisplay2.h @@ -4,6 +4,7 @@ #include "GxEPD2_BW.h" #include +#include "EinkMultiWrapper.h" /** * An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation. @@ -64,8 +65,11 @@ class EInkDisplay : public OLEDDisplay virtual bool connect() override; // AdafruitGFX display object - instantiated in connect(), variant specific +#if defined(HELTEC_WIRELESS_PAPER) + EInkMultiWrapper *adafruitDisplay; +#else GxEPD2_BW *adafruitDisplay = NULL; - +#endif // If display uses HSPI #if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \ defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \ diff --git a/src/graphics/EInkMultiWrapper.h b/src/graphics/EInkMultiWrapper.h new file mode 100644 index 000000000..3ac0b194d --- /dev/null +++ b/src/graphics/EInkMultiWrapper.h @@ -0,0 +1,327 @@ +// Wrapper class for GxEPD2_BW + +// Generic signature at build time, allowing display model to be detected at run-time +// Workaround for issue of GxEPD2_BW objects not having a shared base class +// Only exposes methods which we are actually using +#ifndef _EINKMULTIWRAPPER_H_ +#define _EINKMULTIWRAPPER_H_ + +#include "GxEPD2_BW.h" +#include "GxEPD2_EPD.h" + +template +class EInkMultiWrapper +{ +public: + void drawPixel(int16_t x, int16_t y, uint16_t color) + { + if (model == 1) + model1->drawPixel(x, y, color); + else + model2->drawPixel(x, y, color); + } + void init(uint32_t serial_diag_bitrate = 0) // = 0 : disabled + { + if (model == 1) + model1->init(serial_diag_bitrate); + else + model2->init(serial_diag_bitrate); + } + + void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration = 20, bool pulldown_rst_mode = false) + { + if (model == 1) + model1->init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode); + else + model2->init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode); + } + void fillScreen(uint16_t color) // 0x0 black, >0x0 white, to buffer + { + if (model == 1) + model1->fillScreen(color); + else + model2->fillScreen(color); + } + void display(bool partial_update_mode = false) + { + if (model == 1) + model1->display(partial_update_mode); + else + model2->display(partial_update_mode); + } + void displayWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) + { + if (model == 1) + model1->displayWindow(x, y, w, h); + else + model2->displayWindow(x, y, w, h); + } + + void setFullWindow() + { + if (model == 1) + model1->setFullWindow(); + else + model2->setFullWindow(); + } + + void setPartialWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) + { + if (model == 1) + model1->setPartialWindow(x, y, w, h); + else + model2->setPartialWindow(x, y, w, h); + } + + void firstPage() + { + if (model == 1) + model1->firstPage(); + else + model2->firstPage(); + } + void endAsyncFull() + { + if (model == 1) + model1->endAsyncFull(); + else + model2->endAsyncFull(); + } + + bool nextPage() + { + if (model == 1) + return model1->nextPage(); + else + return model2->nextPage(); + } + void drawPaged(void (*drawCallback)(const void*), const void* pv) + { + if (model == 1) + model1->drawPaged(drawCallback, pv); + else + model2->drawPaged(drawCallback, pv); + } + + void drawInvertedBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) + { + if (model == 1) + model1->drawInvertedBitmap(x, y, bitmap, w, h, color); + else + model2->drawInvertedBitmap(x, y, bitmap, w, h, color); + } + + void clearScreen(uint8_t value = 0xFF) // init controller memory and screen (default white) + { + if (model == 1) + model1->clearScreen(value); + else + model2->clearScreen(value); + } + void writeScreenBuffer(uint8_t value = 0xFF) // init controller memory (default white) + { + if (model == 1) + model1->writeScreenBuffer(value); + else + model2->writeScreenBuffer(value); + } + // write to controller memory, without screen refresh; x and w should be multiple of 8 + void writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) + { + if (model == 1) + model1->writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm); + else + model2->writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm); + } + void writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) + { + if (model == 1) + model1->writeImagePart(x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + else + model2->writeImagePart(x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + } + void writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) + { + if (model == 1) + model1->writeImage(black, color, x, y, w, h, invert, mirror_y, pgm); + else + model2->writeImage(black, color, x, y, w, h, invert, mirror_y, pgm); + } + void writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h) + { + if (model == 1) + model1->writeImage(black, color, x, y, w, h); + else + model2->writeImage(black, color, x, y, w, h); + } + void writeImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) + { + if (model == 1) + model1->writeImagePart( black, color, x_part, y_part, w_bitmap, h_bitmap,x, y, w, h, invert, mirror_y, pgm); + else + model2->writeImagePart( black, color, x_part, y_part, w_bitmap, h_bitmap,x, y, w, h, invert, mirror_y, pgm); + } + + void writeImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h) + { + if (model == 1) + model1->writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap,x, y, w, h); + else + model2->writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap,x, y, w, h); + } + // write sprite of native data to controller memory, without screen refresh; x and w should be multiple of 8 + void writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) + { + if (model == 1) + model1->writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm); + else + model2->writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm); + } + // write to controller memory, with screen refresh; x and w should be multiple of 8 + void drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) + { + if (model == 1) + model1->drawImage(bitmap, x, y, w, h, invert, mirror_y, pgm); + else + model2->drawImage(bitmap, x, y, w, h, invert, mirror_y, pgm); + } + void drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) + { + if (model == 1) + model1->drawImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + else + model2->drawImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + } + void drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) + { + if (model == 1) + model1->drawImage(black, color, x, y, w, h, invert, mirror_y, pgm); + else + model2->drawImage(black, color, x, y, w, h, invert, mirror_y, pgm); + } + void drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h) + { + if (model == 1) + model1->drawImage(black, color, x, y, w, h); + else + model2->drawImage(black, color, x, y, w, h); + } + void drawImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) + { + if (model == 1) + model1->drawImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + else + model2->drawImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); + } + void drawImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, + int16_t x, int16_t y, int16_t w, int16_t h) + { + if (model == 1) + model1->drawImagePart( black, color, x_part, y_part, w_bitmap, h_bitmap,x, y, w, h); + else + model2->drawImagePart( black, color, x_part, y_part, w_bitmap, h_bitmap,x, y, w, h); + } + // write sprite of native data to controller memory, with screen refresh; x and w should be multiple of 8 + void drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) + { + if (model == 1) + model1->drawNative(data1, data2, x, y, w, h, invert, mirror_y, pgm); + else + model2->drawNative(data1, data2, x, y, w, h, invert, mirror_y, pgm); + } + void refresh(bool partial_update_mode = false) // screen refresh from controller memory to full screen + { + if (model == 1) + model1->refresh(partial_update_mode); + else + model2->refresh(partial_update_mode); + } + void refresh(int16_t x, int16_t y, int16_t w, int16_t h) // screen refresh from controller memory, partial screen + { + if (model == 1) + model1->refresh(x, y, w, h); + else + model2->refresh(x, y, w, h); + } + // turns off generation of panel driving voltages, avoids screen fading over time + void powerOff() + { + if (model == 1) + model1->powerOff(); + else + model2->powerOff(); + } + // turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0) + void hibernate() + { + if (model == 1) + model1->hibernate(); + else + model2->hibernate(); + } + + void setRotation(uint8_t x) + { + if (model == 1) + model1->setRotation(x); + else + model2->setRotation(x); + } + + int16_t width() + { + if (model == 1) + return model1->width(); + else + return model2->width(); + } + + int16_t height() + { + if (model == 1) + return model1->height(); + else + return model2->height(); + } + + + // Exposes methods of the GxEPD2_EPD object which is usually available as GxEPD2_BW::epd + class Epd2Wrapper + { + public: + bool isBusy() { return m_epd2->isBusy(); } + GxEPD2_EPD *m_epd2; + } epd2; + + // Constructor + // Select driver by passing whichModel as 1 or 2 + EInkMultiWrapper(uint8_t whichModel, int16_t cs, int16_t dc, int16_t rst, int16_t busy, SPIClass &spi) + { + assert(whichModel == 1 || whichModel == 2); + model = whichModel; + // LOG_DEBUG("GxEPD2_BW_MultiWrapper using driver %d", model); + + if (model == 1) + { + model1 = new GxEPD2_BW(DISPLAY_MODEL_1(cs, dc, rst, busy, spi)); + epd2.m_epd2 = &(model1->epd2); + } + else if (model == 2) + { + model2 = new GxEPD2_BW(DISPLAY_MODEL_2(cs, dc, rst, busy, spi)); + epd2.m_epd2 = &(model2->epd2); + } + } + +private: + uint8_t model; + GxEPD2_BW *model1; + GxEPD2_BW *model2; +}; + +#endif \ No newline at end of file diff --git a/src/graphics/niche/Drivers/EInk/E0213A367.cpp b/src/graphics/niche/Drivers/EInk/E0213A367.cpp new file mode 100644 index 000000000..4f2a50ba7 --- /dev/null +++ b/src/graphics/niche/Drivers/EInk/E0213A367.cpp @@ -0,0 +1,126 @@ +#include "./E0213A367.h" + +#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS + +using namespace NicheGraphics::Drivers; + +// Map the display controller IC's output to the connected panel +void E0213A367::configScanning() +{ + // "Driver output control" + sendCommand(0x01); + sendData(0xF9); + sendData(0x00); + // Values set here might be redundant: F9, 00 seems to be default +} + +// Specify which information is used to control the sequence of voltages applied to move the pixels +// - For this display, configUpdateSequence() specifies that a suitable LUT will be loaded from +// the controller IC's OTP memory, when the update procedure begins. +void E0213A367::configWaveform() +{ + sendCommand(0x37); // Waveform ID register + sendData(0x40); // ByteA + sendData(0x80); // ByteB DM[7:0] + sendData(0x03); // ByteC DM[[15:8] + sendData(0x0E); // ByteD DM[[23:16] + + switch (updateType) { + case FAST: + sendCommand(0x3C); // Border waveform: + sendData(0x81); + break; + case FULL: + sendCommand(0x3C); // Border waveform: + sendData(0x01); + default: + // From OTP memory + break; + } +} + +void E0213A367::configUpdateSequence() +{ + switch (updateType) { + case FAST: + sendCommand(0x22); + sendData(0xFF); + break; + case FULL: + default: + sendCommand(0x22); // Set "update sequence" + sendData(0xF7); + break; + } +} + +// Once the refresh operation has been started, +// begin periodically polling the display to check for completion, using the normal Meshtastic threading code +// Only used when refresh is "async" +void E0213A367::detachFromUpdate() +{ + switch (updateType) { + case FAST: + return beginPolling(50, 500); // At least 500ms for fast refresh + case FULL: + default: + return beginPolling(100, 2000); // At least 2 seconds for full refresh + } +} +void E0213A367::configFullscreen() +{ + // Placing this code in a separate method because it's probably pretty consistent between displays + // Should make it tidier to override SSD16XX::configure + + // Define the boundaries of the "fullscreen" region, for the controller IC + static const uint16_t sx = bufferOffsetX; // Notice the offset + static const uint16_t sy = 0; + static const uint16_t ex = bufferRowSize + bufferOffsetX - 1; // End is "max index", not "count". Minus 1 handles this + static const uint16_t ey = height; + + // Split into bytes + static const uint8_t sy1 = sy & 0xFF; + static const uint8_t ey1 = ey & 0xFF; + + // Data entry mode - Left to Right, Top to Bottom + sendCommand(0x11); + sendData(0x03); + + // Select controller IC memory region to display a fullscreen image + sendCommand(0x44); // Memory X start - end + sendData(sx); + sendData(ex); + sendCommand(0x45); // Memory Y start - end + sendData(sy1); + sendData(ey1); + + // Place the cursor at the start of this memory region, ready to send image data x=0 y=0 + sendCommand(0x4E); // Memory cursor X + sendData(sx); + sendCommand(0x4F); // Memory cursor y + sendData(sy1); +} +void E0213A367::finalizeUpdate() +{ + // Put a copy of the image into the "old memory". + // Used with differential refreshes (e.g. FAST update), to determine which px need to move, and which can remain in place + // We need to keep the "old memory" up to date, because don't know whether next refresh will be FULL or FAST etc. + if (updateType != FULL) { + writeNewImage(); // Only required by some controller variants. Todo: Override just for GDEY0154D678? + writeOldImage(); + sendCommand(0x7F); // Terminate image write without update + wait(); + } + + //After waking up from sleep mode, the local refresh is abnormal, which may be due to the loss of data in RAM. + // if ((pin_rst != 0xFF) && (updateType ==FULL)) + // deepSleep(); +} + +void E0213A367::deepSleep() +{ + sendCommand(0x10); // Enter deep sleep + sendData(0x03); // Will not retain image RAM +} + +#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS \ No newline at end of file diff --git a/src/graphics/niche/Drivers/EInk/E0213A367.h b/src/graphics/niche/Drivers/EInk/E0213A367.h new file mode 100644 index 000000000..c00d73378 --- /dev/null +++ b/src/graphics/niche/Drivers/EInk/E0213A367.h @@ -0,0 +1,44 @@ +/* + +E-Ink display driver + - SSD1682 + - Manufacturer: WISEVAST + - Size: 2.13 inch + - Resolution: 122px x 255px + - Flex connector marking: HINK-E0213A162-FPC-A0 (Hidden, printed on back-side) + +*/ + +#pragma once + +#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS + +#include "configuration.h" + +#include "./SSD16XX.h" + +namespace NicheGraphics::Drivers +{ +class E0213A367 : public SSD16XX +{ + // Display properties + private: + static constexpr uint32_t width = 122; + static constexpr uint32_t height = 250; + static constexpr UpdateTypes supported = (UpdateTypes)(FULL | FAST); + + public: + E0213A367() : SSD16XX(width, height, supported, 0) {} + + protected: + virtual void configScanning() override; + virtual void configWaveform() override; + virtual void configUpdateSequence() override; + virtual void detachFromUpdate() override; + virtual void configFullscreen() override; + virtual void deepSleep() override; + virtual void finalizeUpdate() override; +}; + +} // namespace NicheGraphics::Drivers +#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS \ No newline at end of file diff --git a/variants/heltec_wireless_paper/nicheGraphics.h b/variants/heltec_wireless_paper/nicheGraphics.h index c8994b7f1..e42a4df85 100644 --- a/variants/heltec_wireless_paper/nicheGraphics.h +++ b/variants/heltec_wireless_paper/nicheGraphics.h @@ -19,12 +19,58 @@ // Shared NicheGraphics components // -------------------------------- #include "graphics/niche/Drivers/EInk/LCMEN2R13EFC1.h" +#include "graphics/niche/Drivers/EInk/E0213A367.h" #include "graphics/niche/Inputs/TwoButton.h" void setupNicheGraphics() { using namespace NicheGraphics; + pinMode(PIN_EINK_SCLK, OUTPUT); + pinMode(PIN_EINK_DC, OUTPUT); + pinMode(PIN_EINK_CS, OUTPUT); + pinMode(PIN_EINK_RES, OUTPUT); + + //rest e-ink + digitalWrite(PIN_EINK_RES, LOW); + delay(20); + digitalWrite(PIN_EINK_RES, HIGH); + delay(20); + + digitalWrite(PIN_EINK_DC, LOW); + digitalWrite(PIN_EINK_CS, LOW); + + // write cmd + uint8_t cmd = 0x2F; + pinMode(PIN_EINK_MOSI, OUTPUT); + digitalWrite(PIN_EINK_SCLK, LOW); + for (int i = 0; i < 8; i++) + { + digitalWrite(PIN_EINK_MOSI, (cmd & 0x80) ? HIGH : LOW); + cmd <<= 1; + digitalWrite(PIN_EINK_SCLK, HIGH); + delayMicroseconds(1); + digitalWrite(PIN_EINK_SCLK, LOW); + delayMicroseconds(1); + } + delay(10); + + digitalWrite(PIN_EINK_DC, HIGH); + pinMode(PIN_EINK_MOSI, INPUT_PULLUP); + + // read chip ID + uint8_t chipId = 0; + for (int8_t b = 7; b >= 0; b--) + { + digitalWrite(PIN_EINK_SCLK, LOW); + delayMicroseconds(1); + digitalWrite(PIN_EINK_SCLK, HIGH); + delayMicroseconds(1); + if (digitalRead(PIN_EINK_MOSI)) chipId |= (1 << b); + } + digitalWrite(PIN_EINK_CS, HIGH); + LOG_INFO("eink chipId: %02X", chipId); + // SPI // ----------------------------- @@ -34,8 +80,15 @@ void setupNicheGraphics() // E-Ink Driver // ----------------------------- - - Drivers::EInk *driver = new Drivers::LCMEN213EFC1; + Drivers::EInk *driver; + if((chipId &0x03) !=0x01) + { + driver = new Drivers::LCMEN213EFC1; + } + else + { + driver = new Drivers::E0213A367; + } driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES); // InkHUD diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini index 51430ebff..762b793cc 100644 --- a/variants/heltec_wireless_paper/platformio.ini +++ b/variants/heltec_wireless_paper/platformio.ini @@ -8,6 +8,8 @@ build_flags = -I variants/heltec_wireless_paper -D HELTEC_WIRELESS_PAPER -D EINK_DISPLAY_MODEL=GxEPD2_213_FC1 + -D EINK_DISPLAY_MODEL1=GxEPD2_213_FC1 + -D EINK_DISPLAY_MODEL2=GxEPD2_213_E0213A367 -D EINK_WIDTH=250 -D EINK_HEIGHT=122 -D USE_EINK @@ -17,9 +19,9 @@ build_flags = -D EINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting" lib_deps = ${esp32s3_base.lib_deps} - https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip + https://github.com/Quency-D/GxEPD2/archive/0513405847b281d9dea400488714643ef84507ec.zip lewisxhe/PCF8563_Library@^1.0.1 -upload_speed = 115200 +upload_speed = 921600 [env:heltec-wireless-paper-inkhud] extends = esp32s3_base, inkhud From 7a7166d57555f42156eb15a8923667e63fdb6a95 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 29 May 2025 10:17:20 -0500 Subject: [PATCH 08/21] Revert "Add a new screen for heltec_wireless_paper. (#6894)" (#6918) This reverts commit ba535433543f40b0e15280c7beb9e0afabe56142. --- src/graphics/EInkDisplay2.cpp | 64 +--- src/graphics/EInkDisplay2.h | 6 +- src/graphics/EInkMultiWrapper.h | 327 ------------------ src/graphics/niche/Drivers/EInk/E0213A367.cpp | 126 ------- src/graphics/niche/Drivers/EInk/E0213A367.h | 44 --- .../heltec_wireless_paper/nicheGraphics.h | 57 +-- variants/heltec_wireless_paper/platformio.ini | 6 +- 7 files changed, 6 insertions(+), 624 deletions(-) delete mode 100644 src/graphics/EInkMultiWrapper.h delete mode 100644 src/graphics/niche/Drivers/EInk/E0213A367.cpp delete mode 100644 src/graphics/niche/Drivers/EInk/E0213A367.h diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index b518299f7..5a2749482 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -174,7 +174,7 @@ bool EInkDisplay::connect() } } -#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \ +#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) || \ defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \ defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER) { @@ -228,68 +228,6 @@ bool EInkDisplay::connect() auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, *spi1); adafruitDisplay = new GxEPD2_BW(*lowLevel); - // Init GxEPD2 - adafruitDisplay->init(); - adafruitDisplay->setRotation(3); - } -#elif defined(HELTEC_WIRELESS_PAPER) - { - uint8_t model; - pinMode(PIN_EINK_SCLK, OUTPUT); - pinMode(PIN_EINK_DC, OUTPUT); - pinMode(PIN_EINK_CS, OUTPUT); - pinMode(PIN_EINK_RES, OUTPUT); - - //rest e-ink - digitalWrite(PIN_EINK_RES, LOW); - delay(20); - digitalWrite(PIN_EINK_RES, HIGH); - delay(20); - - digitalWrite(PIN_EINK_DC, LOW); - digitalWrite(PIN_EINK_CS, LOW); - - // write cmd - uint8_t cmd = 0x2F; - pinMode(PIN_EINK_MOSI, OUTPUT); - digitalWrite(PIN_EINK_SCLK, LOW); - for (int i = 0; i < 8; i++) - { - digitalWrite(PIN_EINK_MOSI, (cmd & 0x80) ? HIGH : LOW); - cmd <<= 1; - digitalWrite(PIN_EINK_SCLK, HIGH); - delayMicroseconds(1); - digitalWrite(PIN_EINK_SCLK, LOW); - delayMicroseconds(1); - } - delay(10); - - digitalWrite(PIN_EINK_DC, HIGH); - pinMode(PIN_EINK_MOSI, INPUT_PULLUP); - - // read chip ID - uint8_t chipId = 0; - for (int8_t b = 7; b >= 0; b--) - { - digitalWrite(PIN_EINK_SCLK, LOW); - delayMicroseconds(1); - digitalWrite(PIN_EINK_SCLK, HIGH); - delayMicroseconds(1); - if (digitalRead(PIN_EINK_MOSI)) chipId |= (1 << b); - } - digitalWrite(PIN_EINK_CS, HIGH); - LOG_INFO("eink chipId: %02X", chipId); - model = ((chipId&0x03) !=0x01) ? 1 : 2; - - // Start HSPI - hspi = new SPIClass(HSPI); - hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS - // VExt already enabled in setup() - // RTC GPIO hold disabled in setup() - - // Create GxEPD2 objects - adafruitDisplay = new EInkMultiWrapper(model, PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, *hspi); - // Init GxEPD2 adafruitDisplay->init(); adafruitDisplay->setRotation(3); diff --git a/src/graphics/EInkDisplay2.h b/src/graphics/EInkDisplay2.h index 965a3307a..93be197b0 100644 --- a/src/graphics/EInkDisplay2.h +++ b/src/graphics/EInkDisplay2.h @@ -4,7 +4,6 @@ #include "GxEPD2_BW.h" #include -#include "EinkMultiWrapper.h" /** * An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation. @@ -65,11 +64,8 @@ class EInkDisplay : public OLEDDisplay virtual bool connect() override; // AdafruitGFX display object - instantiated in connect(), variant specific -#if defined(HELTEC_WIRELESS_PAPER) - EInkMultiWrapper *adafruitDisplay; -#else GxEPD2_BW *adafruitDisplay = NULL; -#endif + // If display uses HSPI #if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \ defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \ diff --git a/src/graphics/EInkMultiWrapper.h b/src/graphics/EInkMultiWrapper.h deleted file mode 100644 index 3ac0b194d..000000000 --- a/src/graphics/EInkMultiWrapper.h +++ /dev/null @@ -1,327 +0,0 @@ -// Wrapper class for GxEPD2_BW - -// Generic signature at build time, allowing display model to be detected at run-time -// Workaround for issue of GxEPD2_BW objects not having a shared base class -// Only exposes methods which we are actually using -#ifndef _EINKMULTIWRAPPER_H_ -#define _EINKMULTIWRAPPER_H_ - -#include "GxEPD2_BW.h" -#include "GxEPD2_EPD.h" - -template -class EInkMultiWrapper -{ -public: - void drawPixel(int16_t x, int16_t y, uint16_t color) - { - if (model == 1) - model1->drawPixel(x, y, color); - else - model2->drawPixel(x, y, color); - } - void init(uint32_t serial_diag_bitrate = 0) // = 0 : disabled - { - if (model == 1) - model1->init(serial_diag_bitrate); - else - model2->init(serial_diag_bitrate); - } - - void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration = 20, bool pulldown_rst_mode = false) - { - if (model == 1) - model1->init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode); - else - model2->init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode); - } - void fillScreen(uint16_t color) // 0x0 black, >0x0 white, to buffer - { - if (model == 1) - model1->fillScreen(color); - else - model2->fillScreen(color); - } - void display(bool partial_update_mode = false) - { - if (model == 1) - model1->display(partial_update_mode); - else - model2->display(partial_update_mode); - } - void displayWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) - { - if (model == 1) - model1->displayWindow(x, y, w, h); - else - model2->displayWindow(x, y, w, h); - } - - void setFullWindow() - { - if (model == 1) - model1->setFullWindow(); - else - model2->setFullWindow(); - } - - void setPartialWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) - { - if (model == 1) - model1->setPartialWindow(x, y, w, h); - else - model2->setPartialWindow(x, y, w, h); - } - - void firstPage() - { - if (model == 1) - model1->firstPage(); - else - model2->firstPage(); - } - void endAsyncFull() - { - if (model == 1) - model1->endAsyncFull(); - else - model2->endAsyncFull(); - } - - bool nextPage() - { - if (model == 1) - return model1->nextPage(); - else - return model2->nextPage(); - } - void drawPaged(void (*drawCallback)(const void*), const void* pv) - { - if (model == 1) - model1->drawPaged(drawCallback, pv); - else - model2->drawPaged(drawCallback, pv); - } - - void drawInvertedBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) - { - if (model == 1) - model1->drawInvertedBitmap(x, y, bitmap, w, h, color); - else - model2->drawInvertedBitmap(x, y, bitmap, w, h, color); - } - - void clearScreen(uint8_t value = 0xFF) // init controller memory and screen (default white) - { - if (model == 1) - model1->clearScreen(value); - else - model2->clearScreen(value); - } - void writeScreenBuffer(uint8_t value = 0xFF) // init controller memory (default white) - { - if (model == 1) - model1->writeScreenBuffer(value); - else - model2->writeScreenBuffer(value); - } - // write to controller memory, without screen refresh; x and w should be multiple of 8 - void writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) - { - if (model == 1) - model1->writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm); - else - model2->writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm); - } - void writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, - int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) - { - if (model == 1) - model1->writeImagePart(x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); - else - model2->writeImagePart(x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); - } - void writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) - { - if (model == 1) - model1->writeImage(black, color, x, y, w, h, invert, mirror_y, pgm); - else - model2->writeImage(black, color, x, y, w, h, invert, mirror_y, pgm); - } - void writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h) - { - if (model == 1) - model1->writeImage(black, color, x, y, w, h); - else - model2->writeImage(black, color, x, y, w, h); - } - void writeImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, - int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) - { - if (model == 1) - model1->writeImagePart( black, color, x_part, y_part, w_bitmap, h_bitmap,x, y, w, h, invert, mirror_y, pgm); - else - model2->writeImagePart( black, color, x_part, y_part, w_bitmap, h_bitmap,x, y, w, h, invert, mirror_y, pgm); - } - - void writeImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, - int16_t x, int16_t y, int16_t w, int16_t h) - { - if (model == 1) - model1->writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap,x, y, w, h); - else - model2->writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap,x, y, w, h); - } - // write sprite of native data to controller memory, without screen refresh; x and w should be multiple of 8 - void writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) - { - if (model == 1) - model1->writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm); - else - model2->writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm); - } - // write to controller memory, with screen refresh; x and w should be multiple of 8 - void drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) - { - if (model == 1) - model1->drawImage(bitmap, x, y, w, h, invert, mirror_y, pgm); - else - model2->drawImage(bitmap, x, y, w, h, invert, mirror_y, pgm); - } - void drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, - int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) - { - if (model == 1) - model1->drawImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); - else - model2->drawImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); - } - void drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) - { - if (model == 1) - model1->drawImage(black, color, x, y, w, h, invert, mirror_y, pgm); - else - model2->drawImage(black, color, x, y, w, h, invert, mirror_y, pgm); - } - void drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h) - { - if (model == 1) - model1->drawImage(black, color, x, y, w, h); - else - model2->drawImage(black, color, x, y, w, h); - } - void drawImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, - int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) - { - if (model == 1) - model1->drawImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); - else - model2->drawImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); - } - void drawImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, - int16_t x, int16_t y, int16_t w, int16_t h) - { - if (model == 1) - model1->drawImagePart( black, color, x_part, y_part, w_bitmap, h_bitmap,x, y, w, h); - else - model2->drawImagePart( black, color, x_part, y_part, w_bitmap, h_bitmap,x, y, w, h); - } - // write sprite of native data to controller memory, with screen refresh; x and w should be multiple of 8 - void drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) - { - if (model == 1) - model1->drawNative(data1, data2, x, y, w, h, invert, mirror_y, pgm); - else - model2->drawNative(data1, data2, x, y, w, h, invert, mirror_y, pgm); - } - void refresh(bool partial_update_mode = false) // screen refresh from controller memory to full screen - { - if (model == 1) - model1->refresh(partial_update_mode); - else - model2->refresh(partial_update_mode); - } - void refresh(int16_t x, int16_t y, int16_t w, int16_t h) // screen refresh from controller memory, partial screen - { - if (model == 1) - model1->refresh(x, y, w, h); - else - model2->refresh(x, y, w, h); - } - // turns off generation of panel driving voltages, avoids screen fading over time - void powerOff() - { - if (model == 1) - model1->powerOff(); - else - model2->powerOff(); - } - // turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0) - void hibernate() - { - if (model == 1) - model1->hibernate(); - else - model2->hibernate(); - } - - void setRotation(uint8_t x) - { - if (model == 1) - model1->setRotation(x); - else - model2->setRotation(x); - } - - int16_t width() - { - if (model == 1) - return model1->width(); - else - return model2->width(); - } - - int16_t height() - { - if (model == 1) - return model1->height(); - else - return model2->height(); - } - - - // Exposes methods of the GxEPD2_EPD object which is usually available as GxEPD2_BW::epd - class Epd2Wrapper - { - public: - bool isBusy() { return m_epd2->isBusy(); } - GxEPD2_EPD *m_epd2; - } epd2; - - // Constructor - // Select driver by passing whichModel as 1 or 2 - EInkMultiWrapper(uint8_t whichModel, int16_t cs, int16_t dc, int16_t rst, int16_t busy, SPIClass &spi) - { - assert(whichModel == 1 || whichModel == 2); - model = whichModel; - // LOG_DEBUG("GxEPD2_BW_MultiWrapper using driver %d", model); - - if (model == 1) - { - model1 = new GxEPD2_BW(DISPLAY_MODEL_1(cs, dc, rst, busy, spi)); - epd2.m_epd2 = &(model1->epd2); - } - else if (model == 2) - { - model2 = new GxEPD2_BW(DISPLAY_MODEL_2(cs, dc, rst, busy, spi)); - epd2.m_epd2 = &(model2->epd2); - } - } - -private: - uint8_t model; - GxEPD2_BW *model1; - GxEPD2_BW *model2; -}; - -#endif \ No newline at end of file diff --git a/src/graphics/niche/Drivers/EInk/E0213A367.cpp b/src/graphics/niche/Drivers/EInk/E0213A367.cpp deleted file mode 100644 index 4f2a50ba7..000000000 --- a/src/graphics/niche/Drivers/EInk/E0213A367.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include "./E0213A367.h" - -#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS - -using namespace NicheGraphics::Drivers; - -// Map the display controller IC's output to the connected panel -void E0213A367::configScanning() -{ - // "Driver output control" - sendCommand(0x01); - sendData(0xF9); - sendData(0x00); - // Values set here might be redundant: F9, 00 seems to be default -} - -// Specify which information is used to control the sequence of voltages applied to move the pixels -// - For this display, configUpdateSequence() specifies that a suitable LUT will be loaded from -// the controller IC's OTP memory, when the update procedure begins. -void E0213A367::configWaveform() -{ - sendCommand(0x37); // Waveform ID register - sendData(0x40); // ByteA - sendData(0x80); // ByteB DM[7:0] - sendData(0x03); // ByteC DM[[15:8] - sendData(0x0E); // ByteD DM[[23:16] - - switch (updateType) { - case FAST: - sendCommand(0x3C); // Border waveform: - sendData(0x81); - break; - case FULL: - sendCommand(0x3C); // Border waveform: - sendData(0x01); - default: - // From OTP memory - break; - } -} - -void E0213A367::configUpdateSequence() -{ - switch (updateType) { - case FAST: - sendCommand(0x22); - sendData(0xFF); - break; - case FULL: - default: - sendCommand(0x22); // Set "update sequence" - sendData(0xF7); - break; - } -} - -// Once the refresh operation has been started, -// begin periodically polling the display to check for completion, using the normal Meshtastic threading code -// Only used when refresh is "async" -void E0213A367::detachFromUpdate() -{ - switch (updateType) { - case FAST: - return beginPolling(50, 500); // At least 500ms for fast refresh - case FULL: - default: - return beginPolling(100, 2000); // At least 2 seconds for full refresh - } -} -void E0213A367::configFullscreen() -{ - // Placing this code in a separate method because it's probably pretty consistent between displays - // Should make it tidier to override SSD16XX::configure - - // Define the boundaries of the "fullscreen" region, for the controller IC - static const uint16_t sx = bufferOffsetX; // Notice the offset - static const uint16_t sy = 0; - static const uint16_t ex = bufferRowSize + bufferOffsetX - 1; // End is "max index", not "count". Minus 1 handles this - static const uint16_t ey = height; - - // Split into bytes - static const uint8_t sy1 = sy & 0xFF; - static const uint8_t ey1 = ey & 0xFF; - - // Data entry mode - Left to Right, Top to Bottom - sendCommand(0x11); - sendData(0x03); - - // Select controller IC memory region to display a fullscreen image - sendCommand(0x44); // Memory X start - end - sendData(sx); - sendData(ex); - sendCommand(0x45); // Memory Y start - end - sendData(sy1); - sendData(ey1); - - // Place the cursor at the start of this memory region, ready to send image data x=0 y=0 - sendCommand(0x4E); // Memory cursor X - sendData(sx); - sendCommand(0x4F); // Memory cursor y - sendData(sy1); -} -void E0213A367::finalizeUpdate() -{ - // Put a copy of the image into the "old memory". - // Used with differential refreshes (e.g. FAST update), to determine which px need to move, and which can remain in place - // We need to keep the "old memory" up to date, because don't know whether next refresh will be FULL or FAST etc. - if (updateType != FULL) { - writeNewImage(); // Only required by some controller variants. Todo: Override just for GDEY0154D678? - writeOldImage(); - sendCommand(0x7F); // Terminate image write without update - wait(); - } - - //After waking up from sleep mode, the local refresh is abnormal, which may be due to the loss of data in RAM. - // if ((pin_rst != 0xFF) && (updateType ==FULL)) - // deepSleep(); -} - -void E0213A367::deepSleep() -{ - sendCommand(0x10); // Enter deep sleep - sendData(0x03); // Will not retain image RAM -} - -#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS \ No newline at end of file diff --git a/src/graphics/niche/Drivers/EInk/E0213A367.h b/src/graphics/niche/Drivers/EInk/E0213A367.h deleted file mode 100644 index c00d73378..000000000 --- a/src/graphics/niche/Drivers/EInk/E0213A367.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - -E-Ink display driver - - SSD1682 - - Manufacturer: WISEVAST - - Size: 2.13 inch - - Resolution: 122px x 255px - - Flex connector marking: HINK-E0213A162-FPC-A0 (Hidden, printed on back-side) - -*/ - -#pragma once - -#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS - -#include "configuration.h" - -#include "./SSD16XX.h" - -namespace NicheGraphics::Drivers -{ -class E0213A367 : public SSD16XX -{ - // Display properties - private: - static constexpr uint32_t width = 122; - static constexpr uint32_t height = 250; - static constexpr UpdateTypes supported = (UpdateTypes)(FULL | FAST); - - public: - E0213A367() : SSD16XX(width, height, supported, 0) {} - - protected: - virtual void configScanning() override; - virtual void configWaveform() override; - virtual void configUpdateSequence() override; - virtual void detachFromUpdate() override; - virtual void configFullscreen() override; - virtual void deepSleep() override; - virtual void finalizeUpdate() override; -}; - -} // namespace NicheGraphics::Drivers -#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS \ No newline at end of file diff --git a/variants/heltec_wireless_paper/nicheGraphics.h b/variants/heltec_wireless_paper/nicheGraphics.h index e42a4df85..c8994b7f1 100644 --- a/variants/heltec_wireless_paper/nicheGraphics.h +++ b/variants/heltec_wireless_paper/nicheGraphics.h @@ -19,58 +19,12 @@ // Shared NicheGraphics components // -------------------------------- #include "graphics/niche/Drivers/EInk/LCMEN2R13EFC1.h" -#include "graphics/niche/Drivers/EInk/E0213A367.h" #include "graphics/niche/Inputs/TwoButton.h" void setupNicheGraphics() { using namespace NicheGraphics; - pinMode(PIN_EINK_SCLK, OUTPUT); - pinMode(PIN_EINK_DC, OUTPUT); - pinMode(PIN_EINK_CS, OUTPUT); - pinMode(PIN_EINK_RES, OUTPUT); - - //rest e-ink - digitalWrite(PIN_EINK_RES, LOW); - delay(20); - digitalWrite(PIN_EINK_RES, HIGH); - delay(20); - - digitalWrite(PIN_EINK_DC, LOW); - digitalWrite(PIN_EINK_CS, LOW); - - // write cmd - uint8_t cmd = 0x2F; - pinMode(PIN_EINK_MOSI, OUTPUT); - digitalWrite(PIN_EINK_SCLK, LOW); - for (int i = 0; i < 8; i++) - { - digitalWrite(PIN_EINK_MOSI, (cmd & 0x80) ? HIGH : LOW); - cmd <<= 1; - digitalWrite(PIN_EINK_SCLK, HIGH); - delayMicroseconds(1); - digitalWrite(PIN_EINK_SCLK, LOW); - delayMicroseconds(1); - } - delay(10); - - digitalWrite(PIN_EINK_DC, HIGH); - pinMode(PIN_EINK_MOSI, INPUT_PULLUP); - - // read chip ID - uint8_t chipId = 0; - for (int8_t b = 7; b >= 0; b--) - { - digitalWrite(PIN_EINK_SCLK, LOW); - delayMicroseconds(1); - digitalWrite(PIN_EINK_SCLK, HIGH); - delayMicroseconds(1); - if (digitalRead(PIN_EINK_MOSI)) chipId |= (1 << b); - } - digitalWrite(PIN_EINK_CS, HIGH); - LOG_INFO("eink chipId: %02X", chipId); - // SPI // ----------------------------- @@ -80,15 +34,8 @@ void setupNicheGraphics() // E-Ink Driver // ----------------------------- - Drivers::EInk *driver; - if((chipId &0x03) !=0x01) - { - driver = new Drivers::LCMEN213EFC1; - } - else - { - driver = new Drivers::E0213A367; - } + + Drivers::EInk *driver = new Drivers::LCMEN213EFC1; driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES); // InkHUD diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini index 762b793cc..51430ebff 100644 --- a/variants/heltec_wireless_paper/platformio.ini +++ b/variants/heltec_wireless_paper/platformio.ini @@ -8,8 +8,6 @@ build_flags = -I variants/heltec_wireless_paper -D HELTEC_WIRELESS_PAPER -D EINK_DISPLAY_MODEL=GxEPD2_213_FC1 - -D EINK_DISPLAY_MODEL1=GxEPD2_213_FC1 - -D EINK_DISPLAY_MODEL2=GxEPD2_213_E0213A367 -D EINK_WIDTH=250 -D EINK_HEIGHT=122 -D USE_EINK @@ -19,9 +17,9 @@ build_flags = -D EINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting" lib_deps = ${esp32s3_base.lib_deps} - https://github.com/Quency-D/GxEPD2/archive/0513405847b281d9dea400488714643ef84507ec.zip + https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip lewisxhe/PCF8563_Library@^1.0.1 -upload_speed = 921600 +upload_speed = 115200 [env:heltec-wireless-paper-inkhud] extends = esp32s3_base, inkhud From b6cb0b148cdf2ed01f1a1dfd4f17ddb4e1838ece Mon Sep 17 00:00:00 2001 From: Austin Date: Thu, 29 May 2025 17:33:10 -0400 Subject: [PATCH 09/21] Fix renovate for Adafruit PCT2075 (#6919) --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 125dfb573..ac74a352a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -163,7 +163,7 @@ lib_deps = sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@1.3.2 # renovate: datasource=custom.pio depName=Adafruit LTR390 Library packageName=adafruit/library/Adafruit LTR390 Library adafruit/Adafruit LTR390 Library@1.1.2 - # renovate: datasource=custom.pio depName=Adafruit PCT2075 packageName=adafruit/Adafruit PCT2075 + # renovate: datasource=custom.pio depName=Adafruit PCT2075 packageName=adafruit/library/Adafruit PCT2075 adafruit/Adafruit PCT2075@1.0.5 ; (not included in native / portduino) From f9d4fdbb52440ee35fb597c2dc7695b6d1cada75 Mon Sep 17 00:00:00 2001 From: ArgoNavi <63644530+ArgoNavi@users.noreply.github.com> Date: Fri, 30 May 2025 07:00:20 -0400 Subject: [PATCH 10/21] Update TSL2591Sensor.cpp (#6921) Lower gain and timing to avoid saturation in bright light --- src/modules/Telemetry/Sensor/TSL2591Sensor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/Telemetry/Sensor/TSL2591Sensor.cpp b/src/modules/Telemetry/Sensor/TSL2591Sensor.cpp index beec3c70b..04443ebec 100644 --- a/src/modules/Telemetry/Sensor/TSL2591Sensor.cpp +++ b/src/modules/Telemetry/Sensor/TSL2591Sensor.cpp @@ -23,8 +23,8 @@ int32_t TSL2591Sensor::runOnce() void TSL2591Sensor::setup() { - tsl.setGain(TSL2591_GAIN_MED); // 25x gain - tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS); + tsl.setGain(TSL2591_GAIN_LOW); // 1x gain + tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS); } bool TSL2591Sensor::getMetrics(meshtastic_Telemetry *measurement) @@ -41,4 +41,4 @@ bool TSL2591Sensor::getMetrics(meshtastic_Telemetry *measurement) return true; } -#endif \ No newline at end of file +#endif From 9799f10e6363703bf64490044dbac813f0ddf2ea Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 08:38:13 -0500 Subject: [PATCH 11/21] Upgrade trunk (#6922) Co-authored-by: sachaw <11172820+sachaw@users.noreply.github.com> --- .trunk/trunk.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 3a02034a6..f45bba826 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -9,7 +9,7 @@ plugins: lint: enabled: - checkov@3.2.435 - - renovate@40.33.8 + - renovate@40.34.4 - prettier@3.5.3 - trufflehog@3.88.34 - yamllint@1.37.1 From 284b8bcff283b05d320c81c4dcc64a6fe6e47104 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 31 May 2025 06:15:37 -0500 Subject: [PATCH 12/21] chore(deps): update meshtastic/device-ui digest to 37e2fb8 (#6925) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index ac74a352a..40517eea0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -108,7 +108,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/3dfcc973cdfec8b34719510952e160bbfb57d9df.zip + https://github.com/meshtastic/device-ui/archive/37e2fb84a8d1b7d8cc1e2ed00d34cfb1f284bd59.zip ; Common libs for environmental measurements in telemetry module [environmental_base] From 5cd74f4b53a70ce18303ccdee75260be2e689ea7 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sun, 1 Jun 2025 21:03:38 -0500 Subject: [PATCH 13/21] Don't give LOG_INFO a null --- src/modules/Telemetry/HostMetrics.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/Telemetry/HostMetrics.cpp b/src/modules/Telemetry/HostMetrics.cpp index dc4315efa..9a9d8fecc 100644 --- a/src/modules/Telemetry/HostMetrics.cpp +++ b/src/modules/Telemetry/HostMetrics.cpp @@ -34,7 +34,8 @@ bool HostMetricsModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, sender, t->variant.host_metrics.uptime_seconds, t->variant.host_metrics.diskfree1_bytes, t->variant.host_metrics.freemem_bytes, static_cast(t->variant.host_metrics.load1) / 100, static_cast(t->variant.host_metrics.load5) / 100, - static_cast(t->variant.host_metrics.load15) / 100, t->variant.host_metrics.user_string); + static_cast(t->variant.host_metrics.load15) / 100, + t->variant.host_metrics.has_user_string ? t->variant.host_metrics.user_string : ""); #endif } return false; // Let others look at this message also if they want @@ -124,7 +125,8 @@ bool HostMetricsModule::sendMetrics() telemetry.variant.host_metrics.uptime_seconds, telemetry.variant.host_metrics.diskfree1_bytes, telemetry.variant.host_metrics.freemem_bytes, static_cast(telemetry.variant.host_metrics.load1) / 100, static_cast(telemetry.variant.host_metrics.load5) / 100, - static_cast(telemetry.variant.host_metrics.load15) / 100, telemetry.variant.host_metrics.user_string); + static_cast(telemetry.variant.host_metrics.load15) / 100, + telemetry.variant.host_metrics.has_user_string ? telemetry.variant.host_metrics.user_string : ""); meshtastic_MeshPacket *p = allocDataProtobuf(telemetry); p->to = NODENUM_BROADCAST; From d833a9ea61fcad0999944ff8879204fb8611e123 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 Jun 2025 06:16:01 -0500 Subject: [PATCH 14/21] chore(deps): update meshtastic/device-ui digest to 04e3a07 (#6942) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 40517eea0..095cf3b9d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -108,7 +108,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/37e2fb84a8d1b7d8cc1e2ed00d34cfb1f284bd59.zip + https://github.com/meshtastic/device-ui/archive/04e3a075dc848f49e1344c5404ccce03a1876017.zip ; Common libs for environmental measurements in telemetry module [environmental_base] From be0c7d73a34c73b68ee1277bb17f17af970493bd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 2 Jun 2025 06:16:24 -0500 Subject: [PATCH 15/21] Upgrade trunk (#6941) Co-authored-by: sachaw <11172820+sachaw@users.noreply.github.com> Co-authored-by: Ben Meadors --- .trunk/trunk.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index f45bba826..fd827e229 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -9,14 +9,14 @@ plugins: lint: enabled: - checkov@3.2.435 - - renovate@40.34.4 + - renovate@40.36.2 - prettier@3.5.3 - - trufflehog@3.88.34 + - trufflehog@3.88.35 - yamllint@1.37.1 - bandit@1.8.3 - - trivy@0.62.1 + - trivy@0.63.0 - taplo@0.9.3 - - ruff@0.11.11 + - ruff@0.11.12 - isort@6.0.1 - markdownlint@0.45.0 - oxipng@9.1.5 From 9ce44556ceaabaf1c6cd689d6390651dcc29d3de Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 Jun 2025 06:29:41 -0500 Subject: [PATCH 16/21] chore(deps): update meshtastic/device-ui digest to 649e095 (#6943) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 095cf3b9d..ecde59de2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -108,7 +108,7 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/04e3a075dc848f49e1344c5404ccce03a1876017.zip + https://github.com/meshtastic/device-ui/archive/649e0953508ee4aabf1171519ee2eb69fb125647.zip ; Common libs for environmental measurements in telemetry module [environmental_base] From 4d81280ac25a006fb66e2e954577e607de5b7e51 Mon Sep 17 00:00:00 2001 From: Kalle Lilja <15094562+ThatKalle@users.noreply.github.com> Date: Tue, 3 Jun 2025 03:35:26 +0200 Subject: [PATCH 17/21] Add --1200bps-reset param to device-install/update scripts (#6752) * add change-mode support * add change-mode support * tab to space * fix if check * change param name to 1200bps-reset * update help section * missed one in help seciton --------- Co-authored-by: Ben Meadors --- bin/device-install.bat | 21 +++++++++++++++++++-- bin/device-install.sh | 12 +++++++++++- bin/device-update.bat | 21 +++++++++++++++++++-- bin/device-update.sh | 16 +++++++++++++--- 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/bin/device-install.bat b/bin/device-install.bat index 3ffca0b63..816d2fbba 100755 --- a/bin/device-install.bat +++ b/bin/device-install.bat @@ -12,6 +12,7 @@ SET "BIGDB16=0" SET "ESPTOOL_BAUD=115200" SET "ESPTOOL_CMD=" SET "LOGCOUNTER=0" +SET "BPS_RESET=0" @REM FIXME: Determine mcu from PlatformIO variant, this is unmaintainable. SET "S3=s3 v3 t-deck wireless-paper wireless-tracker station-g2 unphone" @@ -24,7 +25,7 @@ GOTO getopts :help ECHO Flash image file to device, but first erasing and writing system information. ECHO. -ECHO Usage: %SCRIPT_NAME% -f filename [-p PORT] [-P python] (--web) +ECHO Usage: %SCRIPT_NAME% -f filename [-p PORT] [-P python] (--web) [--1200bps-reset] ECHO. ECHO Options: ECHO -f filename The firmware .bin file to flash. Custom to your device type and region. (required) @@ -35,13 +36,16 @@ ECHO -P python Specify alternate python interpreter to use to invoke ECHO If supplied the script will use python. ECHO If not supplied the script will try to find esptool in Path. ECHO --web Enable WebUI. (default: false) +ECHO --1200bps-reset Attempt to place the device in correct mode. (1200bps Reset) +ECHO Some hardware requires this twice. ECHO. +ECHO Example: %SCRIPT_NAME% -p COM17 --1200bps-reset ECHO Example: %SCRIPT_NAME% -f firmware-t-deck-tft-2.6.0.0b106d4.bin -p COM11 ECHO Example: %SCRIPT_NAME% -f firmware-unphone-2.6.0.0b106d4.bin -p COM11 --web GOTO eof :version -ECHO %SCRIPT_NAME% [Version 2.6.1] +ECHO %SCRIPT_NAME% [Version 2.6.2] ECHO Meshtastic GOTO eof @@ -58,10 +62,13 @@ IF "%~1"=="-p" SET "ESPTOOL_PORT=%~2" & SHIFT IF /I "%~1"=="--port" SET "ESPTOOL_PORT=%~2" & SHIFT IF "%~1"=="-P" SET "PYTHON=%~2" & SHIFT IF /I "%~1"=="--web" SET "WEB_APP=1" +IF /I "%~1"=="--1200bps-reset" SET "BPS_RESET=1" SHIFT GOTO getopts :endopts +IF %BPS_RESET% EQU 1 GOTO skip-filename + CALL :LOG_MESSAGE DEBUG "Checking FILENAME parameter..." IF "__!FILENAME!__"=="____" ( CALL :LOG_MESSAGE DEBUG "Missing -f filename input." @@ -95,6 +102,9 @@ IF NOT "!FILENAME:update=!"=="!FILENAME!" ( CALL :LOG_MESSAGE DEBUG "We are NOT working with a *update* file. !FILENAME!" ) +:skip-filename +SET "ESPTOOL_BAUD=1200" + CALL :LOG_MESSAGE DEBUG "Determine the correct esptool command to use..." IF NOT "__%PYTHON%__"=="____" ( SET "ESPTOOL_CMD=!PYTHON! -m esptool" @@ -133,6 +143,12 @@ IF "__!ESPTOOL_PORT!__" == "____" ( ) CALL :LOG_MESSAGE INFO "Using esptool baud: !ESPTOOL_BAUD!." +IF %BPS_RESET% EQU 1 ( + @REM Attempt to change mode via 1200bps Reset. + CALL :RUN_ESPTOOL !ESPTOOL_BAUD! --after no_reset read_flash_status + GOTO eof +) + @REM Check if FILENAME contains "-tft-" and set target partitionScheme accordingly. @REM https://github.com/meshtastic/web-flasher/blob/main/types/resources.ts#L3 IF NOT "!FILENAME:-tft-=!"=="!FILENAME!" ( @@ -254,6 +270,7 @@ EXIT /B %ERRORLEVEL% IF %DEBUG% EQU 1 CALL :LOG_MESSAGE DEBUG "About to run command: !ESPTOOL_CMD! --baud %~1 %~2 %~3 %~4" CALL :RESET_ERROR !ESPTOOL_CMD! --baud %~1 %~2 %~3 %~4 +IF %BPS_RESET% EQU 1 GOTO :eof IF %ERRORLEVEL% NEQ 0 ( CALL :LOG_MESSAGE ERROR "Error running command: !ESPTOOL_CMD! --baud %~1 %~2 %~3 %~4" EXIT /B %ERRORLEVEL% diff --git a/bin/device-install.sh b/bin/device-install.sh index 7fa5ffdbb..76765bb5f 100755 --- a/bin/device-install.sh +++ b/bin/device-install.sh @@ -2,6 +2,7 @@ PYTHON=${PYTHON:-$(which python3 python | head -n 1)} WEB_APP=false +BPS_RESET=false TFT_BUILD=false MCU="" @@ -72,7 +73,7 @@ set -e # Usage info show_help() { cat </dev/null 2>&1; then @@ -17,14 +18,15 @@ fi # Usage info show_help() { cat << EOF -Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME] -Flash image file to device, leave existing system intact." +Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME] [--change-mode] +Flash image file to device, leave existing system intact. -h Display this help and exit -p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous). -P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON") -f FILENAME The *update.bin file to flash. Custom to your device type. - + --change-mode Attempt to place the device in correct mode. Some hardware requires this twice. (1200bps Reset) + EOF } @@ -41,6 +43,9 @@ while getopts ":hp:P:f:" opt; do ;; f) FILENAME=${OPTARG} ;; + --change-mode) + CHANGE_MODE=true + ;; *) echo "Invalid flag." show_help >&2 @@ -50,6 +55,11 @@ while getopts ":hp:P:f:" opt; do done shift "$((OPTIND-1))" +if [[ $CHANGE_MODE == true ]]; then + $ESPTOOL_CMD --baud 1200 --after no_reset read_flash_status + exit 0 +fi + [ -z "$FILENAME" -a -n "$1" ] && { FILENAME=$1 shift From a5716cf25c6ad17a1473306fac5656669c351ad5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 07:08:46 -0500 Subject: [PATCH 18/21] automated bumps (#6944) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- bin/org.meshtastic.meshtasticd.metainfo.xml | 3 +++ debian/changelog | 7 +++++-- version.properties | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/bin/org.meshtastic.meshtasticd.metainfo.xml b/bin/org.meshtastic.meshtasticd.metainfo.xml index 30f684fef..40f86fb0b 100644 --- a/bin/org.meshtastic.meshtasticd.metainfo.xml +++ b/bin/org.meshtastic.meshtasticd.metainfo.xml @@ -87,6 +87,9 @@ + + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.6.11 + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.6.10 diff --git a/debian/changelog b/debian/changelog index 87e3aea9b..4b67eecd4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -meshtasticd (2.6.10.0) UNRELEASED; urgency=medium +meshtasticd (2.6.11.0) UNRELEASED; urgency=medium [ Austin Lane ] * Initial packaging @@ -16,4 +16,7 @@ meshtasticd (2.6.10.0) UNRELEASED; urgency=medium [ ] * GitHub Actions Automatic version bump - -- Sun, 25 May 2025 20:46:49 +0000 + [ ] + * GitHub Actions Automatic version bump + + -- Mon, 02 Jun 2025 20:00:55 +0000 diff --git a/version.properties b/version.properties index 71de951f1..e13094769 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 6 -build = 10 +build = 11 From 55b2bbf93756fc7bbbfdbc7cbf29f88e6b637f22 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 4 Jun 2025 12:16:37 -0500 Subject: [PATCH 19/21] Generate keys when Lora Region is set (#6951) * Generate keys when Lora Region changes * Nest the ifs * Even more entropy * Namespacing --- src/mesh/CryptoEngine.cpp | 13 +++++++++++++ src/mesh/NodeDB.cpp | 2 +- src/modules/AdminModule.cpp | 18 ++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/mesh/CryptoEngine.cpp b/src/mesh/CryptoEngine.cpp index d32b73855..82d0a9f57 100644 --- a/src/mesh/CryptoEngine.cpp +++ b/src/mesh/CryptoEngine.cpp @@ -3,12 +3,17 @@ #include "architecture.h" #if !(MESHTASTIC_EXCLUDE_PKI) +#include "NodeDB.h" #include "aes-ccm.h" #include "meshUtils.h" #include #include +#include #include #if !(MESHTASTIC_EXCLUDE_PKI_KEYGEN) +#if !defined(ARCH_STM32WL) +#define CryptRNG RNG +#endif /** * Create a public/private key pair with Curve25519. @@ -18,6 +23,14 @@ */ void CryptoEngine::generateKeyPair(uint8_t *pubKey, uint8_t *privKey) { + // Mix in any randomness we can, to make key generation stronger. + CryptRNG.begin(optstr(APP_VERSION)); + if (myNodeInfo.device_id.size == 16) { + CryptRNG.stir(myNodeInfo.device_id.bytes, myNodeInfo.device_id.size); + } + auto noise = random(); + CryptRNG.stir((uint8_t *)&noise, sizeof(noise)); + LOG_DEBUG("Generate Curve25519 keypair"); Curve25519::dh1(public_key, private_key); memcpy(pubKey, public_key, sizeof(public_key)); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 28af7d308..0a79f94a8 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -261,7 +261,7 @@ NodeDB::NodeDB() #if !(MESHTASTIC_EXCLUDE_PKI_KEYGEN || MESHTASTIC_EXCLUDE_PKI) - if (!owner.is_licensed) { + if (!owner.is_licensed && config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_UNSET) { bool keygenSuccess = false; if (config.security.private_key.size == 32) { if (crypto->regeneratePublicKey(config.security.public_key.bytes, config.security.private_key.bytes)) { diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 3ff4fa74d..4005222dc 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -661,6 +661,24 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) config.lora = c.payload_variant.lora; // If we're setting region for the first time, init the region if (isRegionUnset && config.lora.region > meshtastic_Config_LoRaConfig_RegionCode_UNSET) { + if (!owner.is_licensed) { + bool keygenSuccess = false; + if (config.security.private_key.size == 32) { + if (crypto->regeneratePublicKey(config.security.public_key.bytes, config.security.private_key.bytes)) { + keygenSuccess = true; + } + } else { + LOG_INFO("Generate new PKI keys"); + crypto->generateKeyPair(config.security.public_key.bytes, config.security.private_key.bytes); + keygenSuccess = true; + } + if (keygenSuccess) { + config.security.public_key.size = 32; + config.security.private_key.size = 32; + owner.public_key.size = 32; + memcpy(owner.public_key.bytes, config.security.public_key.bytes, 32); + } + } config.lora.tx_enabled = true; initRegion(); if (myRegion->dutyCycle < 100) { From 76f72074632e0709c5f4f88c372c09129403e3f6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 15:15:51 -0500 Subject: [PATCH 20/21] chore(deps): update meshtastic/web to v2.6.4 (#6950) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- bin/web.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/web.version b/bin/web.version index a4db534a2..e46a05b19 100644 --- a/bin/web.version +++ b/bin/web.version @@ -1 +1 @@ -2.5.3 \ No newline at end of file +2.6.4 \ No newline at end of file From 070deb290f56735da581fb3d2225cde63d611f8d Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Thu, 5 Jun 2025 19:45:43 +0800 Subject: [PATCH 21/21] seeed_xiao_nrf52840_kit improvements (#6930) * feat: seeed_xiao_nrf52840_kit improvements - LEDs: - Change RGB LED to be active low as it is common anode - Remove re-definition of LED_PIN - Use red LED to indicate flash writes - Use blue LED as user LED (External Notification module) - GPIO: Re-word unused BUTTON_PIN comment - Wire: Set I2C pins to match XIAO nRF52840 Sense's LSM6DS3TR IMU - Battery: - Use charge LED to detect charging state - Move voltage divider boilerplate out of src/main.cpp and into initVariant() - Fix dependencies for above in related XIAO BLE DIY variants Build tested variants: - seeed_xiao_nrf52840_kit - xiao_ble - seeed-xiao-nrf52840-wio-sx1262 Flashed to and tested on hardware: - seeed_xiao_nrf52840_kit Signed-off-by: Andrew Yong * chore(seeed_xiao_nrf52840_kit): Re-order generic GPIO definitions Signed-off-by: Andrew Yong * chore: Use ADC_CTRL for XIAO nRF52840 Signed-off-by: Andrew Yong --------- Signed-off-by: Andrew Yong --- src/main.cpp | 13 --- .../variant.cpp | 9 +- .../seeed-xiao-nrf52840-wio-sx1262/variant.h | 3 +- variants/seeed_xiao_nrf52840_kit/variant.cpp | 28 ++--- variants/seeed_xiao_nrf52840_kit/variant.h | 101 +++++++++--------- variants/xiao_ble/variant.cpp | 9 +- variants/xiao_ble/variant.h | 5 +- 7 files changed, 88 insertions(+), 80 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 7a11ca2e0..2d49b2fbe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -482,19 +482,6 @@ void setup() fsInit(); -#if defined(_SEEED_XIAO_NRF52840_SENSE_H_) - - pinMode(CHARGE_LED, INPUT); // sets to detect if charge LED is on or off to see if USB is plugged in - - pinMode(HICHG, OUTPUT); - digitalWrite(HICHG, LOW); // 100 mA charging current if set to LOW and 50mA (actually about 20mA) if set to HIGH - - pinMode(BAT_READ, OUTPUT); - digitalWrite(BAT_READ, LOW); // This is pin P0_14 = 14 and by pullling low to GND it provices path to read on pin 32 (P0,31) - // PIN_VBAT the voltage from divider on XIAO board - -#endif - #if !MESHTASTIC_EXCLUDE_I2C #if defined(I2C_SDA1) && defined(ARCH_RP2040) Wire1.setSDA(I2C_SDA1); diff --git a/variants/diy/seeed-xiao-nrf52840-wio-sx1262/variant.cpp b/variants/diy/seeed-xiao-nrf52840-wio-sx1262/variant.cpp index 2c6c3e539..300f69d0b 100644 --- a/variants/diy/seeed-xiao-nrf52840-wio-sx1262/variant.cpp +++ b/variants/diy/seeed-xiao-nrf52840-wio-sx1262/variant.cpp @@ -52,4 +52,11 @@ const uint32_t g_ADigitalPinMap[] = { // VBAT 31, // D32 is P0.10 (VBAT) -}; \ No newline at end of file +}; + +void initVariant() +{ + // Set BQ25101 ISET to 100mA instead of 50mA + pinMode(HICHG, OUTPUT); + digitalWrite(HICHG, LOW); +} diff --git a/variants/diy/seeed-xiao-nrf52840-wio-sx1262/variant.h b/variants/diy/seeed-xiao-nrf52840-wio-sx1262/variant.h index 7a76727f2..277377d71 100644 --- a/variants/diy/seeed-xiao-nrf52840-wio-sx1262/variant.h +++ b/variants/diy/seeed-xiao-nrf52840-wio-sx1262/variant.h @@ -164,7 +164,8 @@ static const uint8_t SCK = PIN_SPI_SCK; // ------- // P0_14 = 14 Reads battery voltage from divider on signal board. // PIN_VBAT is reading voltage divider on XIAO and is program pin 32 / or P0.31 -#define BAT_READ 14 +#define ADC_CTRL VBAT_ENABLE +#define ADC_CTRL_ENABLED LOW #define BATTERY_SENSE_RESOLUTION_BITS 10 #define CHARGE_LED 23 // P0_17 = 17 D23 YELLOW CHARGE LED #define HICHG 22 // P0_13 = 13 D22 Charge-select pin for Lipo for 100 mA instead of default 50mA charge diff --git a/variants/seeed_xiao_nrf52840_kit/variant.cpp b/variants/seeed_xiao_nrf52840_kit/variant.cpp index 22072312a..70cadf5db 100644 --- a/variants/seeed_xiao_nrf52840_kit/variant.cpp +++ b/variants/seeed_xiao_nrf52840_kit/variant.cpp @@ -34,9 +34,9 @@ const uint32_t g_ADigitalPinMap[] = { 11, // D18 is P0.11 (6D_INT1) // MIC - 42, // 17,//42, // D19 is P1.10 (MIC_PWR) - 32, // 26,//32, // D20 is P1.00 (PDM_CLK) - 16, // 25,//16, // D21 is P0.16 (PDM_DATA) + 42, // D19 is P1.10 (MIC_PWR) + 32, // D20 is P1.00 (PDM_CLK) + 16, // D21 is P0.16 (PDM_DATA) // BQ25100 13, // D22 is P0.13 (HICHG) @@ -80,13 +80,17 @@ const uint32_t g_ADigitalPinMap[] = { void initVariant() { - // LED1 & LED2 - pinMode(21, OUTPUT); - digitalWrite(21, LOW); - // LED1 & LED2 - pinMode(22, OUTPUT); - digitalWrite(22, LOW); + // Set BQ25101 ISET to 100mA instead of 50mA + pinMode(HICHG, OUTPUT); + digitalWrite(HICHG, LOW); - pinMode(PIN_WIRE_SDA, INPUT_PULLUP); - pinMode(PIN_WIRE_SCL, INPUT_PULLUP); -} \ No newline at end of file + // LEDs + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); + + pinMode(PIN_LED3, OUTPUT); + ledOff(PIN_LED3); +} diff --git a/variants/seeed_xiao_nrf52840_kit/variant.h b/variants/seeed_xiao_nrf52840_kit/variant.h index 869c3d405..e6ef74e2e 100644 --- a/variants/seeed_xiao_nrf52840_kit/variant.h +++ b/variants/seeed_xiao_nrf52840_kit/variant.h @@ -19,31 +19,12 @@ extern "C" { #define PINS_COUNT (33) #define NUM_DIGITAL_PINS (33) -#define NUM_ANALOG_INPUTS (8) // A6 is used for battery, A7 is analog reference +#define NUM_ANALOG_INPUTS (8) #define NUM_ANALOG_OUTPUTS (0) -// LEDs - -#define LED_RED 11 -#define LED_BLUE 12 -#define LED_GREEN 13 - -#define PIN_LED1 LED_GREEN -#define PIN_LED2 LED_BLUE -#define PIN_LED3 LED_RED - -#define PIN_LED PIN_LED1 -#define LED_PWR (PINS_COUNT) - -#define LED_BUILTIN PIN_LED - -#define LED_STATE_ON 1 // State when LED is lit - /* - * Buttons + * Digital Pins */ - -// Digital PINs #define D0 (0ul) #define D1 (1ul) #define D2 (2ul) @@ -56,15 +37,6 @@ extern "C" { #define D9 (9ul) #define D10 (10ul) -/*Due to the lack of pins,and have to make sure gps standby work well we have temporarily removed the button. -There are some technical solutions that can solve this problem, -and we are currently exploring and researching them*/ - -// #define BUTTON_PIN D0 // This is the Program Button -// // #define BUTTON_NEED_PULLUP 1 -// #define BUTTON_ACTIVE_LOW true -// #define BUTTON_ACTIVE_PULLUP false - /* * Analog pins */ @@ -85,6 +57,38 @@ static const uint8_t A4 = PIN_A4; static const uint8_t A5 = PIN_A5; #define ADC_RESOLUTION 12 +/* + * LEDs + */ +#define LED_STATE_ON (0) // RGB LED is common anode +#define LED_RED (11) +#define LED_GREEN (13) +#define LED_BLUE (12) + +#define PIN_LED1 LED_GREEN // PIN_LED1 is used in src/platform/nrf52/architecture.h to define LED_PIN +#define PIN_LED2 LED_BLUE +#define PIN_LED3 LED_RED + +#define LED_BUILTIN LED_RED // LED_BUILTIN is used by framework-arduinoadafruitnrf52 to indicate flash writes + +#define LED_PWR LED_RED +#define USER_LED LED_BLUE + +/* + * Buttons + */ + +/* + * D0 is shared with PIN_GPS_STANDBY on the L76K GNSS Module. + * There are some technical solutions that can solve this problem, and we are + * currently exploring and researching them. + */ + +// #define BUTTON_PIN D0 + +/* + * Serial Interfaces + */ #define PIN_SERIAL2_RX (-1) #define PIN_SERIAL2_TX (-1) @@ -102,11 +106,9 @@ static const uint8_t MOSI = PIN_SPI_MOSI; static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t SCK = PIN_SPI_SCK; -// supported modules list #define USE_SX1262 -// common pinouts for SX126X modules - +// Pinout for SX126X #define SX126X_CS D4 #define SX126X_DIO1 D1 #define SX126X_BUSY D3 @@ -121,16 +123,19 @@ static const uint8_t SCK = PIN_SPI_SCK; /* * Wire Interfaces */ - #define I2C_NO_RESCAN // I2C is a bit finicky, don't scan too much #define WIRE_INTERFACES_COUNT 1 // 2 -#define PIN_WIRE_SDA (24) // change to use the correct pins if needed -#define PIN_WIRE_SCL (25) // change to use the correct pins if needed +// LSM6DS3TR on XIAO nRF52840 Series +#define PIN_WIRE_SDA (17) +#define PIN_WIRE_SCL (16) static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; +/* + * GPS + */ // GPS L76KB #define GPS_L76K #ifdef GPS_L76K @@ -144,20 +149,18 @@ static const uint8_t SCL = PIN_WIRE_SCL; #define PIN_GPS_STANDBY D0 #endif -// Battery +/* + * Battery + */ +#define BATTERY_PIN PIN_VBAT // P0.31: VBAT voltage divider +#define ADC_MULTIPLIER (3) // ... R17=1M, R18=510k +#define ADC_CTRL VBAT_ENABLE // P0.14: VBAT voltage divider +#define ADC_CTRL_ENABLED LOW // ... sink +#define EXT_CHRG_DETECT (23) // P0.17: Charge LED +#define EXT_CHRG_DETECT_VALUE LOW // ... BQ25101 ~CHG indicates charging +#define HICHG (22) // P0.13: BQ25101 ISET 100mA instead of 50mA -#define BAT_READ \ - 14 // P0_14 = 14 Reads battery voltage from divider on signal board. (PIN_VBAT is reading voltage divider on XIAO and is - // program pin 32 / or P0.31) -#define BATTERY_SENSE_RESOLUTION_BITS 10 -#define CHARGE_LED 23 // P0_17 = 17 D23 YELLOW CHARGE LED -#define HICHG 22 // P0_13 = 13 D22 Charge-select pin for Lipo for 100 mA instead of default 50mA charge - -// The battery sense is hooked to pin A0 (5) -#define BATTERY_PIN PIN_VBAT // PIN_A0 - -// ratio of voltage divider = 3.0 (R17=1M, R18=510k) -#define ADC_MULTIPLIER 3 // 3.0 + a bit for being optimistic +#define BATTERY_SENSE_RESOLUTION_BITS (10) #ifdef __cplusplus } diff --git a/variants/xiao_ble/variant.cpp b/variants/xiao_ble/variant.cpp index 2c6c3e539..300f69d0b 100644 --- a/variants/xiao_ble/variant.cpp +++ b/variants/xiao_ble/variant.cpp @@ -52,4 +52,11 @@ const uint32_t g_ADigitalPinMap[] = { // VBAT 31, // D32 is P0.10 (VBAT) -}; \ No newline at end of file +}; + +void initVariant() +{ + // Set BQ25101 ISET to 100mA instead of 50mA + pinMode(HICHG, OUTPUT); + digitalWrite(HICHG, LOW); +} diff --git a/variants/xiao_ble/variant.h b/variants/xiao_ble/variant.h index b46aa96ae..e511c6869 100644 --- a/variants/xiao_ble/variant.h +++ b/variants/xiao_ble/variant.h @@ -189,9 +189,8 @@ static const uint8_t SCL = PIN_WIRE_SCL; // Battery -#define BAT_READ \ - 14 // P0_14 = 14 Reads battery voltage from divider on signal board. (PIN_VBAT is reading voltage divider on XIAO and is - // program pin 32 / or P0.31) +#define ADC_CTRL VBAT_ENABLE // P0.14: VBAT voltage divider +#define ADC_CTRL_ENABLED LOW // ... sink #define BATTERY_SENSE_RESOLUTION_BITS 10 #define CHARGE_LED 23 // P0_17 = 17 D23 YELLOW CHARGE LED #define HICHG 22 // P0_13 = 13 D22 Charge-select pin for Lipo for 100 mA instead of default 50mA charge