mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-14 15:31:31 +10:00
Compare commits
84
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6208c243f9 | ||
|
|
3a87e746a8 | ||
|
|
cd04206334 | ||
|
|
8e55a6e4c1 | ||
|
|
f14ef121ef | ||
|
|
92263859a7 | ||
|
|
2768080edf | ||
|
|
466cc4cecd | ||
|
|
fe90c49795 | ||
|
|
23f92c1cbd | ||
|
|
31418ca821 | ||
|
|
0ee5777c15 | ||
|
|
026213aab7 | ||
|
|
c1bee82baf | ||
|
|
0cab43fb43 | ||
|
|
47e129f4bd | ||
|
|
1341cd4078 | ||
|
|
4059202a5c | ||
|
|
d24d8806e1 | ||
|
|
a67eb15ad3 | ||
|
|
9e182a595c | ||
|
|
4587dc2d64 | ||
|
|
00fccd87f9 | ||
|
|
01bd4cfb73 | ||
|
|
125c1b7f13 | ||
|
|
d6cf67b6bc | ||
|
|
96dd647882 | ||
|
|
77f378dd53 | ||
|
|
e42ff3590c | ||
|
|
7527233130 | ||
|
|
197226365b | ||
|
|
16dcafa7fb | ||
|
|
eeb95d6bff | ||
|
|
4ac74edf38 | ||
|
|
323830c7cc | ||
|
|
a9acd506a8 | ||
|
|
a1d6c6db62 | ||
|
|
69495dcd98 | ||
|
|
0f2d224e74 | ||
|
|
381cefa6b2 | ||
|
|
a50cbdc95b | ||
|
|
e7c7af40ae | ||
|
|
288d7a3e7b | ||
|
|
48ae4b6c7a | ||
|
|
ae5019bec6 | ||
|
|
4990bf51e3 | ||
|
|
3cd3fd3386 | ||
|
|
839cf554b7 | ||
|
|
b2c8cbb78d | ||
|
|
8061f83704 | ||
|
|
216655f05f | ||
|
|
a3b49b9028 | ||
|
|
2c633b6458 | ||
|
|
17945884a5 | ||
|
|
7fdee353b5 | ||
|
|
1116f06139 | ||
|
|
16cf962351 | ||
|
|
12f0a74557 | ||
|
|
2dd9c5eef2 | ||
|
|
98963218ad | ||
|
|
6628c9e66e | ||
|
|
c728cfdaf4 | ||
|
|
d96770007d | ||
|
|
9322bcdb21 | ||
|
|
1370b234eb | ||
|
|
9ba44bfbfb | ||
|
|
2f19a1d7a4 | ||
|
|
71c8143f72 | ||
|
|
222d3e6b62 | ||
|
|
2e6519bb98 | ||
|
|
934c3fa8be | ||
|
|
726d539174 | ||
|
|
e7ee4bea18 | ||
|
|
7f0cd70c07 | ||
|
|
d5fe7dc9e6 | ||
|
|
98efb25a0c | ||
|
|
8dc3c0541b | ||
|
|
fc6c89abeb | ||
|
|
c7feef00c0 | ||
|
|
8c905427a1 | ||
|
|
90befeeeb1 | ||
|
|
9e61c44629 | ||
|
|
3ad80b80ee | ||
|
|
8fe12e9fda |
+164
-27
@@ -4,11 +4,11 @@ This document provides context and guidelines for AI assistants working with the
|
|||||||
|
|
||||||
## Project Overview
|
## 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
|
### 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
|
- **nRF52** (nRF52840, nRF52833) - Low power Nordic chips
|
||||||
- **RP2040/RP2350** - Raspberry Pi Pico variants
|
- **RP2040/RP2350** - Raspberry Pi Pico variants
|
||||||
- **STM32WL** - STM32 with integrated LoRa
|
- **STM32WL** - STM32 with integrated LoRa
|
||||||
@@ -80,21 +80,46 @@ firmware/
|
|||||||
│ │ ├── NodeDB.* # Node database management
|
│ │ ├── NodeDB.* # Node database management
|
||||||
│ │ ├── Router.* # Packet routing
|
│ │ ├── Router.* # Packet routing
|
||||||
│ │ ├── Channels.* # Channel management
|
│ │ ├── Channels.* # Channel management
|
||||||
|
│ │ ├── CryptoEngine.* # AES-CCM encryption
|
||||||
│ │ ├── *Interface.* # Radio interface implementations
|
│ │ ├── *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
|
│ │ └── generated/ # Protobuf generated code
|
||||||
│ ├── modules/ # Feature modules (Position, Telemetry, etc.)
|
│ ├── modules/ # Feature modules (Position, Telemetry, etc.)
|
||||||
|
│ │ └── Telemetry/ # Telemetry subsystem
|
||||||
|
│ │ └── Sensor/ # 50+ I2C sensor drivers
|
||||||
│ ├── gps/ # GPS handling
|
│ ├── gps/ # GPS handling
|
||||||
│ ├── graphics/ # Display drivers and UI
|
│ ├── graphics/ # Display drivers and UI
|
||||||
│ ├── platform/ # Platform-specific code
|
│ │ └── niche/ # Specialized UIs (InkHUD e-ink framework)
|
||||||
│ ├── input/ # Input device handling
|
│ ├── platform/ # Platform-specific code (esp32, nrf52, rp2xx0, stm32wl, portduino)
|
||||||
│ └── concurrency/ # Threading utilities
|
│ ├── 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
|
├── variants/ # Hardware variant definitions
|
||||||
│ ├── esp32/ # ESP32 variants
|
│ ├── esp32/ # ESP32 variants
|
||||||
│ ├── esp32s3/ # ESP32-S3 variants
|
│ ├── esp32s3/ # ESP32-S3 variants
|
||||||
│ ├── nrf52/ # nRF52 variants
|
│ ├── esp32c3/ # ESP32-C3 variants
|
||||||
│ └── rp2xxx/ # RP2040/RP2350 variants
|
│ ├── esp32c6/ # ESP32-C6 variants
|
||||||
|
│ ├── nrf52840/ # nRF52 variants
|
||||||
|
│ ├── rp2040/ # RP2040/RP2350 variants
|
||||||
|
│ ├── stm32/ # STM32WL variants
|
||||||
|
│ └── native/ # Linux/Portduino variants
|
||||||
├── protobufs/ # Protocol buffer definitions
|
├── protobufs/ # Protocol buffer definitions
|
||||||
├── boards/ # Custom PlatformIO board definitions
|
├── boards/ # Custom PlatformIO board definitions
|
||||||
|
├── test/ # Unit tests (12 test suites)
|
||||||
└── bin/ # Build and utility scripts
|
└── bin/ # Build and utility scripts
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -105,6 +130,7 @@ firmware/
|
|||||||
- Follow existing code style - run `trunk fmt` before commits
|
- Follow existing code style - run `trunk fmt` before commits
|
||||||
- Prefer `LOG_DEBUG`, `LOG_INFO`, `LOG_WARN`, `LOG_ERROR` for logging
|
- Prefer `LOG_DEBUG`, `LOG_INFO`, `LOG_WARN`, `LOG_ERROR` for logging
|
||||||
- Use `assert()` for invariants that should never fail
|
- Use `assert()` for invariants that should never fail
|
||||||
|
- C++17 features are available (`std::optional`, structured bindings, `if constexpr`, etc.)
|
||||||
|
|
||||||
### Naming Conventions
|
### Naming Conventions
|
||||||
|
|
||||||
@@ -118,70 +144,151 @@ firmware/
|
|||||||
|
|
||||||
#### Module System
|
#### Module System
|
||||||
|
|
||||||
Modules inherit from `MeshModule` or `ProtobufModule<T>` and implement:
|
Modules use a three-tier class hierarchy:
|
||||||
|
|
||||||
- `handleReceivedProtobuf()` - Process incoming packets
|
1. **`MeshModule`** - Base class. Implement `wantPacket()` and `handleReceived()`. Returns `ProcessMessage::STOP` or `ProcessMessage::CONTINUE`.
|
||||||
- `allocReply()` - Generate response packets
|
2. **`SinglePortModule`** - Handles a single portnum. Simplified `wantPacket()` that checks `decoded.portnum`.
|
||||||
- `runOnce()` - Periodic task execution (returns next run interval in ms)
|
3. **`ProtobufModule<T>`** - Template for protobuf-based modules. Handles encoding/decoding automatically.
|
||||||
|
|
||||||
|
Most modules also inherit from **`OSThread`** for periodic tasks (the "mixin" pattern):
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
class MyModule : public ProtobufModule<meshtastic_MyMessage>
|
class MyModule : public ProtobufModule<meshtastic_MyMessage>, private concurrency::OSThread
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
MyModule();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_MyMessage *msg) override;
|
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<const meshtastic::Status *> newStatus;
|
||||||
|
newStatus.notifyObservers(&status);
|
||||||
|
|
||||||
|
// Observer receives events via callback
|
||||||
|
CallbackObserver<MyClass, const meshtastic::Status *> statusObserver =
|
||||||
|
CallbackObserver<MyClass, const meshtastic::Status *>(this, &MyClass::handleStatusUpdate);
|
||||||
|
```
|
||||||
|
|
||||||
#### Configuration Access
|
#### Configuration Access
|
||||||
|
|
||||||
- `config.*` - Device configuration (LoRa, position, power, etc.)
|
- `config.*` - Device configuration (LoRa, position, power, etc.)
|
||||||
- `moduleConfig.*` - Module-specific configuration
|
- `moduleConfig.*` - Module-specific configuration
|
||||||
- `channels.*` - Channel configuration and management
|
- `channels.*` - Channel configuration and management
|
||||||
|
- `owner` - Device owner info
|
||||||
|
- `myNodeInfo` - Local node info
|
||||||
|
|
||||||
#### Default Values
|
#### Default Values
|
||||||
|
|
||||||
Use the `Default` class helpers in `src/mesh/Default.h`:
|
Use the `Default` class helpers in `src/mesh/Default.h`:
|
||||||
|
|
||||||
- `Default::getConfiguredOrDefaultMs(configured, default)` - Returns ms, using default if configured is 0
|
- `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::getConfiguredOrMinimumValue(configured, min)` - Enforces minimum values
|
||||||
- `Default::getConfiguredOrDefaultMsScaled(configured, default, numNodes)` - Scales based on network size
|
- `Default::getConfiguredOrDefaultMsScaled(configured, default, numNodes)` - Scales based on network size
|
||||||
|
|
||||||
#### Thread Safety
|
#### Thread Safety
|
||||||
|
|
||||||
- Use `concurrency::Lock` for mutex protection
|
- Use `concurrency::Lock` and `concurrency::LockGuard` for mutex protection
|
||||||
- Radio SPI access uses `SPILock`
|
- Radio SPI access uses `SPILock`
|
||||||
- Prefer `OSThread` for background tasks
|
- 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
|
### Hardware Variants
|
||||||
|
|
||||||
Each hardware variant has:
|
Each hardware variant has:
|
||||||
|
|
||||||
- `variant.h` - Pin definitions and hardware capabilities
|
- `variant.h` - Pin definitions and hardware capabilities
|
||||||
- `platformio.ini` - Build configuration
|
- `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:
|
Key defines in variant.h:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#define USE_SX1262 // Radio chip selection
|
#define USE_SX1262 // Radio chip selection
|
||||||
#define HAS_GPS 1 // Hardware capabilities
|
#define HAS_GPS 1 // Hardware capabilities
|
||||||
|
#define HAS_SCREEN 1 // Display present
|
||||||
#define LORA_CS 36 // Pin assignments
|
#define LORA_CS 36 // Pin assignments
|
||||||
#define SX126X_DIO1 14 // Radio-specific pins
|
#define SX126X_DIO1 14 // Radio-specific pins
|
||||||
```
|
```
|
||||||
|
|
||||||
### Protobuf Messages
|
### Protobuf Messages
|
||||||
|
|
||||||
- Defined in `protobufs/meshtastic/*.proto`
|
- Defined in `protobufs/meshtastic/*.proto` (~32 proto files)
|
||||||
- Generated code in `src/mesh/generated/`
|
- Generated code in `src/mesh/generated/meshtastic/`
|
||||||
- Regenerate with `bin/regen-protos.sh`
|
- Regenerate with `bin/regen-protos.sh`
|
||||||
- Message types prefixed with `meshtastic_`
|
- Message types prefixed with `meshtastic_`
|
||||||
|
- Nanopb `.options` files control field sizes and encoding
|
||||||
|
|
||||||
### Conditional Compilation
|
### Conditional Compilation
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#if !MESHTASTIC_EXCLUDE_GPS // Feature exclusion
|
#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_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
|
#if defined(USE_SX1262) // Radio-specific
|
||||||
#ifdef HAS_SCREEN // Hardware capability
|
#ifdef HAS_SCREEN // Hardware capability
|
||||||
#if USERPREFS_EVENT_MODE // User preferences
|
#if USERPREFS_EVENT_MODE // User preferences
|
||||||
@@ -192,7 +299,7 @@ Key defines in variant.h:
|
|||||||
Uses **PlatformIO** with custom scripts:
|
Uses **PlatformIO** with custom scripts:
|
||||||
|
|
||||||
- `bin/platformio-pre.py` - Pre-build script
|
- `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:
|
Build commands:
|
||||||
|
|
||||||
@@ -202,21 +309,38 @@ pio run -e tbeam -t upload # Build and upload
|
|||||||
pio run -e native # Build native/Linux version
|
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
|
## Common Tasks
|
||||||
|
|
||||||
### Adding a New Module
|
### Adding a New Module
|
||||||
|
|
||||||
1. Create `src/modules/MyModule.cpp` and `.h`
|
1. Create `src/modules/MyModule.cpp` and `.h`
|
||||||
2. Inherit from appropriate base class
|
2. Inherit from appropriate base class (`MeshModule`, `SinglePortModule`, or `ProtobufModule<T>`)
|
||||||
3. Register in `src/modules/Modules.cpp`
|
3. Mix in `concurrency::OSThread` if periodic work is needed
|
||||||
4. Add protobuf messages if needed in `protobufs/`
|
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
|
### Adding a New Hardware Variant
|
||||||
|
|
||||||
1. Create directory under `variants/<arch>/<name>/`
|
1. Create directory under `variants/<arch>/<name>/`
|
||||||
2. Add `variant.h` with pin definitions
|
2. Add `variant.h` with pin definitions and hardware capability defines
|
||||||
3. Add `platformio.ini` with build config
|
3. Add `platformio.ini` with build config — use `extends` to reference common base (e.g., `esp32s3_base`)
|
||||||
4. Reference common configs with `extends`
|
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
|
### Modifying Configuration Defaults
|
||||||
|
|
||||||
@@ -305,9 +429,22 @@ Most workflows can be triggered manually via `workflow_dispatch` for testing.
|
|||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
- Unit tests in `test/` directory
|
Unit tests in `test/` directory with 12 test suites:
|
||||||
- Run with `pio test -e native`
|
|
||||||
- Use `bin/test-simulator.sh` for simulation testing
|
- `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
|
## Resources
|
||||||
|
|
||||||
|
|||||||
@@ -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<T>`** — 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<meshtastic_MyMessage>, 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<MyModule, const meshtastic::Status *> statusObserver =
|
||||||
|
CallbackObserver<MyModule, const meshtastic::Status *>(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/`
|
||||||
@@ -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 <MySensorLibrary.h> // 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
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
# New Hardware Variant
|
||||||
|
|
||||||
|
Guide for adding a new Meshtastic hardware variant to the firmware.
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
Create under `variants/<arch>/<name>/`:
|
||||||
|
|
||||||
|
```
|
||||||
|
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/<arch>/<name>/variant.h` with pin definitions
|
||||||
|
- [ ] Create `variants/<arch>/<name>/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
|
||||||
@@ -56,6 +56,25 @@ jobs:
|
|||||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
id: version
|
id: version
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v4
|
||||||
|
with:
|
||||||
|
cache-image: true
|
||||||
|
|
||||||
|
- name: Docker setup
|
||||||
|
uses: docker/setup-buildx-action@v4
|
||||||
|
with:
|
||||||
|
# Add Google/Amazon DockerHub mirrors to buildkit config
|
||||||
|
# https://docs.docker.com/build/ci/github-actions/configure-builder/#registry-mirror
|
||||||
|
buildkitd-config-inline: |
|
||||||
|
[registry."docker.io"]
|
||||||
|
mirrors = ["mirror.gcr.io", "public.ecr.aws"]
|
||||||
|
|
||||||
|
- name: Sanitize platform string
|
||||||
|
id: sanitize_platform
|
||||||
|
# Replace slashes with underscores
|
||||||
|
run: echo "cleaned_platform=${{ inputs.platform }}" | sed 's/\//_/g' >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Docker login
|
- name: Docker login
|
||||||
if: ${{ inputs.push }}
|
if: ${{ inputs.push }}
|
||||||
uses: docker/login-action@v4
|
uses: docker/login-action@v4
|
||||||
@@ -63,17 +82,6 @@ jobs:
|
|||||||
username: meshtastic
|
username: meshtastic
|
||||||
password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }}
|
password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v4
|
|
||||||
|
|
||||||
- name: Docker setup
|
|
||||||
uses: docker/setup-buildx-action@v4
|
|
||||||
|
|
||||||
- name: Sanitize platform string
|
|
||||||
id: sanitize_platform
|
|
||||||
# Replace slashes with underscores
|
|
||||||
run: echo "cleaned_platform=${{ inputs.platform }}" | sed 's/\//_/g' >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Docker tag
|
- name: Docker tag
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v6
|
uses: docker/metadata-action@v6
|
||||||
@@ -95,3 +103,6 @@ jobs:
|
|||||||
platforms: ${{ inputs.platform }}
|
platforms: ${{ inputs.platform }}
|
||||||
build-args: |
|
build-args: |
|
||||||
PIO_ENV=${{ inputs.pio_env }}
|
PIO_ENV=${{ inputs.pio_env }}
|
||||||
|
# Cache image layers in GitHub Actions cache to speed up subsequent builds.
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|||||||
@@ -301,15 +301,17 @@ jobs:
|
|||||||
id: release_notes
|
id: release_notes
|
||||||
run: |
|
run: |
|
||||||
chmod +x ./bin/generate_release_notes.py
|
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<<EOF" >> $GITHUB_OUTPUT
|
echo "notes<<EOF" >> $GITHUB_OUTPUT
|
||||||
echo "$NOTES" >> $GITHUB_OUTPUT
|
echo "$NOTES" >> $GITHUB_OUTPUT
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
echo "### Release note range" >> $GITHUB_STEP_SUMMARY
|
||||||
|
cat release_notes.log >> $GITHUB_STEP_SUMMARY
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v3
|
||||||
id: create_release
|
id: create_release
|
||||||
with:
|
with:
|
||||||
draft: true
|
draft: true
|
||||||
@@ -466,7 +468,7 @@ jobs:
|
|||||||
- name: Generate release notes
|
- name: Generate release notes
|
||||||
run: |
|
run: |
|
||||||
chmod +x ./bin/generate_release_notes.py
|
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:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Apply quality label if needed
|
- name: Apply quality label if needed
|
||||||
if: steps.quality.outputs.response != '' && steps.quality.outputs.response != 'ok'
|
if: steps.quality.outputs.response != '' && steps.quality.outputs.response != 'ok'
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v9
|
||||||
env:
|
env:
|
||||||
QUALITY_LABEL: ${{ steps.quality.outputs.response }}
|
QUALITY_LABEL: ${{ steps.quality.outputs.response }}
|
||||||
with:
|
with:
|
||||||
@@ -80,7 +80,7 @@ jobs:
|
|||||||
# ─────────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
- name: Determine if completeness check should be skipped
|
- name: Determine if completeness check should be skipped
|
||||||
if: steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == ''
|
if: steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == ''
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v9
|
||||||
id: check-skip
|
id: check-skip
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
@@ -134,7 +134,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Process analysis result
|
- name: Process analysis result
|
||||||
if: (steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == '') && steps.check-skip.outputs.should_skip != 'true' && steps.analysis.outputs.response != ''
|
if: (steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == '') && steps.check-skip.outputs.should_skip != 'true' && steps.analysis.outputs.response != ''
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v9
|
||||||
id: process
|
id: process
|
||||||
env:
|
env:
|
||||||
AI_RESPONSE: ${{ steps.analysis.outputs.response }}
|
AI_RESPONSE: ${{ steps.analysis.outputs.response }}
|
||||||
@@ -174,7 +174,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Apply triage label
|
- name: Apply triage label
|
||||||
if: steps.process.outputs.label != '' && steps.process.outputs.label != 'none'
|
if: steps.process.outputs.label != '' && steps.process.outputs.label != 'none'
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v9
|
||||||
env:
|
env:
|
||||||
LABEL_NAME: ${{ steps.process.outputs.label }}
|
LABEL_NAME: ${{ steps.process.outputs.label }}
|
||||||
with:
|
with:
|
||||||
@@ -200,7 +200,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Comment on issue
|
- name: Comment on issue
|
||||||
if: steps.process.outputs.should_comment == 'true'
|
if: steps.process.outputs.should_comment == 'true'
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v9
|
||||||
env:
|
env:
|
||||||
COMMENT_BODY: ${{ steps.process.outputs.comment_body }}
|
COMMENT_BODY: ${{ steps.process.outputs.comment_body }}
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ jobs:
|
|||||||
# Step 1: Check if PR already has automation/type labels (skip if so)
|
# Step 1: Check if PR already has automation/type labels (skip if so)
|
||||||
# ─────────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
- name: Check existing labels
|
- name: Check existing labels
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v9
|
||||||
id: check-labels
|
id: check-labels
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Apply quality label if needed
|
- name: Apply quality label if needed
|
||||||
if: steps.check-labels.outputs.skip_all != 'true' && steps.quality.outputs.response != '' && steps.quality.outputs.response != 'ok'
|
if: steps.check-labels.outputs.skip_all != 'true' && steps.quality.outputs.response != '' && steps.quality.outputs.response != 'ok'
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v9
|
||||||
id: quality-label
|
id: quality-label
|
||||||
env:
|
env:
|
||||||
QUALITY_LABEL: ${{ steps.quality.outputs.response }}
|
QUALITY_LABEL: ${{ steps.quality.outputs.response }}
|
||||||
@@ -113,7 +113,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Apply type label
|
- name: Apply type label
|
||||||
if: steps.check-labels.outputs.skip_all != 'true' && steps.check-labels.outputs.has_type_label != 'true' && steps.classify.outputs.response != ''
|
if: steps.check-labels.outputs.skip_all != 'true' && steps.check-labels.outputs.has_type_label != 'true' && steps.classify.outputs.response != ''
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v9
|
||||||
env:
|
env:
|
||||||
TYPE_LABEL: ${{ steps.classify.outputs.response }}
|
TYPE_LABEL: ${{ steps.classify.outputs.response }}
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ on:
|
|||||||
secrets:
|
secrets:
|
||||||
PPA_GPG_PRIVATE_KEY:
|
PPA_GPG_PRIVATE_KEY:
|
||||||
required: true
|
required: true
|
||||||
|
PPA_SFTP_PRIVATE_KEY:
|
||||||
|
required: true
|
||||||
inputs:
|
inputs:
|
||||||
ppa_repo:
|
ppa_repo:
|
||||||
description: Meshtastic PPA to target
|
description: Meshtastic PPA to target
|
||||||
@@ -27,6 +29,7 @@ jobs:
|
|||||||
build_location: ppa
|
build_location: ppa
|
||||||
|
|
||||||
package-ppa:
|
package-ppa:
|
||||||
|
if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
needs: build-debian-src
|
needs: build-debian-src
|
||||||
steps:
|
steps:
|
||||||
@@ -40,7 +43,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update -y --fix-missing
|
sudo apt-get update -y --fix-missing
|
||||||
sudo apt-get install -y dput
|
sudo apt-get install -y dput openssh-client
|
||||||
|
|
||||||
- name: Import GPG key
|
- name: Import GPG key
|
||||||
uses: crazy-max/ghaction-import-gpg@v7
|
uses: crazy-max/ghaction-import-gpg@v7
|
||||||
@@ -65,8 +68,42 @@ jobs:
|
|||||||
- name: Display structure of downloaded files
|
- name: Display structure of downloaded files
|
||||||
run: ls -lah
|
run: ls -lah
|
||||||
|
|
||||||
- name: Publish with dput
|
- name: Trust Launchpad's SSH key
|
||||||
if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
|
|
||||||
timeout-minutes: 15 # dput is terrible, sometimes runs 'forever'
|
|
||||||
run: |
|
run: |
|
||||||
dput ${{ inputs.ppa_repo }} meshtasticd_${{ steps.version.outputs.deb }}~${{ inputs.series }}_source.changes
|
mkdir -p ~/.ssh
|
||||||
|
ssh-keyscan -H ppa.launchpad.net >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Setup dput config
|
||||||
|
env:
|
||||||
|
ppa_login: meshtasticorg
|
||||||
|
run: |
|
||||||
|
sudo tee /etc/meshtastic-dput.cf >/dev/null <<EOF
|
||||||
|
[ppa]
|
||||||
|
fqdn = ppa.launchpad.net
|
||||||
|
method = ftp
|
||||||
|
incoming = ~%(ppa)s
|
||||||
|
login = anonymous
|
||||||
|
|
||||||
|
[ssh-ppa]
|
||||||
|
fqdn = ppa.launchpad.net
|
||||||
|
method = sftp
|
||||||
|
incoming = ~%(ssh-ppa)s
|
||||||
|
login = ${ppa_login}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Import SSH key
|
||||||
|
uses: webfactory/ssh-agent@v0.10.0
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.PPA_SFTP_PRIVATE_KEY }}
|
||||||
|
id: ssh
|
||||||
|
|
||||||
|
- name: Publish with dput (sftp)
|
||||||
|
timeout-minutes: 30 # dput is terrible, sometimes runs 'forever'
|
||||||
|
env:
|
||||||
|
up_ppa_repo: ${{ inputs.ppa_repo }}
|
||||||
|
up_series: ${{ inputs.series }}
|
||||||
|
up_version: ${{ steps.version.outputs.deb }}
|
||||||
|
run: >
|
||||||
|
dput -c /etc/meshtastic-dput.cf
|
||||||
|
ssh-${up_ppa_repo}
|
||||||
|
meshtasticd_${up_version}~${up_series}_source.changes
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check for PR labels
|
- name: Check for PR labels
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v9
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const labels = context.payload.pull_request.labels.map(label => label.name);
|
const labels = context.payload.pull_request.labels.map(label => label.name);
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Comment test results on PR
|
- name: Comment test results on PR
|
||||||
if: github.event_name == 'pull_request' && needs.native-tests.result != 'skipped'
|
if: github.event_name == 'pull_request' && needs.native-tests.result != 'skipped'
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v9
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ jobs:
|
|||||||
node-version: 24
|
node-version: 24
|
||||||
|
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v5
|
uses: pnpm/action-setup@v6
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -8,20 +8,20 @@ plugins:
|
|||||||
uri: https://github.com/trunk-io/plugins
|
uri: https://github.com/trunk-io/plugins
|
||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
- checkov@3.2.513
|
- checkov@3.2.517
|
||||||
- renovate@43.100.0
|
- renovate@43.110.9
|
||||||
- prettier@3.8.1
|
- prettier@3.8.1
|
||||||
- trufflehog@3.94.1
|
- trufflehog@3.94.3
|
||||||
- yamllint@1.38.0
|
- yamllint@1.38.0
|
||||||
- bandit@1.9.4
|
- bandit@1.9.4
|
||||||
- trivy@0.69.3
|
- trivy@0.69.3
|
||||||
- taplo@0.10.0
|
- taplo@0.10.0
|
||||||
- ruff@0.15.8
|
- ruff@0.15.9
|
||||||
- isort@8.0.1
|
- isort@8.0.1
|
||||||
- markdownlint@0.48.0
|
- markdownlint@0.48.0
|
||||||
- oxipng@10.1.0
|
- oxipng@10.1.0
|
||||||
- svgo@4.0.1
|
- svgo@4.0.1
|
||||||
- actionlint@1.7.11
|
- actionlint@1.7.12
|
||||||
- flake8@7.3.0
|
- flake8@7.3.0
|
||||||
- hadolint@2.14.0
|
- hadolint@2.14.0
|
||||||
- shfmt@3.6.0
|
- shfmt@3.6.0
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# MeshAdv-Pi E22-900M30S
|
||||||
|
# https://github.com/chrismyers2000/MeshAdv-Pi-Hat
|
||||||
|
Meta:
|
||||||
|
name: MeshAdv-Pi E22-900M30S
|
||||||
|
support: community
|
||||||
|
compatible:
|
||||||
|
- ebyte-ecb41-pge # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
CS: # GPIO0_A1 (physical 40)
|
||||||
|
pin: 1
|
||||||
|
gpiochip: 0
|
||||||
|
line: 1
|
||||||
|
IRQ: # GPIO0_A3 (physical 36)
|
||||||
|
pin: 3
|
||||||
|
gpiochip: 0
|
||||||
|
line: 3
|
||||||
|
Busy: # GPIO0_A0 (physical 38)
|
||||||
|
pin: 0
|
||||||
|
gpiochip: 0
|
||||||
|
line: 0
|
||||||
|
Reset: # GPIO0_B4 (physical 12)
|
||||||
|
pin: 12
|
||||||
|
gpiochip: 0
|
||||||
|
line: 12
|
||||||
|
TXen: # GPIO1_D1 (physical 33)
|
||||||
|
pin: 57
|
||||||
|
gpiochip: 1
|
||||||
|
line: 25
|
||||||
|
RXen: # GPIO1_B3 (physical 32)
|
||||||
|
pin: 43
|
||||||
|
gpiochip: 1
|
||||||
|
line: 11
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
# Only for E22-900M33S:
|
||||||
|
# Limit the output power to 8 dBm
|
||||||
|
# SX126X_MAX_POWER: 8
|
||||||
|
spidev: spidev0.0
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# MeshAdv Mini E22-900M22S
|
||||||
|
# https://github.com/chrismyers2000/MeshAdv-Mini
|
||||||
|
Meta:
|
||||||
|
name: MeshAdv Mini E22-900M22S
|
||||||
|
support: community
|
||||||
|
compatible:
|
||||||
|
- ebyte-ecb41-pge # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262 # Ebyte E22-900M22S
|
||||||
|
CS: # GPIO0_B6 (physical 24, SPI1_CSN0)
|
||||||
|
pin: 14
|
||||||
|
gpiochip: 0
|
||||||
|
line: 14
|
||||||
|
IRQ: # GPIO0_A3 (physical 36)
|
||||||
|
pin: 3
|
||||||
|
gpiochip: 0
|
||||||
|
line: 3
|
||||||
|
Busy: # GPIO0_A0 (physical 38)
|
||||||
|
pin: 0
|
||||||
|
gpiochip: 0
|
||||||
|
line: 0
|
||||||
|
Reset: # GPIO1_C3 (physical 18)
|
||||||
|
pin: 51
|
||||||
|
gpiochip: 1
|
||||||
|
line: 19
|
||||||
|
RXen: # GPIO1_B3 (physical 32)
|
||||||
|
pin: 43
|
||||||
|
gpiochip: 1
|
||||||
|
line: 11
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
spidev: spidev0.0
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
Meta:
|
||||||
|
name: RAK6421 + RAK13300 Slot 1
|
||||||
|
support: community # Promote when tested
|
||||||
|
compatible:
|
||||||
|
- ebyte-ecb41-pge # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: # GPIO0_A5 (IO6, physical 15)
|
||||||
|
pin: 5
|
||||||
|
gpiochip: 0
|
||||||
|
line: 5
|
||||||
|
Reset: # GPIO0_A3 (IO4, physical 36)
|
||||||
|
pin: 3
|
||||||
|
gpiochip: 0
|
||||||
|
line: 3
|
||||||
|
Busy: # GPIO1_C3 (IO5, physical 18)
|
||||||
|
pin: 51
|
||||||
|
gpiochip: 1
|
||||||
|
line: 19
|
||||||
|
# Ant_sw: # GPIO1_C2 (IO3, physical 16)
|
||||||
|
# pin: 50
|
||||||
|
# gpiochip: 1
|
||||||
|
# line: 18
|
||||||
|
Enable_Pins:
|
||||||
|
- pin: 43 # GPIO1_B3 (physical 32)
|
||||||
|
gpiochip: 1
|
||||||
|
line: 11
|
||||||
|
- pin: 57 # GPIO1_D1 (physical 33)
|
||||||
|
gpiochip: 1
|
||||||
|
line: 25
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
spidev: spidev0.0
|
||||||
|
# CS: # GPIO0_B6 (SPI1_CSN0, physical 24)
|
||||||
|
# pin: 14
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 14
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
Meta:
|
||||||
|
name: RAK6421 + RAK13300 Slot 2
|
||||||
|
support: community # Promote when tested
|
||||||
|
compatible:
|
||||||
|
- ebyte-ecb41-pge # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: # GPIO0_B4 (IO6, physical 12)
|
||||||
|
pin: 12
|
||||||
|
gpiochip: 0
|
||||||
|
line: 12
|
||||||
|
Reset: # GPIO1_C3 (IO4, physical 18)
|
||||||
|
pin: 51
|
||||||
|
gpiochip: 1
|
||||||
|
line: 19
|
||||||
|
Busy: # GPIO0_B3 (IO5, physical 35)
|
||||||
|
pin: 11
|
||||||
|
gpiochip: 0
|
||||||
|
line: 11
|
||||||
|
# Ant_sw: # GPIO1_C2 (IO3, physical 16)
|
||||||
|
# pin: 50
|
||||||
|
# gpiochip: 1
|
||||||
|
# line: 18
|
||||||
|
Enable_Pins:
|
||||||
|
- pin: 2 # GPIO0_A2 (physical 37)
|
||||||
|
gpiochip: 0
|
||||||
|
line: 2
|
||||||
|
- pin: 50 # GPIO1_C2 (physical 16)
|
||||||
|
gpiochip: 1
|
||||||
|
line: 18
|
||||||
|
spidev: spidev0.1
|
||||||
|
# CS: # GPIO0_A7 (SPI1_CSN1, physical 26)
|
||||||
|
# pin: 7
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 7
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
Meta:
|
||||||
|
name: RAK6421 + RAK13302 Slot 1
|
||||||
|
support: community # Promote when tested
|
||||||
|
compatible:
|
||||||
|
- ebyte-ecb41-pge # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: # GPIO0_A5 (IO6, physical 15)
|
||||||
|
pin: 5
|
||||||
|
gpiochip: 0
|
||||||
|
line: 5
|
||||||
|
Reset: # GPIO0_A3 (IO4, physical 36)
|
||||||
|
pin: 3
|
||||||
|
gpiochip: 0
|
||||||
|
line: 3
|
||||||
|
Busy: # GPIO1_C3 (IO5, physical 18)
|
||||||
|
pin: 51
|
||||||
|
gpiochip: 1
|
||||||
|
line: 19
|
||||||
|
# Ant_sw: # GPIO1_C2 (IO3, physical 16)
|
||||||
|
# pin: 50
|
||||||
|
# gpiochip: 1
|
||||||
|
# line: 18
|
||||||
|
Enable_Pins:
|
||||||
|
- pin: 43 # GPIO1_B3 (physical 32)
|
||||||
|
gpiochip: 1
|
||||||
|
line: 11
|
||||||
|
- pin: 57 # GPIO1_D1 (physical 33)
|
||||||
|
gpiochip: 1
|
||||||
|
line: 25
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
spidev: spidev0.0
|
||||||
|
# CS: # GPIO0_B6 (SPI1_CSN0, physical 24)
|
||||||
|
# pin: 14
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 14
|
||||||
|
TX_GAIN_LORA: [9, 9, 10, 11, 9, 8, 9, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 10, 9, 8]
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
Meta:
|
||||||
|
name: RAK6421 + RAK13302 Slot 2
|
||||||
|
support: community # Promote when tested
|
||||||
|
compatible:
|
||||||
|
- ebyte-ecb41-pge # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: # GPIO0_B4 (IO6, physical 12)
|
||||||
|
pin: 12
|
||||||
|
gpiochip: 0
|
||||||
|
line: 12
|
||||||
|
Reset: # GPIO1_C3 (IO4, physical 18)
|
||||||
|
pin: 51
|
||||||
|
gpiochip: 1
|
||||||
|
line: 19
|
||||||
|
Busy: # GPIO0_B3 (IO5, physical 35)
|
||||||
|
pin: 11
|
||||||
|
gpiochip: 0
|
||||||
|
line: 11
|
||||||
|
# Ant_sw: # GPIO1_C2 (IO3, physical 16)
|
||||||
|
# pin: 50
|
||||||
|
# gpiochip: 1
|
||||||
|
# line: 18
|
||||||
|
Enable_Pins:
|
||||||
|
- pin: 2 # GPIO0_A2 (physical 37)
|
||||||
|
gpiochip: 0
|
||||||
|
line: 2
|
||||||
|
- pin: 50 # GPIO1_C2 (physical 16)
|
||||||
|
gpiochip: 1
|
||||||
|
line: 18
|
||||||
|
spidev: spidev0.1
|
||||||
|
# CS: # GPIO0_A7 (SPI1_CSN1, physical 26)
|
||||||
|
# pin: 7
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 7
|
||||||
|
TX_GAIN_LORA: [9, 9, 10, 11, 9, 8, 9, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 10, 9, 8]
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
Meta:
|
||||||
|
name: Waveshare SX1262
|
||||||
|
support: deprecated
|
||||||
|
compatible:
|
||||||
|
- ebyte-ecb41-pge # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262 # Waveshare SX126X XXXM
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
CS: # GPIO0_A1 (physical 40)
|
||||||
|
pin: 1
|
||||||
|
gpiochip: 0
|
||||||
|
line: 1
|
||||||
|
IRQ: # GPIO0_A3 (physical 36)
|
||||||
|
pin: 3
|
||||||
|
gpiochip: 0
|
||||||
|
line: 3
|
||||||
|
Busy: # GPIO0_A0 (physical 38)
|
||||||
|
pin: 0
|
||||||
|
gpiochip: 0
|
||||||
|
line: 0
|
||||||
|
Reset: # GPIO0_B4 (physical 12)
|
||||||
|
pin: 12
|
||||||
|
gpiochip: 0
|
||||||
|
line: 12
|
||||||
|
SX126X_ANT_SW: # GPIO1_B2 (physical 31)
|
||||||
|
pin: 42
|
||||||
|
gpiochip: 1
|
||||||
|
line: 10
|
||||||
|
spidev: spidev0.0
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# MeshAdv-Pi E22-900M30S
|
||||||
|
# https://github.com/chrismyers2000/MeshAdv-Pi-Hat
|
||||||
|
Meta:
|
||||||
|
name: MeshAdv-Pi E22-900M30S
|
||||||
|
support: community
|
||||||
|
compatible:
|
||||||
|
- luckfox-lyra-zero-w # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
CS: # GPIO0_C2 (physical 40)
|
||||||
|
pin: 18
|
||||||
|
gpiochip: 0
|
||||||
|
line: 18
|
||||||
|
IRQ: # GPIO1_D1 (physical 36)
|
||||||
|
pin: 57
|
||||||
|
gpiochip: 1
|
||||||
|
line: 25
|
||||||
|
Busy: # GPIO0_C1 (physical 38)
|
||||||
|
pin: 17
|
||||||
|
gpiochip: 0
|
||||||
|
line: 17
|
||||||
|
Reset: # GPIO0_B6 (physical 12)
|
||||||
|
pin: 14
|
||||||
|
gpiochip: 0
|
||||||
|
line: 14
|
||||||
|
TXen: # GPIO1_C2 (physical 33)
|
||||||
|
pin: 50
|
||||||
|
gpiochip: 1
|
||||||
|
line: 18
|
||||||
|
RXen: # GPIO1_D2 (physical 32)
|
||||||
|
pin: 58
|
||||||
|
gpiochip: 1
|
||||||
|
line: 26
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
# Only for E22-900M33S:
|
||||||
|
# Limit the output power to 8 dBm
|
||||||
|
# SX126X_MAX_POWER: 8
|
||||||
|
spidev: spidev0.0
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# MeshAdv Mini E22-900M22S
|
||||||
|
# https://github.com/chrismyers2000/MeshAdv-Mini
|
||||||
|
Meta:
|
||||||
|
name: MeshAdv Mini E22-900M22S
|
||||||
|
support: community
|
||||||
|
compatible:
|
||||||
|
- luckfox-lyra-zero-w # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262 # Ebyte E22-900M22S
|
||||||
|
CS: # GPIO0_B2_d (phys 24, RPi CE0)
|
||||||
|
pin: 10
|
||||||
|
gpiochip: 0
|
||||||
|
line: 10
|
||||||
|
IRQ: # GPIO1_D1_d (phys 36, RPi GPIO16)
|
||||||
|
pin: 57
|
||||||
|
gpiochip: 1
|
||||||
|
line: 25
|
||||||
|
Busy: # GPIO0_C1_d (phys 38, RPi GPIO20)
|
||||||
|
pin: 17
|
||||||
|
gpiochip: 0
|
||||||
|
line: 17
|
||||||
|
Reset: # GPIO0_B4_d (phys 18, RPi GPIO24)
|
||||||
|
pin: 12
|
||||||
|
gpiochip: 0
|
||||||
|
line: 12
|
||||||
|
RXen: # GPIO1_D2_d (phys 32, RPi GPIO12)
|
||||||
|
pin: 58
|
||||||
|
gpiochip: 1
|
||||||
|
line: 26
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
spidev: spidev0.0
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
Meta:
|
||||||
|
name: RAK6421 + RAK13300 Slot 1
|
||||||
|
support: community # Promote when tested
|
||||||
|
compatible:
|
||||||
|
- luckfox-lyra-zero-w # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: # GPIO0_A5 (IO6)
|
||||||
|
pin: 5
|
||||||
|
gpiochip: 0
|
||||||
|
line: 5
|
||||||
|
Reset: # GPIO1_D1 (IO4)
|
||||||
|
pin: 57
|
||||||
|
gpiochip: 1
|
||||||
|
line: 25
|
||||||
|
Busy: # GPIO0_B4 (IO5)
|
||||||
|
pin: 12
|
||||||
|
gpiochip: 0
|
||||||
|
line: 12
|
||||||
|
# Ant_sw: # GPIO1_C2 (IO3)
|
||||||
|
# pin: 50
|
||||||
|
# gpiochip: 1
|
||||||
|
# line: 18
|
||||||
|
Enable_Pins:
|
||||||
|
- pin: 58 # GPIO1_D2
|
||||||
|
gpiochip: 1
|
||||||
|
line: 26
|
||||||
|
- pin: 50 # GPIO1_C2
|
||||||
|
gpiochip: 1
|
||||||
|
line: 18
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
spidev: spidev0.0
|
||||||
|
# CS: # GPIO0_B2
|
||||||
|
# pin: 10
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 10
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
Meta:
|
||||||
|
name: RAK6421 + RAK13300 Slot 2
|
||||||
|
support: community # Promote when tested
|
||||||
|
compatible:
|
||||||
|
- luckfox-lyra-zero-w # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: # GPIO0_B6 (IO6)
|
||||||
|
pin: 14
|
||||||
|
gpiochip: 0
|
||||||
|
line: 14
|
||||||
|
Reset: # GPIO0_B4 (IO4)
|
||||||
|
pin: 12
|
||||||
|
gpiochip: 0
|
||||||
|
line: 12
|
||||||
|
Busy: # GPIO1_C0 (IO5)
|
||||||
|
pin: 48
|
||||||
|
gpiochip: 1
|
||||||
|
line: 16
|
||||||
|
# Ant_sw: # GPIO0_B5 (IO3)
|
||||||
|
# pin: 13
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 13
|
||||||
|
Enable_Pins:
|
||||||
|
- pin: 51 # GPIO1_C3
|
||||||
|
gpiochip: 1
|
||||||
|
line: 19
|
||||||
|
- pin: 13 # GPIO0_B5
|
||||||
|
gpiochip: 0
|
||||||
|
line: 13
|
||||||
|
spidev: spidev0.1
|
||||||
|
# CS: # GPIO0_B1
|
||||||
|
# pin: 9
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 9
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
Meta:
|
||||||
|
name: RAK6421 + RAK13300 Slot 1
|
||||||
|
support: community # Promote when tested
|
||||||
|
compatible:
|
||||||
|
- luckfox-lyra-zero-w # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: # GPIO0_A5 (IO6)
|
||||||
|
pin: 5
|
||||||
|
gpiochip: 0
|
||||||
|
line: 5
|
||||||
|
Reset: # GPIO1_D1 (IO4)
|
||||||
|
pin: 57
|
||||||
|
gpiochip: 1
|
||||||
|
line: 25
|
||||||
|
Busy: # GPIO0_B4 (IO5)
|
||||||
|
pin: 12
|
||||||
|
gpiochip: 0
|
||||||
|
line: 12
|
||||||
|
# Ant_sw: # GPIO1_C2 (IO3)
|
||||||
|
# pin: 50
|
||||||
|
# gpiochip: 1
|
||||||
|
# line: 18
|
||||||
|
Enable_Pins:
|
||||||
|
- pin: 58 # GPIO1_D2
|
||||||
|
gpiochip: 1
|
||||||
|
line: 26
|
||||||
|
- pin: 50 # GPIO1_C2
|
||||||
|
gpiochip: 1
|
||||||
|
line: 18
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
spidev: spidev0.0
|
||||||
|
# CS: # GPIO0_B2
|
||||||
|
# pin: 10
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 10
|
||||||
|
TX_GAIN_LORA: [9, 9, 10, 11, 9, 8, 9, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 10, 9, 8]
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
Meta:
|
||||||
|
name: RAK6421 + RAK13300 Slot 2
|
||||||
|
support: community # Promote when tested
|
||||||
|
compatible:
|
||||||
|
- luckfox-lyra-zero-w # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: # GPIO0_B6 (IO6)
|
||||||
|
pin: 14
|
||||||
|
gpiochip: 0
|
||||||
|
line: 14
|
||||||
|
Reset: # GPIO0_B4 (IO4)
|
||||||
|
pin: 12
|
||||||
|
gpiochip: 0
|
||||||
|
line: 12
|
||||||
|
Busy: # GPIO1_C0 (IO5)
|
||||||
|
pin: 48
|
||||||
|
gpiochip: 1
|
||||||
|
line: 16
|
||||||
|
# Ant_sw: # GPIO0_B5 (IO3)
|
||||||
|
# pin: 13
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 13
|
||||||
|
Enable_Pins:
|
||||||
|
- pin: 51 # GPIO1_C3
|
||||||
|
gpiochip: 1
|
||||||
|
line: 19
|
||||||
|
- pin: 13 # GPIO0_B5
|
||||||
|
gpiochip: 0
|
||||||
|
line: 13
|
||||||
|
spidev: spidev0.1
|
||||||
|
# CS: # GPIO0_B1
|
||||||
|
# pin: 9
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 9
|
||||||
|
TX_GAIN_LORA: [9, 9, 10, 11, 9, 8, 9, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 10, 9, 8]
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
Meta:
|
||||||
|
name: Waveshare SX1262
|
||||||
|
support: deprecated
|
||||||
|
compatible:
|
||||||
|
- luckfox-lyra-zero-w # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262 # Waveshare SX126X XXXM
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
CS: # GPIO0_C2 (physical 40)
|
||||||
|
pin: 18
|
||||||
|
gpiochip: 0
|
||||||
|
line: 18
|
||||||
|
IRQ: # GPIO1_D1 (physical 36)
|
||||||
|
pin: 57
|
||||||
|
gpiochip: 1
|
||||||
|
line: 25
|
||||||
|
Busy: # GPIO0_C1 (physical 38)
|
||||||
|
pin: 17
|
||||||
|
gpiochip: 0
|
||||||
|
line: 17
|
||||||
|
Reset: # GPIO0_B6 (physical 12)
|
||||||
|
pin: 14
|
||||||
|
gpiochip: 0
|
||||||
|
line: 14
|
||||||
|
SX126X_ANT_SW: # GPIO1_B3 (physical 31)
|
||||||
|
pin: 43
|
||||||
|
gpiochip: 1
|
||||||
|
line: 11
|
||||||
|
spidev: spidev0.0
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards)
|
||||||
|
|
||||||
|
# MeshAdv-Pi E22-900M30S
|
||||||
|
# https://github.com/chrismyers2000/MeshAdv-Pi-Hat
|
||||||
|
Meta:
|
||||||
|
name: MeshAdv-Pi E22-900M30S
|
||||||
|
support: community
|
||||||
|
compatible:
|
||||||
|
- forlinx-ok3506-s12 # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
CS: # GPIO0_B0 (physical 40)
|
||||||
|
pin: 8
|
||||||
|
gpiochip: 0
|
||||||
|
line: 8
|
||||||
|
IRQ: # GPIO3_B0 (physical 36)
|
||||||
|
pin: 104
|
||||||
|
gpiochip: 3
|
||||||
|
line: 8
|
||||||
|
Busy: # GPIO0_B1 (physical 38)
|
||||||
|
pin: 9
|
||||||
|
gpiochip: 0
|
||||||
|
line: 9
|
||||||
|
Reset: # GPIO0_B6 (physical 12)
|
||||||
|
pin: 14
|
||||||
|
gpiochip: 0
|
||||||
|
line: 14
|
||||||
|
TXen: # GPIO0_A3 (physical 33)
|
||||||
|
pin: 3
|
||||||
|
gpiochip: 0
|
||||||
|
line: 3
|
||||||
|
RXen: # GPIO0_A2 (physical 32)
|
||||||
|
pin: 2
|
||||||
|
gpiochip: 0
|
||||||
|
line: 2
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
# Only for E22-900M33S:
|
||||||
|
# Limit the output power to 8 dBm
|
||||||
|
# SX126X_MAX_POWER: 8
|
||||||
|
spidev: spidev0.0
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards)
|
||||||
|
|
||||||
|
# MeshAdv Mini E22-900M22S
|
||||||
|
# https://github.com/chrismyers2000/MeshAdv-Mini
|
||||||
|
Meta:
|
||||||
|
name: MeshAdv Mini E22-900M22S
|
||||||
|
support: community
|
||||||
|
compatible:
|
||||||
|
- forlinx-ok3506-s12 # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262 # Ebyte E22-900M22S
|
||||||
|
CS: # GPIO0_C3 (physical 24, SPI0_CSN0)
|
||||||
|
pin: 19
|
||||||
|
gpiochip: 0
|
||||||
|
line: 19
|
||||||
|
IRQ: # GPIO3_B0 (physical 36)
|
||||||
|
pin: 104
|
||||||
|
gpiochip: 3
|
||||||
|
line: 8
|
||||||
|
Busy: # GPIO0_B1 (physical 38)
|
||||||
|
pin: 9
|
||||||
|
gpiochip: 0
|
||||||
|
line: 9
|
||||||
|
Reset: # GPIO3_A6 (physical 18)
|
||||||
|
pin: 102
|
||||||
|
gpiochip: 3
|
||||||
|
line: 6
|
||||||
|
RXen: # GPIO0_A2 (physical 32)
|
||||||
|
pin: 2
|
||||||
|
gpiochip: 0
|
||||||
|
line: 2
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
spidev: spidev0.0
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards)
|
||||||
|
|
||||||
|
Meta:
|
||||||
|
name: RAK6421 + RAK13300 Slot 1
|
||||||
|
support: community # Promote when tested
|
||||||
|
compatible:
|
||||||
|
- forlinx-ok3506-s12 # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: # GPIO3_B5 (IO6, physical 15)
|
||||||
|
pin: 109
|
||||||
|
gpiochip: 3
|
||||||
|
line: 13
|
||||||
|
Reset: # GPIO3_B0 (IO4, physical 36)
|
||||||
|
pin: 104
|
||||||
|
gpiochip: 3
|
||||||
|
line: 8
|
||||||
|
Busy: # GPIO3_A6 (IO5, physical 18)
|
||||||
|
pin: 102
|
||||||
|
gpiochip: 3
|
||||||
|
line: 6
|
||||||
|
# Ant_sw: # GPIO0_A3 (IO3, physical 33)
|
||||||
|
# pin: 3
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 3
|
||||||
|
Enable_Pins:
|
||||||
|
- pin: 2 # GPIO0_A2 (physical 32)
|
||||||
|
gpiochip: 0
|
||||||
|
line: 2
|
||||||
|
- pin: 3 # GPIO0_A3 (physical 33)
|
||||||
|
gpiochip: 0
|
||||||
|
line: 3
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
spidev: spidev0.0
|
||||||
|
# CS: # GPIO0_C3 (SPI0_CSN0, physical 24)
|
||||||
|
# pin: 19
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 19
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards)
|
||||||
|
|
||||||
|
Meta:
|
||||||
|
name: RAK6421 + RAK13300 Slot 2
|
||||||
|
support: community # Promote when tested
|
||||||
|
compatible:
|
||||||
|
- forlinx-ok3506-s12 # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: # GPIO0_B6 (IO6, physical 12)
|
||||||
|
pin: 14
|
||||||
|
gpiochip: 0
|
||||||
|
line: 14
|
||||||
|
Reset: # GPIO3_A6 (IO4, physical 18)
|
||||||
|
pin: 102
|
||||||
|
gpiochip: 3
|
||||||
|
line: 6
|
||||||
|
Busy: # GPIO0_B2 (IO5, physical 35)
|
||||||
|
pin: 10
|
||||||
|
gpiochip: 0
|
||||||
|
line: 10
|
||||||
|
# Ant_sw: # GPIO3_A7 (IO3, physical 16)
|
||||||
|
# pin: 103
|
||||||
|
# gpiochip: 3
|
||||||
|
# line: 7
|
||||||
|
Enable_Pins:
|
||||||
|
- pin: 106 # GPIO3_B2 (physical 37)
|
||||||
|
gpiochip: 3
|
||||||
|
line: 10
|
||||||
|
- pin: 103 # GPIO3_A7 (physical 16)
|
||||||
|
gpiochip: 3
|
||||||
|
line: 7
|
||||||
|
spidev: spidev0.1
|
||||||
|
# CS: # GPIO0_B7 (SPI0_CSN1, physical 26)
|
||||||
|
# pin: 15
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 15
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards)
|
||||||
|
|
||||||
|
Meta:
|
||||||
|
name: RAK6421 + RAK13302 Slot 1
|
||||||
|
support: community # Promote when tested
|
||||||
|
compatible:
|
||||||
|
- forlinx-ok3506-s12 # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: # GPIO3_B5 (IO6, physical 15)
|
||||||
|
pin: 109
|
||||||
|
gpiochip: 3
|
||||||
|
line: 13
|
||||||
|
Reset: # GPIO3_B0 (IO4, physical 36)
|
||||||
|
pin: 104
|
||||||
|
gpiochip: 3
|
||||||
|
line: 8
|
||||||
|
Busy: # GPIO3_A6 (IO5, physical 18)
|
||||||
|
pin: 102
|
||||||
|
gpiochip: 3
|
||||||
|
line: 6
|
||||||
|
# Ant_sw: # GPIO0_A3 (IO3, physical 33)
|
||||||
|
# pin: 3
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 3
|
||||||
|
Enable_Pins:
|
||||||
|
- pin: 2 # GPIO0_A2 (physical 32)
|
||||||
|
gpiochip: 0
|
||||||
|
line: 2
|
||||||
|
- pin: 3 # GPIO0_A3 (physical 33)
|
||||||
|
gpiochip: 0
|
||||||
|
line: 3
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
spidev: spidev0.0
|
||||||
|
# CS: # GPIO0_C3 (SPI0_CSN0, physical 24)
|
||||||
|
# pin: 19
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 19
|
||||||
|
TX_GAIN_LORA: [9, 9, 10, 11, 9, 8, 9, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 10, 9, 8]
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards)
|
||||||
|
|
||||||
|
Meta:
|
||||||
|
name: RAK6421 + RAK13302 Slot 2
|
||||||
|
support: community # Promote when tested
|
||||||
|
compatible:
|
||||||
|
- forlinx-ok3506-s12 # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: # GPIO0_B6 (IO6, physical 12)
|
||||||
|
pin: 14
|
||||||
|
gpiochip: 0
|
||||||
|
line: 14
|
||||||
|
Reset: # GPIO3_A6 (IO4, physical 18)
|
||||||
|
pin: 102
|
||||||
|
gpiochip: 3
|
||||||
|
line: 6
|
||||||
|
Busy: # GPIO0_B2 (IO5, physical 35)
|
||||||
|
pin: 10
|
||||||
|
gpiochip: 0
|
||||||
|
line: 10
|
||||||
|
# Ant_sw: # GPIO3_A7 (IO3, physical 16)
|
||||||
|
# pin: 103
|
||||||
|
# gpiochip: 3
|
||||||
|
# line: 7
|
||||||
|
Enable_Pins:
|
||||||
|
- pin: 106 # GPIO3_B2 (physical 37)
|
||||||
|
gpiochip: 3
|
||||||
|
line: 10
|
||||||
|
- pin: 103 # GPIO3_A7 (physical 16)
|
||||||
|
gpiochip: 3
|
||||||
|
line: 7
|
||||||
|
spidev: spidev0.1
|
||||||
|
# CS: # GPIO0_B7 (SPI0_CSN1, physical 26)
|
||||||
|
# pin: 15
|
||||||
|
# gpiochip: 0
|
||||||
|
# line: 15
|
||||||
|
TX_GAIN_LORA: [9, 9, 10, 11, 9, 8, 9, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 10, 9, 8]
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards)
|
||||||
|
|
||||||
|
Meta:
|
||||||
|
name: Waveshare SX1262
|
||||||
|
support: deprecated
|
||||||
|
compatible:
|
||||||
|
- forlinx-ok3506-s12 # Armbian
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262 # Waveshare SX126X XXXM
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
CS: # GPIO0_B0 (physical 40)
|
||||||
|
pin: 8
|
||||||
|
gpiochip: 0
|
||||||
|
line: 8
|
||||||
|
IRQ: # GPIO3_B0 (physical 36)
|
||||||
|
pin: 104
|
||||||
|
gpiochip: 3
|
||||||
|
line: 8
|
||||||
|
Busy: # GPIO0_B1 (physical 38)
|
||||||
|
pin: 9
|
||||||
|
gpiochip: 0
|
||||||
|
line: 9
|
||||||
|
Reset: # GPIO0_B6 (physical 12)
|
||||||
|
pin: 14
|
||||||
|
gpiochip: 0
|
||||||
|
line: 14
|
||||||
|
SX126X_ANT_SW: # GPIO3_B3 (physical 31)
|
||||||
|
pin: 107
|
||||||
|
gpiochip: 3
|
||||||
|
line: 11
|
||||||
|
spidev: spidev0.0
|
||||||
@@ -1,25 +1,31 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""Generate release notes from the actual release commit range."""
|
||||||
Generate release notes from merged PRs on develop and master branches.
|
|
||||||
Categorizes PRs into Enhancements and Bug Fixes/Maintenance sections.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import subprocess
|
import argparse
|
||||||
import re
|
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
|
|
||||||
def get_last_release_tag():
|
def get_last_release_tag(compare_ref, exclude_tag=None):
|
||||||
"""Get the most recent release tag."""
|
"""Get the most recent version tag merged into compare_ref."""
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["git", "describe", "--tags", "--abbrev=0"],
|
["git", "tag", "--merged", compare_ref, "--sort=-version:refname", "v*"],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
check=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):
|
def get_tag_date(tag):
|
||||||
@@ -33,18 +39,18 @@ def get_tag_date(tag):
|
|||||||
return result.stdout.strip()
|
return result.stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
def get_merged_prs_since_tag(tag, branch):
|
def get_merged_prs_in_range(tag, compare_ref):
|
||||||
"""Get all merged PRs since the given tag on the specified branch."""
|
"""Get all merged PRs in the git range between tag and compare_ref."""
|
||||||
# Get commits since tag on the branch - look for PR numbers in parentheses
|
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
[
|
[
|
||||||
"git",
|
"git",
|
||||||
"log",
|
"log",
|
||||||
f"{tag}..origin/{branch}",
|
f"{tag}..{compare_ref}",
|
||||||
"--oneline",
|
"--oneline",
|
||||||
],
|
],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
|
check=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
prs = []
|
prs = []
|
||||||
@@ -65,6 +71,25 @@ def get_merged_prs_since_tag(tag, branch):
|
|||||||
return prs
|
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):
|
def get_pr_details(pr_number):
|
||||||
"""Get PR details from GitHub API via gh CLI."""
|
"""Get PR details from GitHub API via gh CLI."""
|
||||||
try:
|
try:
|
||||||
@@ -268,28 +293,28 @@ def get_new_contributors(pr_details_list, tag, repo="meshtastic/firmware"):
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if len(sys.argv) < 2:
|
args = parse_args()
|
||||||
print("Usage: generate_release_notes.py <new_version>", file=sys.stderr)
|
new_version = args.new_version
|
||||||
sys.exit(1)
|
compare_ref = args.compare_ref
|
||||||
|
current_tag = f"v{new_version}"
|
||||||
new_version = sys.argv[1]
|
|
||||||
|
|
||||||
# Get last release tag
|
# Get last release tag
|
||||||
try:
|
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:
|
except subprocess.CalledProcessError:
|
||||||
print("Error: Could not find last release tag", file=sys.stderr)
|
print("Error: Could not find last release tag", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Collect PRs from both branches
|
print(
|
||||||
all_pr_numbers = set()
|
f"Resolved release note range: {last_tag}..{compare_ref}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
|
||||||
for branch in ["develop", "master"]:
|
try:
|
||||||
try:
|
all_pr_numbers = set(get_merged_prs_in_range(last_tag, compare_ref))
|
||||||
prs = get_merged_prs_since_tag(last_tag, branch)
|
except subprocess.CalledProcessError as e:
|
||||||
all_pr_numbers.update(prs)
|
print(f"Error: Could not get PRs for range {last_tag}..{compare_ref}: {e}", file=sys.stderr)
|
||||||
except Exception as e:
|
sys.exit(1)
|
||||||
print(f"Warning: Could not get PRs from {branch}: {e}", file=sys.stderr)
|
|
||||||
|
|
||||||
# Get details for all PRs
|
# Get details for all PRs
|
||||||
enhancements = []
|
enhancements = []
|
||||||
|
|||||||
@@ -87,6 +87,12 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="2.7.23" date="2026-04-14">
|
||||||
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.23</url>
|
||||||
|
</release>
|
||||||
|
<release version="2.7.22" date="2026-04-06">
|
||||||
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.22</url>
|
||||||
|
</release>
|
||||||
<release version="2.7.21" date="2026-03-11">
|
<release version="2.7.21" date="2026-03-11">
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.21</url>
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.21</url>
|
||||||
</release>
|
</release>
|
||||||
|
|||||||
Vendored
+12
@@ -1,3 +1,15 @@
|
|||||||
|
meshtasticd (2.7.23.0) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Version 2.7.23
|
||||||
|
|
||||||
|
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Tue, 14 Apr 2026 12:29:48 +0000
|
||||||
|
|
||||||
|
meshtasticd (2.7.22.0) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Version 2.7.22
|
||||||
|
|
||||||
|
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Mon, 06 Apr 2026 11:34:12 +0000
|
||||||
|
|
||||||
meshtasticd (2.7.21.0) unstable; urgency=medium
|
meshtasticd (2.7.21.0) unstable; urgency=medium
|
||||||
|
|
||||||
* Version 2.7.21
|
* Version 2.7.21
|
||||||
|
|||||||
+93
-85
@@ -56,9 +56,7 @@ build_flags = -Wno-missing-field-initializers
|
|||||||
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
|
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
|
||||||
-DMESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE=1
|
-DMESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE=1
|
||||||
-DMESHTASTIC_EXCLUDE_POWERMON=1
|
-DMESHTASTIC_EXCLUDE_POWERMON=1
|
||||||
-DMESHTASTIC_EXCLUDE_STATUS=1
|
|
||||||
-D MAX_THREADS=40 ; As we've split modules, we have more threads to manage
|
-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
|
#-DBUILD_EPOCH=$UNIX_TIME ; set in platformio-custom.py now
|
||||||
#-D OLED_PL=1
|
#-D OLED_PL=1
|
||||||
#-D DEBUG_HEAP=1 ; uncomment to add free heap space / memory leak debugging logs
|
#-D DEBUG_HEAP=1 ; uncomment to add free heap space / memory leak debugging logs
|
||||||
@@ -126,112 +124,122 @@ lib_deps =
|
|||||||
[device-ui_base]
|
[device-ui_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
||||||
https://github.com/meshtastic/device-ui/archive/7b1485b86c8d55a40e5226749097767e8b87f396.zip
|
https://github.com/meshtastic/device-ui/archive/5305670b68eb5b92d14e62b5b536969ca4bb441f.zip
|
||||||
|
|
||||||
; Common libs for environmental measurements in telemetry module
|
; Common libs for environmental measurements in telemetry module
|
||||||
[environmental_base]
|
[environmental_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=custom.pio depName=Adafruit BusIO packageName=adafruit/library/Adafruit BusIO
|
# renovate: datasource=github-tags depName=Adafruit BusIO packageName=adafruit/Adafruit_BusIO
|
||||||
adafruit/Adafruit BusIO@1.17.4
|
https://github.com/adafruit/Adafruit_BusIO/archive/refs/tags/1.17.4.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit Unified Sensor packageName=adafruit/library/Adafruit Unified Sensor
|
# renovate: datasource=github-tags depName=Adafruit Unified Sensor packageName=adafruit/Adafruit_Sensor
|
||||||
adafruit/Adafruit Unified Sensor@1.1.15
|
https://github.com/adafruit/Adafruit_Sensor/archive/refs/tags/1.1.15.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit BMP280 packageName=adafruit/library/Adafruit BMP280 Library
|
# renovate: datasource=github-tags depName=Adafruit GFX packageName=adafruit/Adafruit-GFX-Library
|
||||||
adafruit/Adafruit BMP280 Library@3.0.0
|
https://github.com/adafruit/Adafruit-GFX-Library/archive/refs/tags/1.12.6.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit BMP085 packageName=adafruit/library/Adafruit BMP085 Library
|
# renovate: datasource=github-tags depName=NeoPixel packageName=adafruit/Adafruit_NeoPixel
|
||||||
adafruit/Adafruit BMP085 Library@1.2.4
|
https://github.com/adafruit/Adafruit_NeoPixel/archive/refs/tags/1.15.4.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit BME280 packageName=adafruit/library/Adafruit BME280 Library
|
# renovate: datasource=github-tags depName=Adafruit SSD1306 packageName=adafruit/Adafruit_SSD1306
|
||||||
adafruit/Adafruit BME280 Library@2.3.0
|
https://github.com/adafruit/Adafruit_SSD1306/archive/refs/tags/2.5.16.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit DPS310 packageName=adafruit/library/Adafruit DPS310
|
# renovate: datasource=github-tags depName=Adafruit BMP280 packageName=adafruit/Adafruit_BMP280_Library
|
||||||
adafruit/Adafruit DPS310@1.1.6
|
https://github.com/adafruit/Adafruit_BMP280_Library/archive/refs/tags/3.0.0.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit MCP9808 packageName=adafruit/library/Adafruit MCP9808 Library
|
# renovate: datasource=github-tags depName=Adafruit BMP085 packageName=adafruit/Adafruit-BMP085-Library
|
||||||
adafruit/Adafruit MCP9808 Library@2.0.2
|
https://github.com/adafruit/Adafruit-BMP085-Library/archive/refs/tags/1.2.4.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit INA260 packageName=adafruit/library/Adafruit INA260 Library
|
# renovate: datasource=github-tags depName=Adafruit BME280 packageName=adafruit/Adafruit_BME280_Library
|
||||||
adafruit/Adafruit INA260 Library@1.5.3
|
https://github.com/adafruit/Adafruit_BME280_Library/archive/refs/tags/2.3.0.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit INA219 packageName=adafruit/library/Adafruit INA219
|
# renovate: datasource=github-tags depName=Adafruit DPS310 packageName=adafruit/Adafruit_DPS310
|
||||||
adafruit/Adafruit INA219@1.2.3
|
https://github.com/adafruit/Adafruit_DPS310/archive/refs/tags/1.1.6.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit MPU6050 packageName=adafruit/library/Adafruit MPU6050
|
# renovate: datasource=github-tags depName=Adafruit SH110x packageName=adafruit/Adafruit_SH110x
|
||||||
adafruit/Adafruit MPU6050@2.2.9
|
https://github.com/adafruit/Adafruit_SH110x/archive/refs/tags/2.1.14.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit LIS3DH packageName=adafruit/library/Adafruit LIS3DH
|
# renovate: datasource=github-tags depName=Adafruit MCP9808 packageName=adafruit/Adafruit_MCP9808_Library
|
||||||
adafruit/Adafruit LIS3DH@1.3.0
|
https://github.com/adafruit/Adafruit_MCP9808_Library/archive/refs/tags/2.0.2.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit AHTX0 packageName=adafruit/library/Adafruit AHTX0
|
# renovate: datasource=github-tags depName=Adafruit INA260 packageName=adafruit/Adafruit_INA260
|
||||||
adafruit/Adafruit AHTX0@2.0.6
|
https://github.com/adafruit/Adafruit_INA260/archive/refs/tags/1.5.3.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit LSM6DS packageName=adafruit/library/Adafruit LSM6DS
|
# renovate: datasource=github-tags depName=Adafruit INA219 packageName=adafruit/Adafruit_INA219
|
||||||
adafruit/Adafruit LSM6DS@4.7.4
|
https://github.com/adafruit/Adafruit_INA219/archive/refs/tags/1.2.3.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit TSL2591 packageName=adafruit/library/Adafruit TSL2591 Library
|
# renovate: datasource=github-tags depName=Adafruit MPU6050 packageName=adafruit/Adafruit_MPU6050
|
||||||
adafruit/Adafruit TSL2591 Library@1.4.5
|
https://github.com/adafruit/Adafruit_MPU6050/archive/refs/tags/2.2.9.zip
|
||||||
# renovate: datasource=custom.pio depName=EmotiBit MLX90632 packageName=emotibit/library/EmotiBit MLX90632
|
# renovate: datasource=github-tags depName=Adafruit LIS3DH packageName=adafruit/Adafruit_LIS3DH
|
||||||
emotibit/EmotiBit MLX90632@1.0.8
|
https://github.com/adafruit/Adafruit_LIS3DH/archive/refs/tags/1.3.0.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit MLX90614 packageName=adafruit/library/Adafruit MLX90614 Library
|
# renovate: datasource=github-tags depName=Adafruit AHTX0 packageName=adafruit/Adafruit_AHTX0
|
||||||
adafruit/Adafruit MLX90614 Library@2.1.6
|
https://github.com/adafruit/Adafruit_AHTX0/archive/refs/tags/2.0.6.zip
|
||||||
|
# renovate: datasource=github-tags depName=Adafruit LSM6DS packageName=adafruit/Adafruit_LSM6DS
|
||||||
|
https://github.com/adafruit/Adafruit_LSM6DS/archive/refs/tags/4.7.4.zip
|
||||||
|
# renovate: datasource=github-tags depName=Adafruit TSL2591 packageName=adafruit/Adafruit_TSL2591_Library
|
||||||
|
https://github.com/adafruit/Adafruit_TSL2591_Library/archive/refs/tags/1.4.5.zip
|
||||||
|
# renovate: datasource=github-tags depName=EmotiBit MLX90632 packageName=emotibit/EmotiBit_MLX90632
|
||||||
|
https://github.com/EmotiBit/EmotiBit_MLX90632/archive/refs/tags/v1.0.8.zip
|
||||||
|
# renovate: datasource=github-tags depName=Adafruit MLX90614 packageName=adafruit/Adafruit_MLX90614
|
||||||
|
https://github.com/adafruit/Adafruit-MLX90614-Library/archive/refs/tags/2.1.6.zip
|
||||||
# renovate: datasource=git-refs depName=INA3221 packageName=https://github.com/sgtwilko/INA3221 gitBranch=FixOverflow
|
# renovate: datasource=git-refs depName=INA3221 packageName=https://github.com/sgtwilko/INA3221 gitBranch=FixOverflow
|
||||||
https://github.com/sgtwilko/INA3221/archive/bb03d7e9bfcc74fc798838a54f4f99738f29fc6a.zip
|
https://github.com/sgtwilko/INA3221/archive/bb03d7e9bfcc74fc798838a54f4f99738f29fc6a.zip
|
||||||
# renovate: datasource=custom.pio depName=QMC5883L Compass packageName=mprograms/library/QMC5883LCompass
|
# renovate: datasource=github-tags depName=QMC5883L Compass packageName=mprograms/QMC5883LCompass
|
||||||
mprograms/QMC5883LCompass@1.2.3
|
https://github.com/mprograms/QMC5883LCompass/archive/refs/tags/v1.2.3.zip
|
||||||
# renovate: datasource=custom.pio depName=DFRobot_RTU packageName=dfrobot/library/DFRobot_RTU
|
# renovate: datasource=github-tags depName=DFRobot_RTU packageName=dfrobot/DFRobot_RTU
|
||||||
dfrobot/DFRobot_RTU@1.0.6
|
https://github.com/DFRobot/DFRobot_RTU/archive/refs/tags/V1.0.6.zip
|
||||||
# renovate: datasource=git-refs depName=DFRobot_RainfallSensor packageName=https://github.com/DFRobot/DFRobot_RainfallSensor gitBranch=master
|
# renovate: datasource=git-refs depName=DFRobot_RainfallSensor packageName=https://github.com/DFRobot/DFRobot_RainfallSensor gitBranch=master
|
||||||
https://github.com/DFRobot/DFRobot_RainfallSensor/archive/38fea5e02b40a5430be6dab39a99a6f6347d667e.zip
|
https://github.com/DFRobot/DFRobot_RainfallSensor/archive/38fea5e02b40a5430be6dab39a99a6f6347d667e.zip
|
||||||
# renovate: datasource=custom.pio depName=INA226 packageName=robtillaart/library/INA226
|
# renovate: datasource=github-tags depName=INA226 packageName=robtillaart/INA226
|
||||||
robtillaart/INA226@0.6.6
|
https://github.com/RobTillaart/INA226/archive/refs/tags/0.6.6.zip
|
||||||
# renovate: datasource=custom.pio depName=SparkFun MAX3010x packageName=sparkfun/library/SparkFun MAX3010x Pulse and Proximity Sensor Library
|
# renovate: datasource=github-tags depName=SparkFun MAX3010x packageName=sparkfun/SparkFun_MAX3010x_Sensor_Library
|
||||||
sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2
|
https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library/archive/refs/tags/v1.1.2.zip
|
||||||
# renovate: datasource=custom.pio depName=SparkFun 9DoF IMU Breakout ICM 20948 packageName=sparkfun/library/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library
|
# renovate: datasource=github-tags depName=SparkFun 9DoF IMU Breakout ICM 20948 packageName=sparkfun/SparkFun_ICM-20948_ArduinoLibrary
|
||||||
sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@1.3.2
|
https://github.com/sparkfun/SparkFun_ICM-20948_ArduinoLibrary/archive/refs/tags/v1.3.2.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit LTR390 Library packageName=adafruit/library/Adafruit LTR390 Library
|
# renovate: datasource=github-tags depName=Adafruit LTR390 Library packageName=adafruit/Adafruit_LTR390
|
||||||
adafruit/Adafruit LTR390 Library@1.1.2
|
https://github.com/adafruit/Adafruit_LTR390/archive/refs/tags/1.1.2.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit PCT2075 packageName=adafruit/library/Adafruit PCT2075
|
# renovate: datasource=github-tags depName=Adafruit PCT2075 packageName=adafruit/Adafruit_PCT2075
|
||||||
adafruit/Adafruit PCT2075@1.0.6
|
https://github.com/adafruit/Adafruit_PCT2075/archive/refs/tags/1.0.6.zip
|
||||||
# renovate: datasource=custom.pio depName=DFRobot_BMM150 packageName=dfrobot/library/DFRobot_BMM150
|
# renovate: datasource=github-tags depName=DFRobot_BMM150 packageName=dfrobot/DFRobot_BMM150
|
||||||
dfrobot/DFRobot_BMM150@1.0.0
|
https://github.com/DFRobot/DFRobot_BMM150/archive/refs/tags/V1.0.0.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit_TSL2561 packageName=adafruit/library/Adafruit TSL2561
|
# renovate: datasource=github-tags depName=Adafruit_TSL2561 packageName=adafruit/Adafruit_TSL2561
|
||||||
adafruit/Adafruit TSL2561@1.1.3
|
https://github.com/adafruit/Adafruit_TSL2561/archive/refs/tags/1.1.3.zip
|
||||||
# renovate: datasource=custom.pio depName=BH1750_WE packageName=wollewald/library/BH1750_WE
|
# renovate: datasource=github-tags depName=BH1750_WE packageName=wollewald/BH1750_WE
|
||||||
wollewald/BH1750_WE@1.1.10
|
https://github.com/wollewald/BH1750_WE/archive/refs/tags/1.1.10.zip
|
||||||
|
|
||||||
; Common environmental sensor libraries (not included in native / portduino)
|
; Common environmental sensor libraries (not included in native / portduino)
|
||||||
[environmental_extra_common]
|
[environmental_extra_common]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=custom.pio depName=Adafruit BMP3XX packageName=adafruit/library/Adafruit BMP3XX Library
|
# renovate: datasource=github-tags depName=Adafruit BMP3XX packageName=adafruit/Adafruit_BMP3XX
|
||||||
adafruit/Adafruit BMP3XX Library@2.1.6
|
https://github.com/adafruit/Adafruit_BMP3XX/archive/refs/tags/2.1.6.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit MAX1704X packageName=adafruit/library/Adafruit MAX1704X
|
# renovate: datasource=github-tags depName=Adafruit MAX1704X packageName=adafruit/Adafruit_MAX1704X
|
||||||
adafruit/Adafruit MAX1704X@1.0.3
|
https://github.com/adafruit/Adafruit_MAX1704X/archive/refs/tags/1.0.3.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit SHTC3 packageName=adafruit/library/Adafruit SHTC3 Library
|
# renovate: datasource=github-tags depName=Adafruit SHTC3 packageName=adafruit/Adafruit_SHTC3
|
||||||
adafruit/Adafruit SHTC3 Library@1.0.2
|
https://github.com/adafruit/Adafruit_SHTC3/archive/refs/tags/1.0.2.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit LPS2X packageName=adafruit/library/Adafruit LPS2X
|
# renovate: datasource=github-tags depName=Adafruit LPS2X packageName=adafruit/Adafruit_LPS2X
|
||||||
adafruit/Adafruit LPS2X@2.0.6
|
https://github.com/adafruit/Adafruit_LPS2X/archive/refs/tags/2.0.6.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit SHT31 packageName=adafruit/library/Adafruit SHT31 Library
|
# renovate: datasource=github-tags depName=Adafruit SHT31 packageName=adafruit/Adafruit_SHT31
|
||||||
adafruit/Adafruit SHT31 Library@2.2.2
|
https://github.com/adafruit/Adafruit_SHT31/archive/refs/tags/2.2.2.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit VEML7700 packageName=adafruit/library/Adafruit VEML7700 Library
|
# renovate: datasource=github-tags depName=Adafruit VEML7700 packageName=adafruit/Adafruit_VEML7700
|
||||||
adafruit/Adafruit VEML7700 Library@2.1.6
|
https://github.com/adafruit/Adafruit_VEML7700/archive/refs/tags/2.1.6.zip
|
||||||
# renovate: datasource=custom.pio depName=Adafruit SHT4x packageName=adafruit/library/Adafruit SHT4x Library
|
# renovate: datasource=github-tags depName=Adafruit SHT4x packageName=adafruit/Adafruit_SHT4X
|
||||||
adafruit/Adafruit SHT4x Library@1.0.5
|
https://github.com/adafruit/Adafruit_SHT4X/archive/refs/tags/1.0.5.zip
|
||||||
# renovate: datasource=custom.pio depName=SparkFun Qwiic Scale NAU7802 packageName=sparkfun/library/SparkFun Qwiic Scale NAU7802 Arduino Library
|
# renovate: datasource=github-tags depName=SparkFun Qwiic Scale NAU7802 packageName=sparkfun/SparkFun_Qwiic_Scale_NAU7802_Arduino_Library
|
||||||
sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@1.0.6
|
https://github.com/sparkfun/SparkFun_Qwiic_Scale_NAU7802_Arduino_Library/archive/refs/tags/v1.0.6.zip
|
||||||
# renovate: datasource=custom.pio depName=ClosedCube OPT3001 packageName=closedcube/library/ClosedCube OPT3001
|
# renovate: datasource=custom.pio depName=ClosedCube OPT3001 packageName=closedcube/library/ClosedCube OPT3001
|
||||||
closedcube/ClosedCube OPT3001@1.1.2
|
closedcube/ClosedCube OPT3001@1.1.2
|
||||||
# renovate: datasource=git-refs depName=meshtastic-DFRobot_LarkWeatherStation packageName=https://github.com/meshtastic/DFRobot_LarkWeatherStation gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic-DFRobot_LarkWeatherStation packageName=https://github.com/meshtastic/DFRobot_LarkWeatherStation gitBranch=master
|
||||||
https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip
|
https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip
|
||||||
# renovate: datasource=custom.pio depName=Sensirion Core packageName=sensirion/library/Sensirion Core
|
# renovate: datasource=github-tags depName=Sensirion Core packageName=sensirion/arduino-core
|
||||||
sensirion/Sensirion Core@0.7.3
|
https://github.com/Sensirion/arduino-core/archive/refs/tags/0.7.3.zip
|
||||||
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
|
# renovate: datasource=github-tags depName=Sensirion I2C SCD4x packageName=sensirion/arduino-i2c-scd4x
|
||||||
sensirion/Sensirion I2C SCD4x@1.1.0
|
https://github.com/Sensirion/arduino-i2c-scd4x/archive/refs/tags/1.1.0.zip
|
||||||
# renovate: datasource=custom.pio depName=Sensirion I2C SFA3x packageName=sensirion/library/Sensirion I2C SFA3x
|
# renovate: datasource=github-tags depName=Sensirion I2C SFA3x packageName=sensirion/arduino-i2c-sfa3x
|
||||||
sensirion/Sensirion I2C SFA3x@1.0.0
|
https://github.com/Sensirion/arduino-i2c-sfa3x/archive/refs/tags/1.0.0.zip
|
||||||
# renovate: datasource=custom.pio depName=Sensirion I2C SCD30 packageName=sensirion/library/Sensirion I2C SCD30
|
# renovate: datasource=github-tags depName=Sensirion I2C SCD30 packageName=sensirion/arduino-i2c-scd30
|
||||||
sensirion/Sensirion I2C SCD30@1.0.0
|
https://github.com/Sensirion/arduino-i2c-scd30/archive/refs/tags/1.0.0.zip
|
||||||
|
# renovate: datasource=github-tags depName=arduino-sht packageName=sensirion/arduino-sht
|
||||||
|
https://github.com/Sensirion/arduino-sht/archive/refs/tags/v1.2.6.zip
|
||||||
|
|
||||||
; Environmental sensors with BSEC2 (Bosch proprietary IAQ)
|
; Environmental sensors with BSEC2 (Bosch proprietary IAQ)
|
||||||
[environmental_extra]
|
[environmental_extra]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${environmental_extra_common.lib_deps}
|
${environmental_extra_common.lib_deps}
|
||||||
# renovate: datasource=custom.pio depName=Bosch BSEC2 packageName=boschsensortec/library/bsec2
|
# renovate: datasource=github-tags depName=Bosch BSEC2 packageName=boschsensortec/Bosch-BSEC2-Library
|
||||||
boschsensortec/bsec2@1.10.2610
|
https://github.com/boschsensortec/Bosch-BSEC2-Library/archive/refs/tags/1.10.2610.zip
|
||||||
# renovate: datasource=custom.pio depName=Bosch BME68x packageName=boschsensortec/library/BME68x Sensor Library
|
# renovate: datasource=github-tags depName=Bosch BME68x packageName=boschsensortec/Bosch-BME68x-Library
|
||||||
boschsensortec/BME68x Sensor Library@1.3.40408
|
https://github.com/boschsensortec/Bosch-BME68x-Library/archive/refs/tags/v1.3.40408.zip
|
||||||
|
|
||||||
; Environmental sensors without BSEC (saves ~3.5KB DRAM for original ESP32 targets)
|
; Environmental sensors without BSEC (saves ~3.5KB DRAM for original ESP32 targets)
|
||||||
[environmental_extra_no_bsec]
|
[environmental_extra_no_bsec]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${environmental_extra_common.lib_deps}
|
${environmental_extra_common.lib_deps}
|
||||||
# renovate: datasource=custom.pio depName=Adafruit_BME680 packageName=adafruit/library/Adafruit BME680 Library
|
# renovate: datasource=github-tags depName=Adafruit_BME680 packageName=adafruit/Adafruit_BME680
|
||||||
adafruit/Adafruit BME680 Library@2.0.6
|
https://github.com/adafruit/Adafruit_BME680/archive/refs/tags/2.0.6.zip
|
||||||
|
|||||||
+1
-1
Submodule protobufs updated: cb1f89372a...e30092e616
@@ -21,8 +21,15 @@
|
|||||||
// How many messages are stored (RAM + flash).
|
// How many messages are stored (RAM + flash).
|
||||||
// Define -DMESSAGE_HISTORY_LIMIT=N in build_flags to control memory usage.
|
// Define -DMESSAGE_HISTORY_LIMIT=N in build_flags to control memory usage.
|
||||||
#ifndef MESSAGE_HISTORY_LIMIT
|
#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
|
#define MESSAGE_HISTORY_LIMIT 20
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
// Internal alias used everywhere in code – do NOT redefine elsewhere.
|
// Internal alias used everywhere in code – do NOT redefine elsewhere.
|
||||||
#define MAX_MESSAGES_SAVED MESSAGE_HISTORY_LIMIT
|
#define MAX_MESSAGES_SAVED MESSAGE_HISTORY_LIMIT
|
||||||
|
|||||||
+34
-5
@@ -40,6 +40,22 @@
|
|||||||
#include "concurrency/LockGuard.h"
|
#include "concurrency/LockGuard.h"
|
||||||
#endif
|
#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
|
#if defined(DEBUG_HEAP_MQTT) && !MESHTASTIC_EXCLUDE_MQTT
|
||||||
#include "mqtt/MQTT.h"
|
#include "mqtt/MQTT.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
@@ -328,11 +344,17 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
float scaled = 0;
|
float scaled = 0;
|
||||||
|
|
||||||
battery_adcEnable();
|
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();
|
raw = espAdcRead();
|
||||||
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
|
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
|
||||||
scaled *= operativeAdcMultiplier;
|
scaled *= operativeAdcMultiplier;
|
||||||
#else // block for all other platforms
|
#else // block for all other platforms
|
||||||
#ifdef ARCH_NRF52
|
#ifdef ARCH_NRF52
|
||||||
concurrency::LockGuard saadcGuard(concurrency::nrf52SaadcLock);
|
concurrency::LockGuard saadcGuard(concurrency::nrf52SaadcLock);
|
||||||
#endif
|
#endif
|
||||||
@@ -530,6 +552,11 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
bool initial_read_done = false;
|
bool initial_read_done = false;
|
||||||
float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS);
|
float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS);
|
||||||
uint32_t last_read_time_ms = 0;
|
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)
|
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(HAS_RAKPROT)
|
||||||
|
|
||||||
@@ -639,7 +666,9 @@ bool Power::analogInit()
|
|||||||
#define BATTERY_SENSE_RESOLUTION_BITS 10
|
#define BATTERY_SENSE_RESOLUTION_BITS 10
|
||||||
#endif
|
#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
|
#ifndef ADC_WIDTH // max resolution by default
|
||||||
static const adc_bits_width_t width = ADC_WIDTH_BIT_12;
|
static const adc_bits_width_t width = ADC_WIDTH_BIT_12;
|
||||||
@@ -649,7 +678,7 @@ bool Power::analogInit()
|
|||||||
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
|
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
|
||||||
adc1_config_width(width);
|
adc1_config_width(width);
|
||||||
adc1_config_channel_atten(adc_channel, atten);
|
adc1_config_channel_atten(adc_channel, atten);
|
||||||
#else // ADC2
|
#else // ADC2
|
||||||
adc2_config_channel_atten(adc_channel, atten);
|
adc2_config_channel_atten(adc_channel, atten);
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32S3
|
#ifndef CONFIG_IDF_TARGET_ESP32S3
|
||||||
// ADC2 wifi bug workaround
|
// ADC2 wifi bug workaround
|
||||||
@@ -679,7 +708,7 @@ bool Power::analogInit()
|
|||||||
|
|
||||||
// NRF52 ADC init moved to powerHAL_init in nrf52 platform
|
// 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);
|
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format,
|
|||||||
if (color) {
|
if (color) {
|
||||||
::printf("\u001b[0m");
|
::printf("\u001b[0m");
|
||||||
}
|
}
|
||||||
::printf("| %02d:%02d:%02d %u ", hour, min, sec, millis() / 1000);
|
::printf("| %02d:%02d:%02d %u.%03u ", hour, min, sec, millis() / 1000, millis() % 1000);
|
||||||
#else
|
#else
|
||||||
printf("%s ", logLevel);
|
printf("%s ", logLevel);
|
||||||
if (color) {
|
if (color) {
|
||||||
@@ -151,7 +151,7 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format,
|
|||||||
if (color) {
|
if (color) {
|
||||||
::printf("\u001b[0m");
|
::printf("\u001b[0m");
|
||||||
}
|
}
|
||||||
::printf("| ??:??:?? %u ", millis() / 1000);
|
::printf("| ??:??:?? %u.%03u ", millis() / 1000, millis() % 1000);
|
||||||
#else
|
#else
|
||||||
printf("%s ", logLevel);
|
printf("%s ", logLevel);
|
||||||
if (color) {
|
if (color) {
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ SerialConsole *console;
|
|||||||
|
|
||||||
void consoleInit()
|
void consoleInit()
|
||||||
{
|
{
|
||||||
|
if (console) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto sc = new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread
|
auto sc = new SerialConsole(); // Must be dynamically allocated because we are now inheriting from thread
|
||||||
|
|
||||||
#if defined(SERIAL_HAS_ON_RECEIVE)
|
#if defined(SERIAL_HAS_ON_RECEIVE)
|
||||||
|
|||||||
@@ -1,10 +1,85 @@
|
|||||||
#include "concurrency/BinarySemaphorePosix.h"
|
#include "concurrency/BinarySemaphorePosix.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#ifndef HAS_FREE_RTOS
|
#ifndef HAS_FREE_RTOS
|
||||||
|
|
||||||
namespace concurrency
|
namespace concurrency
|
||||||
{
|
{
|
||||||
|
#ifdef ARCH_PORTDUINO
|
||||||
|
|
||||||
|
BinarySemaphorePosix::BinarySemaphorePosix()
|
||||||
|
{
|
||||||
|
if (pthread_mutex_init(&mutex, NULL) != 0) {
|
||||||
|
throw std::runtime_error("pthread_mutex_init failed");
|
||||||
|
}
|
||||||
|
if (pthread_cond_init(&cond, NULL) != 0) {
|
||||||
|
pthread_mutex_destroy(&mutex);
|
||||||
|
throw std::runtime_error("pthread_cond_init failed");
|
||||||
|
}
|
||||||
|
signaled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinarySemaphorePosix::~BinarySemaphorePosix()
|
||||||
|
{
|
||||||
|
pthread_cond_destroy(&cond);
|
||||||
|
pthread_mutex_destroy(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns false if we timed out
|
||||||
|
*/
|
||||||
|
bool BinarySemaphorePosix::take(uint32_t msec)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
|
||||||
|
if (!signaled) {
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_REALTIME, &ts);
|
||||||
|
|
||||||
|
ts.tv_sec += msec / 1000;
|
||||||
|
ts.tv_nsec += (msec % 1000) * 1000000L;
|
||||||
|
if (ts.tv_nsec >= 1000000000L) {
|
||||||
|
ts.tv_sec += 1;
|
||||||
|
ts.tv_nsec -= 1000000000L;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!signaled) {
|
||||||
|
int rc = pthread_cond_timedwait(&cond, &mutex, &ts);
|
||||||
|
if (rc == ETIMEDOUT)
|
||||||
|
break;
|
||||||
|
if (rc != 0) {
|
||||||
|
// Some other error occurred
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
throw std::runtime_error("pthread_cond_timedwait failed: " + std::to_string(rc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wasSignaled = signaled;
|
||||||
|
signaled = false; // consume the signal (binary semaphore)
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
return wasSignaled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BinarySemaphorePosix::give()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
signaled = true;
|
||||||
|
pthread_cond_signal(&cond);
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
IRAM_ATTR void BinarySemaphorePosix::giveFromISR(BaseType_t *pxHigherPriorityTaskWoken)
|
||||||
|
{
|
||||||
|
give();
|
||||||
|
if (pxHigherPriorityTaskWoken)
|
||||||
|
*pxHigherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
BinarySemaphorePosix::BinarySemaphorePosix() {}
|
BinarySemaphorePosix::BinarySemaphorePosix() {}
|
||||||
|
|
||||||
@@ -22,7 +97,8 @@ bool BinarySemaphorePosix::take(uint32_t msec)
|
|||||||
void BinarySemaphorePosix::give() {}
|
void BinarySemaphorePosix::give() {}
|
||||||
|
|
||||||
IRAM_ATTR void BinarySemaphorePosix::giveFromISR(BaseType_t *pxHigherPriorityTaskWoken) {}
|
IRAM_ATTR void BinarySemaphorePosix::giveFromISR(BaseType_t *pxHigherPriorityTaskWoken) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace concurrency
|
} // namespace concurrency
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
#include "../freertosinc.h"
|
#include "../freertosinc.h"
|
||||||
|
|
||||||
|
#ifdef ARCH_PORTDUINO
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace concurrency
|
namespace concurrency
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -9,7 +13,12 @@ namespace concurrency
|
|||||||
|
|
||||||
class BinarySemaphorePosix
|
class BinarySemaphorePosix
|
||||||
{
|
{
|
||||||
// SemaphoreHandle_t semaphore;
|
|
||||||
|
#ifdef ARCH_PORTDUINO
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
pthread_cond_t cond;
|
||||||
|
bool signaled;
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BinarySemaphorePosix();
|
BinarySemaphorePosix();
|
||||||
@@ -27,4 +36,4 @@ class BinarySemaphorePosix
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace concurrency
|
} // namespace concurrency
|
||||||
|
|||||||
+3
-3
@@ -231,7 +231,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define BME_ADDR 0x76
|
#define BME_ADDR 0x76
|
||||||
#define BME_ADDR_ALTERNATE 0x77
|
#define BME_ADDR_ALTERNATE 0x77
|
||||||
#define MCP9808_ADDR 0x18
|
#define MCP9808_ADDR 0x18
|
||||||
#define INA_ADDR 0x40
|
#define INA_ADDR 0x40 // same as SHT2X
|
||||||
#define INA_ADDR_ALTERNATE 0x41
|
#define INA_ADDR_ALTERNATE 0x41
|
||||||
#define INA_ADDR_WAVESHARE_UPS 0x43
|
#define INA_ADDR_WAVESHARE_UPS 0x43
|
||||||
#define INA3221_ADDR 0x42
|
#define INA3221_ADDR 0x42
|
||||||
@@ -244,8 +244,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define LPS22HB_ADDR 0x5C
|
#define LPS22HB_ADDR 0x5C
|
||||||
#define LPS22HB_ADDR_ALT 0x5D
|
#define LPS22HB_ADDR_ALT 0x5D
|
||||||
#define SFA30_ADDR 0x5D
|
#define SFA30_ADDR 0x5D
|
||||||
#define SHT31_4x_ADDR 0x44
|
#define SHTXX_ADDR 0x44
|
||||||
#define SHT31_4x_ADDR_ALT 0x45
|
#define SHTXX_ADDR_ALT 0x45
|
||||||
#define PMSA003I_ADDR 0x12
|
#define PMSA003I_ADDR 0x12
|
||||||
#define QMA6100P_ADDR 0x12
|
#define QMA6100P_ADDR 0x12
|
||||||
#define AHT10_ADDR 0x38
|
#define AHT10_ADDR 0x38
|
||||||
|
|||||||
@@ -31,9 +31,6 @@ class ScanI2C
|
|||||||
INA3221,
|
INA3221,
|
||||||
MAX17048,
|
MAX17048,
|
||||||
MCP9808,
|
MCP9808,
|
||||||
SHT31,
|
|
||||||
SHT4X,
|
|
||||||
SHTC3,
|
|
||||||
LPS22HB,
|
LPS22HB,
|
||||||
QMC6310U,
|
QMC6310U,
|
||||||
QMC6310N,
|
QMC6310N,
|
||||||
@@ -94,7 +91,8 @@ class ScanI2C
|
|||||||
SFA30,
|
SFA30,
|
||||||
CW2015,
|
CW2015,
|
||||||
SCD30,
|
SCD30,
|
||||||
ADS1115
|
ADS1115,
|
||||||
|
SHTXX
|
||||||
} DeviceType;
|
} DeviceType;
|
||||||
|
|
||||||
// typedef uint8_t DeviceAddress;
|
// typedef uint8_t DeviceAddress;
|
||||||
|
|||||||
@@ -136,7 +136,9 @@ bool ScanI2CTwoWire::i2cCommandResponseLength(ScanI2C::DeviceAddress addr, uint1
|
|||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// for SEN5X detection
|
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
||||||
|
// FIXME Move to a separate file for detection of sensors that require more complex interactions?
|
||||||
|
// For SEN5X detection
|
||||||
// Note, this code needs to be called before setting the I2C bus speed
|
// Note, this code needs to be called before setting the I2C bus speed
|
||||||
// for the screen at high speed. The speed needs to be at 100kHz, otherwise
|
// for the screen at high speed. The speed needs to be at 100kHz, otherwise
|
||||||
// detection will not work
|
// detection will not work
|
||||||
@@ -174,6 +176,46 @@ String readSEN5xProductName(TwoWire *i2cBus, uint8_t address)
|
|||||||
|
|
||||||
return String(productName);
|
return String(productName);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
|
bool detectSHT21SerialNumber(TwoWire *i2cBus, uint8_t address)
|
||||||
|
{
|
||||||
|
|
||||||
|
i2cBus->beginTransmission(address);
|
||||||
|
i2cBus->write(0xFA);
|
||||||
|
i2cBus->write(0x0F);
|
||||||
|
|
||||||
|
if (i2cBus->endTransmission() != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (i2cBus->requestFrom(address, (uint8_t)8) != 8)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Just flush the data
|
||||||
|
while (i2cBus->available() < 8) {
|
||||||
|
i2cBus->read();
|
||||||
|
}
|
||||||
|
|
||||||
|
i2cBus->beginTransmission(address);
|
||||||
|
i2cBus->write(0xFC);
|
||||||
|
i2cBus->write(0xC9);
|
||||||
|
|
||||||
|
if (i2cBus->endTransmission() != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (i2cBus->requestFrom(address, (uint8_t)6) != 6)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Just flush the data
|
||||||
|
while (i2cBus->available() < 6) {
|
||||||
|
i2cBus->read();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume we detect the SHT21 if something came back from the request
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
|
#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
|
||||||
case ADDR: \
|
case ADDR: \
|
||||||
@@ -371,7 +413,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if !defined(M5STACK_UNITC6L)
|
#if !defined(M5STACK_UNITC6L)
|
||||||
case INA_ADDR:
|
case INA_ADDR: // Same as SHT2X
|
||||||
case INA_ADDR_ALTERNATE:
|
case INA_ADDR_ALTERNATE:
|
||||||
case INA_ADDR_WAVESHARE_UPS:
|
case INA_ADDR_WAVESHARE_UPS:
|
||||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
|
||||||
@@ -387,7 +429,12 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
logFoundDevice("INA260", (uint8_t)addr.address);
|
logFoundDevice("INA260", (uint8_t)addr.address);
|
||||||
type = INA260;
|
type = INA260;
|
||||||
}
|
}
|
||||||
} else { // Assume INA219 if INA260 ID is not found
|
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
|
} else if (detectSHT21SerialNumber(i2cBus, (uint8_t)addr.address)) {
|
||||||
|
logFoundDevice("SHTXX (SHT2X)", (uint8_t)addr.address);
|
||||||
|
type = SHTXX;
|
||||||
|
#endif
|
||||||
|
} else { // Assume INA219 if none of the above ones are found
|
||||||
logFoundDevice("INA219", (uint8_t)addr.address);
|
logFoundDevice("INA219", (uint8_t)addr.address);
|
||||||
type = INA219;
|
type = INA219;
|
||||||
}
|
}
|
||||||
@@ -448,22 +495,19 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT
|
case SHTXX_ADDR: // same as OPT3001_ADDR_ALT
|
||||||
case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR
|
case SHTXX_ADDR_ALT: // same as OPT3001_ADDR
|
||||||
if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) {
|
if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) {
|
||||||
type = OPT3001;
|
type = OPT3001;
|
||||||
logFoundDevice("OPT3001", (uint8_t)addr.address);
|
logFoundDevice("OPT3001", (uint8_t)addr.address);
|
||||||
} else if (i2cCommandResponseLength(addr, 0x89, 6)) { // SHT4x serial number (6 bytes inc. CRC)
|
} else { // SHTXX
|
||||||
type = SHT4X;
|
type = SHTXX;
|
||||||
logFoundDevice("SHT4X", (uint8_t)addr.address);
|
logFoundDevice("SHTXX", (uint8_t)addr.address);
|
||||||
} else {
|
|
||||||
type = SHT31;
|
|
||||||
logFoundDevice("SHT31", (uint8_t)addr.address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3", (uint8_t)addr.address)
|
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTXX, "SHTXX", (uint8_t)addr.address)
|
||||||
case RCWL9620_ADDR:
|
case RCWL9620_ADDR:
|
||||||
// get MAX30102 PARTID
|
// get MAX30102 PARTID
|
||||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFF), 1);
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFF), 1);
|
||||||
@@ -675,6 +719,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
logFoundDevice("BMX160", (uint8_t)addr.address);
|
logFoundDevice("BMX160", (uint8_t)addr.address);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
||||||
String prod = "";
|
String prod = "";
|
||||||
prod = readSEN5xProductName(i2cBus, addr.address);
|
prod = readSEN5xProductName(i2cBus, addr.address);
|
||||||
if (prod.startsWith("SEN55")) {
|
if (prod.startsWith("SEN55")) {
|
||||||
@@ -690,6 +735,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
logFoundDevice("Sensirion SEN50", addr.address);
|
logFoundDevice("Sensirion SEN50", addr.address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (addr.address == BMX160_ADDR) {
|
if (addr.address == BMX160_ADDR) {
|
||||||
type = BMX160;
|
type = BMX160;
|
||||||
logFoundDevice("BMX160", (uint8_t)addr.address);
|
logFoundDevice("BMX160", (uint8_t)addr.address);
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ void EInkParallelDisplay::display(void)
|
|||||||
|
|
||||||
// Get pointers to internal buffers
|
// Get pointers to internal buffers
|
||||||
uint8_t *cur = epaper->currentBuffer();
|
uint8_t *cur = epaper->currentBuffer();
|
||||||
uint8_t *prev = epaper->previousBuffer(); // may be NULL on first init
|
const uint8_t *prev = epaper->previousBuffer(); // may be NULL on first init
|
||||||
|
|
||||||
// Track changed row range while converting
|
// Track changed row range while converting
|
||||||
int newTop = h; // min changed row (initialized to out-of-range)
|
int newTop = h; // min changed row (initialized to out-of-range)
|
||||||
|
|||||||
@@ -1197,7 +1197,7 @@ void Screen::setFrames(FrameFocus focus)
|
|||||||
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||||
const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
|
const meshtastic_NodeInfoLite *n = nodeDB->getMeshNodeByIndex(i);
|
||||||
if (n && n->num != nodeDB->getNodeNum() && n->is_favorite) {
|
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};
|
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
|
||||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
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
|
// Focus on a specific frame, in the frame set we just created
|
||||||
switch (focus) {
|
switch (focus) {
|
||||||
|
|||||||
@@ -1254,14 +1254,14 @@ void TFTDisplay::display(bool fromBlank)
|
|||||||
|
|
||||||
// Did we find a pixel that needs updating on this row?
|
// Did we find a pixel that needs updating on this row?
|
||||||
if (x_FirstPixelUpdate < displayWidth) {
|
if (x_FirstPixelUpdate < displayWidth) {
|
||||||
|
// Align the first pixel for update to an even number so the total alignment of
|
||||||
|
// the data will be at 32-bit boundary, which is required by GDMA SPI transfers.
|
||||||
|
x_FirstPixelUpdate &= ~1;
|
||||||
|
|
||||||
// Quickly write out the first changed pixel (saves another array lookup)
|
// Step 3a: copy rest of the pixels in this row into the pixel line buffer,
|
||||||
linePixelBuffer[x_FirstPixelUpdate] = isset ? colorTftMesh : colorTftBlack;
|
// while also recording the last pixel in the row that needs updating.
|
||||||
x_LastPixelUpdate = x_FirstPixelUpdate;
|
// Since the first changed pixel will be looked up, the x_LastPixelUpdate will be set.
|
||||||
|
for (x = x_FirstPixelUpdate; x < displayWidth; x++) {
|
||||||
// Step 3: copy all remaining pixels in this row into the pixel line buffer,
|
|
||||||
// while also recording the last pixel in the row that needs updating
|
|
||||||
for (x = x_FirstPixelUpdate + 1; x < displayWidth; x++) {
|
|
||||||
isset = buffer[x + y_byteIndex] & y_byteMask;
|
isset = buffer[x + y_byteIndex] & y_byteMask;
|
||||||
linePixelBuffer[x] = isset ? colorTftMesh : colorTftBlack;
|
linePixelBuffer[x] = isset ? colorTftMesh : colorTftBlack;
|
||||||
|
|
||||||
@@ -1274,6 +1274,14 @@ void TFTDisplay::display(bool fromBlank)
|
|||||||
x_LastPixelUpdate = x;
|
x_LastPixelUpdate = x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Step 3b: Round up the last pixel to odd number to maintain 32-bit alignment for SPIs.
|
||||||
|
// Most displays will have even number of pixels in a row -- this will be in bounds
|
||||||
|
// of the displayWidth. (Hopefully odd displays will just ignore that extra pixel.)
|
||||||
|
x_LastPixelUpdate |= 1;
|
||||||
|
// Ensure the last pixel index does not exceed the display width.
|
||||||
|
if (x_LastPixelUpdate >= displayWidth) {
|
||||||
|
x_LastPixelUpdate = displayWidth - 1;
|
||||||
|
}
|
||||||
#if defined(HACKADAY_COMMUNICATOR)
|
#if defined(HACKADAY_COMMUNICATOR)
|
||||||
tft->draw16bitBeRGBBitmap(x_FirstPixelUpdate, y, &linePixelBuffer[x_FirstPixelUpdate],
|
tft->draw16bitBeRGBBitmap(x_FirstPixelUpdate, y, &linePixelBuffer[x_FirstPixelUpdate],
|
||||||
(x_LastPixelUpdate - x_FirstPixelUpdate + 1), 1);
|
(x_LastPixelUpdate - x_FirstPixelUpdate + 1), 1);
|
||||||
|
|||||||
@@ -163,9 +163,11 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
|||||||
|
|
||||||
// Guard: without a reboot, reconfigure() applies the region directly.
|
// Guard: without a reboot, reconfigure() applies the region directly.
|
||||||
// Reject LORA_24 on sub-GHz-only hardware — getRadio() used to catch this post-reboot.
|
// Reject LORA_24 on sub-GHz-only hardware — getRadio() used to catch this post-reboot.
|
||||||
|
// TODO: change this to either use the validateLoraConfig() logic or at least check the region for wideLora
|
||||||
|
// rather than a hardcoded check for LORA_24.
|
||||||
if (selectedRegion == meshtastic_Config_LoRaConfig_RegionCode_LORA_24 &&
|
if (selectedRegion == meshtastic_Config_LoRaConfig_RegionCode_LORA_24 &&
|
||||||
!(RadioLibInterface::instance && RadioLibInterface::instance->wideLora())) {
|
!(RadioLibInterface::instance && RadioLibInterface::instance->wideLora())) {
|
||||||
LOG_WARN("Radio hardware does not support 2.4 GHz; ignoring LORA_24 selection");
|
LOG_WARN("Radio hardware does not support 2.4 GHz; ignoring region selection");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -422,6 +422,17 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
std::vector<bool> isMine; // track alignment
|
std::vector<bool> isMine; // track alignment
|
||||||
std::vector<bool> isHeader; // track header lines
|
std::vector<bool> isHeader; // track header lines
|
||||||
std::vector<AckStatus> ackForLine;
|
std::vector<AckStatus> 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) {
|
for (auto it = filtered.rbegin(); it != filtered.rend(); ++it) {
|
||||||
const auto &m = *it;
|
const auto &m = *it;
|
||||||
@@ -565,16 +576,23 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
|
|
||||||
int wrapWidth = mine ? rightTextWidth : leftTextWidth;
|
int wrapWidth = mine ? rightTextWidth : leftTextWidth;
|
||||||
std::vector<std::string> wrapped = generateLines(display, "", msgText, wrapWidth);
|
std::vector<std::string> 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) {
|
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);
|
isMine.push_back(mine);
|
||||||
isHeader.push_back(false);
|
isHeader.push_back(false);
|
||||||
ackForLine.push_back(AckStatus::NONE);
|
ackForLine.push_back(AckStatus::NONE);
|
||||||
|
++wrappedCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache lines and heights
|
// Cache lines and heights
|
||||||
cachedLines = allLines;
|
cachedLines.swap(allLines);
|
||||||
cachedHeights = calculateLineHeights(cachedLines, emotes, isHeader);
|
cachedHeights = calculateLineHeights(cachedLines, emotes, isHeader);
|
||||||
|
|
||||||
std::vector<MessageBlock> blocks = buildMessageBlocks(isHeader, isMine);
|
std::vector<MessageBlock> blocks = buildMessageBlocks(isHeader, isMine);
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
#include "CompassRenderer.h"
|
#include "CompassRenderer.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "NodeListRenderer.h"
|
#include "NodeListRenderer.h"
|
||||||
|
#if !MESHTASTIC_EXCLUDE_STATUS
|
||||||
|
#include "modules/StatusMessageModule.h"
|
||||||
|
#endif
|
||||||
#include "UIRenderer.h"
|
#include "UIRenderer.h"
|
||||||
#include "gps/GeoCoord.h"
|
#include "gps/GeoCoord.h"
|
||||||
#include "gps/RTC.h" // for getTime() function
|
#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
|
// 1) Choose target candidate (long vs short) only if present
|
||||||
const char *raw = nullptr;
|
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.
|
// 2) Preserve UTF-8 names so emotes can be detected and rendered.
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "NodeListRenderer.h"
|
#include "NodeListRenderer.h"
|
||||||
|
#if !MESHTASTIC_EXCLUDE_STATUS
|
||||||
|
#include "modules/StatusMessageModule.h"
|
||||||
|
#endif
|
||||||
#include "UIRenderer.h"
|
#include "UIRenderer.h"
|
||||||
#include "airtime.h"
|
#include "airtime.h"
|
||||||
#include "gps/GeoCoord.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 *
|
// * Favorite Node Info *
|
||||||
// **********************
|
// **********************
|
||||||
// cppcheck-suppress constParameterPointer; signature must match FrameCallback typedef from OLEDDisplayUi library
|
// 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())
|
if (favoritedNodes.empty())
|
||||||
return;
|
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);
|
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) ===
|
// === 2. Signal and Hops (combined on one line, if available) ===
|
||||||
char signalHopsStr[32] = "";
|
char signalHopsStr[32] = "";
|
||||||
bool haveSignal = false;
|
bool haveSignal = false;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class UIRenderer
|
|||||||
// Navigation bar overlay
|
// Navigation bar overlay
|
||||||
static void drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *state);
|
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);
|
static void drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,6 @@ void CardputerKeyboard::pressed(uint8_t key)
|
|||||||
modifierFlag = 0;
|
modifierFlag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t next_key = 0;
|
|
||||||
int row = (key - 1) / 10;
|
int row = (key - 1) / 10;
|
||||||
int col = (key - 1) % 10;
|
int col = (key - 1) % 10;
|
||||||
|
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ void InputBroker::Init()
|
|||||||
// Buttons. Moved here cause we need NodeDB to be initialized
|
// Buttons. Moved here cause we need NodeDB to be initialized
|
||||||
// If your variant.h has a BUTTON_PIN defined, go ahead and define BUTTON_ACTIVE_LOW and BUTTON_ACTIVE_PULLUP
|
// If your variant.h has a BUTTON_PIN defined, go ahead and define BUTTON_ACTIVE_LOW and BUTTON_ACTIVE_PULLUP
|
||||||
UserButtonThread = new ButtonThread("UserButton");
|
UserButtonThread = new ButtonThread("UserButton");
|
||||||
|
#if !MESHTASTIC_EXCLUDE_SCREEN
|
||||||
if (screen) {
|
if (screen) {
|
||||||
ButtonConfig userConfig;
|
ButtonConfig userConfig;
|
||||||
userConfig.pinNumber = (uint8_t)_pinNum;
|
userConfig.pinNumber = (uint8_t)_pinNum;
|
||||||
@@ -317,7 +318,9 @@ void InputBroker::Init()
|
|||||||
userConfig.longPressTime = 500;
|
userConfig.longPressTime = 500;
|
||||||
userConfig.longLongPress = INPUT_BROKER_SHUTDOWN;
|
userConfig.longLongPress = INPUT_BROKER_SHUTDOWN;
|
||||||
UserButtonThread->initButton(userConfig);
|
UserButtonThread->initButton(userConfig);
|
||||||
} else {
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
ButtonConfig userConfigNoScreen;
|
ButtonConfig userConfigNoScreen;
|
||||||
userConfigNoScreen.pinNumber = (uint8_t)_pinNum;
|
userConfigNoScreen.pinNumber = (uint8_t)_pinNum;
|
||||||
userConfigNoScreen.activeLow = BUTTON_ACTIVE_LOW;
|
userConfigNoScreen.activeLow = BUTTON_ACTIVE_LOW;
|
||||||
@@ -379,11 +382,13 @@ void InputBroker::Init()
|
|||||||
}
|
}
|
||||||
#endif // HAS_BUTTON
|
#endif // HAS_BUTTON
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
seesawRotary = new SeesawRotary("SeesawRotary");
|
if (portduino_config.i2cdev != "") {
|
||||||
if (!seesawRotary->init()) {
|
seesawRotary = new SeesawRotary("SeesawRotary");
|
||||||
delete seesawRotary;
|
if (!seesawRotary->init()) {
|
||||||
seesawRotary = nullptr;
|
delete seesawRotary;
|
||||||
|
seesawRotary = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
aLinuxInputImpl = new LinuxInputImpl();
|
aLinuxInputImpl = new LinuxInputImpl();
|
||||||
aLinuxInputImpl->init();
|
aLinuxInputImpl->init();
|
||||||
|
|||||||
+23
-5
@@ -10,8 +10,26 @@
|
|||||||
#include "memGet.h"
|
#include "memGet.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#ifdef ARCH_STM32WL
|
#if defined(MESHTASTIC_DYNAMIC_SBRK_HEAP)
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <unistd.h> // 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
|
#endif
|
||||||
|
|
||||||
MemGet memGet;
|
MemGet memGet;
|
||||||
@@ -28,9 +46,9 @@ uint32_t MemGet::getFreeHeap()
|
|||||||
return dbgHeapFree();
|
return dbgHeapFree();
|
||||||
#elif defined(ARCH_RP2040)
|
#elif defined(ARCH_RP2040)
|
||||||
return rp2040.getFreeHeap();
|
return rp2040.getFreeHeap();
|
||||||
#elif defined(ARCH_STM32WL)
|
#elif defined(MESHTASTIC_DYNAMIC_SBRK_HEAP) // Currently: ARCH_STM32WL
|
||||||
struct mallinfo m = mallinfo();
|
struct mallinfo m = mallinfo();
|
||||||
return m.fordblks; // Total free space (bytes)
|
return m.fordblks + sbrkHeadroom(); // Free space within arena + uncommitted sbrk headroom
|
||||||
#else
|
#else
|
||||||
// this platform does not have heap management function implemented
|
// this platform does not have heap management function implemented
|
||||||
return UINT32_MAX;
|
return UINT32_MAX;
|
||||||
@@ -49,9 +67,9 @@ uint32_t MemGet::getHeapSize()
|
|||||||
return dbgHeapTotal();
|
return dbgHeapTotal();
|
||||||
#elif defined(ARCH_RP2040)
|
#elif defined(ARCH_RP2040)
|
||||||
return rp2040.getTotalHeap();
|
return rp2040.getTotalHeap();
|
||||||
#elif defined(ARCH_STM32WL)
|
#elif defined(MESHTASTIC_DYNAMIC_SBRK_HEAP) // Currently: ARCH_STM32WL
|
||||||
struct mallinfo m = mallinfo();
|
struct mallinfo m = mallinfo();
|
||||||
return m.arena; // Non-mmapped space allocated (bytes)
|
return m.arena + sbrkHeadroom(); // Non-mmapped space allocated + uncommitted sbrk headroom
|
||||||
#else
|
#else
|
||||||
// this platform does not have heap management function implemented
|
// this platform does not have heap management function implemented
|
||||||
return UINT32_MAX;
|
return UINT32_MAX;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#if !(MESHTASTIC_EXCLUDE_PKI)
|
#if !(MESHTASTIC_EXCLUDE_PKI)
|
||||||
|
#include "HardwareRNG.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "aes-ccm.h"
|
#include "aes-ccm.h"
|
||||||
#include "meshUtils.h"
|
#include "meshUtils.h"
|
||||||
@@ -26,6 +27,15 @@ void CryptoEngine::generateKeyPair(uint8_t *pubKey, uint8_t *privKey)
|
|||||||
{
|
{
|
||||||
// Mix in any randomness we can, to make key generation stronger.
|
// Mix in any randomness we can, to make key generation stronger.
|
||||||
CryptRNG.begin(optstr(APP_VERSION));
|
CryptRNG.begin(optstr(APP_VERSION));
|
||||||
|
|
||||||
|
uint8_t hardwareEntropy[64] = {0};
|
||||||
|
if (HardwareRNG::fill(hardwareEntropy, sizeof(hardwareEntropy), true)) {
|
||||||
|
CryptRNG.stir(hardwareEntropy, sizeof(hardwareEntropy));
|
||||||
|
} else {
|
||||||
|
LOG_WARN("Hardware entropy unavailable, falling back to software RNG");
|
||||||
|
}
|
||||||
|
memset(hardwareEntropy, 0, sizeof(hardwareEntropy));
|
||||||
|
|
||||||
if (myNodeInfo.device_id.size == 16) {
|
if (myNodeInfo.device_id.size == 16) {
|
||||||
CryptRNG.stir(myNodeInfo.device_id.bytes, myNodeInfo.device_id.size);
|
CryptRNG.stir(myNodeInfo.device_id.bytes, myNodeInfo.device_id.size);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -32,8 +32,8 @@
|
|||||||
#define default_map_publish_interval_secs 60 * 60
|
#define default_map_publish_interval_secs 60 * 60
|
||||||
|
|
||||||
// Traffic management defaults
|
// Traffic management defaults
|
||||||
#define default_traffic_mgmt_position_precision_bits 24 // ~10m grid cells
|
#define default_traffic_mgmt_position_precision_bits 24 // ~10m grid cells
|
||||||
#define default_traffic_mgmt_position_min_interval_secs ONE_DAY // 1 day between identical positions
|
#define default_traffic_mgmt_position_min_interval_secs (ONE_DAY / 2) // 12 hours between identical positions
|
||||||
|
|
||||||
#ifdef USERPREFS_RINGTONE_NAG_SECS
|
#ifdef USERPREFS_RINGTONE_NAG_SECS
|
||||||
#define default_ringtone_nag_secs USERPREFS_RINGTONE_NAG_SECS
|
#define default_ringtone_nag_secs USERPREFS_RINGTONE_NAG_SECS
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
#include "HardwareRNG.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#if HAS_RADIO
|
||||||
|
#include "RadioLibInterface.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ARCH_NRF52)
|
||||||
|
#include <Adafruit_nRFCrypto.h>
|
||||||
|
extern Adafruit_nRFCrypto nRFCrypto;
|
||||||
|
#elif defined(ARCH_ESP32)
|
||||||
|
#include <esp_system.h>
|
||||||
|
#elif defined(ARCH_RP2040)
|
||||||
|
#include <Arduino.h>
|
||||||
|
#elif defined(ARCH_PORTDUINO)
|
||||||
|
#include <random>
|
||||||
|
#include <sys/random.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace HardwareRNG
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void fillWithRandomDevice(uint8_t *buffer, size_t length)
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
size_t offset = 0;
|
||||||
|
while (offset < length) {
|
||||||
|
uint32_t value = rd();
|
||||||
|
size_t toCopy = std::min(length - offset, sizeof(value));
|
||||||
|
memcpy(buffer + offset, &value, toCopy);
|
||||||
|
offset += toCopy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAS_RADIO
|
||||||
|
bool mixWithLoRaEntropy(uint8_t *buffer, size_t length)
|
||||||
|
{
|
||||||
|
// Only attempt to pull entropy from the modem if it is initialized and exposes the helper.
|
||||||
|
// When the radio stack is disabled or has not yet been configured, we simply skip this step
|
||||||
|
// and return false so callers know no extra mixing occurred.
|
||||||
|
RadioLibInterface *radio = RadioLibInterface::instance;
|
||||||
|
if (!radio) {
|
||||||
|
// Intentionally silent: this path runs during portduinoSetup() before the
|
||||||
|
// console/SerialConsole is initialized, so LOG_* here would dereference a null pointer.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t chunkSize = 16;
|
||||||
|
uint8_t scratch[chunkSize];
|
||||||
|
size_t offset = 0;
|
||||||
|
bool mixed = false;
|
||||||
|
|
||||||
|
while (offset < length) {
|
||||||
|
size_t toCopy = std::min(length - offset, chunkSize);
|
||||||
|
|
||||||
|
// randomBytes() returns false if the modem does not support it or is not ready
|
||||||
|
// (for instance, when the radio is powered down). We break immediately to avoid
|
||||||
|
// blocking or returning partially-filled entropy and simply report failure.
|
||||||
|
if (!radio->randomBytes(scratch, toCopy)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < toCopy; ++i) {
|
||||||
|
buffer[offset + i] ^= scratch[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
mixed = true;
|
||||||
|
offset += toCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid leaving the modem-sourced bytes sitting on the stack longer than needed.
|
||||||
|
if (mixed) {
|
||||||
|
memset(scratch, 0, sizeof(scratch));
|
||||||
|
}
|
||||||
|
|
||||||
|
return mixed;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool fill(uint8_t *buffer, size_t length, bool useRadioEntropy)
|
||||||
|
{
|
||||||
|
if (!buffer || length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool filled = false;
|
||||||
|
|
||||||
|
#if defined(ARCH_NRF52)
|
||||||
|
// The Nordic SDK RNG provides cryptographic-quality randomness backed by hardware.
|
||||||
|
nRFCrypto.begin();
|
||||||
|
auto result = nRFCrypto.Random.generate(buffer, length);
|
||||||
|
nRFCrypto.end();
|
||||||
|
filled = result;
|
||||||
|
#elif defined(ARCH_ESP32)
|
||||||
|
// ESP32 exposes a true RNG via esp_fill_random().
|
||||||
|
esp_fill_random(buffer, length);
|
||||||
|
filled = true;
|
||||||
|
#elif defined(ARCH_RP2040)
|
||||||
|
// RP2040 has a hardware random number generator accessible through the Arduino core.
|
||||||
|
size_t offset = 0;
|
||||||
|
while (offset < length) {
|
||||||
|
uint32_t value = rp2040.hwrand32();
|
||||||
|
size_t toCopy = std::min(length - offset, sizeof(value));
|
||||||
|
memcpy(buffer + offset, &value, toCopy);
|
||||||
|
offset += toCopy;
|
||||||
|
}
|
||||||
|
filled = true;
|
||||||
|
#elif defined(ARCH_PORTDUINO)
|
||||||
|
// Prefer the host OS RNG first when running under Portduino.
|
||||||
|
ssize_t generated = ::getrandom(buffer, length, 0);
|
||||||
|
if (generated == static_cast<ssize_t>(length)) {
|
||||||
|
filled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filled) {
|
||||||
|
fillWithRandomDevice(buffer, length);
|
||||||
|
filled = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!filled) {
|
||||||
|
// As a last resort, fall back to std::random_device. This should only be reached
|
||||||
|
// if a platform-specific source was unavailable.
|
||||||
|
fillWithRandomDevice(buffer, length);
|
||||||
|
filled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAS_RADIO
|
||||||
|
if (useRadioEntropy) {
|
||||||
|
// Best-effort: if the radio is active and can provide modem entropy, XOR it over the
|
||||||
|
// buffer to improve overall quality. We consider the filling a success if either a
|
||||||
|
// good platform RNG or the modem RNG provided data, so we return true as long as at
|
||||||
|
// least one of those steps succeeded.
|
||||||
|
filled = mixWithLoRaEntropy(buffer, length) || filled;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return filled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool seed(uint32_t &seedOut)
|
||||||
|
{
|
||||||
|
uint32_t candidate = 0;
|
||||||
|
if (!fill(reinterpret_cast<uint8_t *>(&candidate), sizeof(candidate), true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seedOut = candidate;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace HardwareRNG
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace HardwareRNG
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the provided buffer with random bytes sourced from the most
|
||||||
|
* appropriate hardware-backed RNG available on the current platform.
|
||||||
|
*
|
||||||
|
* @param buffer Destination buffer for random bytes
|
||||||
|
* @param length Number of bytes to write
|
||||||
|
* @param useRadioEntropy If true, attempt to mix radio entropy into the output as well.
|
||||||
|
* @return true if the buffer was fully populated with entropy, false on failure
|
||||||
|
*/
|
||||||
|
bool fill(uint8_t *buffer, size_t length, bool useRadioEntropy = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate a 32-bit seed value with hardware-backed randomness where possible.
|
||||||
|
*
|
||||||
|
* @param seedOut Destination for the generated seed value
|
||||||
|
* @return true if a seed was produced from a reliable entropy source
|
||||||
|
*/
|
||||||
|
bool seed(uint32_t &seedOut);
|
||||||
|
|
||||||
|
} // namespace HardwareRNG
|
||||||
@@ -71,12 +71,10 @@ template <typename T> bool LR11x0Interface<T>::init()
|
|||||||
|
|
||||||
RadioLibInterface::init();
|
RadioLibInterface::init();
|
||||||
|
|
||||||
limitPower(LR1110_MAX_POWER);
|
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24) { // clamp if wide freq range
|
||||||
|
limitPower(LR1120_MAX_POWER);
|
||||||
if ((power > LR1120_MAX_POWER) &&
|
} else {
|
||||||
(config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) { // clamp again if wide freq range
|
limitPower(LR1110_MAX_POWER); // default clamp for non-wide freq range
|
||||||
power = LR1120_MAX_POWER;
|
|
||||||
preambleLength = 12; // 12 is the default for operation above 2GHz
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LR11X0_RF_SWITCH_SUBGHZ
|
#ifdef LR11X0_RF_SWITCH_SUBGHZ
|
||||||
@@ -177,6 +175,12 @@ template <typename T> bool LR11x0Interface<T>::reconfigure()
|
|||||||
err = lora.setSyncWord(syncWord);
|
err = lora.setSyncWord(syncWord);
|
||||||
assert(err == RADIOLIB_ERR_NONE);
|
assert(err == RADIOLIB_ERR_NONE);
|
||||||
|
|
||||||
|
if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24) { // clamp if wide freq range
|
||||||
|
limitPower(LR1120_MAX_POWER);
|
||||||
|
} else {
|
||||||
|
limitPower(LR1110_MAX_POWER); // default clamp for non-wide freq range
|
||||||
|
}
|
||||||
|
|
||||||
err = lora.setPreambleLength(preambleLength);
|
err = lora.setPreambleLength(preambleLength);
|
||||||
assert(err == RADIOLIB_ERR_NONE);
|
assert(err == RADIOLIB_ERR_NONE);
|
||||||
|
|
||||||
@@ -184,11 +188,6 @@ template <typename T> bool LR11x0Interface<T>::reconfigure()
|
|||||||
if (err != RADIOLIB_ERR_NONE)
|
if (err != RADIOLIB_ERR_NONE)
|
||||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
|
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
|
||||||
|
|
||||||
if (power > LR1110_MAX_POWER) // This chip has lower power limits than some
|
|
||||||
power = LR1110_MAX_POWER;
|
|
||||||
if ((power > LR1120_MAX_POWER) && (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) // 2.4G power limit
|
|
||||||
power = LR1120_MAX_POWER;
|
|
||||||
|
|
||||||
err = lora.setOutputPower(power);
|
err = lora.setOutputPower(power);
|
||||||
assert(err == RADIOLIB_ERR_NONE);
|
assert(err == RADIOLIB_ERR_NONE);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
#include "PointerQueue.h"
|
#include "PointerQueue.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "detect/LoRaRadioType.h"
|
||||||
|
|
||||||
// Sentinel marking the end of a modem preset array
|
// Sentinel marking the end of a modem preset array
|
||||||
static constexpr meshtastic_Config_LoRaConfig_ModemPreset MODEM_PRESET_END =
|
static constexpr meshtastic_Config_LoRaConfig_ModemPreset MODEM_PRESET_END =
|
||||||
@@ -59,7 +60,7 @@ extern const RegionInfo *myRegion;
|
|||||||
extern void initRegion();
|
extern void initRegion();
|
||||||
|
|
||||||
// Valid LoRa spread factor range and defaults
|
// 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_MAX = 12;
|
||||||
constexpr uint8_t LORA_SF_DEFAULT = 11; // LONG_FAST default
|
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)
|
// Default bandwidth in kHz (LONG_FAST)
|
||||||
constexpr float LORA_BW_DEFAULT_KHZ = 250.0f;
|
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.
|
/// Out-of-range values (including 0 from unset preset mode) return LORA_SF_DEFAULT.
|
||||||
static inline uint8_t clampSpreadFactor(uint8_t sf)
|
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)
|
if (sf < LORA_SF_MIN || sf > LORA_SF_MAX)
|
||||||
return LORA_SF_DEFAULT;
|
return LORA_SF_DEFAULT;
|
||||||
return sf;
|
return sf;
|
||||||
|
|||||||
+1
-1
@@ -819,7 +819,7 @@ void NodeDB::installDefaultModuleConfig()
|
|||||||
moduleConfig.has_store_forward = true;
|
moduleConfig.has_store_forward = true;
|
||||||
moduleConfig.has_telemetry = true;
|
moduleConfig.has_telemetry = true;
|
||||||
moduleConfig.has_external_notification = true;
|
moduleConfig.has_external_notification = true;
|
||||||
#if defined(PIN_BUZZER) || defined(PIN_VIBRATION) || defined(LED_NOTIFICATION)
|
#if defined(PIN_BUZZER) || defined(PIN_VIBRATION) || defined(LED_NOTIFICATION) || defined(PCA_LED_NOTIFICATION)
|
||||||
moduleConfig.external_notification.enabled = true;
|
moduleConfig.external_notification.enabled = true;
|
||||||
#endif
|
#endif
|
||||||
#if defined(PIN_BUZZER)
|
#if defined(PIN_BUZZER)
|
||||||
|
|||||||
@@ -17,14 +17,4 @@ template <class T> class PointerQueue : public TypedQueue<T *>
|
|||||||
|
|
||||||
return this->dequeue(&p, maxWait) ? p : nullptr;
|
return this->dequeue(&p, maxWait) ? p : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_FREE_RTOS
|
|
||||||
// returns a ptr or null if the queue was empty
|
|
||||||
T *dequeuePtrFromISR(BaseType_t *higherPriWoken)
|
|
||||||
{
|
|
||||||
T *p;
|
|
||||||
|
|
||||||
return this->dequeueFromISR(&p, higherPriWoken) ? p : nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -240,8 +240,7 @@ bool RF95Interface::reconfigure()
|
|||||||
if (err != RADIOLIB_ERR_NONE)
|
if (err != RADIOLIB_ERR_NONE)
|
||||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
|
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
|
||||||
|
|
||||||
if (power > RF95_MAX_POWER) // This chip has lower power limits than some
|
limitPower(RF95_MAX_POWER);
|
||||||
power = RF95_MAX_POWER;
|
|
||||||
|
|
||||||
#ifdef USE_RF95_RFO
|
#ifdef USE_RF95_RFO
|
||||||
err = lora->setOutputPower(power, true);
|
err = lora->setOutputPower(power, true);
|
||||||
|
|||||||
@@ -152,8 +152,10 @@ const RegionInfo regions[] = {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
||||||
|
https://standard.nbtc.go.th/getattachment/Standards/%E0%B8%A1%E0%B8%B2%E0%B8%95%E0%B8%A3%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%97%E0%B8%B2%E0%B8%87%E0%B9%80%E0%B8%97%E0%B8%84%E0%B8%99%E0%B8%B4%E0%B8%84%E0%B8%82%E0%B8%AD%E0%B8%87%E0%B9%80%E0%B8%84%E0%B8%A3%E0%B8%B7%E0%B9%88%E0%B8%AD%E0%B8%87%E0%B9%82%E0%B8%97%E0%B8%A3%E0%B8%84%E0%B8%A1%E0%B8%99%E0%B8%B2%E0%B8%84%E0%B8%A1/1033-2565.pdf.aspx?lang=th-TH
|
||||||
|
Thailand 920–925 MHz set max TX power to 27 dBm and enforce 10% duty cycle, aligned with NBTC regulations.
|
||||||
*/
|
*/
|
||||||
RDEF(TH, 920.0f, 925.0f, 100, 16, false, false, PROFILE_STD),
|
RDEF(TH, 920.0f, 925.0f, 10, 27, false, false, PROFILE_STD),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
433,05-434,7 Mhz 10 mW
|
433,05-434,7 Mhz 10 mW
|
||||||
@@ -961,7 +963,7 @@ void RadioInterface::applyModemConfig()
|
|||||||
cr = loraConfig.coding_rate;
|
cr = loraConfig.coding_rate;
|
||||||
LOG_INFO("Using custom Coding Rate %u", cr);
|
LOG_INFO("Using custom Coding Rate %u", cr);
|
||||||
} else {
|
} else {
|
||||||
cr = loraConfig.coding_rate;
|
cr = newcr;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { // if not using preset, then just use the custom settings
|
} else { // if not using preset, then just use the custom settings
|
||||||
@@ -1036,6 +1038,13 @@ void RadioInterface::applyModemConfig()
|
|||||||
saveFreq(freq + loraConfig.frequency_offset);
|
saveFreq(freq + loraConfig.frequency_offset);
|
||||||
const char *channelName = channels.getName(channels.getPrimaryIndex());
|
const char *channelName = channels.getName(channels.getPrimaryIndex());
|
||||||
|
|
||||||
|
if (newRegion->wideLora) { // clamp if wide freq range
|
||||||
|
preambleLength = wideLoraPreambleLengthDefault; // 12 is the default for operation above 2GHz
|
||||||
|
} else {
|
||||||
|
preambleLength =
|
||||||
|
preambleLengthDefault; // 8 is default, but we use longer to increase the amount of sleep time when receiving
|
||||||
|
}
|
||||||
|
|
||||||
slotTimeMsec = computeSlotTimeMsec();
|
slotTimeMsec = computeSlotTimeMsec();
|
||||||
preambleTimeMsec = preambleLength * (pow_of_2(sf) / bw);
|
preambleTimeMsec = preambleLength * (pow_of_2(sf) / bw);
|
||||||
|
|
||||||
|
|||||||
@@ -92,15 +92,20 @@ class RadioInterface
|
|||||||
uint8_t sf = 9;
|
uint8_t sf = 9;
|
||||||
uint8_t cr = 5;
|
uint8_t cr = 5;
|
||||||
|
|
||||||
const uint8_t NUM_SYM_CAD = 2; // Number of symbols used for CAD, 2 is the default since RadioLib 6.3.0 as per AN1200.48
|
static constexpr uint8_t NUM_SYM_CAD =
|
||||||
const uint8_t NUM_SYM_CAD_24GHZ = 4; // Number of symbols used for CAD in 2.4 GHz, 4 is recommended in AN1200.22 of SX1280
|
2; // Number of symbols used for CAD, 2 is the default since RadioLib 6.3.0 as per AN1200.48
|
||||||
|
static constexpr uint8_t NUM_SYM_CAD_24GHZ =
|
||||||
|
4; // Number of symbols used for CAD in 2.4 GHz, 4 is recommended in AN1200.22 of SX1280
|
||||||
uint32_t slotTimeMsec = computeSlotTimeMsec();
|
uint32_t slotTimeMsec = computeSlotTimeMsec();
|
||||||
uint16_t preambleLength = 16; // 8 is default, but we use longer to increase the amount of sleep time when receiving
|
uint16_t preambleLength = 16; // 8 is default, but we use longer to increase the amount of sleep time when receiving
|
||||||
uint32_t preambleTimeMsec = 165; // calculated on startup, this is the default for LongFast
|
static constexpr uint16_t preambleLengthDefault =
|
||||||
const uint32_t PROCESSING_TIME_MSEC =
|
16; // 8 is default, but we use longer to increase the amount of sleep time when receiving
|
||||||
4500; // time to construct, process and construct a packet again (empirically determined)
|
static constexpr uint16_t wideLoraPreambleLengthDefault = 12; // 12 is default for wide Lora
|
||||||
const uint8_t CWmin = 3; // minimum CWsize
|
uint32_t preambleTimeMsec = 165; // calculated on startup, this is the default for LongFast
|
||||||
const uint8_t CWmax = 8; // maximum CWsize
|
static constexpr uint32_t PROCESSING_TIME_MSEC =
|
||||||
|
4500; // time to construct, process and construct a packet again (empirically determined)
|
||||||
|
static constexpr uint8_t CWmin = 3; // minimum CWsize
|
||||||
|
static constexpr uint8_t CWmax = 8; // maximum CWsize
|
||||||
|
|
||||||
meshtastic_MeshPacket *sendingPacket = NULL; // The packet we are currently sending
|
meshtastic_MeshPacket *sendingPacket = NULL; // The packet we are currently sending
|
||||||
uint32_t lastTxStart = 0L;
|
uint32_t lastTxStart = 0L;
|
||||||
|
|||||||
@@ -246,6 +246,24 @@ bool RadioLibInterface::findInTxQueue(NodeNum from, PacketId id)
|
|||||||
return txQueue.find(from, id);
|
return txQueue.find(from, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RadioLibInterface::randomBytes(uint8_t *buffer, size_t length)
|
||||||
|
{
|
||||||
|
if (!buffer || length == 0 || !iface) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Older RadioLib versions only expose random(min, max), so fill the buffer byte-by-byte.
|
||||||
|
for (size_t i = 0; i < length; ++i) {
|
||||||
|
int32_t value = iface->random(0, 255);
|
||||||
|
if (value < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
buffer[i] = static_cast<uint8_t>(value & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/** radio helper thread callback.
|
/** radio helper thread callback.
|
||||||
We never immediately transmit after any operation (either Rx or Tx). Instead we should wait a random multiple of
|
We never immediately transmit after any operation (either Rx or Tx). Instead we should wait a random multiple of
|
||||||
'slotTimes' (see definition in RadioInterface.h) taken from a contention window (CW) to lower the chance of collision.
|
'slotTimes' (see definition in RadioInterface.h) taken from a contention window (CW) to lower the chance of collision.
|
||||||
@@ -587,4 +605,4 @@ bool RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
|
|||||||
|
|
||||||
return res == RADIOLIB_ERR_NONE;
|
return res == RADIOLIB_ERR_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,6 +172,12 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
|||||||
/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */
|
/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */
|
||||||
virtual bool findInTxQueue(NodeNum from, PacketId id) override;
|
virtual bool findInTxQueue(NodeNum from, PacketId id) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request randomness sourced from the LoRa modem, if supported by the active RadioLib interface.
|
||||||
|
* @return true if len bytes were produced, false otherwise.
|
||||||
|
*/
|
||||||
|
bool randomBytes(uint8_t *buffer, size_t length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually
|
/** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually
|
||||||
* doing the transmit */
|
* doing the transmit */
|
||||||
|
|||||||
@@ -245,8 +245,10 @@ template <typename T> bool SX126xInterface<T>::reconfigure()
|
|||||||
if (err != RADIOLIB_ERR_NONE)
|
if (err != RADIOLIB_ERR_NONE)
|
||||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
|
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
|
||||||
|
|
||||||
if (power > SX126X_MAX_POWER) // This chip has lower power limits than some
|
limitPower(SX126X_MAX_POWER);
|
||||||
power = SX126X_MAX_POWER;
|
// Make sure we reach the minimum power supported to turn the chip on (-9dBm)
|
||||||
|
if (power < -9)
|
||||||
|
power = -9;
|
||||||
|
|
||||||
err = lora.setOutputPower(power);
|
err = lora.setOutputPower(power);
|
||||||
if (err != RADIOLIB_ERR_NONE)
|
if (err != RADIOLIB_ERR_NONE)
|
||||||
|
|||||||
@@ -144,8 +144,7 @@ template <typename T> bool SX128xInterface<T>::reconfigure()
|
|||||||
if (err != RADIOLIB_ERR_NONE)
|
if (err != RADIOLIB_ERR_NONE)
|
||||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
|
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
|
||||||
|
|
||||||
if (power > SX128X_MAX_POWER) // This chip has lower power limits than some
|
limitPower(SX128X_MAX_POWER);
|
||||||
power = SX128X_MAX_POWER;
|
|
||||||
|
|
||||||
err = lora.setOutputPower(power);
|
err = lora.setOutputPower(power);
|
||||||
if (err != RADIOLIB_ERR_NONE)
|
if (err != RADIOLIB_ERR_NONE)
|
||||||
|
|||||||
@@ -22,6 +22,80 @@ PB_BIND(meshtastic_Contact, meshtastic_Contact, AUTO)
|
|||||||
|
|
||||||
|
|
||||||
PB_BIND(meshtastic_PLI, meshtastic_PLI, AUTO)
|
PB_BIND(meshtastic_PLI, meshtastic_PLI, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_AircraftTrack, meshtastic_AircraftTrack, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_CotGeoPoint, meshtastic_CotGeoPoint, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_DrawnShape, meshtastic_DrawnShape, 2)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_Marker, meshtastic_Marker, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_RangeAndBearing, meshtastic_RangeAndBearing, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_Route, meshtastic_Route, 2)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_Route_Link, meshtastic_Route_Link, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_CasevacReport, meshtastic_CasevacReport, 2)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_ZMistEntry, meshtastic_ZMistEntry, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,9 @@ PB_BIND(meshtastic_KeyVerification, meshtastic_KeyVerification, AUTO)
|
|||||||
PB_BIND(meshtastic_StoreForwardPlusPlus, meshtastic_StoreForwardPlusPlus, 2)
|
PB_BIND(meshtastic_StoreForwardPlusPlus, meshtastic_StoreForwardPlusPlus, 2)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_RemoteShell, meshtastic_RemoteShell, AUTO)
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(meshtastic_Waypoint, meshtastic_Waypoint, AUTO)
|
PB_BIND(meshtastic_Waypoint, meshtastic_Waypoint, AUTO)
|
||||||
|
|
||||||
|
|
||||||
@@ -129,6 +132,8 @@ PB_BIND(meshtastic_ChunkedPayloadResponse, meshtastic_ChunkedPayloadResponse, AU
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -308,6 +308,13 @@ typedef enum _meshtastic_HardwareModel {
|
|||||||
meshtastic_HardwareModel_TDISPLAY_S3_PRO = 126,
|
meshtastic_HardwareModel_TDISPLAY_S3_PRO = 126,
|
||||||
/* Heltec Mesh Node T096 board features an nRF52840 CPU and a TFT screen. */
|
/* Heltec Mesh Node T096 board features an nRF52840 CPU and a TFT screen. */
|
||||||
meshtastic_HardwareModel_HELTEC_MESH_NODE_T096 = 127,
|
meshtastic_HardwareModel_HELTEC_MESH_NODE_T096 = 127,
|
||||||
|
/* Seeed studio T1000-E Pro tracker card. NRF52840 w/ LR2021 radio,
|
||||||
|
GPS, button, buzzer, and sensors. */
|
||||||
|
meshtastic_HardwareModel_TRACKER_T1000_E_PRO = 128,
|
||||||
|
/* Elecrow ThinkNode M7, M8 and M9 */
|
||||||
|
meshtastic_HardwareModel_THINKNODE_M7 = 129,
|
||||||
|
meshtastic_HardwareModel_THINKNODE_M8 = 130,
|
||||||
|
meshtastic_HardwareModel_THINKNODE_M9 = 131,
|
||||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||||
@@ -511,6 +518,27 @@ typedef enum _meshtastic_StoreForwardPlusPlus_SFPP_message_type {
|
|||||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF = 6
|
meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF = 6
|
||||||
} meshtastic_StoreForwardPlusPlus_SFPP_message_type;
|
} meshtastic_StoreForwardPlusPlus_SFPP_message_type;
|
||||||
|
|
||||||
|
/* Frame op code for PTY session control and stream transport.
|
||||||
|
|
||||||
|
Values 1-63 are client->server requests.
|
||||||
|
Values 64-127 are server->client responses/events. */
|
||||||
|
typedef enum _meshtastic_RemoteShell_OpCode {
|
||||||
|
meshtastic_RemoteShell_OpCode_OP_UNSET = 0,
|
||||||
|
/* Client -> server */
|
||||||
|
meshtastic_RemoteShell_OpCode_OPEN = 1,
|
||||||
|
meshtastic_RemoteShell_OpCode_INPUT = 2,
|
||||||
|
meshtastic_RemoteShell_OpCode_RESIZE = 3,
|
||||||
|
meshtastic_RemoteShell_OpCode_CLOSE = 4,
|
||||||
|
meshtastic_RemoteShell_OpCode_PING = 5,
|
||||||
|
meshtastic_RemoteShell_OpCode_ACK = 6,
|
||||||
|
/* Server -> client */
|
||||||
|
meshtastic_RemoteShell_OpCode_OPEN_OK = 64,
|
||||||
|
meshtastic_RemoteShell_OpCode_OUTPUT = 65,
|
||||||
|
meshtastic_RemoteShell_OpCode_CLOSED = 66,
|
||||||
|
meshtastic_RemoteShell_OpCode_ERROR = 67,
|
||||||
|
meshtastic_RemoteShell_OpCode_PONG = 68
|
||||||
|
} meshtastic_RemoteShell_OpCode;
|
||||||
|
|
||||||
/* The priority of this message for sending.
|
/* The priority of this message for sending.
|
||||||
Higher priorities are sent first (when managing the transmit queue).
|
Higher priorities are sent first (when managing the transmit queue).
|
||||||
This field is never sent over the air, it is only used internally inside of a local device node.
|
This field is never sent over the air, it is only used internally inside of a local device node.
|
||||||
@@ -843,6 +871,31 @@ typedef struct _meshtastic_StoreForwardPlusPlus {
|
|||||||
uint32_t chain_count;
|
uint32_t chain_count;
|
||||||
} meshtastic_StoreForwardPlusPlus;
|
} meshtastic_StoreForwardPlusPlus;
|
||||||
|
|
||||||
|
typedef PB_BYTES_ARRAY_T(200) meshtastic_RemoteShell_payload_t;
|
||||||
|
/* The actual over-the-mesh message doing RemoteShell */
|
||||||
|
typedef struct _meshtastic_RemoteShell {
|
||||||
|
/* Structured frame operation. */
|
||||||
|
meshtastic_RemoteShell_OpCode op;
|
||||||
|
/* Logical PTY session identifier. */
|
||||||
|
uint32_t session_id;
|
||||||
|
/* Monotonic sequence number for this frame. */
|
||||||
|
uint32_t seq;
|
||||||
|
/* Cumulative ack sequence number. */
|
||||||
|
uint32_t ack_seq;
|
||||||
|
/* Opaque bytes payload for INPUT/OUTPUT/ERROR and other frame bodies. */
|
||||||
|
meshtastic_RemoteShell_payload_t payload;
|
||||||
|
/* Terminal size columns used for OPEN/RESIZE signaling. */
|
||||||
|
uint32_t cols;
|
||||||
|
/* Terminal size rows used for OPEN/RESIZE signaling. */
|
||||||
|
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 */
|
/* Waypoint message, used to share arbitrary locations across the mesh */
|
||||||
typedef struct _meshtastic_Waypoint {
|
typedef struct _meshtastic_Waypoint {
|
||||||
/* Id of the waypoint */
|
/* Id of the waypoint */
|
||||||
@@ -1383,6 +1436,10 @@ extern "C" {
|
|||||||
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MAX meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF
|
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MAX meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF
|
||||||
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_ARRAYSIZE ((meshtastic_StoreForwardPlusPlus_SFPP_message_type)(meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF+1))
|
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_ARRAYSIZE ((meshtastic_StoreForwardPlusPlus_SFPP_message_type)(meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF+1))
|
||||||
|
|
||||||
|
#define _meshtastic_RemoteShell_OpCode_MIN meshtastic_RemoteShell_OpCode_OP_UNSET
|
||||||
|
#define _meshtastic_RemoteShell_OpCode_MAX meshtastic_RemoteShell_OpCode_PONG
|
||||||
|
#define _meshtastic_RemoteShell_OpCode_ARRAYSIZE ((meshtastic_RemoteShell_OpCode)(meshtastic_RemoteShell_OpCode_PONG+1))
|
||||||
|
|
||||||
#define _meshtastic_MeshPacket_Priority_MIN meshtastic_MeshPacket_Priority_UNSET
|
#define _meshtastic_MeshPacket_Priority_MIN meshtastic_MeshPacket_Priority_UNSET
|
||||||
#define _meshtastic_MeshPacket_Priority_MAX meshtastic_MeshPacket_Priority_MAX
|
#define _meshtastic_MeshPacket_Priority_MAX meshtastic_MeshPacket_Priority_MAX
|
||||||
#define _meshtastic_MeshPacket_Priority_ARRAYSIZE ((meshtastic_MeshPacket_Priority)(meshtastic_MeshPacket_Priority_MAX+1))
|
#define _meshtastic_MeshPacket_Priority_ARRAYSIZE ((meshtastic_MeshPacket_Priority)(meshtastic_MeshPacket_Priority_MAX+1))
|
||||||
@@ -1413,6 +1470,8 @@ extern "C" {
|
|||||||
|
|
||||||
#define meshtastic_StoreForwardPlusPlus_sfpp_message_type_ENUMTYPE meshtastic_StoreForwardPlusPlus_SFPP_message_type
|
#define meshtastic_StoreForwardPlusPlus_sfpp_message_type_ENUMTYPE meshtastic_StoreForwardPlusPlus_SFPP_message_type
|
||||||
|
|
||||||
|
#define meshtastic_RemoteShell_op_ENUMTYPE meshtastic_RemoteShell_OpCode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1457,6 +1516,7 @@ extern "C" {
|
|||||||
#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0}
|
#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_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_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, 0, 0}
|
||||||
#define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0}
|
#define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0}
|
||||||
#define meshtastic_StatusMessage_init_default {""}
|
#define meshtastic_StatusMessage_init_default {""}
|
||||||
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
|
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
|
||||||
@@ -1490,6 +1550,7 @@ extern "C" {
|
|||||||
#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0}
|
#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_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_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, 0, 0}
|
||||||
#define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0}
|
#define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0}
|
||||||
#define meshtastic_StatusMessage_init_zero {""}
|
#define meshtastic_StatusMessage_init_zero {""}
|
||||||
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
|
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
|
||||||
@@ -1579,6 +1640,16 @@ extern "C" {
|
|||||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_from_tag 8
|
#define meshtastic_StoreForwardPlusPlus_encapsulated_from_tag 8
|
||||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_rxtime_tag 9
|
#define meshtastic_StoreForwardPlusPlus_encapsulated_rxtime_tag 9
|
||||||
#define meshtastic_StoreForwardPlusPlus_chain_count_tag 10
|
#define meshtastic_StoreForwardPlusPlus_chain_count_tag 10
|
||||||
|
#define meshtastic_RemoteShell_op_tag 1
|
||||||
|
#define meshtastic_RemoteShell_session_id_tag 2
|
||||||
|
#define meshtastic_RemoteShell_seq_tag 3
|
||||||
|
#define meshtastic_RemoteShell_ack_seq_tag 4
|
||||||
|
#define meshtastic_RemoteShell_payload_tag 5
|
||||||
|
#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_id_tag 1
|
||||||
#define meshtastic_Waypoint_latitude_i_tag 2
|
#define meshtastic_Waypoint_latitude_i_tag 2
|
||||||
#define meshtastic_Waypoint_longitude_i_tag 3
|
#define meshtastic_Waypoint_longitude_i_tag 3
|
||||||
@@ -1811,6 +1882,20 @@ X(a, STATIC, SINGULAR, UINT32, chain_count, 10)
|
|||||||
#define meshtastic_StoreForwardPlusPlus_CALLBACK NULL
|
#define meshtastic_StoreForwardPlusPlus_CALLBACK NULL
|
||||||
#define meshtastic_StoreForwardPlusPlus_DEFAULT NULL
|
#define meshtastic_StoreForwardPlusPlus_DEFAULT NULL
|
||||||
|
|
||||||
|
#define meshtastic_RemoteShell_FIELDLIST(X, a) \
|
||||||
|
X(a, STATIC, SINGULAR, UENUM, op, 1) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, session_id, 2) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, seq, 3) \
|
||||||
|
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, last_tx_seq, 9) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, last_rx_seq, 10)
|
||||||
|
#define meshtastic_RemoteShell_CALLBACK NULL
|
||||||
|
#define meshtastic_RemoteShell_DEFAULT NULL
|
||||||
|
|
||||||
#define meshtastic_Waypoint_FIELDLIST(X, a) \
|
#define meshtastic_Waypoint_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, id, 1) \
|
X(a, STATIC, SINGULAR, UINT32, id, 1) \
|
||||||
X(a, STATIC, OPTIONAL, SFIXED32, latitude_i, 2) \
|
X(a, STATIC, OPTIONAL, SFIXED32, latitude_i, 2) \
|
||||||
@@ -2093,6 +2178,7 @@ extern const pb_msgdesc_t meshtastic_Routing_msg;
|
|||||||
extern const pb_msgdesc_t meshtastic_Data_msg;
|
extern const pb_msgdesc_t meshtastic_Data_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_KeyVerification_msg;
|
extern const pb_msgdesc_t meshtastic_KeyVerification_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_StoreForwardPlusPlus_msg;
|
extern const pb_msgdesc_t meshtastic_StoreForwardPlusPlus_msg;
|
||||||
|
extern const pb_msgdesc_t meshtastic_RemoteShell_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_Waypoint_msg;
|
extern const pb_msgdesc_t meshtastic_Waypoint_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_StatusMessage_msg;
|
extern const pb_msgdesc_t meshtastic_StatusMessage_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_MqttClientProxyMessage_msg;
|
extern const pb_msgdesc_t meshtastic_MqttClientProxyMessage_msg;
|
||||||
@@ -2128,6 +2214,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
|
|||||||
#define meshtastic_Data_fields &meshtastic_Data_msg
|
#define meshtastic_Data_fields &meshtastic_Data_msg
|
||||||
#define meshtastic_KeyVerification_fields &meshtastic_KeyVerification_msg
|
#define meshtastic_KeyVerification_fields &meshtastic_KeyVerification_msg
|
||||||
#define meshtastic_StoreForwardPlusPlus_fields &meshtastic_StoreForwardPlusPlus_msg
|
#define meshtastic_StoreForwardPlusPlus_fields &meshtastic_StoreForwardPlusPlus_msg
|
||||||
|
#define meshtastic_RemoteShell_fields &meshtastic_RemoteShell_msg
|
||||||
#define meshtastic_Waypoint_fields &meshtastic_Waypoint_msg
|
#define meshtastic_Waypoint_fields &meshtastic_Waypoint_msg
|
||||||
#define meshtastic_StatusMessage_fields &meshtastic_StatusMessage_msg
|
#define meshtastic_StatusMessage_fields &meshtastic_StatusMessage_msg
|
||||||
#define meshtastic_MqttClientProxyMessage_fields &meshtastic_MqttClientProxyMessage_msg
|
#define meshtastic_MqttClientProxyMessage_fields &meshtastic_MqttClientProxyMessage_msg
|
||||||
@@ -2183,6 +2270,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
|
|||||||
#define meshtastic_NodeRemoteHardwarePin_size 29
|
#define meshtastic_NodeRemoteHardwarePin_size 29
|
||||||
#define meshtastic_Position_size 144
|
#define meshtastic_Position_size 144
|
||||||
#define meshtastic_QueueStatus_size 23
|
#define meshtastic_QueueStatus_size 23
|
||||||
|
#define meshtastic_RemoteShell_size 253
|
||||||
#define meshtastic_RouteDiscovery_size 256
|
#define meshtastic_RouteDiscovery_size 256
|
||||||
#define meshtastic_Routing_size 259
|
#define meshtastic_Routing_size 259
|
||||||
#define meshtastic_StatusMessage_size 81
|
#define meshtastic_StatusMessage_size 81
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ typedef enum _meshtastic_PortNum {
|
|||||||
meshtastic_PortNum_ALERT_APP = 11,
|
meshtastic_PortNum_ALERT_APP = 11,
|
||||||
/* Module/port for handling key verification requests. */
|
/* Module/port for handling key verification requests. */
|
||||||
meshtastic_PortNum_KEY_VERIFICATION_APP = 12,
|
meshtastic_PortNum_KEY_VERIFICATION_APP = 12,
|
||||||
|
/* Module/port for handling primitive remote shell access. */
|
||||||
|
meshtastic_PortNum_REMOTE_SHELL_APP = 13,
|
||||||
/* Provides a 'ping' service that replies to any packet it receives.
|
/* Provides a 'ping' service that replies to any packet it receives.
|
||||||
Also serves as a small example module.
|
Also serves as a small example module.
|
||||||
ENCODING: ASCII Plaintext */
|
ENCODING: ASCII Plaintext */
|
||||||
@@ -150,6 +152,10 @@ typedef enum _meshtastic_PortNum {
|
|||||||
arbitrary telemetry over meshtastic that is not covered by telemetry.proto
|
arbitrary telemetry over meshtastic that is not covered by telemetry.proto
|
||||||
ENCODING: CayenneLLP */
|
ENCODING: CayenneLLP */
|
||||||
meshtastic_PortNum_CAYENNE_APP = 77,
|
meshtastic_PortNum_CAYENNE_APP = 77,
|
||||||
|
/* ATAK Plugin V2
|
||||||
|
Portnum for payloads from the official Meshtastic ATAK plugin using
|
||||||
|
TAKPacketV2 with zstd dictionary compression. */
|
||||||
|
meshtastic_PortNum_ATAK_PLUGIN_V2 = 78,
|
||||||
/* GroupAlarm integration
|
/* GroupAlarm integration
|
||||||
Used for transporting GroupAlarm-related messages between Meshtastic nodes
|
Used for transporting GroupAlarm-related messages between Meshtastic nodes
|
||||||
and companion applications/services. */
|
and companion applications/services. */
|
||||||
|
|||||||
@@ -113,7 +113,9 @@ typedef enum _meshtastic_TelemetrySensorType {
|
|||||||
/* SCD30 CO2, humidity, temperature sensor */
|
/* SCD30 CO2, humidity, temperature sensor */
|
||||||
meshtastic_TelemetrySensorType_SCD30 = 49,
|
meshtastic_TelemetrySensorType_SCD30 = 49,
|
||||||
/* SHT family of sensors for temperature and humidity */
|
/* SHT family of sensors for temperature and humidity */
|
||||||
meshtastic_TelemetrySensorType_SHTXX = 50
|
meshtastic_TelemetrySensorType_SHTXX = 50,
|
||||||
|
/* DS248X Bridge for one-wire temperature sensors */
|
||||||
|
meshtastic_TelemetrySensorType_DS248X = 51
|
||||||
} meshtastic_TelemetrySensorType;
|
} meshtastic_TelemetrySensorType;
|
||||||
|
|
||||||
/* Struct definitions */
|
/* Struct definitions */
|
||||||
@@ -206,6 +208,9 @@ typedef struct _meshtastic_EnvironmentMetrics {
|
|||||||
/* Soil temperature measured (*C) */
|
/* Soil temperature measured (*C) */
|
||||||
bool has_soil_temperature;
|
bool has_soil_temperature;
|
||||||
float soil_temperature;
|
float soil_temperature;
|
||||||
|
/* One-wire temperature (*C) */
|
||||||
|
pb_size_t one_wire_temperature_count;
|
||||||
|
float one_wire_temperature[8];
|
||||||
} meshtastic_EnvironmentMetrics;
|
} meshtastic_EnvironmentMetrics;
|
||||||
|
|
||||||
/* Power Metrics (voltage / current / etc) */
|
/* Power Metrics (voltage / current / etc) */
|
||||||
@@ -491,8 +496,8 @@ extern "C" {
|
|||||||
|
|
||||||
/* Helper constants for enums */
|
/* Helper constants for enums */
|
||||||
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
|
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
|
||||||
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_SHTXX
|
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_DS248X
|
||||||
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_SHTXX+1))
|
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_DS248X+1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -508,7 +513,7 @@ extern "C" {
|
|||||||
|
|
||||||
/* Initializer values for message structs */
|
/* Initializer values for message structs */
|
||||||
#define meshtastic_DeviceMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_DeviceMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||||
#define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
#define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
@@ -519,7 +524,7 @@ extern "C" {
|
|||||||
#define meshtastic_Nau7802Config_init_default {0, 0}
|
#define meshtastic_Nau7802Config_init_default {0, 0}
|
||||||
#define meshtastic_SEN5XState_init_default {0, 0, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_SEN5XState_init_default {0, 0, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_DeviceMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_DeviceMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}
|
||||||
#define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
#define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
@@ -558,6 +563,7 @@ extern "C" {
|
|||||||
#define meshtastic_EnvironmentMetrics_rainfall_24h_tag 20
|
#define meshtastic_EnvironmentMetrics_rainfall_24h_tag 20
|
||||||
#define meshtastic_EnvironmentMetrics_soil_moisture_tag 21
|
#define meshtastic_EnvironmentMetrics_soil_moisture_tag 21
|
||||||
#define meshtastic_EnvironmentMetrics_soil_temperature_tag 22
|
#define meshtastic_EnvironmentMetrics_soil_temperature_tag 22
|
||||||
|
#define meshtastic_EnvironmentMetrics_one_wire_temperature_tag 23
|
||||||
#define meshtastic_PowerMetrics_ch1_voltage_tag 1
|
#define meshtastic_PowerMetrics_ch1_voltage_tag 1
|
||||||
#define meshtastic_PowerMetrics_ch1_current_tag 2
|
#define meshtastic_PowerMetrics_ch1_current_tag 2
|
||||||
#define meshtastic_PowerMetrics_ch2_voltage_tag 3
|
#define meshtastic_PowerMetrics_ch2_voltage_tag 3
|
||||||
@@ -683,7 +689,8 @@ X(a, STATIC, OPTIONAL, FLOAT, radiation, 18) \
|
|||||||
X(a, STATIC, OPTIONAL, FLOAT, rainfall_1h, 19) \
|
X(a, STATIC, OPTIONAL, FLOAT, rainfall_1h, 19) \
|
||||||
X(a, STATIC, OPTIONAL, FLOAT, rainfall_24h, 20) \
|
X(a, STATIC, OPTIONAL, FLOAT, rainfall_24h, 20) \
|
||||||
X(a, STATIC, OPTIONAL, UINT32, soil_moisture, 21) \
|
X(a, STATIC, OPTIONAL, UINT32, soil_moisture, 21) \
|
||||||
X(a, STATIC, OPTIONAL, FLOAT, soil_temperature, 22)
|
X(a, STATIC, OPTIONAL, FLOAT, soil_temperature, 22) \
|
||||||
|
X(a, STATIC, REPEATED, FLOAT, one_wire_temperature, 23)
|
||||||
#define meshtastic_EnvironmentMetrics_CALLBACK NULL
|
#define meshtastic_EnvironmentMetrics_CALLBACK NULL
|
||||||
#define meshtastic_EnvironmentMetrics_DEFAULT NULL
|
#define meshtastic_EnvironmentMetrics_DEFAULT NULL
|
||||||
|
|
||||||
@@ -852,7 +859,7 @@ extern const pb_msgdesc_t meshtastic_SEN5XState_msg;
|
|||||||
#define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size
|
#define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size
|
||||||
#define meshtastic_AirQualityMetrics_size 150
|
#define meshtastic_AirQualityMetrics_size 150
|
||||||
#define meshtastic_DeviceMetrics_size 27
|
#define meshtastic_DeviceMetrics_size 27
|
||||||
#define meshtastic_EnvironmentMetrics_size 113
|
#define meshtastic_EnvironmentMetrics_size 161
|
||||||
#define meshtastic_HealthMetrics_size 11
|
#define meshtastic_HealthMetrics_size 11
|
||||||
#define meshtastic_HostMetrics_size 264
|
#define meshtastic_HostMetrics_size 264
|
||||||
#define meshtastic_LocalStats_size 87
|
#define meshtastic_LocalStats_size 87
|
||||||
|
|||||||
@@ -480,7 +480,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
|||||||
#if HAS_SCREEN
|
#if HAS_SCREEN
|
||||||
IF_SCREEN(screen->showSimpleBanner("Device is rebooting\ninto DFU mode.", 0));
|
IF_SCREEN(screen->showSimpleBanner("Device is rebooting\ninto DFU mode.", 0));
|
||||||
#endif
|
#endif
|
||||||
#if defined(ARCH_NRF52) || defined(ARCH_RP2040)
|
#if defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)
|
||||||
enterDfuMode();
|
enterDfuMode();
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -203,6 +203,10 @@ void ExternalNotificationModule::setExternalState(uint8_t index, bool on)
|
|||||||
default:
|
default:
|
||||||
if (output > 0)
|
if (output > 0)
|
||||||
digitalWrite(output, (moduleConfig.external_notification.active ? on : !on));
|
digitalWrite(output, (moduleConfig.external_notification.active ? on : !on));
|
||||||
|
#ifdef PCA_LED_NOTIFICATION
|
||||||
|
io.digitalWrite(PCA_LED_NOTIFICATION, on);
|
||||||
|
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -651,7 +651,7 @@ void SerialModule::processWXSerial()
|
|||||||
LOG_INFO("WS8X : %i %.1fg%.1f %.1fv %.1fv %.1fC rain: %.1f, %i sum", atoi(windDir), strtof(windVel, nullptr),
|
LOG_INFO("WS8X : %i %.1fg%.1f %.1fv %.1fv %.1fC rain: %.1f, %i sum", atoi(windDir), strtof(windVel, nullptr),
|
||||||
strtof(windGust, nullptr), batVoltageF, capVoltageF, temperatureF, rain, rainSum);
|
strtof(windGust, nullptr), batVoltageF, capVoltageF, temperatureF, rain, rainSum);
|
||||||
}
|
}
|
||||||
if (gotwind && !Throttle::isWithinTimespanMs(lastAveraged, averageIntervalMillis)) {
|
if (gotwind && !Throttle::isWithinTimespanMs(lastAveraged, averageIntervalMillis) && velCount > 0 && dirCount > 0) {
|
||||||
// calculate averages and send to the mesh
|
// calculate averages and send to the mesh
|
||||||
float velAvg = 1.0 * velSum / velCount;
|
float velAvg = 1.0 * velSum / velCount;
|
||||||
|
|
||||||
|
|||||||
@@ -29,10 +29,23 @@ int32_t StatusMessageModule::runOnce()
|
|||||||
ProcessMessage StatusMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
|
ProcessMessage StatusMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||||
{
|
{
|
||||||
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
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,
|
if (pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_StatusMessage_fields,
|
||||||
&incomingMessage)) {
|
&incomingMessage)) {
|
||||||
|
|
||||||
LOG_INFO("Received a NodeStatus message %s", incomingMessage.status);
|
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;
|
return ProcessMessage::CONTINUE;
|
||||||
|
|||||||
@@ -2,10 +2,11 @@
|
|||||||
#if !MESHTASTIC_EXCLUDE_STATUS
|
#if !MESHTASTIC_EXCLUDE_STATUS
|
||||||
#include "SinglePortModule.h"
|
#include "SinglePortModule.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class StatusMessageModule : public SinglePortModule, private concurrency::OSThread
|
class StatusMessageModule : public SinglePortModule, private concurrency::OSThread
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructor
|
/** Constructor
|
||||||
* name is for debugging output
|
* name is for debugging output
|
||||||
@@ -19,16 +20,28 @@ class StatusMessageModule : public SinglePortModule, private concurrency::OSThre
|
|||||||
this->setInterval(1000 * 12 * 60 * 60);
|
this->setInterval(1000 * 12 * 60 * 60);
|
||||||
}
|
}
|
||||||
// TODO: If we have a string, set the initial delay (15 minutes maybe)
|
// 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;
|
virtual int32_t runOnce() override;
|
||||||
|
|
||||||
|
struct RecentStatus {
|
||||||
|
uint32_t fromNodeId; // mp.from
|
||||||
|
std::string statusText; // incomingMessage.status
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::vector<RecentStatus> &getRecentReceived() const { return recentReceived; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Called to handle a particular incoming message
|
/** Called to handle a particular incoming message
|
||||||
*/
|
*/
|
||||||
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
|
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static constexpr size_t MAX_RECENT_STATUSMESSAGES = 5;
|
||||||
|
std::vector<RecentStatus> recentReceived;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern StatusMessageModule *statusMessageModule;
|
extern StatusMessageModule *statusMessageModule;
|
||||||
|
|||||||
@@ -66,18 +66,10 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
|
|||||||
#include "Sensor/MCP9808Sensor.h"
|
#include "Sensor/MCP9808Sensor.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<Adafruit_SHT31.h>)
|
|
||||||
#include "Sensor/SHT31Sensor.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<Adafruit_LPS2X.h>)
|
#if __has_include(<Adafruit_LPS2X.h>)
|
||||||
#include "Sensor/LPS22HBSensor.h"
|
#include "Sensor/LPS22HBSensor.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<Adafruit_SHTC3.h>)
|
|
||||||
#include "Sensor/SHTC3Sensor.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1
|
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1
|
||||||
#include "Sensor/RAK12035Sensor.h"
|
#include "Sensor/RAK12035Sensor.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -94,8 +86,8 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
|
|||||||
#include "Sensor/OPT3001Sensor.h"
|
#include "Sensor/OPT3001Sensor.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<Adafruit_SHT4x.h>)
|
#if __has_include(<SHTSensor.h>)
|
||||||
#include "Sensor/SHT4XSensor.h"
|
#include "Sensor/SHTXXSensor.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<SparkFun_MLX90632_Arduino_Library.h>)
|
#if __has_include(<SparkFun_MLX90632_Arduino_Library.h>)
|
||||||
@@ -155,6 +147,15 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
|
|||||||
}
|
}
|
||||||
LOG_INFO("Environment Telemetry adding I2C devices...");
|
LOG_INFO("Environment Telemetry adding I2C devices...");
|
||||||
|
|
||||||
|
/*
|
||||||
|
Uncomment the preferences below if you want to use the module
|
||||||
|
without having to configure it from the PythonAPI or WebUI.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// moduleConfig.telemetry.environment_measurement_enabled = 1;
|
||||||
|
// moduleConfig.telemetry.environment_screen_enabled = 1;
|
||||||
|
// moduleConfig.telemetry.environment_update_interval = 15;
|
||||||
|
|
||||||
// order by priority of metrics/values (low top, high bottom)
|
// order by priority of metrics/values (low top, high bottom)
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
@@ -202,15 +203,9 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
|
|||||||
#if __has_include(<Adafruit_MCP9808.h>)
|
#if __has_include(<Adafruit_MCP9808.h>)
|
||||||
addSensor<MCP9808Sensor>(i2cScanner, ScanI2C::DeviceType::MCP9808);
|
addSensor<MCP9808Sensor>(i2cScanner, ScanI2C::DeviceType::MCP9808);
|
||||||
#endif
|
#endif
|
||||||
#if __has_include(<Adafruit_SHT31.h>)
|
|
||||||
addSensor<SHT31Sensor>(i2cScanner, ScanI2C::DeviceType::SHT31);
|
|
||||||
#endif
|
|
||||||
#if __has_include(<Adafruit_LPS2X.h>)
|
#if __has_include(<Adafruit_LPS2X.h>)
|
||||||
addSensor<LPS22HBSensor>(i2cScanner, ScanI2C::DeviceType::LPS22HB);
|
addSensor<LPS22HBSensor>(i2cScanner, ScanI2C::DeviceType::LPS22HB);
|
||||||
#endif
|
#endif
|
||||||
#if __has_include(<Adafruit_SHTC3.h>)
|
|
||||||
addSensor<SHTC3Sensor>(i2cScanner, ScanI2C::DeviceType::SHTC3);
|
|
||||||
#endif
|
|
||||||
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1
|
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1
|
||||||
addSensor<RAK12035Sensor>(i2cScanner, ScanI2C::DeviceType::RAK12035);
|
addSensor<RAK12035Sensor>(i2cScanner, ScanI2C::DeviceType::RAK12035);
|
||||||
#endif
|
#endif
|
||||||
@@ -223,13 +218,9 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
|
|||||||
#if __has_include(<ClosedCube_OPT3001.h>)
|
#if __has_include(<ClosedCube_OPT3001.h>)
|
||||||
addSensor<OPT3001Sensor>(i2cScanner, ScanI2C::DeviceType::OPT3001);
|
addSensor<OPT3001Sensor>(i2cScanner, ScanI2C::DeviceType::OPT3001);
|
||||||
#endif
|
#endif
|
||||||
#if __has_include(<Adafruit_SHT4x.h>)
|
|
||||||
addSensor<SHT4XSensor>(i2cScanner, ScanI2C::DeviceType::SHT4X);
|
|
||||||
#endif
|
|
||||||
#if __has_include(<SparkFun_MLX90632_Arduino_Library.h>)
|
#if __has_include(<SparkFun_MLX90632_Arduino_Library.h>)
|
||||||
addSensor<MLX90632Sensor>(i2cScanner, ScanI2C::DeviceType::MLX90632);
|
addSensor<MLX90632Sensor>(i2cScanner, ScanI2C::DeviceType::MLX90632);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<Adafruit_BMP3XX.h>)
|
#if __has_include(<Adafruit_BMP3XX.h>)
|
||||||
addSensor<BMP3XXSensor>(i2cScanner, ScanI2C::DeviceType::BMP_3XX);
|
addSensor<BMP3XXSensor>(i2cScanner, ScanI2C::DeviceType::BMP_3XX);
|
||||||
#endif
|
#endif
|
||||||
@@ -245,7 +236,10 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
|
|||||||
#if __has_include(<BH1750_WE.h>)
|
#if __has_include(<BH1750_WE.h>)
|
||||||
addSensor<BH1750Sensor>(i2cScanner, ScanI2C::DeviceType::BH1750);
|
addSensor<BH1750Sensor>(i2cScanner, ScanI2C::DeviceType::BH1750);
|
||||||
#endif
|
#endif
|
||||||
|
#if __has_include(<SHTSensor.h>)
|
||||||
|
// TODO Can we scan for multiple sensors connected on the same bus?
|
||||||
|
addSensor<SHTXXSensor>(i2cScanner, ScanI2C::DeviceType::SHTXX);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,14 +254,6 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t result = UINT32_MAX;
|
uint32_t result = UINT32_MAX;
|
||||||
/*
|
|
||||||
Uncomment the preferences below if you want to use the module
|
|
||||||
without having to configure it from the PythonAPI or WebUI.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// moduleConfig.telemetry.environment_measurement_enabled = 1;
|
|
||||||
// moduleConfig.telemetry.environment_screen_enabled = 1;
|
|
||||||
// moduleConfig.telemetry.environment_update_interval = 15;
|
|
||||||
|
|
||||||
if (!(moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled ||
|
if (!(moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled ||
|
||||||
ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE)) {
|
ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE)) {
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
#include "configuration.h"
|
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SHT31.h>)
|
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
|
||||||
#include "SHT31Sensor.h"
|
|
||||||
#include "TelemetrySensor.h"
|
|
||||||
#include <Adafruit_SHT31.h>
|
|
||||||
|
|
||||||
SHT31Sensor::SHT31Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHT31, "SHT31") {}
|
|
||||||
|
|
||||||
bool SHT31Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|
||||||
{
|
|
||||||
LOG_INFO("Init sensor: %s", sensorName);
|
|
||||||
sht31 = Adafruit_SHT31(bus);
|
|
||||||
status = sht31.begin(dev->address.address);
|
|
||||||
initI2CSensor();
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SHT31Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
|
||||||
{
|
|
||||||
measurement->variant.environment_metrics.has_temperature = true;
|
|
||||||
measurement->variant.environment_metrics.has_relative_humidity = true;
|
|
||||||
measurement->variant.environment_metrics.temperature = sht31.readTemperature();
|
|
||||||
measurement->variant.environment_metrics.relative_humidity = sht31.readHumidity();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#include "configuration.h"
|
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SHT31.h>)
|
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
|
||||||
#include "TelemetrySensor.h"
|
|
||||||
#include <Adafruit_SHT31.h>
|
|
||||||
|
|
||||||
class SHT31Sensor : public TelemetrySensor
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
Adafruit_SHT31 sht31;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SHT31Sensor();
|
|
||||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
|
||||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#include "configuration.h"
|
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SHT4x.h>)
|
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
|
||||||
#include "SHT4XSensor.h"
|
|
||||||
#include "TelemetrySensor.h"
|
|
||||||
#include <Adafruit_SHT4x.h>
|
|
||||||
|
|
||||||
SHT4XSensor::SHT4XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHT4X, "SHT4X") {}
|
|
||||||
|
|
||||||
bool SHT4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|
||||||
{
|
|
||||||
LOG_INFO("Init sensor: %s", sensorName);
|
|
||||||
|
|
||||||
uint32_t serialNumber = 0;
|
|
||||||
|
|
||||||
status = sht4x.begin(bus);
|
|
||||||
if (!status) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
serialNumber = sht4x.readSerial();
|
|
||||||
if (serialNumber != 0) {
|
|
||||||
LOG_DEBUG("serialNumber : %x", serialNumber);
|
|
||||||
status = 1;
|
|
||||||
} else {
|
|
||||||
LOG_DEBUG("Error trying to execute readSerial(): ");
|
|
||||||
status = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
initI2CSensor();
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SHT4XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
|
||||||
{
|
|
||||||
measurement->variant.environment_metrics.has_temperature = true;
|
|
||||||
measurement->variant.environment_metrics.has_relative_humidity = true;
|
|
||||||
|
|
||||||
sensors_event_t humidity, temp;
|
|
||||||
sht4x.getEvent(&humidity, &temp);
|
|
||||||
measurement->variant.environment_metrics.temperature = temp.temperature;
|
|
||||||
measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#include "configuration.h"
|
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SHT4x.h>)
|
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
|
||||||
#include "TelemetrySensor.h"
|
|
||||||
#include <Adafruit_SHT4x.h>
|
|
||||||
|
|
||||||
class SHT4XSensor : public TelemetrySensor
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
Adafruit_SHT4x sht4x = Adafruit_SHT4x();
|
|
||||||
|
|
||||||
public:
|
|
||||||
SHT4XSensor();
|
|
||||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
|
||||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#include "configuration.h"
|
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SHTC3.h>)
|
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
|
||||||
#include "SHTC3Sensor.h"
|
|
||||||
#include "TelemetrySensor.h"
|
|
||||||
#include <Adafruit_SHTC3.h>
|
|
||||||
|
|
||||||
SHTC3Sensor::SHTC3Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHTC3, "SHTC3") {}
|
|
||||||
|
|
||||||
bool SHTC3Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|
||||||
{
|
|
||||||
LOG_INFO("Init sensor: %s", sensorName);
|
|
||||||
status = shtc3.begin(bus);
|
|
||||||
|
|
||||||
initI2CSensor();
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SHTC3Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
|
||||||
{
|
|
||||||
measurement->variant.environment_metrics.has_temperature = true;
|
|
||||||
measurement->variant.environment_metrics.has_relative_humidity = true;
|
|
||||||
|
|
||||||
sensors_event_t humidity, temp;
|
|
||||||
shtc3.getEvent(&humidity, &temp);
|
|
||||||
|
|
||||||
measurement->variant.environment_metrics.temperature = temp.temperature;
|
|
||||||
measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#include "configuration.h"
|
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SHTC3.h>)
|
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
|
||||||
#include "TelemetrySensor.h"
|
|
||||||
#include <Adafruit_SHTC3.h>
|
|
||||||
|
|
||||||
class SHTC3Sensor : public TelemetrySensor
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
Adafruit_SHTC3 shtc3 = Adafruit_SHTC3();
|
|
||||||
|
|
||||||
public:
|
|
||||||
SHTC3Sensor();
|
|
||||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
|
||||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<SHTSensor.h>)
|
||||||
|
|
||||||
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
|
#include "SHTXXSensor.h"
|
||||||
|
#include "TelemetrySensor.h"
|
||||||
|
#include <SHTSensor.h>
|
||||||
|
|
||||||
|
SHTXXSensor::SHTXXSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHTXX, "SHTXX") {}
|
||||||
|
|
||||||
|
void SHTXXSensor::getSensorVariant(SHTSensor::SHTSensorType sensorType)
|
||||||
|
{
|
||||||
|
switch (sensorType) {
|
||||||
|
case SHTSensor::SHTSensorType::SHT2X:
|
||||||
|
sensorVariant = "SHT2x";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SHTSensor::SHTSensorType::SHT3X:
|
||||||
|
case SHTSensor::SHTSensorType::SHT85:
|
||||||
|
sensorVariant = "SHT3x/SHT85";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SHTSensor::SHTSensorType::SHT3X_ALT:
|
||||||
|
sensorVariant = "SHT3x";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SHTSensor::SHTSensorType::SHTW1:
|
||||||
|
case SHTSensor::SHTSensorType::SHTW2:
|
||||||
|
case SHTSensor::SHTSensorType::SHTC1:
|
||||||
|
case SHTSensor::SHTSensorType::SHTC3:
|
||||||
|
sensorVariant = "SHTC1/SHTC3/SHTW1/SHTW2";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SHTSensor::SHTSensorType::SHT4X:
|
||||||
|
sensorVariant = "SHT4x";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
sensorVariant = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHTXXSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||||
|
{
|
||||||
|
LOG_INFO("Init sensor: %s", sensorName);
|
||||||
|
|
||||||
|
_bus = bus;
|
||||||
|
_address = dev->address.address;
|
||||||
|
|
||||||
|
if (sht.init(*_bus)) {
|
||||||
|
LOG_INFO("%s: init(): success", sensorName);
|
||||||
|
getSensorVariant(sht.mSensorType);
|
||||||
|
LOG_INFO("%s Sensor detected: %s on 0x%x", sensorName, sensorVariant, _address);
|
||||||
|
status = 1;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("%s: init(): failed", sensorName);
|
||||||
|
}
|
||||||
|
|
||||||
|
initI2CSensor();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accuracy setting of measurement.
|
||||||
|
* Not all sensors support changing the sampling accuracy (only SHT3X and SHT4X)
|
||||||
|
* SHTAccuracy:
|
||||||
|
* - SHT_ACCURACY_HIGH: Highest repeatability at the cost of slower measurement
|
||||||
|
* - SHT_ACCURACY_MEDIUM: Balanced repeatability and speed of measurement
|
||||||
|
* - SHT_ACCURACY_LOW: Fastest measurement but lowest repeatability
|
||||||
|
*/
|
||||||
|
bool SHTXXSensor::setAccuracy(SHTSensor::SHTAccuracy newAccuracy)
|
||||||
|
{
|
||||||
|
// Only SHT3X-family (including alternates) and SHT4X support changing accuracy
|
||||||
|
if (sht.mSensorType != SHTSensor::SHTSensorType::SHT3X && sht.mSensorType != SHTSensor::SHTSensorType::SHT3X_ALT &&
|
||||||
|
sht.mSensorType != SHTSensor::SHTSensorType::SHT85 && sht.mSensorType != SHTSensor::SHTSensorType::SHT4X) {
|
||||||
|
LOG_WARN("%s doesn't support accuracy setting", sensorVariant);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LOG_INFO("%s: setting new accuracy setting", sensorVariant);
|
||||||
|
accuracy = newAccuracy;
|
||||||
|
return sht.setAccuracy(accuracy);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHTXXSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||||
|
{
|
||||||
|
if (sht.readSample()) {
|
||||||
|
measurement->variant.environment_metrics.has_temperature = true;
|
||||||
|
measurement->variant.environment_metrics.has_relative_humidity = true;
|
||||||
|
measurement->variant.environment_metrics.temperature = sht.getTemperature();
|
||||||
|
measurement->variant.environment_metrics.relative_humidity = sht.getHumidity();
|
||||||
|
|
||||||
|
LOG_INFO("%s (%s): Got: temp:%fdegC, hum:%f%%rh", sensorName, sensorVariant,
|
||||||
|
measurement->variant.environment_metrics.temperature,
|
||||||
|
measurement->variant.environment_metrics.relative_humidity);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("%s (%s): read sample failed", sensorName, sensorVariant);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AdminMessageHandleResult SHTXXSensor::handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,
|
||||||
|
meshtastic_AdminMessage *response)
|
||||||
|
{
|
||||||
|
AdminMessageHandleResult result;
|
||||||
|
result = AdminMessageHandleResult::NOT_HANDLED;
|
||||||
|
|
||||||
|
switch (request->which_payload_variant) {
|
||||||
|
case meshtastic_AdminMessage_sensor_config_tag:
|
||||||
|
if (!request->sensor_config.has_shtxx_config) {
|
||||||
|
result = AdminMessageHandleResult::NOT_HANDLED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for sensor accuracy setting
|
||||||
|
if (request->sensor_config.shtxx_config.has_set_accuracy) {
|
||||||
|
SHTSensor::SHTAccuracy newAccuracy;
|
||||||
|
if (request->sensor_config.shtxx_config.set_accuracy == 0) {
|
||||||
|
newAccuracy = SHTSensor::SHT_ACCURACY_LOW;
|
||||||
|
} else if (request->sensor_config.shtxx_config.set_accuracy == 1) {
|
||||||
|
newAccuracy = SHTSensor::SHT_ACCURACY_MEDIUM;
|
||||||
|
} else if (request->sensor_config.shtxx_config.set_accuracy == 2) {
|
||||||
|
newAccuracy = SHTSensor::SHT_ACCURACY_HIGH;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("%s: incorrect accuracy setting", sensorName);
|
||||||
|
result = AdminMessageHandleResult::HANDLED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->setAccuracy(newAccuracy);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = AdminMessageHandleResult::HANDLED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = AdminMessageHandleResult::NOT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<SHTSensor.h>)
|
||||||
|
|
||||||
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
|
#include "TelemetrySensor.h"
|
||||||
|
#include <SHTSensor.h>
|
||||||
|
|
||||||
|
class SHTXXSensor : public TelemetrySensor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
SHTSensor sht;
|
||||||
|
TwoWire *_bus{};
|
||||||
|
uint8_t _address{};
|
||||||
|
SHTSensor::SHTAccuracy accuracy{};
|
||||||
|
bool setAccuracy(SHTSensor::SHTAccuracy newAccuracy);
|
||||||
|
|
||||||
|
public:
|
||||||
|
SHTXXSensor();
|
||||||
|
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||||
|
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||||
|
void getSensorVariant(SHTSensor::SHTSensorType);
|
||||||
|
const char *sensorVariant{};
|
||||||
|
|
||||||
|
AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,
|
||||||
|
meshtastic_AdminMessage *response) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "Router.h"
|
#include "Router.h"
|
||||||
#include "TypeConversions.h"
|
#include "TypeConversions.h"
|
||||||
|
#include "airtime.h"
|
||||||
#include "concurrency/LockGuard.h"
|
#include "concurrency/LockGuard.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
@@ -1001,7 +1002,11 @@ void TrafficManagementModule::alterReceived(meshtastic_MeshPacket &mp)
|
|||||||
const auto &cfg = moduleConfig.traffic_management;
|
const auto &cfg = moduleConfig.traffic_management;
|
||||||
const bool isTelemetry = mp.decoded.portnum == meshtastic_PortNum_TELEMETRY_APP;
|
const bool isTelemetry = mp.decoded.portnum == meshtastic_PortNum_TELEMETRY_APP;
|
||||||
const bool isPosition = mp.decoded.portnum == meshtastic_PortNum_POSITION_APP;
|
const bool isPosition = mp.decoded.portnum == meshtastic_PortNum_POSITION_APP;
|
||||||
const bool shouldExhaust = (isTelemetry && cfg.exhaust_hop_telemetry) || (isPosition && cfg.exhaust_hop_position);
|
// Only exhaust telemetry hops when channel is actually congested, mirroring the same
|
||||||
|
// airtime checks that gate self-generated telemetry in the telemetry modules.
|
||||||
|
const bool channelBusy = airTime && (!airTime->isTxAllowedChannelUtil(true) || !airTime->isTxAllowedAirUtil());
|
||||||
|
const bool shouldExhaust =
|
||||||
|
((channelBusy && isTelemetry && cfg.exhaust_hop_telemetry) || (isPosition && cfg.exhaust_hop_position));
|
||||||
|
|
||||||
if (!shouldExhaust || !isBroadcast(mp.to))
|
if (!shouldExhaust || !isBroadcast(mp.to))
|
||||||
return;
|
return;
|
||||||
|
|||||||
+2
-2
@@ -322,8 +322,8 @@ bool connectPubSub(const PubSubConfig &config, PubSubClient &pubSub, Client &cli
|
|||||||
pubSub.setClient(client);
|
pubSub.setClient(client);
|
||||||
pubSub.setServer(config.serverAddr.c_str(), config.serverPort);
|
pubSub.setServer(config.serverAddr.c_str(), config.serverPort);
|
||||||
|
|
||||||
LOG_INFO("Connecting directly to MQTT server %s, port: %d, username: %s, password: %s", config.serverAddr.c_str(),
|
LOG_INFO("Connecting directly to MQTT server %s, port: %d, username: %s, password: ***", config.serverAddr.c_str(),
|
||||||
config.serverPort, config.mqttUsername, config.mqttPassword);
|
config.serverPort, config.mqttUsername);
|
||||||
|
|
||||||
// Generate node ID from nodenum for client identification
|
// Generate node ID from nodenum for client identification
|
||||||
std::string nodeId = nodeDB->getNodeId();
|
std::string nodeId = nodeDB->getNodeId();
|
||||||
|
|||||||
@@ -231,7 +231,9 @@ void cpuDeepSleep(uint32_t msecToWake)
|
|||||||
#if SOC_RTCIO_HOLD_SUPPORTED && SOC_PM_SUPPORT_EXT_WAKEUP
|
#if SOC_RTCIO_HOLD_SUPPORTED && SOC_PM_SUPPORT_EXT_WAKEUP
|
||||||
uint64_t gpioMask = (1ULL << (config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
|
uint64_t gpioMask = (1ULL << (config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ALT_BUTTON_WAKE
|
||||||
|
gpioMask |= (1ULL << BUTTON_PIN_ALT);
|
||||||
|
#endif
|
||||||
#ifdef BUTTON_NEED_PULLUP
|
#ifdef BUTTON_NEED_PULLUP
|
||||||
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -23,5 +23,6 @@ void lateInitVariant()
|
|||||||
cfg.i2s.bits = BIT_LENGTH_16BITS;
|
cfg.i2s.bits = BIT_LENGTH_16BITS;
|
||||||
cfg.i2s.rate = RATE_44K;
|
cfg.i2s.rate = RATE_44K;
|
||||||
board.begin(cfg);
|
board.begin(cfg);
|
||||||
|
board.setVolume(75); // 75% volume
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <nrfx_wdt.h>
|
#include <nrfx_wdt.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
// #include <Adafruit_USBD_Device.h>
|
// #include <Adafruit_USBD_Device.h>
|
||||||
|
#include "HardwareRNG.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerMon.h"
|
#include "PowerMon.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
@@ -398,15 +399,14 @@ void nrf52Setup()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Init random seed
|
// Init random seed
|
||||||
union seedParts {
|
uint32_t seed = 0;
|
||||||
uint32_t seed32;
|
if (!HardwareRNG::seed(seed)) {
|
||||||
uint8_t seed8[4];
|
LOG_WARN("Hardware RNG seed unavailable, using PRNG fallback");
|
||||||
} seed;
|
// Use a hardware timer value as a fallback seed for better entropy
|
||||||
nRFCrypto.begin();
|
seed = micros();
|
||||||
nRFCrypto.Random.generate(seed.seed8, sizeof(seed.seed8));
|
}
|
||||||
LOG_DEBUG("Set random seed %u", seed.seed32);
|
LOG_DEBUG("Set random seed %u", seed);
|
||||||
randomSeed(seed.seed32);
|
randomSeed(seed);
|
||||||
nRFCrypto.end();
|
|
||||||
|
|
||||||
// Set up nrfx watchdog. Do not enable the watchdog yet (we do that
|
// Set up nrfx watchdog. Do not enable the watchdog yet (we do that
|
||||||
// the first time through the main loop), so that other threads can
|
// the first time through the main loop), so that other threads can
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user