diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 14601b058..24e11bd4d 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -4,11 +4,11 @@ This document provides context and guidelines for AI assistants working with the ## Project Overview -Meshtastic is an open-source LoRa mesh networking project for long-range, low-power communication without relying on internet or cellular infrastructure. The firmware enables text messaging, location sharing, and telemetry over a decentralized mesh network. +Meshtastic is an open-source LoRa mesh networking project for long-range, low-power communication without relying on internet or cellular infrastructure. The firmware enables text messaging, location sharing, and telemetry over a decentralized mesh network. The project uses **C++17** as its language standard across all platforms. ### Supported Hardware Platforms -- **ESP32** (ESP32, ESP32-S3, ESP32-C3) - Most common platform +- **ESP32** (ESP32, ESP32-S3, ESP32-C3, ESP32-C6) - Most common platform - **nRF52** (nRF52840, nRF52833) - Low power Nordic chips - **RP2040/RP2350** - Raspberry Pi Pico variants - **STM32WL** - STM32 with integrated LoRa @@ -80,21 +80,46 @@ firmware/ │ │ ├── NodeDB.* # Node database management │ │ ├── Router.* # Packet routing │ │ ├── Channels.* # Channel management +│ │ ├── CryptoEngine.* # AES-CCM encryption │ │ ├── *Interface.* # Radio interface implementations +│ │ ├── api/ # WiFi/Ethernet server APIs (ServerAPI, PacketAPI) +│ │ ├── http/ # HTTP server (WebServer, ContentHandler) +│ │ ├── wifi/ # WiFi support (WiFiAPClient) +│ │ ├── eth/ # Ethernet support (ethClient) +│ │ ├── udp/ # UDP multicast +│ │ ├── compression/ # Message compression (unishox2) │ │ └── generated/ # Protobuf generated code │ ├── modules/ # Feature modules (Position, Telemetry, etc.) +│ │ └── Telemetry/ # Telemetry subsystem +│ │ └── Sensor/ # 50+ I2C sensor drivers │ ├── gps/ # GPS handling │ ├── graphics/ # Display drivers and UI -│ ├── platform/ # Platform-specific code -│ ├── input/ # Input device handling -│ └── concurrency/ # Threading utilities +│ │ └── niche/ # Specialized UIs (InkHUD e-ink framework) +│ ├── platform/ # Platform-specific code (esp32, nrf52, rp2xx0, stm32wl, portduino) +│ ├── input/ # Input device handling (InputBroker, keyboards, buttons) +│ ├── detect/ # I2C hardware auto-detection (80+ device types) +│ ├── motion/ # Accelerometer drivers (BMA423, BMI270, MPU6050, etc.) +│ ├── mqtt/ # MQTT bridge client +│ ├── power/ # Power HAL +│ ├── nimble/ # BLE via NimBLE +│ ├── buzz/ # Audio/notification (buzzer, RTTTL) +│ ├── serialization/ # JSON serialization, COBS encoding +│ ├── watchdog/ # Hardware watchdog thread +│ ├── concurrency/ # Threading utilities (OSThread, Lock) +│ ├── PowerFSM.* # Power finite state machine +│ └── Observer.h # Observer/Observable event pattern ├── variants/ # Hardware variant definitions │ ├── esp32/ # ESP32 variants │ ├── esp32s3/ # ESP32-S3 variants -│ ├── nrf52/ # nRF52 variants -│ └── rp2xxx/ # RP2040/RP2350 variants +│ ├── esp32c3/ # ESP32-C3 variants +│ ├── esp32c6/ # ESP32-C6 variants +│ ├── nrf52840/ # nRF52 variants +│ ├── rp2040/ # RP2040/RP2350 variants +│ ├── stm32/ # STM32WL variants +│ └── native/ # Linux/Portduino variants ├── protobufs/ # Protocol buffer definitions ├── boards/ # Custom PlatformIO board definitions +├── test/ # Unit tests (12 test suites) └── bin/ # Build and utility scripts ``` @@ -105,6 +130,7 @@ firmware/ - Follow existing code style - run `trunk fmt` before commits - Prefer `LOG_DEBUG`, `LOG_INFO`, `LOG_WARN`, `LOG_ERROR` for logging - Use `assert()` for invariants that should never fail +- C++17 features are available (`std::optional`, structured bindings, `if constexpr`, etc.) ### Naming Conventions @@ -118,70 +144,151 @@ firmware/ #### Module System -Modules inherit from `MeshModule` or `ProtobufModule` and implement: +Modules use a three-tier class hierarchy: -- `handleReceivedProtobuf()` - Process incoming packets -- `allocReply()` - Generate response packets -- `runOnce()` - Periodic task execution (returns next run interval in ms) +1. **`MeshModule`** - Base class. Implement `wantPacket()` and `handleReceived()`. Returns `ProcessMessage::STOP` or `ProcessMessage::CONTINUE`. +2. **`SinglePortModule`** - Handles a single portnum. Simplified `wantPacket()` that checks `decoded.portnum`. +3. **`ProtobufModule`** - Template for protobuf-based modules. Handles encoding/decoding automatically. + +Most modules also inherit from **`OSThread`** for periodic tasks (the "mixin" pattern): ```cpp -class MyModule : public ProtobufModule +class MyModule : public ProtobufModule, private concurrency::OSThread { + public: + MyModule(); + protected: virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_MyMessage *msg) override; - virtual int32_t runOnce() override; + virtual meshtastic_MeshPacket *allocReply() override; // Generate response packets + virtual int32_t runOnce() override; // Periodic task (returns next interval in ms) + virtual bool alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_MyMessage *msg); // Modify in-flight + virtual bool wantUIFrame(); // Request a UI display frame }; ``` +Modules are registered in `src/modules/Modules.cpp` guarded by `MESHTASTIC_EXCLUDE_*` flags. + +#### Observer/Observable Pattern + +Event-driven communication between subsystems uses `src/Observer.h`: + +```cpp +// Observable emits events +Observable newStatus; +newStatus.notifyObservers(&status); + +// Observer receives events via callback +CallbackObserver statusObserver = + CallbackObserver(this, &MyClass::handleStatusUpdate); +``` + #### Configuration Access - `config.*` - Device configuration (LoRa, position, power, etc.) - `moduleConfig.*` - Module-specific configuration - `channels.*` - Channel configuration and management +- `owner` - Device owner info +- `myNodeInfo` - Local node info #### Default Values Use the `Default` class helpers in `src/mesh/Default.h`: - `Default::getConfiguredOrDefaultMs(configured, default)` - Returns ms, using default if configured is 0 +- `Default::getConfiguredOrDefault(configured, default)` - Generic configured/default getter - `Default::getConfiguredOrMinimumValue(configured, min)` - Enforces minimum values - `Default::getConfiguredOrDefaultMsScaled(configured, default, numNodes)` - Scales based on network size #### Thread Safety -- Use `concurrency::Lock` for mutex protection +- Use `concurrency::Lock` and `concurrency::LockGuard` for mutex protection - Radio SPI access uses `SPILock` - Prefer `OSThread` for background tasks +### Hardware Detection + +`src/detect/ScanI2C` automatically enumerates 80+ I2C device types at boot including displays, sensors, RTCs, keyboards, PMUs, and touch controllers. This drives automatic initialization of the correct drivers. + +### Graphics/UI System + +Multiple display driver families in `src/graphics/`: + +- **OLED**: SSD1306, SH1106, ST7567 +- **TFT**: TFTDisplay (LovyanGFX-based) +- **E-Ink**: EInkDisplay2, EInkDynamicDisplay, EInkParallelDisplay + +**InkHUD** (`src/graphics/niche/InkHUD/`) is an event-driven e-ink UI framework: + +- Applet-based architecture — modular display tiles +- Read-only, static display optimized for minimal refreshes and low power +- Configured per-variant via `nicheGraphics.h` +- Separate PlatformIO config: `src/graphics/niche/InkHUD/PlatformioConfig.ini` + +### Input System + +`src/input/InputBroker` is the centralized input event dispatcher. Supports multiple input sources: buttons, keyboards (BBQ10, Cardputer, TCA8418), touch screens, rotary encoders, and matrix keyboards. + +### Power Management + +`src/PowerFSM.*` implements a finite state machine with states: `stateON`, `statePOWER`, `stateSERIAL`, `stateDARK`. Key events: `EVENT_PRESS`, `EVENT_WAKE_TIMER`, `EVENT_LOW_BATTERY`, `EVENT_RECEIVED_MSG`, `EVENT_SHUTDOWN`. Conditionally excluded with `MESHTASTIC_EXCLUDE_POWER_FSM` (falls back to `FakeFsm`). + +### Motion Sensors + +`src/motion/AccelerometerThread` provides background motion monitoring with automatic screen wake and double-tap button press detection. Supports 10+ accelerometer/gyroscope chips (BMA423, BMI270, MPU6050, LIS3DH, LSM6DS3, STK8XXX, QMA6100P, ICM20948, BMX160). + +### Telemetry Sensor Library + +`src/modules/Telemetry/Sensor/` contains 50+ I2C sensor drivers organized by category: + +- **Power monitoring**: INA219/226/260/3221, MAX17048 +- **Environmental**: BME280/680, SCD4X (CO₂), SEN5X (particulate) +- **Humidity/Temperature**: SHT3X/4X, AHT10, MCP9808, MLX90614 +- **Light**: BH1750, TSL2561/2591, VEML7700, LTR390UV, OPT3001 +- **Air quality**: PMSA003I, SFA30 +- **Specialized**: CGRadSens (radiation), NAU7802 (weight scale) + +### API/Networking + +`src/mesh/api/` provides a template-based `ServerAPI` for client communication over WiFi (`WiFiServerAPI`) and Ethernet (`ethServerAPI`). Default port: **4403**. HTTP server in `src/mesh/http/`. JSON serialization in `src/serialization/MeshPacketSerializer`. + ### Hardware Variants Each hardware variant has: - `variant.h` - Pin definitions and hardware capabilities - `platformio.ini` - Build configuration -- Optional: `pins_arduino.h`, `rfswitch.h` +- Optional: `pins_arduino.h`, `rfswitch.h`, `nicheGraphics.h` (for InkHUD variants) Key defines in variant.h: ```cpp #define USE_SX1262 // Radio chip selection #define HAS_GPS 1 // Hardware capabilities +#define HAS_SCREEN 1 // Display present #define LORA_CS 36 // Pin assignments #define SX126X_DIO1 14 // Radio-specific pins ``` ### Protobuf Messages -- Defined in `protobufs/meshtastic/*.proto` -- Generated code in `src/mesh/generated/` +- Defined in `protobufs/meshtastic/*.proto` (~32 proto files) +- Generated code in `src/mesh/generated/meshtastic/` - Regenerate with `bin/regen-protos.sh` - Message types prefixed with `meshtastic_` +- Nanopb `.options` files control field sizes and encoding ### Conditional Compilation ```cpp #if !MESHTASTIC_EXCLUDE_GPS // Feature exclusion +#if !MESHTASTIC_EXCLUDE_WIFI // Network feature exclusion +#if !MESHTASTIC_EXCLUDE_BLUETOOTH // BLE exclusion +#if !MESHTASTIC_EXCLUDE_POWER_FSM // Power FSM exclusion #ifdef ARCH_ESP32 // Architecture-specific +#ifdef ARCH_NRF52 // Nordic platform +#ifdef ARCH_RP2040 // Raspberry Pi Pico +#ifdef ARCH_PORTDUINO // Linux native #if defined(USE_SX1262) // Radio-specific #ifdef HAS_SCREEN // Hardware capability #if USERPREFS_EVENT_MODE // User preferences @@ -192,7 +299,7 @@ Key defines in variant.h: Uses **PlatformIO** with custom scripts: - `bin/platformio-pre.py` - Pre-build script -- `bin/platformio-custom.py` - Custom build logic +- `bin/platformio-custom.py` - Custom build logic, manifest generation Build commands: @@ -202,21 +309,38 @@ pio run -e tbeam -t upload # Build and upload pio run -e native # Build native/Linux version ``` +### Build Manifest + +`bin/platformio-custom.py` emits a build manifest with metadata: + +- `hasMui`, `hasInkHud` - UI capability flags (overridable via `custom_meshtastic_has_mui`, `custom_meshtastic_has_ink_hud`) +- Architecture normalization (e.g., `esp32s3` → `esp32-s3` for API compatibility) + ## Common Tasks ### Adding a New Module 1. Create `src/modules/MyModule.cpp` and `.h` -2. Inherit from appropriate base class -3. Register in `src/modules/Modules.cpp` -4. Add protobuf messages if needed in `protobufs/` +2. Inherit from appropriate base class (`MeshModule`, `SinglePortModule`, or `ProtobufModule`) +3. Mix in `concurrency::OSThread` if periodic work is needed +4. Register in `src/modules/Modules.cpp` guarded by `#if !MESHTASTIC_EXCLUDE_MYMODULE` +5. Add protobuf messages if needed in `protobufs/meshtastic/` +6. Add test suite in `test/test_mymodule/` if applicable ### Adding a New Hardware Variant 1. Create directory under `variants///` -2. Add `variant.h` with pin definitions -3. Add `platformio.ini` with build config -4. Reference common configs with `extends` +2. Add `variant.h` with pin definitions and hardware capability defines +3. Add `platformio.ini` with build config — use `extends` to reference common base (e.g., `esp32s3_base`) +4. Set `custom_meshtastic_support_level = 1` (PR builds) or `2` (merge builds) +5. For e-ink displays, add `nicheGraphics.h` for InkHUD configuration + +### Adding a New Telemetry Sensor + +1. Create driver in `src/modules/Telemetry/Sensor/` following existing sensor pattern +2. Register I2C address in `src/detect/ScanI2C` for auto-detection +3. Integrate with the appropriate telemetry module (Environment, Health, Power, AirQuality) +4. Add proto fields in `protobufs/meshtastic/telemetry.proto` if new data types are needed ### Modifying Configuration Defaults @@ -305,9 +429,22 @@ Most workflows can be triggered manually via `workflow_dispatch` for testing. ## Testing -- Unit tests in `test/` directory -- Run with `pio test -e native` -- Use `bin/test-simulator.sh` for simulation testing +Unit tests in `test/` directory with 12 test suites: + +- `test_crypto/` - Cryptography +- `test_mqtt/` - MQTT integration +- `test_radio/` - Radio interface +- `test_mesh_module/` - Module framework +- `test_meshpacket_serializer/` - Packet serialization +- `test_transmit_history/` - Retransmission tracking +- `test_atak/` - ATAK integration +- `test_default/` - Default configuration +- `test_http_content_handler/` - HTTP handling +- `test_serial/` - Serial communication + +Run with: `pio test -e native` + +Simulation testing: `bin/test-simulator.sh` ## Resources diff --git a/.github/prompts/new-module.prompt.md b/.github/prompts/new-module.prompt.md new file mode 100644 index 000000000..8569a622c --- /dev/null +++ b/.github/prompts/new-module.prompt.md @@ -0,0 +1,138 @@ +# New Meshtastic Module + +Guide for developing a new Meshtastic firmware module. + +## Module Hierarchy + +Choose the appropriate base class: + +1. **`MeshModule`** — Raw base class. Override `wantPacket()` and `handleReceived()`. Returns `ProcessMessage::STOP` or `ProcessMessage::CONTINUE`. +2. **`SinglePortModule`** — Handles a single `meshtastic_PortNum`. Constructor takes `(name, portNum)`. Simplified `wantPacket()` checking `decoded.portnum`. Use `allocDataPacket()` to create outgoing packets. +3. **`ProtobufModule`** — Template for protobuf-encoded modules. Constructor takes `(name, portNum, fields)`. Override `handleReceivedProtobuf()`. Use `allocDataProtobuf(payload)` to create outgoing packets. + +Most modules also mix in `concurrency::OSThread` for periodic background tasks. + +## Implementation Pattern + +```cpp +// src/modules/MyModule.h +#pragma once +#include "ProtobufModule.h" +#include "concurrency/OSThread.h" + +class MyModule : public ProtobufModule, private concurrency::OSThread +{ + public: + MyModule(); + + protected: + // Process incoming protobuf packet. Return true to stop further processing. + virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_MyMessage *msg) override; + + // Generate response packet (optional) + virtual meshtastic_MeshPacket *allocReply() override; + + // Periodic task — return next run interval in ms, or disable() + virtual int32_t runOnce() override; + + // Modify packet in-flight before delivery (optional) + virtual bool alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_MyMessage *msg); + + // Request a UI display frame (optional) + virtual bool wantUIFrame(); +}; +``` + +## Registration + +Register in `src/modules/Modules.cpp` inside `setupModules()`: + +```cpp +#if !MESHTASTIC_EXCLUDE_MYMODULE + new MyModule(); +#endif +``` + +If other code needs to reference the module instance: + +```cpp +#if !MESHTASTIC_EXCLUDE_MYMODULE + myModule = new MyModule(); +#endif +``` + +And declare the global in the header: + +```cpp +extern MyModule *myModule; +``` + +Some modules also conditionally instantiate based on `moduleConfig`: + +```cpp +#if !MESHTASTIC_EXCLUDE_MYMODULE + if (moduleConfig.has_my_module && moduleConfig.my_module.enabled) { + new MyModule(); + } +#endif +``` + +## Conditional Compilation + +Add a `MESHTASTIC_EXCLUDE_MYMODULE` guard. This allows the module to be excluded from constrained builds. The flag name must follow the pattern: `MESHTASTIC_EXCLUDE_` + uppercase module name. + +## Protobuf Messages (if needed) + +1. Define messages in `protobufs/meshtastic/` (e.g., `mymodule.proto`) +2. Add a `.options` file for nanopb field size constraints +3. Regenerate with `bin/regen-protos.sh` +4. Generated code appears in `src/mesh/generated/meshtastic/` +5. Assign a `meshtastic_PortNum` if the module uses a new port number + +## Timing and Defaults + +Use `Default` class helpers for configurable intervals: + +```cpp +int32_t MyModule::runOnce() +{ + uint32_t interval = Default::getConfiguredOrDefaultMs(moduleConfig.my_module.update_interval, + default_my_module_interval); + // ... do work ... + return interval; +} +``` + +On public/default channels, enforce minimums with `Default::getConfiguredOrMinimumValue()`. + +## Observer Pattern + +Subscribe to system events: + +```cpp +CallbackObserver statusObserver = + CallbackObserver(this, &MyModule::handleStatusUpdate); +``` + +## Testing + +Add test suite in `test/test_mymodule/`: + +``` +test/ +└── test_mymodule/ + └── test_main.cpp +``` + +Run with: `pio test -e native` + +## Checklist + +- [ ] Header and implementation files in `src/modules/` +- [ ] Inherit from appropriate base class (MeshModule / SinglePortModule / ProtobufModule) +- [ ] Mix in OSThread if periodic work is needed +- [ ] Register in `src/modules/Modules.cpp` with `MESHTASTIC_EXCLUDE_` guard +- [ ] Add protobuf definitions if needed (`protobufs/meshtastic/`) +- [ ] Use `Default::getConfiguredOrDefaultMs()` for timing +- [ ] Respect bandwidth limits on public channels +- [ ] Add test suite in `test/` diff --git a/.github/prompts/new-sensor.prompt.md b/.github/prompts/new-sensor.prompt.md new file mode 100644 index 000000000..e02fc2462 --- /dev/null +++ b/.github/prompts/new-sensor.prompt.md @@ -0,0 +1,149 @@ +# New Telemetry Sensor + +Guide for adding a new I2C telemetry sensor driver to Meshtastic firmware. + +## Overview + +Telemetry sensors live in `src/modules/Telemetry/Sensor/`. There are 50+ existing drivers organized by measurement type. Each sensor integrates with one of the telemetry modules: + +- **EnvironmentTelemetryModule** — Temperature, humidity, pressure, gas, light +- **AirQualityTelemetryModule** — Particulate matter, VOCs +- **PowerTelemetryModule** — Voltage, current, power monitoring +- **HealthTelemetryModule** — Heart rate, SpO2, body temperature + +## Sensor Driver Pattern + +Each sensor has a `.h` and `.cpp` file pair following this pattern: + +```cpp +// src/modules/Telemetry/Sensor/MySensor.h +#pragma once +#include "TelemetrySensor.h" +#include // Arduino/PlatformIO library + +class MySensor : virtual public TelemetrySensor +{ + private: + MySensorLibrary sensor; + + public: + MySensor() : TelemetrySensor(meshtastic_TelemetrySensorType_MY_SENSOR, "MySensor") {} + + // Initialize sensor hardware. Return true on success. + virtual void setup() override; + + // Read sensor data into the telemetry protobuf. Return true on success. + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; +}; +``` + +```cpp +// src/modules/Telemetry/Sensor/MySensor.cpp +#include "MySensor.h" +#include "TelemetrySensor.h" + +void MySensor::setup() +{ + sensor.begin(); + // Configure sensor parameters... +} + +bool MySensor::getMetrics(meshtastic_Telemetry *measurement) +{ + // Read from hardware + float value = sensor.readValue(); + + // Populate the appropriate protobuf variant + measurement->variant.environment_metrics.temperature = value; + // ... other fields ... + + return true; +} +``` + +## I2C Address Registration + +Register the sensor's I2C address(es) in `src/detect/ScanI2C` so it's auto-detected at boot: + +1. Add a `DeviceType` enum entry in `src/detect/ScanI2C.h` +2. Add the I2C address mapping in `src/detect/ScanI2CTwoWire.cpp` + +The scan runs at boot and populates a device map that telemetry modules use to decide which sensors to initialize. + +## Protobuf Fields + +If the sensor provides data not covered by existing telemetry fields: + +1. Add fields to the appropriate message in `protobufs/meshtastic/telemetry.proto`: + - `EnvironmentMetrics` — Environmental measurements + - `AirQualityMetrics` — Air quality data + - `PowerMetrics` — Power/energy data + - `HealthMetrics` — Health/biometric data +2. Add a `.options` constraint if needed (field sizes for nanopb) +3. Regenerate: `bin/regen-protos.sh` + +## Sensor Type Enum + +Add the sensor to `meshtastic_TelemetrySensorType` enum in `protobufs/meshtastic/telemetry.proto`: + +```protobuf +enum TelemetrySensorType { + // ... existing entries ... + MY_SENSOR = XX; +} +``` + +## Integration with Telemetry Module + +Wire the sensor into the appropriate telemetry module. For environment sensors, this is typically in `src/modules/Telemetry/EnvironmentTelemetry.cpp`: + +1. Include the sensor header +2. Add initialization in `setupSensor()` guarded by detection results +3. Call `getMetrics()` in the measurement collection path + +Example pattern from existing sensors: + +```cpp +#include "Sensor/MySensor.h" + +MySensor mySensor; + +// In setup: +if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MY_SENSOR].first > 0) { + mySensor.setup(); +} + +// In measurement collection: +if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MY_SENSOR].first > 0) { + mySensor.getMetrics(&measurement); +} +``` + +## Library Dependencies + +If the sensor needs an external library, add it to the `lib_deps` in the relevant base platformio.ini configs: + +```ini +lib_deps = + ${env.lib_deps} + mysensorlibrary@^1.0.0 +``` + +Or use a conditional dependency if it's platform-specific. + +## Unit Conversions + +If the sensor reports values in non-standard units, use `src/modules/Telemetry/UnitConversions.h` for conversion helpers (e.g., Celsius ↔ Fahrenheit, hPa ↔ inHg). + +## Checklist + +- [ ] Create `src/modules/Telemetry/Sensor/MySensor.h` and `.cpp` +- [ ] Inherit from `TelemetrySensor` base class +- [ ] Implement `setup()` and `getMetrics()` methods +- [ ] Add `meshtastic_TelemetrySensorType` enum entry in `telemetry.proto` +- [ ] Add I2C address to `src/detect/ScanI2C` for auto-detection +- [ ] Add protobuf fields in `telemetry.proto` if new data types needed +- [ ] Regenerate protos: `bin/regen-protos.sh` +- [ ] Wire into the appropriate telemetry module (Environment/AirQuality/Power/Health) +- [ ] Add library dependency if external library required +- [ ] Test on hardware or native build diff --git a/.github/prompts/new-variant.prompt.md b/.github/prompts/new-variant.prompt.md new file mode 100644 index 000000000..1a324cea9 --- /dev/null +++ b/.github/prompts/new-variant.prompt.md @@ -0,0 +1,178 @@ +# New Hardware Variant + +Guide for adding a new Meshtastic hardware variant to the firmware. + +## Directory Structure + +Create under `variants///`: + +``` +variants/ +├── esp32/ # ESP32 +├── esp32s3/ # ESP32-S3 +├── esp32c3/ # ESP32-C3 +├── esp32c6/ # ESP32-C6 +├── nrf52840/ # nRF52840 +├── rp2040/ # RP2040/RP2350 +├── stm32/ # STM32WL +└── native/ # Linux/Portduino +``` + +Each variant needs at minimum: + +- `variant.h` — Pin definitions and hardware capabilities +- `platformio.ini` — Build configuration + +Optional files: + +- `pins_arduino.h` — Arduino pin mapping overrides +- `rfswitch.h` — RF switch control for multi-band radios +- `nicheGraphics.h` — InkHUD e-ink configuration + +## variant.h Template + +```cpp +// Pin definitions +#define I2C_SDA 21 +#define I2C_SCL 22 + +// LoRa radio +#define USE_SX1262 // Radio chip: USE_SX1262, USE_SX1268, USE_SX1280, USE_RF95, USE_LLCC68, USE_LR1110, USE_LR1120, USE_LR1121 +#define LORA_CS 18 +#define LORA_SCK 5 +#define LORA_MOSI 27 +#define LORA_MISO 19 +#define LORA_DIO1 33 // SX126x: DIO1, SX128x: DIO1, RF95: IRQ +#define LORA_RESET 23 +#define LORA_BUSY 32 // SX126x/SX128x only +#define SX126X_DIO2_AS_RF_SWITCH // Common for SX1262 boards + +// GPS +#define HAS_GPS 1 +#define GPS_RX_PIN 34 +#define GPS_TX_PIN 12 +// #define PIN_GPS_EN 47 // Optional GPS enable pin +// #define GPS_BAUDRATE 9600 // Override default 9600 + +// Display +#define HAS_SCREEN 1 +// #define USE_SSD1306 // OLED type +// #define USE_SH1106 // Alternative OLED +// #define USE_ST7789 // TFT type +// #define SCREEN_WIDTH 128 +// #define SCREEN_HEIGHT 64 + +// LEDs +#define LED_PIN 2 // Status LED (optional) +// #define HAS_NEOPIXEL 1 // WS2812 support + +// Buttons +#define BUTTON_PIN 38 +// #define BUTTON_PIN_ALT 0 // Secondary button + +// Power management +// #define HAS_AXP192 1 // AXP192 PMU (T-Beam v1.0) +// #define HAS_AXP2101 1 // AXP2101 PMU (T-Beam v1.2+) +// #define BATTERY_PIN 35 // ADC battery voltage pin +// #define ADC_MULTIPLIER 2.0 // Voltage divider ratio + +// Optional I2C devices +// #define HAS_RTC 1 // Real-time clock +// #define HAS_TELEMETRY 1 // Enable telemetry sensor support +// #define HAS_SENSOR 1 // I2C sensors present +``` + +## platformio.ini Template + +```ini +[env:my_variant] +extends = esp32s3_base ; Use architecture-specific base +board = esp32-s3-devkitc-1 ; PlatformIO board definition (or custom in boards/) +board_level = extra ; Build level: extra, or omit for default +custom_meshtastic_support_level = 1 ; 1 = PR builds, 2 = merge builds only + +build_flags = + ${esp32s3_base.build_flags} + -D MY_VARIANT_SPECIFIC_FLAG=1 + -I variants/esp32s3/my_variant ; Include path for variant.h + +upload_speed = 921600 +``` + +### Common Base Configs + +- `esp32_base` / `esp32-common.ini` — ESP32 +- `esp32s3_base` — ESP32-S3 +- `esp32c3_base` — ESP32-C3 +- `esp32c6_base` — ESP32-C6 +- `nrf52840_base` / `nrf52.ini` — nRF52840 +- `rp2040_base` — RP2040/RP2350 + +### Support Levels + +- `custom_meshtastic_support_level = 1` — Built on every PR (actively supported) +- `custom_meshtastic_support_level = 2` — Built only on merge to main branches +- `board_level = extra` — Only built on full releases + +## Build Manifest Metadata + +`bin/platformio-custom.py` emits UI capability flags in the build manifest: + +- `custom_meshtastic_has_mui = true/false` — Override MUI detection +- `custom_meshtastic_has_ink_hud = true/false` — Override InkHUD detection +- Architecture names are normalized (e.g., `esp32s3` → `esp32-s3`) + +## InkHUD E-Ink Variants + +For e-ink display variants using the InkHUD framework, add `nicheGraphics.h`: + +```cpp +// nicheGraphics.h — InkHUD configuration for this variant +#define INKHUD // Enable InkHUD +// Configure display, applets, and refresh behavior per device +``` + +InkHUD has its own PlatformIO config: `src/graphics/niche/InkHUD/PlatformioConfig.ini` + +## I2C Device Detection + +If the variant has I2C devices, ensure `src/detect/ScanI2C` will detect them. The auto-detection system handles 80+ device types including displays, sensors, RTCs, keyboards, PMUs, and touch controllers at boot. + +## Custom Board Definitions + +If the PlatformIO board doesn't exist, create a custom board JSON in `boards/`: + +```json +{ + "build": { + "arduino": { "ldscript": "esp32s3_out.ld" }, + "core": "esp32", + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "mcu": "esp32s3", + "variant": "esp32s3" + }, + "connectivity": ["wifi", "bluetooth"], + "frameworks": ["arduino", "espidf"], + "name": "My Custom Board", + "upload": { + "flash_size": "8MB", + "maximum_ram_size": 327680, + "maximum_size": 8388608 + }, + "url": "https://example.com", + "vendor": "MyVendor" +} +``` + +## Checklist + +- [ ] Create `variants///variant.h` with pin definitions +- [ ] Create `variants///platformio.ini` extending correct base +- [ ] Set `custom_meshtastic_support_level` (1 or 2) +- [ ] Verify radio chip define matches hardware (`USE_SX1262`, etc.) +- [ ] Set hardware capability flags (`HAS_GPS`, `HAS_SCREEN`, etc.) +- [ ] Add custom board JSON in `boards/` if needed +- [ ] Test build: `pio run -e my_variant` +- [ ] For e-ink: add `nicheGraphics.h` with InkHUD config diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index f0b16a31f..88395600a 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -301,10 +301,12 @@ jobs: id: release_notes run: | chmod +x ./bin/generate_release_notes.py - NOTES=$(./bin/generate_release_notes.py ${{ needs.version.outputs.long }}) + NOTES=$(./bin/generate_release_notes.py ${{ needs.version.outputs.long }} --compare-ref HEAD 2>release_notes.log) echo "notes<> $GITHUB_OUTPUT echo "$NOTES" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT + echo "### Release note range" >> $GITHUB_STEP_SUMMARY + cat release_notes.log >> $GITHUB_STEP_SUMMARY env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -466,7 +468,7 @@ jobs: - name: Generate release notes run: | chmod +x ./bin/generate_release_notes.py - ./bin/generate_release_notes.py ${{ needs.version.outputs.long }} > ./publish/release_notes.md + ./bin/generate_release_notes.py ${{ needs.version.outputs.long }} --compare-ref HEAD > ./publish/release_notes.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/bin/config.d/lora-luckfox-pico-max-ws-raspberry-pi-pico-hat.yaml b/bin/config.d/lora-luckfox-pico-max-ws-raspberry-pi-pico-hat.yaml new file mode 100644 index 000000000..e0cc6197b --- /dev/null +++ b/bin/config.d/lora-luckfox-pico-max-ws-raspberry-pi-pico-hat.yaml @@ -0,0 +1,31 @@ +# For use with Armbian luckfox-pico-max +# Waveshare LoRa HAT for Raspberry Pi Pico +# https://www.waveshare.com/wiki/Pico-LoRa-SX1262 + +Meta: + name: luckfox-pico-max-ws-raspberry-pi-pico-hat + support: community + compatible: + - luckfox-pico-max # Armbian + +Lora: + Module: sx1262 + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true + spidev: spidev0.0 + Busy: # GPIO1_C7 / GP2 + pin: 55 + gpiochip: 1 + line: 23 + CS: # GPIO1_C6 / GP3 + pin: 54 + gpiochip: 1 + line: 22 + Reset: # GPIO1_D1 / GP15 + pin: 57 + gpiochip: 1 + line: 25 + IRQ: # GPIO2_A2 / GP20 + pin: 66 + gpiochip: 2 + line: 2 diff --git a/bin/generate_release_notes.py b/bin/generate_release_notes.py index d0f1147da..533ff6909 100755 --- a/bin/generate_release_notes.py +++ b/bin/generate_release_notes.py @@ -1,25 +1,31 @@ #!/usr/bin/env python3 -""" -Generate release notes from merged PRs on develop and master branches. -Categorizes PRs into Enhancements and Bug Fixes/Maintenance sections. -""" +"""Generate release notes from the actual release commit range.""" -import subprocess -import re +import argparse import json +import re +import subprocess import sys -from datetime import datetime -def get_last_release_tag(): - """Get the most recent release tag.""" +def get_last_release_tag(compare_ref, exclude_tag=None): + """Get the most recent version tag merged into compare_ref.""" result = subprocess.run( - ["git", "describe", "--tags", "--abbrev=0"], + ["git", "tag", "--merged", compare_ref, "--sort=-version:refname", "v*"], capture_output=True, text=True, check=True, ) - return result.stdout.strip() + + for line in result.stdout.splitlines(): + candidate = line.strip() + if not candidate: + continue + if exclude_tag and candidate == exclude_tag: + continue + return candidate + + raise subprocess.CalledProcessError(result.returncode, result.args, output=result.stdout, stderr=result.stderr) def get_tag_date(tag): @@ -33,18 +39,18 @@ def get_tag_date(tag): return result.stdout.strip() -def get_merged_prs_since_tag(tag, branch): - """Get all merged PRs since the given tag on the specified branch.""" - # Get commits since tag on the branch - look for PR numbers in parentheses +def get_merged_prs_in_range(tag, compare_ref): + """Get all merged PRs in the git range between tag and compare_ref.""" result = subprocess.run( [ "git", "log", - f"{tag}..origin/{branch}", + f"{tag}..{compare_ref}", "--oneline", ], capture_output=True, text=True, + check=True, ) prs = [] @@ -65,6 +71,25 @@ def get_merged_prs_since_tag(tag, branch): return prs +def parse_args(): + """Parse CLI arguments.""" + parser = argparse.ArgumentParser( + description="Generate release notes from the actual release commit range." + ) + parser.add_argument("new_version", help="Version that will be tagged for this release") + parser.add_argument( + "--base-tag", + dest="base_tag", + help="Existing version tag to diff from. Defaults to the latest version tag merged into the compare ref.", + ) + parser.add_argument( + "--compare-ref", + default="HEAD", + help="Git ref to diff to. Defaults to HEAD.", + ) + return parser.parse_args() + + def get_pr_details(pr_number): """Get PR details from GitHub API via gh CLI.""" try: @@ -268,28 +293,28 @@ def get_new_contributors(pr_details_list, tag, repo="meshtastic/firmware"): def main(): - if len(sys.argv) < 2: - print("Usage: generate_release_notes.py ", file=sys.stderr) - sys.exit(1) - - new_version = sys.argv[1] + args = parse_args() + new_version = args.new_version + compare_ref = args.compare_ref + current_tag = f"v{new_version}" # Get last release tag try: - last_tag = get_last_release_tag() + last_tag = args.base_tag or get_last_release_tag(compare_ref, exclude_tag=current_tag) except subprocess.CalledProcessError: print("Error: Could not find last release tag", file=sys.stderr) sys.exit(1) - # Collect PRs from both branches - all_pr_numbers = set() + print( + f"Resolved release note range: {last_tag}..{compare_ref}", + file=sys.stderr, + ) - for branch in ["develop", "master"]: - try: - prs = get_merged_prs_since_tag(last_tag, branch) - all_pr_numbers.update(prs) - except Exception as e: - print(f"Warning: Could not get PRs from {branch}: {e}", file=sys.stderr) + try: + all_pr_numbers = set(get_merged_prs_in_range(last_tag, compare_ref)) + except subprocess.CalledProcessError as e: + print(f"Error: Could not get PRs for range {last_tag}..{compare_ref}: {e}", file=sys.stderr) + sys.exit(1) # Get details for all PRs enhancements = [] diff --git a/bin/org.meshtastic.meshtasticd.metainfo.xml b/bin/org.meshtastic.meshtasticd.metainfo.xml index 0642fdb07..a1690186b 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.7.23 + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.22 diff --git a/debian/changelog b/debian/changelog index b13a2ae9d..c3f1424a5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +meshtasticd (2.7.23.0) unstable; urgency=medium + + * Version 2.7.23 + + -- GitHub Actions Tue, 14 Apr 2026 12:29:48 +0000 + meshtasticd (2.7.22.0) unstable; urgency=medium * Version 2.7.22 diff --git a/platformio.ini b/platformio.ini index 46170fe09..0205d1ad8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -56,9 +56,7 @@ build_flags = -Wno-missing-field-initializers -DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware -DMESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE=1 -DMESHTASTIC_EXCLUDE_POWERMON=1 - -DMESHTASTIC_EXCLUDE_STATUS=1 -D MAX_THREADS=40 ; As we've split modules, we have more threads to manage - -DLED_BUILTIN=-1 #-DBUILD_EPOCH=$UNIX_TIME ; set in platformio-custom.py now #-D OLED_PL=1 #-D DEBUG_HEAP=1 ; uncomment to add free heap space / memory leak debugging logs @@ -126,7 +124,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/1897dd17fceb1f101bb1a3245680aa3439edcfdd.zip + https://github.com/meshtastic/device-ui/archive/5305670b68eb5b92d14e62b5b536969ca4bb441f.zip ; Common libs for environmental measurements in telemetry module [environmental_base] diff --git a/protobufs b/protobufs index 940ac382a..e30092e61 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 940ac382a7d143040da5a880237f84c48ee31f2b +Subproject commit e30092e6168b13341c2b7ec4be19c789ad5cd77f diff --git a/src/MessageStore.h b/src/MessageStore.h index 6203d8ed0..77271f1c9 100644 --- a/src/MessageStore.h +++ b/src/MessageStore.h @@ -21,8 +21,15 @@ // How many messages are stored (RAM + flash). // Define -DMESSAGE_HISTORY_LIMIT=N in build_flags to control memory usage. #ifndef MESSAGE_HISTORY_LIMIT +#if defined(ARCH_ESP32) && \ + !(defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32S2)) +// Baseline ESP32 (non-PSRAM variants) has limited heap; reduce message history on resource-constrained builds. +// Override with -DMESSAGE_HISTORY_LIMIT=N if needed. +#define MESSAGE_HISTORY_LIMIT 10 +#else #define MESSAGE_HISTORY_LIMIT 20 #endif +#endif // Internal alias used everywhere in code – do NOT redefine elsewhere. #define MAX_MESSAGES_SAVED MESSAGE_HISTORY_LIMIT diff --git a/src/Power.cpp b/src/Power.cpp index d82c870ed..26b961525 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -40,6 +40,22 @@ #include "concurrency/LockGuard.h" #endif +#if defined(ARCH_STM32WL) && defined(BATTERY_PIN) +#include "stm32yyxx_ll_adc.h" + +/* Analog read resolution */ +#if defined(LL_ADC_RESOLUTION_12B) +#define LL_ADC_RESOLUTION LL_ADC_RESOLUTION_12B +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#elif defined(LL_ADC_DS_DATA_WIDTH_12_BIT) +#define LL_ADC_RESOLUTION LL_ADC_DS_DATA_WIDTH_12_BIT +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#else +#error "ADC resolution could not be defined!" +#endif +#define ADC_RANGE (1 << BATTERY_SENSE_RESOLUTION_BITS) +#endif + #if defined(DEBUG_HEAP_MQTT) && !MESHTASTIC_EXCLUDE_MQTT #include "mqtt/MQTT.h" #include "target_specific.h" @@ -328,11 +344,17 @@ class AnalogBatteryLevel : public HasBatteryLevel float scaled = 0; battery_adcEnable(); -#ifdef ARCH_ESP32 // ADC block for espressif platforms +#ifdef ARCH_STM32WL + // STM32 ADC with VREFINT runtime calibration + Vref = __LL_ADC_CALC_VREFANALOG_VOLTAGE(analogRead(AVREF), LL_ADC_RESOLUTION); + raw = analogRead(BATTERY_PIN); + scaled = __LL_ADC_CALC_DATA_TO_VOLTAGE(Vref, raw, LL_ADC_RESOLUTION); + scaled *= operativeAdcMultiplier; +#elif defined(ARCH_ESP32) // ADC block for espressif platforms raw = espAdcRead(); scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs); scaled *= operativeAdcMultiplier; -#else // block for all other platforms +#else // block for all other platforms #ifdef ARCH_NRF52 concurrency::LockGuard saadcGuard(concurrency::nrf52SaadcLock); #endif @@ -530,6 +552,11 @@ class AnalogBatteryLevel : public HasBatteryLevel bool initial_read_done = false; float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS); uint32_t last_read_time_ms = 0; +#ifdef ARCH_STM32WL + // 3300mV placeholder for STM32 errata where VREFINT factory calibration may be missing + // (e.g. STM32U0, see DS14756 Rev 3 §2.4.1 "VREFINT offset") + uint32_t Vref = 3300; +#endif #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(HAS_RAKPROT) @@ -639,7 +666,9 @@ bool Power::analogInit() #define BATTERY_SENSE_RESOLUTION_BITS 10 #endif -#ifdef ARCH_ESP32 // ESP32 needs special analog stuff +#ifdef ARCH_STM32WL + analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS); +#elif defined(ARCH_ESP32) // ESP32 needs special analog stuff #ifndef ADC_WIDTH // max resolution by default static const adc_bits_width_t width = ADC_WIDTH_BIT_12; @@ -649,7 +678,7 @@ bool Power::analogInit() #ifndef BAT_MEASURE_ADC_UNIT // ADC1 adc1_config_width(width); adc1_config_channel_atten(adc_channel, atten); -#else // ADC2 +#else // ADC2 adc2_config_channel_atten(adc_channel, atten); #ifndef CONFIG_IDF_TARGET_ESP32S3 // ADC2 wifi bug workaround @@ -679,7 +708,7 @@ bool Power::analogInit() // NRF52 ADC init moved to powerHAL_init in nrf52 platform -#ifndef ARCH_ESP32 +#if !defined(ARCH_ESP32) && !defined(ARCH_STM32WL) analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS); #endif diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 55ec93db5..fa9d98a0e 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1197,7 +1197,7 @@ void Screen::setFrames(FrameFocus focus) for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) { const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i); if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) { - favoriteFrames.push_back(graphics::UIRenderer::drawNodeInfo); + favoriteFrames.push_back(graphics::UIRenderer::drawFavoriteNode); } } @@ -1226,7 +1226,7 @@ void Screen::setFrames(FrameFocus focus) static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback}; ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0])); - prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list just changed) + prevFrame = -1; // Force drawFavoriteNode to pick a new node (because our list just changed) // Focus on a specific frame, in the frame set we just created switch (focus) { diff --git a/src/graphics/draw/MessageRenderer.cpp b/src/graphics/draw/MessageRenderer.cpp index 501a7ae2c..2fd9bf541 100644 --- a/src/graphics/draw/MessageRenderer.cpp +++ b/src/graphics/draw/MessageRenderer.cpp @@ -422,6 +422,17 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 std::vector isMine; // track alignment std::vector isHeader; // track header lines std::vector ackForLine; + // Hard limit on total cached lines to prevent unbounded growth from a single long message. + // Reserve to the actual cache cap up front, because a single message can expand to many more + // wrapped display lines than a small per-message estimate would predict. For a display + // rendering only ~5-30 lines at a time, caching more than this limit wastes heap. Stop + // appending once we reach MAX_CACHED_LINES to prevent a single message from blowing out the + // heap. + constexpr size_t MAX_CACHED_LINES = 100U; // ~5-6KB for std::string overhead on 32-bit (if each ~50-60 bytes avg) + allLines.reserve(MAX_CACHED_LINES); + isMine.reserve(MAX_CACHED_LINES); + isHeader.reserve(MAX_CACHED_LINES); + ackForLine.reserve(MAX_CACHED_LINES); for (auto it = filtered.rbegin(); it != filtered.rend(); ++it) { const auto &m = *it; @@ -565,16 +576,23 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 int wrapWidth = mine ? rightTextWidth : leftTextWidth; std::vector wrapped = generateLines(display, "", msgText, wrapWidth); + // Per-message wrap-line limit: even if wrapping produces many lines, cap them to prevent + // a single long message from consuming most or all of the cache. + constexpr size_t MAX_WRAPPED_LINES_PER_MSG = 20U; + size_t wrappedCount = 0; for (auto &ln : wrapped) { - allLines.push_back(ln); + if (allLines.size() >= MAX_CACHED_LINES || wrappedCount >= MAX_WRAPPED_LINES_PER_MSG) + break; // Cache limit or per-message limit reached; stop adding lines from this message + allLines.emplace_back(std::move(ln)); isMine.push_back(mine); isHeader.push_back(false); ackForLine.push_back(AckStatus::NONE); + ++wrappedCount; } } // Cache lines and heights - cachedLines = allLines; + cachedLines.swap(allLines); cachedHeights = calculateLineHeights(cachedLines, emotes, isHeader); std::vector blocks = buildMessageBlocks(isHeader, isMine); diff --git a/src/graphics/draw/NodeListRenderer.cpp b/src/graphics/draw/NodeListRenderer.cpp index 98644ee3b..654c27222 100644 --- a/src/graphics/draw/NodeListRenderer.cpp +++ b/src/graphics/draw/NodeListRenderer.cpp @@ -3,6 +3,9 @@ #include "CompassRenderer.h" #include "NodeDB.h" #include "NodeListRenderer.h" +#if !MESHTASTIC_EXCLUDE_STATUS +#include "modules/StatusMessageModule.h" +#endif #include "UIRenderer.h" #include "gps/GeoCoord.h" #include "gps/RTC.h" // for getTime() function @@ -92,8 +95,41 @@ std::string getSafeNodeName(OLEDDisplay *display, meshtastic_NodeInfoLite *node, // 1) Choose target candidate (long vs short) only if present const char *raw = nullptr; - if (node && node->has_user) { - raw = config.display.use_long_node_name ? node->user.long_name : node->user.short_name; + +#if !MESHTASTIC_EXCLUDE_STATUS + // If long-name mode is enabled, and we have a recent status for this node, + // prefer "(short_name) statusText" as the raw candidate. + std::string composedFromStatus; + if (config.display.use_long_node_name && node && node->has_user && statusMessageModule) { + const auto &recent = statusMessageModule->getRecentReceived(); + const StatusMessageModule::RecentStatus *found = nullptr; + for (auto it = recent.rbegin(); it != recent.rend(); ++it) { + if (it->fromNodeId == node->num && !it->statusText.empty()) { + found = &(*it); + break; + } + } + + if (found) { + const char *shortName = node->user.short_name; + composedFromStatus.reserve(4 + (shortName ? std::strlen(shortName) : 0) + 1 + found->statusText.size()); + composedFromStatus += "("; + if (shortName && *shortName) { + composedFromStatus += shortName; + } + composedFromStatus += ") "; + composedFromStatus += found->statusText; + + raw = composedFromStatus.c_str(); // safe for now; we'll sanitize immediately into std::string + } + } +#endif + + // If we didn't compose from status, use normal long/short selection + if (!raw) { + if (node && node->has_user) { + raw = config.display.use_long_node_name ? node->user.long_name : node->user.short_name; + } } // 2) Preserve UTF-8 names so emotes can be detected and rendered. diff --git a/src/graphics/draw/UIRenderer.cpp b/src/graphics/draw/UIRenderer.cpp index e3a4d13a2..78d109881 100644 --- a/src/graphics/draw/UIRenderer.cpp +++ b/src/graphics/draw/UIRenderer.cpp @@ -5,6 +5,9 @@ #include "MeshService.h" #include "NodeDB.h" #include "NodeListRenderer.h" +#if !MESHTASTIC_EXCLUDE_STATUS +#include "modules/StatusMessageModule.h" +#endif #include "UIRenderer.h" #include "airtime.h" #include "gps/GeoCoord.h" @@ -290,7 +293,7 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes // * Favorite Node Info * // ********************** // cppcheck-suppress constParameterPointer; signature must match FrameCallback typedef from OLEDDisplayUi library -void UIRenderer::drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +void UIRenderer::drawFavoriteNode(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { if (favoritedNodes.empty()) return; @@ -342,6 +345,57 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, i UIRenderer::drawStringWithEmotes(display, x, getTextPositions(display)[line++], username, FONT_HEIGHT_SMALL, 1, false); } +#if !MESHTASTIC_EXCLUDE_STATUS + // === Optional: Last received StatusMessage line for this node === + // Display it directly under the username line (if we have one). + if (statusMessageModule) { + const auto &recent = statusMessageModule->getRecentReceived(); + const StatusMessageModule::RecentStatus *found = nullptr; + + // Search newest-to-oldest + for (auto it = recent.rbegin(); it != recent.rend(); ++it) { + if (it->fromNodeId == node->num && !it->statusText.empty()) { + found = &(*it); + break; + } + } + + if (found) { + std::string statusLine = std::string(" Status: ") + found->statusText; + { + const int screenW = display->getWidth(); + const int ellipseW = display->getStringWidth("..."); + int w = display->getStringWidth(statusLine.c_str()); + + // Only do work if it overflows + if (w > screenW) { + bool truncated = false; + if (ellipseW > screenW) { + statusLine.clear(); + } else { + while (!statusLine.empty()) { + // remove one char (byte) at a time + statusLine.pop_back(); + truncated = true; + + // Measure candidate with ellipsis appended + std::string candidate = statusLine + "..."; + if (display->getStringWidth(candidate.c_str()) <= screenW) { + statusLine = std::move(candidate); + break; + } + } + if (statusLine.empty() && ellipseW <= screenW) { + statusLine = "..."; + } + } + } + } + display->drawString(x, getTextPositions(display)[line++], statusLine.c_str()); + } + } +#endif + // === 2. Signal and Hops (combined on one line, if available) === char signalHopsStr[32] = ""; bool haveSignal = false; diff --git a/src/graphics/draw/UIRenderer.h b/src/graphics/draw/UIRenderer.h index a0bb0d849..a705d944d 100644 --- a/src/graphics/draw/UIRenderer.h +++ b/src/graphics/draw/UIRenderer.h @@ -50,7 +50,7 @@ class UIRenderer // Navigation bar overlay static void drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *state); - static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); + static void drawFavoriteNode(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); static void drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); diff --git a/src/input/CardputerKeyboard.cpp b/src/input/CardputerKeyboard.cpp index ec1ed383a..1bd695461 100644 --- a/src/input/CardputerKeyboard.cpp +++ b/src/input/CardputerKeyboard.cpp @@ -121,7 +121,6 @@ void CardputerKeyboard::pressed(uint8_t key) modifierFlag = 0; } - uint8_t next_key = 0; int row = (key - 1) / 10; int col = (key - 1) % 10; diff --git a/src/memGet.cpp b/src/memGet.cpp index 14e614014..42a3430f6 100644 --- a/src/memGet.cpp +++ b/src/memGet.cpp @@ -10,8 +10,26 @@ #include "memGet.h" #include "configuration.h" -#ifdef ARCH_STM32WL +#if defined(MESHTASTIC_DYNAMIC_SBRK_HEAP) #include +#include // sbrk + +#ifdef ARCH_STM32WL +// Returns the uncommitted sbrk headroom: addressable space between the current heap +// break and the stack pointer that has not yet been committed to the arena. +static uint32_t sbrkHeadroom() +{ + // defined in STM32 linker script + extern char _estack; + extern char _Min_Stack_Size; + + uint32_t max_sp = (uint32_t)(&_estack - &_Min_Stack_Size); + uint32_t heap_end = (uint32_t)sbrk(0); + return (max_sp > heap_end) ? (max_sp - heap_end) : 0; +} +#else +#error Unsupported architecture! +#endif #endif MemGet memGet; @@ -28,9 +46,9 @@ uint32_t MemGet::getFreeHeap() return dbgHeapFree(); #elif defined(ARCH_RP2040) return rp2040.getFreeHeap(); -#elif defined(ARCH_STM32WL) +#elif defined(MESHTASTIC_DYNAMIC_SBRK_HEAP) // Currently: ARCH_STM32WL struct mallinfo m = mallinfo(); - return m.fordblks; // Total free space (bytes) + return m.fordblks + sbrkHeadroom(); // Free space within arena + uncommitted sbrk headroom #else // this platform does not have heap management function implemented return UINT32_MAX; @@ -49,9 +67,9 @@ uint32_t MemGet::getHeapSize() return dbgHeapTotal(); #elif defined(ARCH_RP2040) return rp2040.getTotalHeap(); -#elif defined(ARCH_STM32WL) +#elif defined(MESHTASTIC_DYNAMIC_SBRK_HEAP) // Currently: ARCH_STM32WL struct mallinfo m = mallinfo(); - return m.arena; // Non-mmapped space allocated (bytes) + return m.arena + sbrkHeadroom(); // Non-mmapped space allocated + uncommitted sbrk headroom #else // this platform does not have heap management function implemented return UINT32_MAX; diff --git a/src/mesh/MeshRadio.h b/src/mesh/MeshRadio.h index 3c3a4cf65..089b4b189 100644 --- a/src/mesh/MeshRadio.h +++ b/src/mesh/MeshRadio.h @@ -4,6 +4,7 @@ #include "MeshTypes.h" #include "PointerQueue.h" #include "configuration.h" +#include "detect/LoRaRadioType.h" // Sentinel marking the end of a modem preset array static constexpr meshtastic_Config_LoRaConfig_ModemPreset MODEM_PRESET_END = @@ -59,7 +60,7 @@ extern const RegionInfo *myRegion; extern void initRegion(); // Valid LoRa spread factor range and defaults -constexpr uint8_t LORA_SF_MIN = 7; +constexpr uint8_t LORA_SF_MIN = 5; constexpr uint8_t LORA_SF_MAX = 12; constexpr uint8_t LORA_SF_DEFAULT = 11; // LONG_FAST default @@ -71,10 +72,14 @@ constexpr uint8_t LORA_CR_DEFAULT = 5; // LONG_FAST default // Default bandwidth in kHz (LONG_FAST) constexpr float LORA_BW_DEFAULT_KHZ = 250.0f; -/// Clamp spread factor to the valid LoRa range [7, 12]. +/// Clamp spread factor to the valid LoRa range [5, 12]. /// Out-of-range values (including 0 from unset preset mode) return LORA_SF_DEFAULT. static inline uint8_t clampSpreadFactor(uint8_t sf) { + // We check for RF95 radios that are incompatible with Spreading Factors 5 and 6. + if (radioType == RF95_RADIO && (sf == 5 || sf == 6)) + return LORA_SF_DEFAULT; + if (sf < LORA_SF_MIN || sf > LORA_SF_MAX) return LORA_SF_DEFAULT; return sf; diff --git a/src/mesh/generated/meshtastic/atak.pb.cpp b/src/mesh/generated/meshtastic/atak.pb.cpp index 3f1adea53..dda9fddaf 100644 --- a/src/mesh/generated/meshtastic/atak.pb.cpp +++ b/src/mesh/generated/meshtastic/atak.pb.cpp @@ -45,7 +45,10 @@ PB_BIND(meshtastic_Route, meshtastic_Route, 2) PB_BIND(meshtastic_Route_Link, meshtastic_Route_Link, AUTO) -PB_BIND(meshtastic_CasevacReport, meshtastic_CasevacReport, AUTO) +PB_BIND(meshtastic_CasevacReport, meshtastic_CasevacReport, 2) + + +PB_BIND(meshtastic_ZMistEntry, meshtastic_ZMistEntry, AUTO) PB_BIND(meshtastic_EmergencyAlert, meshtastic_EmergencyAlert, AUTO) @@ -54,6 +57,12 @@ PB_BIND(meshtastic_EmergencyAlert, meshtastic_EmergencyAlert, AUTO) PB_BIND(meshtastic_TaskRequest, meshtastic_TaskRequest, AUTO) +PB_BIND(meshtastic_TAKEnvironment, meshtastic_TAKEnvironment, AUTO) + + +PB_BIND(meshtastic_SensorFov, meshtastic_SensorFov, AUTO) + + PB_BIND(meshtastic_TAKPacketV2, meshtastic_TAKPacketV2, 2) @@ -89,6 +98,8 @@ PB_BIND(meshtastic_TAKPacketV2, meshtastic_TAKPacketV2, 2) + + diff --git a/src/mesh/generated/meshtastic/atak.pb.h b/src/mesh/generated/meshtastic/atak.pb.h index d25fa6543..d69b14009 100644 --- a/src/mesh/generated/meshtastic/atak.pb.h +++ b/src/mesh/generated/meshtastic/atak.pb.h @@ -521,6 +521,19 @@ typedef enum _meshtastic_TaskRequest_Status { meshtastic_TaskRequest_Status_Status_Cancelled = 5 /* cancelled before completion */ } meshtastic_TaskRequest_Status; +/* Coarse sensor category, inferred from `model` on parse when the source + XML doesn't label it. Receivers that render differently per sensor + class (thermal overlay vs daylight cone) use this. */ +typedef enum _meshtastic_SensorFov_SensorType { + meshtastic_SensorFov_SensorType_SensorType_Unspecified = 0, + meshtastic_SensorFov_SensorType_SensorType_Camera = 1, /* daylight / general optical */ + meshtastic_SensorFov_SensorType_SensorType_Thermal = 2, /* FLIR, thermal imager */ + meshtastic_SensorFov_SensorType_SensorType_Laser = 3, /* rangefinder, LRF, designator */ + meshtastic_SensorFov_SensorType_SensorType_Nvg = 4, /* night vision goggles */ + meshtastic_SensorFov_SensorType_SensorType_Rf = 5, /* radio/radar direction-finding */ + meshtastic_SensorFov_SensorType_SensorType_Other = 6 +} meshtastic_SensorFov_SensorType; + /* Struct definitions */ /* ATAK GeoChat message */ typedef struct _meshtastic_GeoChat { @@ -865,8 +878,82 @@ typedef struct _meshtastic_CasevacReport { /* Line 2: radio frequency / callsign metadata (e.g. "38.90 Mhz" or "Victor 6"). Capped tight in options. */ char frequency[16]; + /* Short title / MEDEVAC identifier (e.g. "EAGLE.15.181230"). Usually the + same as the envelope callsign but ATAK sometimes carries a distinct + ops-number here. */ + pb_callback_t title; + /* Primary medline free-text — the single most clinically important line + on a MEDLINE form (e.g. "2 urgent litter patients, smoke on approach"). + MUST be preserved under MTU pressure as long as any casevac is sent. */ + pb_callback_t medline_remarks; + /* Line 3 (newer ATAK format): patient counts by precedence level. + Coexists with the enum-style `precedence` field (tag 1) — older ATAK + emits a single enum, newer ATAK emits these counts, and both can be + set simultaneously. Senders populate whichever style(s) the source + XML had; receivers prefer counts when non-zero. */ + uint32_t urgent_count; + uint32_t urgent_surgical_count; + uint32_t priority_count; + uint32_t routine_count; + uint32_t convenience_count; + /* Line 4 supplementary: free-text description of non-standard equipment + (e.g. "Blood warmer"). Pairs with the `equipment_flags` bitfield. */ + pb_callback_t equipment_detail; + /* Line 1 override: MGRS grid when distinct from the event anchor point + (e.g. "34T CQ 12345 67890"). Event lat/lon/hae still carries the + numeric location; this field preserves the exact MGRS string the + medic entered. */ + pb_callback_t zone_protected_coord; + /* Line 9 supplementary: slope direction (e.g. "N", "NE", "SSW") when + `terrain_flags` bit 0 (slope) is set. */ + pb_callback_t terrain_slope_dir; + /* Line 9 supplementary: free-text description of "other" terrain hazards + (e.g. "Loose debris on west edge") when `terrain_flags` bit 5 (other) + is set. Tier-2 strippable under MTU pressure. */ + pb_callback_t terrain_other_detail; + /* Line 7 supplementary: how the zone is being marked right now + (e.g. "Orange smoke", "VS-17 panel"). Complements the structured + `hlz_marking` enum with a specific human-readable description. */ + pb_callback_t marked_by; + /* Nearby obstacles on the approach (e.g. "Power lines north of HLZ"). */ + pb_callback_t obstacles; + /* Wind direction and speed (e.g. "270 at 12 kts"). */ + pb_callback_t winds_are_from; + /* Friendly forces posture near the pickup zone + (e.g. "Squad east of HLZ"). */ + pb_callback_t friendlies; + /* Known or suspected enemy positions near the pickup zone + (e.g. "Possible enemy on south ridge"). */ + pb_callback_t enemy; + /* Free-text description of the HLZ itself + (e.g. "Primary HLZ is soccer field"). */ + pb_callback_t hlz_remarks; + /* Per-patient clinical records. Each entry is one patient's ZMIST card + (Zap number / Mechanism / Injuries / Signs / Treatment). Repeatable — + a mass-casualty event can carry 1-6 entries in practice, limited by + the 237 B LoRa MTU. */ + pb_callback_t zmist; } meshtastic_CasevacReport; +/* Per-patient clinical summary record — one entry per patient in a CASEVAC. + Maps directly to ATAK's child element inside . + All fields are optional free-text; senders populate what they have. */ +typedef struct _meshtastic_ZMistEntry { + /* Patient identifier / sequence label (e.g. "ZMIST-1", "ZMIST-2"). */ + pb_callback_t title; + /* Zap number — unique patient tracking ID (often a terse code like + "Gunshot" or a serial). */ + pb_callback_t z; + /* Mechanism of injury (e.g. "Penetrating trauma", "Blast injury"). */ + pb_callback_t m; + /* Injuries observed (e.g. "Left thigh", "Concussion"). */ + pb_callback_t i; + /* Signs / vital stats (e.g. "Stable", "Priority", "BP 110/70"). */ + pb_callback_t s; + /* Treatment given (e.g. "Tourniquet 1810Z", "O2 administered"). */ + pb_callback_t t; +} meshtastic_ZMistEntry; + /* Emergency alert / 911 beacon (CoT types b-a-o-tbl, b-a-o-pan, b-a-o-opn, b-a-o-can, b-a-o-c, b-a-g). @@ -911,6 +998,76 @@ typedef struct _meshtastic_TaskRequest { char note[48]; } meshtastic_TaskRequest; +/* Weather annotation from CoT detail element. + + Attaches to any TAKPacketV2 regardless of payload_variant — an Aircraft, + PLI, or Marker can all carry observed conditions at the emitting station. + ATAK-CIV ships an XSD for but no dedicated handler, so the + element round-trips through the generic detail pipeline; this message + promotes it to a first-class structured field. + + Target wire cost: ~6-8 bytes compressed with a fully populated instance. + + Named `TAKEnvironment` (not just `Environment`) because the bare name + collides with `SwiftUI.Environment` — every SwiftUI view in a consuming + iOS app uses the `@Environment` property wrapper, and importing the + generated proto module would make `Environment` ambiguous in every one + of those files. The `TAK` prefix matches the convention used by the + outer `TAKPacketV2` wrapper and is unambiguous across all target + languages (Swift, Kotlin, Python, TypeScript, C#). */ +typedef struct _meshtastic_TAKEnvironment { + /* Temperature in deci-degrees Celsius. 225 = 22.5°C. + Range covers -50°C to +50°C (-500 to +500) which spans every realistic + outdoor TAK deployment. sint32 because negative temps are common in + cold-weather ops. */ + int32_t temperature_c_x10; + /* Wind direction in whole degrees, 0-359. "Direction FROM" per + meteorological convention (matches CoT / ATAK). */ + uint32_t wind_direction_deg; + /* Wind speed in cm/s. Matches the unit of TAKPacketV2.speed for + consistency. 1200 = 12.00 m/s = ~27 mph. */ + uint32_t wind_speed_cm_s; +} meshtastic_TAKEnvironment; + +/* Sensor field-of-view cone from CoT detail element. + + Encodes the 8 geometry attributes that ATAK-CIV's SensorDetailHandler + reads from the wire; drops the 9 visual-styling attributes that are + receiver-side render hints (fovAlpha, fovRed/Green/Blue, strokeColor, + strokeWeight, displayMagneticReference, hideFov, fovLabels, rangeLines). + The receiving ATAK client restores those from its own defaults, same as + every other CoT carried over Meshtastic today. + + Attaches to any TAKPacketV2 — a PLI with a sensor on the operator's head, + an Aircraft with a FLIR turret, a Marker dropped on a UAV. + Target wire cost: ~7-14 bytes compressed (dominated by model string). */ +typedef struct _meshtastic_SensorFov { + meshtastic_SensorFov_SensorType type; + /* Azimuth in whole degrees, 0-359. "Pointing direction" of the cone axis, + measured clockwise from true north. Whole degrees match ATAK-CIV's + SensorDetailHandler default (270°) and save varint bytes over centi-deg. */ + uint32_t azimuth_deg; + /* Maximum range of the cone in meters. + Optional — if unset, receivers should use the ATAK-CIV default of 100m. */ + bool has_range_m; + uint32_t range_m; + /* Horizontal field of view in whole degrees (cone's angular width). + ATAK-CIV default is 45°. */ + uint32_t fov_horizontal_deg; + /* Vertical field of view in whole degrees. ATAK-CIV default is 45°. + Optional — a value of 0 means "not set / use horizontal FOV". */ + uint32_t fov_vertical_deg; + /* Elevation angle in whole degrees. Positive = up, negative = down. + Range -90 to +90. sint32 for varint efficiency on small negatives. */ + int32_t elevation_deg; + /* Roll (camera tilt) in whole degrees, -180 to +180. + Optional — use 0 if the sensor doesn't track roll. */ + int32_t roll_deg; + /* Free-form device model identifier, e.g. "FLIR-Boson-640", "SEEK". + Optional — empty string means "unknown model" (ATAK-CIV default). */ + pb_callback_t model; +} meshtastic_SensorFov; + typedef PB_BYTES_ARRAY_T(220) meshtastic_TAKPacketV2_raw_detail_t; /* ATAK v2 packet with expanded CoT field support and zstd dictionary compression. Sent on ATAK_PLUGIN_V2 port. The wire payload is: @@ -970,6 +1127,14 @@ typedef struct _meshtastic_TAKPacketV2 { GeoChat messages carry their text in GeoChat.message instead. Empty string (proto3 default) means no remarks were present. */ pb_callback_t remarks; + /* Observed weather conditions (temperature, wind). From . + Type is `TAKEnvironment`, not `Environment`, to avoid colliding with + SwiftUI's `@Environment` property wrapper in iOS consumers. */ + bool has_environment; + meshtastic_TAKEnvironment environment; + /* Sensor field-of-view cone (camera, FLIR, laser, etc.). From . */ + bool has_sensor_fov; + meshtastic_SensorFov sensor_fov; pb_size_t which_payload_variant; union { /* Position report (true = PLI, no extra fields beyond the common ones above) */ @@ -1075,6 +1240,10 @@ extern "C" { #define _meshtastic_TaskRequest_Status_MAX meshtastic_TaskRequest_Status_Status_Cancelled #define _meshtastic_TaskRequest_Status_ARRAYSIZE ((meshtastic_TaskRequest_Status)(meshtastic_TaskRequest_Status_Status_Cancelled+1)) +#define _meshtastic_SensorFov_SensorType_MIN meshtastic_SensorFov_SensorType_SensorType_Unspecified +#define _meshtastic_SensorFov_SensorType_MAX meshtastic_SensorFov_SensorType_SensorType_Other +#define _meshtastic_SensorFov_SensorType_ARRAYSIZE ((meshtastic_SensorFov_SensorType)(meshtastic_SensorFov_SensorType_SensorType_Other+1)) + #define meshtastic_GeoChat_receipt_type_ENUMTYPE meshtastic_GeoChat_ReceiptType @@ -1104,11 +1273,15 @@ extern "C" { #define meshtastic_CasevacReport_security_ENUMTYPE meshtastic_CasevacReport_Security #define meshtastic_CasevacReport_hlz_marking_ENUMTYPE meshtastic_CasevacReport_HlzMarking + #define meshtastic_EmergencyAlert_type_ENUMTYPE meshtastic_EmergencyAlert_Type #define meshtastic_TaskRequest_priority_ENUMTYPE meshtastic_TaskRequest_Priority #define meshtastic_TaskRequest_status_ENUMTYPE meshtastic_TaskRequest_Status + +#define meshtastic_SensorFov_type_ENUMTYPE meshtastic_SensorFov_SensorType + #define meshtastic_TAKPacketV2_cot_type_id_ENUMTYPE meshtastic_CotType #define meshtastic_TAKPacketV2_how_ENUMTYPE meshtastic_CotHow #define meshtastic_TAKPacketV2_team_ENUMTYPE meshtastic_Team @@ -1131,10 +1304,13 @@ extern "C" { #define meshtastic_RangeAndBearing_init_default {false, meshtastic_CotGeoPoint_init_default, "", 0, 0, _meshtastic_Team_MIN, 0, 0} #define meshtastic_Route_init_default {_meshtastic_Route_Method_MIN, _meshtastic_Route_Direction_MIN, "", 0, 0, {meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default, meshtastic_Route_Link_init_default}, 0} #define meshtastic_Route_Link_init_default {false, meshtastic_CotGeoPoint_init_default, "", "", 0} -#define meshtastic_CasevacReport_init_default {_meshtastic_CasevacReport_Precedence_MIN, 0, 0, 0, _meshtastic_CasevacReport_Security_MIN, _meshtastic_CasevacReport_HlzMarking_MIN, "", 0, 0, 0, 0, 0, 0, 0, ""} +#define meshtastic_CasevacReport_init_default {_meshtastic_CasevacReport_Precedence_MIN, 0, 0, 0, _meshtastic_CasevacReport_Security_MIN, _meshtastic_CasevacReport_HlzMarking_MIN, "", 0, 0, 0, 0, 0, 0, 0, "", {{NULL}, NULL}, {{NULL}, NULL}, 0, 0, 0, 0, 0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define meshtastic_ZMistEntry_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} #define meshtastic_EmergencyAlert_init_default {_meshtastic_EmergencyAlert_Type_MIN, "", ""} #define meshtastic_TaskRequest_init_default {"", "", "", _meshtastic_TaskRequest_Priority_MIN, _meshtastic_TaskRequest_Status_MIN, ""} -#define meshtastic_TAKPacketV2_init_default {_meshtastic_CotType_MIN, _meshtastic_CotHow_MIN, "", _meshtastic_Team_MIN, _meshtastic_MemberRole_MIN, 0, 0, 0, 0, 0, 0, _meshtastic_GeoPointSource_MIN, _meshtastic_GeoPointSource_MIN, "", "", 0, "", "", "", "", "", "", "", {{NULL}, NULL}, 0, {0}} +#define meshtastic_TAKEnvironment_init_default {0, 0, 0} +#define meshtastic_SensorFov_init_default {_meshtastic_SensorFov_SensorType_MIN, 0, false, 0, 0, 0, 0, 0, {{NULL}, NULL}} +#define meshtastic_TAKPacketV2_init_default {_meshtastic_CotType_MIN, _meshtastic_CotHow_MIN, "", _meshtastic_Team_MIN, _meshtastic_MemberRole_MIN, 0, 0, 0, 0, 0, 0, _meshtastic_GeoPointSource_MIN, _meshtastic_GeoPointSource_MIN, "", "", 0, "", "", "", "", "", "", "", {{NULL}, NULL}, false, meshtastic_TAKEnvironment_init_default, false, meshtastic_SensorFov_init_default, 0, {0}} #define meshtastic_TAKPacket_init_zero {0, false, meshtastic_Contact_init_zero, false, meshtastic_Group_init_zero, false, meshtastic_Status_init_zero, 0, {meshtastic_PLI_init_zero}} #define meshtastic_GeoChat_init_zero {"", false, "", false, "", "", _meshtastic_GeoChat_ReceiptType_MIN} #define meshtastic_Group_init_zero {_meshtastic_MemberRole_MIN, _meshtastic_Team_MIN} @@ -1148,10 +1324,13 @@ extern "C" { #define meshtastic_RangeAndBearing_init_zero {false, meshtastic_CotGeoPoint_init_zero, "", 0, 0, _meshtastic_Team_MIN, 0, 0} #define meshtastic_Route_init_zero {_meshtastic_Route_Method_MIN, _meshtastic_Route_Direction_MIN, "", 0, 0, {meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero, meshtastic_Route_Link_init_zero}, 0} #define meshtastic_Route_Link_init_zero {false, meshtastic_CotGeoPoint_init_zero, "", "", 0} -#define meshtastic_CasevacReport_init_zero {_meshtastic_CasevacReport_Precedence_MIN, 0, 0, 0, _meshtastic_CasevacReport_Security_MIN, _meshtastic_CasevacReport_HlzMarking_MIN, "", 0, 0, 0, 0, 0, 0, 0, ""} +#define meshtastic_CasevacReport_init_zero {_meshtastic_CasevacReport_Precedence_MIN, 0, 0, 0, _meshtastic_CasevacReport_Security_MIN, _meshtastic_CasevacReport_HlzMarking_MIN, "", 0, 0, 0, 0, 0, 0, 0, "", {{NULL}, NULL}, {{NULL}, NULL}, 0, 0, 0, 0, 0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} +#define meshtastic_ZMistEntry_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} #define meshtastic_EmergencyAlert_init_zero {_meshtastic_EmergencyAlert_Type_MIN, "", ""} #define meshtastic_TaskRequest_init_zero {"", "", "", _meshtastic_TaskRequest_Priority_MIN, _meshtastic_TaskRequest_Status_MIN, ""} -#define meshtastic_TAKPacketV2_init_zero {_meshtastic_CotType_MIN, _meshtastic_CotHow_MIN, "", _meshtastic_Team_MIN, _meshtastic_MemberRole_MIN, 0, 0, 0, 0, 0, 0, _meshtastic_GeoPointSource_MIN, _meshtastic_GeoPointSource_MIN, "", "", 0, "", "", "", "", "", "", "", {{NULL}, NULL}, 0, {0}} +#define meshtastic_TAKEnvironment_init_zero {0, 0, 0} +#define meshtastic_SensorFov_init_zero {_meshtastic_SensorFov_SensorType_MIN, 0, false, 0, 0, 0, 0, 0, {{NULL}, NULL}} +#define meshtastic_TAKPacketV2_init_zero {_meshtastic_CotType_MIN, _meshtastic_CotHow_MIN, "", _meshtastic_Team_MIN, _meshtastic_MemberRole_MIN, 0, 0, 0, 0, 0, 0, _meshtastic_GeoPointSource_MIN, _meshtastic_GeoPointSource_MIN, "", "", 0, "", "", "", "", "", "", "", {{NULL}, NULL}, false, meshtastic_TAKEnvironment_init_zero, false, meshtastic_SensorFov_init_zero, 0, {0}} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_GeoChat_message_tag 1 @@ -1244,6 +1423,30 @@ extern "C" { #define meshtastic_CasevacReport_child_tag 13 #define meshtastic_CasevacReport_terrain_flags_tag 14 #define meshtastic_CasevacReport_frequency_tag 15 +#define meshtastic_CasevacReport_title_tag 16 +#define meshtastic_CasevacReport_medline_remarks_tag 17 +#define meshtastic_CasevacReport_urgent_count_tag 18 +#define meshtastic_CasevacReport_urgent_surgical_count_tag 19 +#define meshtastic_CasevacReport_priority_count_tag 20 +#define meshtastic_CasevacReport_routine_count_tag 21 +#define meshtastic_CasevacReport_convenience_count_tag 22 +#define meshtastic_CasevacReport_equipment_detail_tag 23 +#define meshtastic_CasevacReport_zone_protected_coord_tag 24 +#define meshtastic_CasevacReport_terrain_slope_dir_tag 25 +#define meshtastic_CasevacReport_terrain_other_detail_tag 26 +#define meshtastic_CasevacReport_marked_by_tag 27 +#define meshtastic_CasevacReport_obstacles_tag 28 +#define meshtastic_CasevacReport_winds_are_from_tag 29 +#define meshtastic_CasevacReport_friendlies_tag 30 +#define meshtastic_CasevacReport_enemy_tag 31 +#define meshtastic_CasevacReport_hlz_remarks_tag 32 +#define meshtastic_CasevacReport_zmist_tag 33 +#define meshtastic_ZMistEntry_title_tag 1 +#define meshtastic_ZMistEntry_z_tag 2 +#define meshtastic_ZMistEntry_m_tag 3 +#define meshtastic_ZMistEntry_i_tag 4 +#define meshtastic_ZMistEntry_s_tag 5 +#define meshtastic_ZMistEntry_t_tag 6 #define meshtastic_EmergencyAlert_type_tag 1 #define meshtastic_EmergencyAlert_authoring_uid_tag 2 #define meshtastic_EmergencyAlert_cancel_reference_uid_tag 3 @@ -1253,6 +1456,17 @@ extern "C" { #define meshtastic_TaskRequest_priority_tag 4 #define meshtastic_TaskRequest_status_tag 5 #define meshtastic_TaskRequest_note_tag 6 +#define meshtastic_TAKEnvironment_temperature_c_x10_tag 1 +#define meshtastic_TAKEnvironment_wind_direction_deg_tag 2 +#define meshtastic_TAKEnvironment_wind_speed_cm_s_tag 3 +#define meshtastic_SensorFov_type_tag 1 +#define meshtastic_SensorFov_azimuth_deg_tag 2 +#define meshtastic_SensorFov_range_m_tag 3 +#define meshtastic_SensorFov_fov_horizontal_deg_tag 4 +#define meshtastic_SensorFov_fov_vertical_deg_tag 5 +#define meshtastic_SensorFov_elevation_deg_tag 6 +#define meshtastic_SensorFov_roll_deg_tag 7 +#define meshtastic_SensorFov_model_tag 8 #define meshtastic_TAKPacketV2_cot_type_id_tag 1 #define meshtastic_TAKPacketV2_how_tag 2 #define meshtastic_TAKPacketV2_callsign_tag 3 @@ -1277,6 +1491,8 @@ extern "C" { #define meshtastic_TAKPacketV2_phone_tag 22 #define meshtastic_TAKPacketV2_cot_type_str_tag 23 #define meshtastic_TAKPacketV2_remarks_tag 24 +#define meshtastic_TAKPacketV2_environment_tag 25 +#define meshtastic_TAKPacketV2_sensor_fov_tag 26 #define meshtastic_TAKPacketV2_pli_tag 30 #define meshtastic_TAKPacketV2_chat_tag 31 #define meshtastic_TAKPacketV2_aircraft_tag 32 @@ -1441,9 +1657,38 @@ X(a, STATIC, SINGULAR, UINT32, non_us_civilian, 11) \ X(a, STATIC, SINGULAR, UINT32, epw, 12) \ X(a, STATIC, SINGULAR, UINT32, child, 13) \ X(a, STATIC, SINGULAR, UINT32, terrain_flags, 14) \ -X(a, STATIC, SINGULAR, STRING, frequency, 15) -#define meshtastic_CasevacReport_CALLBACK NULL +X(a, STATIC, SINGULAR, STRING, frequency, 15) \ +X(a, CALLBACK, SINGULAR, STRING, title, 16) \ +X(a, CALLBACK, SINGULAR, STRING, medline_remarks, 17) \ +X(a, STATIC, SINGULAR, UINT32, urgent_count, 18) \ +X(a, STATIC, SINGULAR, UINT32, urgent_surgical_count, 19) \ +X(a, STATIC, SINGULAR, UINT32, priority_count, 20) \ +X(a, STATIC, SINGULAR, UINT32, routine_count, 21) \ +X(a, STATIC, SINGULAR, UINT32, convenience_count, 22) \ +X(a, CALLBACK, SINGULAR, STRING, equipment_detail, 23) \ +X(a, CALLBACK, SINGULAR, STRING, zone_protected_coord, 24) \ +X(a, CALLBACK, SINGULAR, STRING, terrain_slope_dir, 25) \ +X(a, CALLBACK, SINGULAR, STRING, terrain_other_detail, 26) \ +X(a, CALLBACK, SINGULAR, STRING, marked_by, 27) \ +X(a, CALLBACK, SINGULAR, STRING, obstacles, 28) \ +X(a, CALLBACK, SINGULAR, STRING, winds_are_from, 29) \ +X(a, CALLBACK, SINGULAR, STRING, friendlies, 30) \ +X(a, CALLBACK, SINGULAR, STRING, enemy, 31) \ +X(a, CALLBACK, SINGULAR, STRING, hlz_remarks, 32) \ +X(a, CALLBACK, REPEATED, MESSAGE, zmist, 33) +#define meshtastic_CasevacReport_CALLBACK pb_default_field_callback #define meshtastic_CasevacReport_DEFAULT NULL +#define meshtastic_CasevacReport_zmist_MSGTYPE meshtastic_ZMistEntry + +#define meshtastic_ZMistEntry_FIELDLIST(X, a) \ +X(a, CALLBACK, SINGULAR, STRING, title, 1) \ +X(a, CALLBACK, SINGULAR, STRING, z, 2) \ +X(a, CALLBACK, SINGULAR, STRING, m, 3) \ +X(a, CALLBACK, SINGULAR, STRING, i, 4) \ +X(a, CALLBACK, SINGULAR, STRING, s, 5) \ +X(a, CALLBACK, SINGULAR, STRING, t, 6) +#define meshtastic_ZMistEntry_CALLBACK pb_default_field_callback +#define meshtastic_ZMistEntry_DEFAULT NULL #define meshtastic_EmergencyAlert_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UENUM, type, 1) \ @@ -1462,6 +1707,25 @@ X(a, STATIC, SINGULAR, STRING, note, 6) #define meshtastic_TaskRequest_CALLBACK NULL #define meshtastic_TaskRequest_DEFAULT NULL +#define meshtastic_TAKEnvironment_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, SINT32, temperature_c_x10, 1) \ +X(a, STATIC, SINGULAR, UINT32, wind_direction_deg, 2) \ +X(a, STATIC, SINGULAR, UINT32, wind_speed_cm_s, 3) +#define meshtastic_TAKEnvironment_CALLBACK NULL +#define meshtastic_TAKEnvironment_DEFAULT NULL + +#define meshtastic_SensorFov_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, type, 1) \ +X(a, STATIC, SINGULAR, UINT32, azimuth_deg, 2) \ +X(a, STATIC, OPTIONAL, UINT32, range_m, 3) \ +X(a, STATIC, SINGULAR, UINT32, fov_horizontal_deg, 4) \ +X(a, STATIC, SINGULAR, UINT32, fov_vertical_deg, 5) \ +X(a, STATIC, SINGULAR, SINT32, elevation_deg, 6) \ +X(a, STATIC, SINGULAR, SINT32, roll_deg, 7) \ +X(a, CALLBACK, SINGULAR, STRING, model, 8) +#define meshtastic_SensorFov_CALLBACK pb_default_field_callback +#define meshtastic_SensorFov_DEFAULT NULL + #define meshtastic_TAKPacketV2_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UENUM, cot_type_id, 1) \ X(a, STATIC, SINGULAR, UENUM, how, 2) \ @@ -1487,6 +1751,8 @@ X(a, STATIC, SINGULAR, STRING, endpoint, 21) \ X(a, STATIC, SINGULAR, STRING, phone, 22) \ X(a, STATIC, SINGULAR, STRING, cot_type_str, 23) \ X(a, CALLBACK, SINGULAR, STRING, remarks, 24) \ +X(a, STATIC, OPTIONAL, MESSAGE, environment, 25) \ +X(a, STATIC, OPTIONAL, MESSAGE, sensor_fov, 26) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,pli,payload_variant.pli), 30) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,chat,payload_variant.chat), 31) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,aircraft,payload_variant.aircraft), 32) \ @@ -1500,6 +1766,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,emergency,payload_variant.em X(a, STATIC, ONEOF, MESSAGE, (payload_variant,task,payload_variant.task), 40) #define meshtastic_TAKPacketV2_CALLBACK pb_default_field_callback #define meshtastic_TAKPacketV2_DEFAULT NULL +#define meshtastic_TAKPacketV2_environment_MSGTYPE meshtastic_TAKEnvironment +#define meshtastic_TAKPacketV2_sensor_fov_MSGTYPE meshtastic_SensorFov #define meshtastic_TAKPacketV2_payload_variant_chat_MSGTYPE meshtastic_GeoChat #define meshtastic_TAKPacketV2_payload_variant_aircraft_MSGTYPE meshtastic_AircraftTrack #define meshtastic_TAKPacketV2_payload_variant_shape_MSGTYPE meshtastic_DrawnShape @@ -1524,8 +1792,11 @@ extern const pb_msgdesc_t meshtastic_RangeAndBearing_msg; extern const pb_msgdesc_t meshtastic_Route_msg; extern const pb_msgdesc_t meshtastic_Route_Link_msg; extern const pb_msgdesc_t meshtastic_CasevacReport_msg; +extern const pb_msgdesc_t meshtastic_ZMistEntry_msg; extern const pb_msgdesc_t meshtastic_EmergencyAlert_msg; extern const pb_msgdesc_t meshtastic_TaskRequest_msg; +extern const pb_msgdesc_t meshtastic_TAKEnvironment_msg; +extern const pb_msgdesc_t meshtastic_SensorFov_msg; extern const pb_msgdesc_t meshtastic_TAKPacketV2_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ @@ -1543,15 +1814,20 @@ extern const pb_msgdesc_t meshtastic_TAKPacketV2_msg; #define meshtastic_Route_fields &meshtastic_Route_msg #define meshtastic_Route_Link_fields &meshtastic_Route_Link_msg #define meshtastic_CasevacReport_fields &meshtastic_CasevacReport_msg +#define meshtastic_ZMistEntry_fields &meshtastic_ZMistEntry_msg #define meshtastic_EmergencyAlert_fields &meshtastic_EmergencyAlert_msg #define meshtastic_TaskRequest_fields &meshtastic_TaskRequest_msg +#define meshtastic_TAKEnvironment_fields &meshtastic_TAKEnvironment_msg +#define meshtastic_SensorFov_fields &meshtastic_SensorFov_msg #define meshtastic_TAKPacketV2_fields &meshtastic_TAKPacketV2_msg /* Maximum encoded size of messages (where known) */ +/* meshtastic_CasevacReport_size depends on runtime parameters */ +/* meshtastic_ZMistEntry_size depends on runtime parameters */ +/* meshtastic_SensorFov_size depends on runtime parameters */ /* meshtastic_TAKPacketV2_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_ATAK_PB_H_MAX_SIZE meshtastic_Route_size #define meshtastic_AircraftTrack_size 134 -#define meshtastic_CasevacReport_size 70 #define meshtastic_Contact_size 242 #define meshtastic_CotGeoPoint_size 12 #define meshtastic_DrawnShape_size 553 @@ -1564,6 +1840,7 @@ extern const pb_msgdesc_t meshtastic_TAKPacketV2_msg; #define meshtastic_Route_Link_size 83 #define meshtastic_Route_size 1379 #define meshtastic_Status_size 3 +#define meshtastic_TAKEnvironment_size 18 #define meshtastic_TAKPacket_size 756 #define meshtastic_TaskRequest_size 132 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 1c7eecd0d..d7ff32cb4 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -890,6 +890,10 @@ typedef struct _meshtastic_RemoteShell { uint32_t rows; /* Bit flags for protocol extensions. */ uint32_t flags; + /* The last sequence number TX'd. */ + uint32_t last_tx_seq; + /* The last sequence number RX'd. */ + uint32_t last_rx_seq; } meshtastic_RemoteShell; /* Waypoint message, used to share arbitrary locations across the mesh */ @@ -1512,7 +1516,7 @@ extern "C" { #define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} #define meshtastic_KeyVerification_init_default {0, {0, {0}}, {0, {0}}} #define meshtastic_StoreForwardPlusPlus_init_default {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0} -#define meshtastic_RemoteShell_init_default {_meshtastic_RemoteShell_OpCode_MIN, 0, 0, 0, {0, {0}}, 0, 0, 0} +#define meshtastic_RemoteShell_init_default {_meshtastic_RemoteShell_OpCode_MIN, 0, 0, 0, {0, {0}}, 0, 0, 0, 0, 0} #define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0} #define meshtastic_StatusMessage_init_default {""} #define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0} @@ -1546,7 +1550,7 @@ extern "C" { #define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} #define meshtastic_KeyVerification_init_zero {0, {0, {0}}, {0, {0}}} #define meshtastic_StoreForwardPlusPlus_init_zero {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0} -#define meshtastic_RemoteShell_init_zero {_meshtastic_RemoteShell_OpCode_MIN, 0, 0, 0, {0, {0}}, 0, 0, 0} +#define meshtastic_RemoteShell_init_zero {_meshtastic_RemoteShell_OpCode_MIN, 0, 0, 0, {0, {0}}, 0, 0, 0, 0, 0} #define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0} #define meshtastic_StatusMessage_init_zero {""} #define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0} @@ -1644,6 +1648,8 @@ extern "C" { #define meshtastic_RemoteShell_cols_tag 6 #define meshtastic_RemoteShell_rows_tag 7 #define meshtastic_RemoteShell_flags_tag 8 +#define meshtastic_RemoteShell_last_tx_seq_tag 9 +#define meshtastic_RemoteShell_last_rx_seq_tag 10 #define meshtastic_Waypoint_id_tag 1 #define meshtastic_Waypoint_latitude_i_tag 2 #define meshtastic_Waypoint_longitude_i_tag 3 @@ -1884,7 +1890,9 @@ X(a, STATIC, SINGULAR, UINT32, ack_seq, 4) \ X(a, STATIC, SINGULAR, BYTES, payload, 5) \ X(a, STATIC, SINGULAR, UINT32, cols, 6) \ X(a, STATIC, SINGULAR, UINT32, rows, 7) \ -X(a, STATIC, SINGULAR, UINT32, flags, 8) +X(a, STATIC, SINGULAR, UINT32, flags, 8) \ +X(a, STATIC, SINGULAR, UINT32, last_tx_seq, 9) \ +X(a, STATIC, SINGULAR, UINT32, last_rx_seq, 10) #define meshtastic_RemoteShell_CALLBACK NULL #define meshtastic_RemoteShell_DEFAULT NULL @@ -2262,7 +2270,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_NodeRemoteHardwarePin_size 29 #define meshtastic_Position_size 144 #define meshtastic_QueueStatus_size 23 -#define meshtastic_RemoteShell_size 241 +#define meshtastic_RemoteShell_size 253 #define meshtastic_RouteDiscovery_size 256 #define meshtastic_Routing_size 259 #define meshtastic_StatusMessage_size 81 diff --git a/src/modules/StatusMessageModule.cpp b/src/modules/StatusMessageModule.cpp index 139a74d8e..0707a4f7d 100644 --- a/src/modules/StatusMessageModule.cpp +++ b/src/modules/StatusMessageModule.cpp @@ -29,10 +29,23 @@ int32_t StatusMessageModule::runOnce() ProcessMessage StatusMessageModule::handleReceived(const meshtastic_MeshPacket &mp) { if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag) { - meshtastic_StatusMessage incomingMessage; + meshtastic_StatusMessage incomingMessage = meshtastic_StatusMessage_init_zero; + if (pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_StatusMessage_fields, &incomingMessage)) { + LOG_INFO("Received a NodeStatus message %s", incomingMessage.status); + + RecentStatus entry; + entry.fromNodeId = mp.from; + entry.statusText = incomingMessage.status; + + recentReceived.push_back(std::move(entry)); + + // Keep only last MAX_RECENT_STATUSMESSAGES + if (recentReceived.size() > MAX_RECENT_STATUSMESSAGES) { + recentReceived.erase(recentReceived.begin()); // drop oldest + } } } return ProcessMessage::CONTINUE; diff --git a/src/modules/StatusMessageModule.h b/src/modules/StatusMessageModule.h index c9ff54018..5090066e6 100644 --- a/src/modules/StatusMessageModule.h +++ b/src/modules/StatusMessageModule.h @@ -2,10 +2,11 @@ #if !MESHTASTIC_EXCLUDE_STATUS #include "SinglePortModule.h" #include "configuration.h" +#include +#include class StatusMessageModule : public SinglePortModule, private concurrency::OSThread { - public: /** Constructor * name is for debugging output @@ -19,16 +20,28 @@ class StatusMessageModule : public SinglePortModule, private concurrency::OSThre this->setInterval(1000 * 12 * 60 * 60); } // TODO: If we have a string, set the initial delay (15 minutes maybe) + + // Keep vector from reallocating as we fill up to MAX_RECENT_STATUSMESSAGES + recentReceived.reserve(MAX_RECENT_STATUSMESSAGES); } virtual int32_t runOnce() override; + struct RecentStatus { + uint32_t fromNodeId; // mp.from + std::string statusText; // incomingMessage.status + }; + + const std::vector &getRecentReceived() const { return recentReceived; } + protected: /** Called to handle a particular incoming message */ virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override; private: + static constexpr size_t MAX_RECENT_STATUSMESSAGES = 5; + std::vector recentReceived; }; extern StatusMessageModule *statusMessageModule; diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index 5f51ee083..7833b3603 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -654,7 +654,9 @@ void portduinoSetup() if (verboseEnabled && portduino_config.logoutputlevel != level_trace) { portduino_config.logoutputlevel = level_debug; } - + if (portduino_config.lora_spi_dev != "") { + portduinoSetOptions({.realHardware = true}); + } return; } diff --git a/src/power.h b/src/power.h index b129e2b74..d46eaadd2 100644 --- a/src/power.h +++ b/src/power.h @@ -15,8 +15,13 @@ // Device specific curves go in variant.h #ifndef OCV_ARRAY +#if defined(ARCH_STM32WL) && BATTERY_PIN == AVBAT +// STM32 VDD/VBAT absolute maximum is 4V so use an LFP curve +#define OCV_ARRAY 3650, 3400, 3340, 3320, 3300, 3280, 3270, 3260, 3240, 3200, 2500 +#else #define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100 #endif +#endif /*Note: 12V lead acid is 6 cells, most board accept only 1 cell LiIon/LiPo*/ #ifndef NUM_CELLS diff --git a/variants/esp32/chatter2/platformio.ini b/variants/esp32/chatter2/platformio.ini index 62d23b1e6..a14e407a1 100644 --- a/variants/esp32/chatter2/platformio.ini +++ b/variants/esp32/chatter2/platformio.ini @@ -8,7 +8,6 @@ build_flags = -I variants/esp32/chatter2 -DMESHTASTIC_EXCLUDE_WEBSERVER=1 -DMESHTASTIC_EXCLUDE_PAXCOUNTER=1 - -ULED_BUILTIN lib_deps = ${esp32_base.lib_deps} diff --git a/variants/esp32/diy/9m2ibr_aprs_lora_tracker/platformio.ini b/variants/esp32/diy/9m2ibr_aprs_lora_tracker/platformio.ini index 3fdb738fc..2ddc5a2db 100644 --- a/variants/esp32/diy/9m2ibr_aprs_lora_tracker/platformio.ini +++ b/variants/esp32/diy/9m2ibr_aprs_lora_tracker/platformio.ini @@ -10,7 +10,6 @@ build_flags = -D EBYTE_E22 -D EBYTE_E22_900M30S ; Assume Tx power curve is identical to 900M30S as there is no documentation -I variants/esp32/diy/9m2ibr_aprs_lora_tracker - -ULED_BUILTIN build_src_filter = ${esp32_base.build_src_filter} +<../variants/esp32/diy/9m2ibr_aprs_lora_tracker> \ No newline at end of file diff --git a/variants/esp32/diy/hydra/platformio.ini b/variants/esp32/diy/hydra/platformio.ini index f23224f0b..3afd17e01 100644 --- a/variants/esp32/diy/hydra/platformio.ini +++ b/variants/esp32/diy/hydra/platformio.ini @@ -14,4 +14,3 @@ build_flags = ${esp32_base.build_flags} -D DIY_V1 -I variants/esp32/diy/hydra - -ULED_BUILTIN diff --git a/variants/esp32/diy/v1/platformio.ini b/variants/esp32/diy/v1/platformio.ini index 6be2bfd09..3d31fc24a 100644 --- a/variants/esp32/diy/v1/platformio.ini +++ b/variants/esp32/diy/v1/platformio.ini @@ -17,4 +17,3 @@ build_flags = -D DIY_V1 -D EBYTE_E22 -I variants/esp32/diy/v1 - -ULED_BUILTIN diff --git a/variants/esp32/heltec_v2.1/platformio.ini b/variants/esp32/heltec_v2.1/platformio.ini index 9fcb2388a..1f7caa16f 100644 --- a/variants/esp32/heltec_v2.1/platformio.ini +++ b/variants/esp32/heltec_v2.1/platformio.ini @@ -14,4 +14,3 @@ build_flags = ${esp32_base.build_flags} -D HELTEC_V2_1 -I variants/esp32/heltec_v2.1 - -ULED_BUILTIN diff --git a/variants/esp32/heltec_v2/platformio.ini b/variants/esp32/heltec_v2/platformio.ini index fc9e05115..5f15fb321 100644 --- a/variants/esp32/heltec_v2/platformio.ini +++ b/variants/esp32/heltec_v2/platformio.ini @@ -14,4 +14,3 @@ build_flags = ${esp32_base.build_flags} -D HELTEC_V2_0 -I variants/esp32/heltec_v2 - -ULED_BUILTIN diff --git a/variants/esp32/heltec_wireless_bridge/platformio.ini b/variants/esp32/heltec_wireless_bridge/platformio.ini index 6f9de7a84..42a35697c 100644 --- a/variants/esp32/heltec_wireless_bridge/platformio.ini +++ b/variants/esp32/heltec_wireless_bridge/platformio.ini @@ -10,6 +10,7 @@ build_flags = -D BOARD_HAS_PSRAM -D RADIOLIB_EXCLUDE_LR11X0=1 -D RADIOLIB_EXCLUDE_SX128X=1 + -D RADIOLIB_EXCLUDE_LR2021=1 -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1 -D MESHTASTIC_EXCLUDE_DETECTIONSENSOR=1 -D MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1 diff --git a/variants/esp32/nano-g1-explorer/platformio.ini b/variants/esp32/nano-g1-explorer/platformio.ini index b27ebf28e..6f57897a8 100644 --- a/variants/esp32/nano-g1-explorer/platformio.ini +++ b/variants/esp32/nano-g1-explorer/platformio.ini @@ -14,4 +14,3 @@ build_flags = ${esp32_base.build_flags} -D NANO_G1_EXPLORER -I variants/esp32/nano-g1-explorer - -ULED_BUILTIN diff --git a/variants/esp32/nano-g1/platformio.ini b/variants/esp32/nano-g1/platformio.ini index b2e392dbd..82d0f5e73 100644 --- a/variants/esp32/nano-g1/platformio.ini +++ b/variants/esp32/nano-g1/platformio.ini @@ -14,4 +14,3 @@ build_flags = ${esp32_base.build_flags} -D NANO_G1 -I variants/esp32/nano-g1 - -ULED_BUILTIN diff --git a/variants/esp32/radiomaster_900_bandit/platformio.ini b/variants/esp32/radiomaster_900_bandit/platformio.ini index 0012f49d3..6729235ed 100644 --- a/variants/esp32/radiomaster_900_bandit/platformio.ini +++ b/variants/esp32/radiomaster_900_bandit/platformio.ini @@ -9,7 +9,6 @@ build_flags = -DHAS_STK8XXX=1 -O2 -I variants/esp32/radiomaster_900_bandit - -ULED_BUILTIN board_build.f_cpu = 240000000L upload_protocol = esptool lib_deps = diff --git a/variants/esp32/radiomaster_900_bandit_micro/platformio.ini b/variants/esp32/radiomaster_900_bandit_micro/platformio.ini index e58d06f1e..32e9280e1 100644 --- a/variants/esp32/radiomaster_900_bandit_micro/platformio.ini +++ b/variants/esp32/radiomaster_900_bandit_micro/platformio.ini @@ -13,6 +13,5 @@ build_flags = -DCONFIG_DISABLE_HAL_LOCKS=1 -O2 -I variants/esp32/radiomaster_900_bandit_nano - -ULED_BUILTIN board_build.f_cpu = 240000000L upload_protocol = esptool diff --git a/variants/esp32/radiomaster_900_bandit_nano/platformio.ini b/variants/esp32/radiomaster_900_bandit_nano/platformio.ini index 7b3d187bf..924447ee4 100644 --- a/variants/esp32/radiomaster_900_bandit_nano/platformio.ini +++ b/variants/esp32/radiomaster_900_bandit_nano/platformio.ini @@ -16,6 +16,5 @@ build_flags = -DCONFIG_DISABLE_HAL_LOCKS=1 -O2 -I variants/esp32/radiomaster_900_bandit_nano - -ULED_BUILTIN board_build.f_cpu = 240000000L upload_protocol = esptool diff --git a/variants/esp32/station-g1/platformio.ini b/variants/esp32/station-g1/platformio.ini index 5a7f33485..20e29764c 100644 --- a/variants/esp32/station-g1/platformio.ini +++ b/variants/esp32/station-g1/platformio.ini @@ -14,4 +14,3 @@ build_flags = ${esp32_base.build_flags} -D STATION_G1 -I variants/esp32/station-g1 - -ULED_BUILTIN diff --git a/variants/esp32/tbeam/platformio.ini b/variants/esp32/tbeam/platformio.ini index c9e6cce1f..96e9879ce 100644 --- a/variants/esp32/tbeam/platformio.ini +++ b/variants/esp32/tbeam/platformio.ini @@ -16,7 +16,6 @@ board_check = true build_flags = ${esp32_base.build_flags} -D TBEAM_V10 -I variants/esp32/tbeam - -ULED_BUILTIN upload_speed = 921600 [env:tbeam-displayshield] diff --git a/variants/esp32/tlora_v1/platformio.ini b/variants/esp32/tlora_v1/platformio.ini index 5f72d634e..c45cc2ce9 100644 --- a/variants/esp32/tlora_v1/platformio.ini +++ b/variants/esp32/tlora_v1/platformio.ini @@ -13,5 +13,4 @@ build_flags = ${esp32_base.build_flags} -D TLORA_V1 -I variants/esp32/tlora_v1 - -ULED_BUILTIN upload_speed = 115200 diff --git a/variants/esp32/tlora_v2_1_16/platformio.ini b/variants/esp32/tlora_v2_1_16/platformio.ini index 2ea9bbb50..a41c5016e 100644 --- a/variants/esp32/tlora_v2_1_16/platformio.ini +++ b/variants/esp32/tlora_v2_1_16/platformio.ini @@ -12,7 +12,7 @@ extends = esp32_base board = ttgo-lora32-v21 board_check = true build_flags = - ${esp32_base.build_flags} -D TLORA_V2_1_16 -I variants/esp32/tlora_v2_1_16 -ULED_BUILTIN + ${esp32_base.build_flags} -D TLORA_V2_1_16 -I variants/esp32/tlora_v2_1_16 upload_speed = 115200 [env:sugarcube] diff --git a/variants/esp32/tlora_v2_1_16_tcxo/platformio.ini b/variants/esp32/tlora_v2_1_16_tcxo/platformio.ini index 235ac7007..3cb64c976 100644 --- a/variants/esp32/tlora_v2_1_16_tcxo/platformio.ini +++ b/variants/esp32/tlora_v2_1_16_tcxo/platformio.ini @@ -7,5 +7,4 @@ build_flags = -D TLORA_V2_1_16 -I variants/esp32/tlora_v2_1_16 -D LORA_TCXO_GPIO=33 - -ULED_BUILTIN upload_speed = 115200 diff --git a/variants/esp32/tlora_v3_3_0_tcxo/platformio.ini b/variants/esp32/tlora_v3_3_0_tcxo/platformio.ini index 38f14ffc5..d3669ce55 100644 --- a/variants/esp32/tlora_v3_3_0_tcxo/platformio.ini +++ b/variants/esp32/tlora_v3_3_0_tcxo/platformio.ini @@ -7,4 +7,3 @@ build_flags = -I variants/esp32/tlora_v2_1_16 -D LORA_TCXO_GPIO=12 -D BUTTON_PIN=0 - -ULED_BUILTIN \ No newline at end of file diff --git a/variants/esp32c6/tlora_c6/platformio.ini b/variants/esp32c6/tlora_c6/platformio.ini index 174e5e297..6b402d7c5 100644 --- a/variants/esp32c6/tlora_c6/platformio.ini +++ b/variants/esp32c6/tlora_c6/platformio.ini @@ -8,4 +8,3 @@ build_flags = -I variants/esp32c6/tlora_c6 -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 - -ULED_BUILTIN diff --git a/variants/esp32s3/heltec_capsule_sensor_v3/platformio.ini b/variants/esp32s3/heltec_capsule_sensor_v3/platformio.ini index 6dd828433..0bb21581a 100644 --- a/variants/esp32s3/heltec_capsule_sensor_v3/platformio.ini +++ b/variants/esp32s3/heltec_capsule_sensor_v3/platformio.ini @@ -6,5 +6,4 @@ board_build.partitions = default_8MB.csv build_flags = ${esp32s3_base.build_flags} -I variants/esp32s3/heltec_capsule_sensor_v3 -D HELTEC_CAPSULE_SENSOR_V3 - -ULED_BUILTIN ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output diff --git a/variants/esp32s3/heltec_sensor_hub/platformio.ini b/variants/esp32s3/heltec_sensor_hub/platformio.ini index 9a5384ccd..ab99e51ed 100644 --- a/variants/esp32s3/heltec_sensor_hub/platformio.ini +++ b/variants/esp32s3/heltec_sensor_hub/platformio.ini @@ -7,4 +7,3 @@ build_flags = ${esp32s3_base.build_flags} -I variants/esp32s3/heltec_sensor_hub -D HELTEC_SENSOR_HUB - -ULED_BUILTIN diff --git a/variants/esp32s3/heltec_v3/platformio.ini b/variants/esp32s3/heltec_v3/platformio.ini index fe31df094..2f53c8756 100644 --- a/variants/esp32s3/heltec_v3/platformio.ini +++ b/variants/esp32s3/heltec_v3/platformio.ini @@ -18,4 +18,3 @@ build_flags = ${esp32s3_base.build_flags} -D HELTEC_V3 -I variants/esp32s3/heltec_v3 - -ULED_BUILTIN diff --git a/variants/esp32s3/heltec_v4/platformio.ini b/variants/esp32s3/heltec_v4/platformio.ini index 0336bf983..5a5004a45 100644 --- a/variants/esp32s3/heltec_v4/platformio.ini +++ b/variants/esp32s3/heltec_v4/platformio.ini @@ -8,7 +8,6 @@ build_flags = -D HELTEC_V4 -D HAS_LORA_FEM=1 -I variants/esp32s3/heltec_v4 - -ULED_BUILTIN [env:heltec-v4] diff --git a/variants/esp32s3/heltec_vision_master_t190/platformio.ini b/variants/esp32s3/heltec_vision_master_t190/platformio.ini index be1ea192d..3dab9f93c 100644 --- a/variants/esp32s3/heltec_vision_master_t190/platformio.ini +++ b/variants/esp32s3/heltec_vision_master_t190/platformio.ini @@ -20,5 +20,5 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-st7789 packageName=https://github.com/meshtastic/st7789 gitBranch=main - https://github.com/meshtastic/st7789/archive/a787beea5c6c8f864ba6787eb432bbefc575e6ad.zip + https://github.com/meshtastic/st7789/archive/92bae2e4a307afb430c3b0bc3d661c55ee1565f0.zip upload_speed = 921600 diff --git a/variants/esp32s3/heltec_wsl_v3/platformio.ini b/variants/esp32s3/heltec_wsl_v3/platformio.ini index 873300c3c..0903a6bc7 100644 --- a/variants/esp32s3/heltec_wsl_v3/platformio.ini +++ b/variants/esp32s3/heltec_wsl_v3/platformio.ini @@ -17,4 +17,3 @@ build_flags = ${esp32s3_base.build_flags} -D HELTEC_WSL_V3 -I variants/esp32s3/heltec_wsl_v3 - -ULED_BUILTIN diff --git a/variants/esp32s3/link32_s3_v1/platformio.ini b/variants/esp32s3/link32_s3_v1/platformio.ini index acce3dafb..b11ffaad0 100644 --- a/variants/esp32s3/link32_s3_v1/platformio.ini +++ b/variants/esp32s3/link32_s3_v1/platformio.ini @@ -11,3 +11,4 @@ build_flags = -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 + -DRADIOLIB_EXCLUDE_LR2021=1 diff --git a/variants/esp32s3/m5stack_cardputer_adv/platformio.ini b/variants/esp32s3/m5stack_cardputer_adv/platformio.ini index 7da039cd4..3b378ed94 100644 --- a/variants/esp32s3/m5stack_cardputer_adv/platformio.ini +++ b/variants/esp32s3/m5stack_cardputer_adv/platformio.ini @@ -16,7 +16,7 @@ build_src_filter = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-st7789 packageName=https://github.com/meshtastic/st7789 gitBranch=main - https://github.com/meshtastic/st7789/archive/a787beea5c6c8f864ba6787eb432bbefc575e6ad.zip + https://github.com/meshtastic/st7789/archive/92bae2e4a307afb430c3b0bc3d661c55ee1565f0.zip # renovate: datasource=github-tags depName=pschatzmann_arduino-audio-driver packageName=pschatzmann/arduino-audio-driver https://github.com/pschatzmann/arduino-audio-driver/archive/v0.2.1.zip # renovate: datasource=git-refs depName=ESP8266Audio packageName=https://github.com/meshtastic/ESP8266Audio gitBranch=meshtastic-2.0.0-dacfix diff --git a/variants/native/portduino.ini b/variants/native/portduino.ini index 86b1fe60a..87d8431a3 100644 --- a/variants/native/portduino.ini +++ b/variants/native/portduino.ini @@ -2,7 +2,7 @@ [portduino_base] platform = # renovate: datasource=git-refs depName=platform-native packageName=https://github.com/meshtastic/platform-native gitBranch=develop - https://github.com/meshtastic/platform-native/archive/f566d364204416cdbf298e349213f7d551f793d9.zip + https://github.com/meshtastic/platform-native/archive/71ed55bb95feb3c43ebde1ec1e2e17643a424c04.zip framework = arduino build_src_filter = diff --git a/variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini b/variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini index e7eede80f..cecca3d81 100644 --- a/variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini +++ b/variants/nrf52840/gat562_mesh_trial_tracker/platformio.ini @@ -11,4 +11,5 @@ build_flags = ${nrf52840_base.build_flags} -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 + -DRADIOLIB_EXCLUDE_LR2021=1 build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/gat562_mesh_trial_tracker> diff --git a/variants/nrf52840/heltec_mesh_node_t114/platformio.ini b/variants/nrf52840/heltec_mesh_node_t114/platformio.ini index ef8bd4a17..c9f998240 100644 --- a/variants/nrf52840/heltec_mesh_node_t114/platformio.ini +++ b/variants/nrf52840/heltec_mesh_node_t114/platformio.ini @@ -23,4 +23,4 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/heltec_ lib_deps = ${nrf52840_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-st7789 packageName=https://github.com/meshtastic/st7789 gitBranch=main - https://github.com/meshtastic/st7789/archive/a787beea5c6c8f864ba6787eb432bbefc575e6ad.zip + https://github.com/meshtastic/st7789/archive/92bae2e4a307afb430c3b0bc3d661c55ee1565f0.zip diff --git a/variants/nrf52840/heltec_mesh_solar/platformio.ini b/variants/nrf52840/heltec_mesh_solar/platformio.ini index 1b15c0758..1b6f59a68 100644 --- a/variants/nrf52840/heltec_mesh_solar/platformio.ini +++ b/variants/nrf52840/heltec_mesh_solar/platformio.ini @@ -132,4 +132,4 @@ build_flags = ${heltec_mesh_solar_base.build_flags} lib_deps = ${heltec_mesh_solar_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-st7789 packageName=https://github.com/meshtastic/st7789 gitBranch=main - https://github.com/meshtastic/st7789/archive/a787beea5c6c8f864ba6787eb432bbefc575e6ad.zip + https://github.com/meshtastic/st7789/archive/92bae2e4a307afb430c3b0bc3d661c55ee1565f0.zip diff --git a/variants/nrf52840/meshlink/platformio.ini b/variants/nrf52840/meshlink/platformio.ini index 28122d9bd..f3dc6185c 100644 --- a/variants/nrf52840/meshlink/platformio.ini +++ b/variants/nrf52840/meshlink/platformio.ini @@ -12,6 +12,7 @@ build_flags = ${nrf52840_base.build_flags} -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 + -DRADIOLIB_EXCLUDE_LR2021=1 build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/meshlink> debug_tool = jlink @@ -30,6 +31,7 @@ build_flags = ${nrf52840_base.build_flags} -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 + -DRADIOLIB_EXCLUDE_LR2021=1 -D USE_EINK -D EINK_DISPLAY_MODEL=GxEPD2_213_B74 -D EINK_WIDTH=250 @@ -51,4 +53,4 @@ lib_deps = debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds -;upload_protocol = jlink \ No newline at end of file +;upload_protocol = jlink diff --git a/variants/nrf52840/nrf52840.ini b/variants/nrf52840/nrf52840.ini index 09b2ef97d..c5590cbc3 100644 --- a/variants/nrf52840/nrf52840.ini +++ b/variants/nrf52840/nrf52840.ini @@ -4,6 +4,7 @@ extends = nrf52_base build_flags = ${nrf52_base.build_flags} -DSERIAL_BUFFER_SIZE=4096 + -DLED_BUILTIN=-1 lib_deps = ${nrf52_base.lib_deps} @@ -79,4 +80,4 @@ debug_speed = 4000 ; The following is not needed because it automatically tries do this ;debug_server_ready_pattern = -.*GDB server started on port \d+.* -;debug_port = localhost:3333 \ No newline at end of file +;debug_port = localhost:3333 diff --git a/variants/nrf52840/r1-neo/platformio.ini b/variants/nrf52840/r1-neo/platformio.ini index 85fe49cf1..0aaec2330 100644 --- a/variants/nrf52840/r1-neo/platformio.ini +++ b/variants/nrf52840/r1-neo/platformio.ini @@ -18,6 +18,7 @@ build_flags = ${nrf52840_base.build_flags} -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 + -DRADIOLIB_EXCLUDE_LR2021=1 build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/r1-neo> + + lib_deps = ${nrf52840_base.lib_deps} diff --git a/variants/nrf52840/rak2560/platformio.ini b/variants/nrf52840/rak2560/platformio.ini index 1703a13ae..54b66f4b2 100644 --- a/variants/nrf52840/rak2560/platformio.ini +++ b/variants/nrf52840/rak2560/platformio.ini @@ -18,6 +18,7 @@ build_flags = ${nrf52840_base.build_flags} -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 + -DRADIOLIB_EXCLUDE_LR2021=1 -DHAS_RAKPROT=1 ; Define if RAk OneWireSerial is used (disables GPS) build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/rak2560> + + + lib_deps = diff --git a/variants/nrf52840/rak3401_1watt/platformio.ini b/variants/nrf52840/rak3401_1watt/platformio.ini index bb8fa28df..889a17ed6 100644 --- a/variants/nrf52840/rak3401_1watt/platformio.ini +++ b/variants/nrf52840/rak3401_1watt/platformio.ini @@ -22,6 +22,7 @@ build_flags = ${nrf52840_base.build_flags} -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 + -DRADIOLIB_EXCLUDE_LR2021=1 build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/rak3401_1watt> + lib_deps = ${nrf52840_base.lib_deps} diff --git a/variants/nrf52840/rak4631/platformio.ini b/variants/nrf52840/rak4631/platformio.ini index 4a96fc8d9..179d73e92 100644 --- a/variants/nrf52840/rak4631/platformio.ini +++ b/variants/nrf52840/rak4631/platformio.ini @@ -21,6 +21,7 @@ build_flags = ${nrf52840_base.build_flags} -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 + -DRADIOLIB_EXCLUDE_LR2021=1 build_src_filter = ${nrf52_base.build_src_filter} \ +<../variants/nrf52840/rak4631> \ + \ diff --git a/variants/nrf52840/rak4631_epaper/platformio.ini b/variants/nrf52840/rak4631_epaper/platformio.ini index caa6ea328..f71fb6301 100644 --- a/variants/nrf52840/rak4631_epaper/platformio.ini +++ b/variants/nrf52840/rak4631_epaper/platformio.ini @@ -11,6 +11,7 @@ build_flags = ${nrf52840_base.build_flags} -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 + -DRADIOLIB_EXCLUDE_LR2021=1 build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/rak4631_epaper> lib_deps = ${nrf52840_base.lib_deps} diff --git a/variants/nrf52840/rak4631_epaper_onrxtx/platformio.ini b/variants/nrf52840/rak4631_epaper_onrxtx/platformio.ini index 84a582fd9..670b2c415 100644 --- a/variants/nrf52840/rak4631_epaper_onrxtx/platformio.ini +++ b/variants/nrf52840/rak4631_epaper_onrxtx/platformio.ini @@ -13,6 +13,7 @@ build_flags = ${nrf52840_base.build_flags} -D RADIOLIB_EXCLUDE_SX128X=1 -D RADIOLIB_EXCLUDE_SX127X=1 -D RADIOLIB_EXCLUDE_LR11X0=1 + -D RADIOLIB_EXCLUDE_LR2021=1 build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/rak4631_epaper_onrxtx> lib_deps = ${nrf52840_base.lib_deps} diff --git a/variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini b/variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini index 9b15e668a..f1641e7e4 100644 --- a/variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini +++ b/variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini @@ -21,6 +21,7 @@ build_flags = ${nrf52840_base.build_flags} -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 + -DRADIOLIB_EXCLUDE_LR2021=1 build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/rak4631_nomadstar_meteor_pro> + + lib_deps = ${nrf52840_base.lib_deps} diff --git a/variants/nrf52840/rak_wismeshtag/platformio.ini b/variants/nrf52840/rak_wismeshtag/platformio.ini index 1e6e63e60..07fd6e73f 100644 --- a/variants/nrf52840/rak_wismeshtag/platformio.ini +++ b/variants/nrf52840/rak_wismeshtag/platformio.ini @@ -19,5 +19,6 @@ build_flags = ${nrf52840_base.build_flags} -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 + -DRADIOLIB_EXCLUDE_LR2021=1 -DMESHTASTIC_EXCLUDE_WIFI=1 build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/rak_wismeshtag> diff --git a/variants/rp2040/rpipicow/platformio.ini b/variants/rp2040/rpipicow/platformio.ini index 9b4b29a5b..99e02a1aa 100644 --- a/variants/rp2040/rpipicow/platformio.ini +++ b/variants/rp2040/rpipicow/platformio.ini @@ -22,7 +22,6 @@ build_flags = -D HW_SPI1_DEVICE -D HAS_UDP_MULTICAST=1 -fexceptions # for exception handling in MQTT - -ULED_BUILTIN build_src_filter = ${rp2040_base.build_src_filter} + lib_deps = ${rp2040_base.lib_deps} diff --git a/variants/stm32/rak3172/variant.h b/variants/stm32/rak3172/variant.h index bd6decd4c..75e3e0c91 100644 --- a/variants/stm32/rak3172/variant.h +++ b/variants/stm32/rak3172/variant.h @@ -16,6 +16,11 @@ Do not expect a working Meshtastic device with this target. #define LED_POWER PA0 // Green LED #define LED_STATE_ON 1 +#define BATTERY_PIN AVBAT +// ADC_MULTIPLIER: 3.0 = internal 1:3 bridge divider (DS13105§3.18.3) +// Margin: 1.10 = AVBAT divider tolerance ±10% (Table 82) +#define ADC_MULTIPLIER (1.01f * 3) + #define RAK3172 #define SERIAL_PRINT_PORT 1 diff --git a/variants/stm32/russell/platformio.ini b/variants/stm32/russell/platformio.ini index 0dd57a2c7..73cf7f81a 100644 --- a/variants/stm32/russell/platformio.ini +++ b/variants/stm32/russell/platformio.ini @@ -13,9 +13,19 @@ build_flags = ${stm32_base.build_flags} -Ivariants/stm32/russell -DPRIVATE_HW + -DMESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR=1 + -DMESHTASTIC_EXCLUDE_RANGETEST=1 + -DMESHTASTIC_EXCLUDE_DETECTIONSENSOR=1 + -DMESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION=1 + -DMESHTASTIC_EXCLUDE_POWERSTRESS=1 + -DMESHTASTIC_EXCLUDE_NEIGHBORINFO=1 + -DMESHTASTIC_EXCLUDE_TRACEROUTE=1 + -DMESHTASTIC_EXCLUDE_WAYPOINT=1 lib_deps = ${stm32_base.lib_deps} # renovate: datasource=custom.pio depName=Adafruit BME280 packageName=adafruit/library/Adafruit BME280 Library adafruit/Adafruit BME280 Library@2.3.0 + # renovate: datasource=custom.pio depName=Adafruit_BME680 packageName=adafruit/library/Adafruit BME680 Library + adafruit/Adafruit BME680 Library@2.0.6 upload_port = stlink diff --git a/variants/stm32/russell/variant.h b/variants/stm32/russell/variant.h index 8773d5d8d..d36826c15 100644 --- a/variants/stm32/russell/variant.h +++ b/variants/stm32/russell/variant.h @@ -13,6 +13,16 @@ // #define EXT_CHRG_DETECT PA5 // #define EXT_PWR_DETECT PA4 +#define BATTERY_PIN AVBAT +// ADC_MULTIPLIER: 3.0 = internal 1:3 bridge divider (DS13105§3.18.3) +// Margin: 1.10 = AVBAT divider tolerance ±10% (Table 82) +#define ADC_MULTIPLIER (1.01f * 3) +/* +Sample OCV curve for Li-SOCl2 primary lithium cells (e.g. Saft cells have fresh OCV of 3.67V) +#define NUM_OCV_POINTS 11 +#define OCV_ARRAY 3670, 3650, 3630, 3610, 3590, 3560, 3530, 3480, 3400, 3200, 2500 +*/ + // Bosch Sensortec BME280 #define HAS_SENSOR 1 @@ -20,6 +30,11 @@ #define ENABLE_HWSERIAL1 #define PIN_SERIAL1_RX PB7 #define PIN_SERIAL1_TX PB6 + +// Debug serial (USART2) +#define ENABLE_HWSERIAL2 +#define PIN_SERIAL2_TX PA2 +#define PIN_SERIAL2_RX PA3 #define HAS_GPS 1 #define PIN_GPS_STANDBY PA15 #define GPS_RX_PIN PB7 diff --git a/variants/stm32/stm32.ini b/variants/stm32/stm32.ini index d2c155398..1efe18e3d 100644 --- a/variants/stm32/stm32.ini +++ b/variants/stm32/stm32.ini @@ -35,6 +35,8 @@ build_flags = -DRADIOLIB_EXCLUDE_SX128X=1 -DRADIOLIB_EXCLUDE_SX127X=1 -DRADIOLIB_EXCLUDE_LR11X0=1 + -DRADIOLIB_EXCLUDE_LR2021=1 + -DMESHTASTIC_DYNAMIC_SBRK_HEAP -DHAL_DAC_MODULE_ONLY -DHAL_RNG_MODULE_ENABLED -Wl,--wrap=__assert_func @@ -56,3 +58,6 @@ lib_deps = lib_ignore = OneButton + +; Set a custom linker script with a higher MinStackSize value, to match NRF52. +board_build.ldscript = $PROJECT_DIR/variants/stm32/stm32wle5xx.ld \ No newline at end of file diff --git a/variants/stm32/stm32wle5xx.ld b/variants/stm32/stm32wle5xx.ld new file mode 100644 index 000000000..c13782926 --- /dev/null +++ b/variants/stm32/stm32wle5xx.ld @@ -0,0 +1,204 @@ +/* +****************************************************************************** +** +** File : LinkerScript.ld +** +** Author : STM32CubeIDE +** +** Abstract : Linker script for STM32WL55xC Device +** 256Kbytes FLASH +** 64Kbytes RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** Distribution: The file is distributed as is without any warranty +** of any kind. +** +***************************************************************************** +** @attention +** +**

© Copyright (c) 2020 STMicroelectronics. +** All rights reserved.

+** +** This software component is licensed by ST under BSD 3-Clause license, +** the "License"; You may not use this file except in compliance with the +** License. You may obtain a copy of the License at: +** opensource.org/licenses/BSD-3-Clause +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ + +_Min_Heap_Size = 0x200 ; /* required amount of heap */ +/* Modified from original to 2KB, to match NRF52 */ +_Min_Stack_Size = 2048 ; /* required amount of stack */ + +/* Memories definition */ +MEMORY +{ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = LD_MAX_DATA_SIZE + FLASH (rx) : ORIGIN = 0x08000000 + LD_FLASH_OFFSET, LENGTH = LD_MAX_SIZE - LD_FLASH_OFFSET +} + +/* Sections */ +SECTIONS +{ + /* The startup code into "FLASH" Rom type memory */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data into "FLASH" Rom type memory */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data into "FLASH" Rom type memory */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab (READONLY) : { + . = ALIGN(4); + *(.ARM.extab* .gnu.linkonce.armextab.*) + . = ALIGN(4); + } >FLASH + + .ARM (READONLY) : { + . = ALIGN(4); + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + . = ALIGN(4); + } >FLASH + + .preinit_array (READONLY) : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + . = ALIGN(4); + } >FLASH + + .init_array (READONLY) : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + . = ALIGN(4); + } >FLASH + + .fini_array (READONLY) : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(4); + } >FLASH + + /* Used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections into "RAM" Ram type memory */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + *(.RamFunc) /* .RamFunc sections */ + *(.RamFunc*) /* .RamFunc* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + + } >RAM AT> FLASH + + /* Uninitialized data section into "RAM" Ram type memory */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* Define a noinit output section and mark it as NOLOAD to prevent + * putting its contents into the resulting .bin file (which is the + * default). */ + .noinit (NOLOAD) : + { + /* Ensure output is aligned */ + . = ALIGN(4); + /* Define a global _snoinit (and _enoinit below) symbol just in case + * code wants to iterate over all noinit variables for some reason */ + _snoinit = .; + /* Actually import the .noinit and .noinit* import sections */ + *(.noinit) + *(.noinit*) + . = ALIGN(4); + _enoinit = .; + } >RAM + + /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM + + /* Remove information from the compiler libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/version.properties b/version.properties index 8621dd9c9..4ee342bb8 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 7 -build = 22 +build = 23