mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-10 05:51:01 +10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd5e0b74ba |
@@ -1,314 +0,0 @@
|
||||
# Meshtastic Firmware - Copilot Instructions
|
||||
|
||||
This document provides context and guidelines for AI assistants working with the Meshtastic firmware codebase.
|
||||
|
||||
## 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.
|
||||
|
||||
### Supported Hardware Platforms
|
||||
|
||||
- **ESP32** (ESP32, ESP32-S3, ESP32-C3) - Most common platform
|
||||
- **nRF52** (nRF52840, nRF52833) - Low power Nordic chips
|
||||
- **RP2040/RP2350** - Raspberry Pi Pico variants
|
||||
- **STM32WL** - STM32 with integrated LoRa
|
||||
- **Linux/Portduino** - Native Linux builds (Raspberry Pi, etc.)
|
||||
|
||||
### Supported Radio Chips
|
||||
|
||||
- **SX1262/SX1268** - Sub-GHz LoRa (868/915 MHz regions)
|
||||
- **SX1280** - 2.4 GHz LoRa
|
||||
- **LR1110/LR1120/LR1121** - Wideband radios (sub-GHz and 2.4 GHz capable, but not simultaneously)
|
||||
- **RF95** - Legacy RFM95 modules
|
||||
- **LLCC68** - Low-cost LoRa
|
||||
|
||||
### MQTT Integration
|
||||
|
||||
MQTT provides a bridge between Meshtastic mesh networks and the internet, enabling nodes with network connectivity to share messages with remote meshes or external services.
|
||||
|
||||
#### Key Components
|
||||
|
||||
- **`src/mqtt/MQTT.cpp`** - Main MQTT client singleton, handles connection and message routing
|
||||
- **`src/mqtt/ServiceEnvelope.cpp`** - Protobuf wrapper for mesh packets sent over MQTT
|
||||
- **`moduleConfig.mqtt`** - MQTT module configuration
|
||||
|
||||
#### MQTT Topic Structure
|
||||
|
||||
Messages are published/subscribed using a hierarchical topic format:
|
||||
|
||||
```
|
||||
{root}/{channel_id}/{gateway_id}
|
||||
```
|
||||
|
||||
- `root` - Configurable prefix (default: `msh`)
|
||||
- `channel_id` - Channel name/identifier
|
||||
- `gateway_id` - Node ID of the publishing gateway
|
||||
|
||||
#### Configuration Defaults (from `Default.h`)
|
||||
|
||||
```cpp
|
||||
#define default_mqtt_address "mqtt.meshtastic.org"
|
||||
#define default_mqtt_username "meshdev"
|
||||
#define default_mqtt_password "large4cats"
|
||||
#define default_mqtt_root "msh"
|
||||
#define default_mqtt_encryption_enabled true
|
||||
#define default_mqtt_tls_enabled false
|
||||
```
|
||||
|
||||
#### Key Concepts
|
||||
|
||||
- **Uplink** - Mesh packets sent TO the MQTT broker (controlled by `uplink_enabled` per channel)
|
||||
- **Downlink** - MQTT messages received and injected INTO the mesh (controlled by `downlink_enabled` per channel)
|
||||
- **Encryption** - When `encryption_enabled` is true, only encrypted packets are sent; plaintext JSON is disabled
|
||||
- **ServiceEnvelope** - Protobuf wrapper containing packet + channel_id + gateway_id for routing
|
||||
- **JSON Support** - Optional JSON encoding for integration with external systems (disabled on nRF52 by default)
|
||||
|
||||
#### PKI Messages
|
||||
|
||||
PKI (Public Key Infrastructure) messages have special handling:
|
||||
|
||||
- Accepted on a special "PKI" channel
|
||||
- Allow encrypted DMs between nodes that discovered each other on downlink-enabled channels
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
firmware/
|
||||
├── src/ # Main source code
|
||||
│ ├── main.cpp # Application entry point
|
||||
│ ├── mesh/ # Core mesh networking
|
||||
│ │ ├── NodeDB.* # Node database management
|
||||
│ │ ├── Router.* # Packet routing
|
||||
│ │ ├── Channels.* # Channel management
|
||||
│ │ ├── *Interface.* # Radio interface implementations
|
||||
│ │ └── generated/ # Protobuf generated code
|
||||
│ ├── modules/ # Feature modules (Position, Telemetry, etc.)
|
||||
│ ├── gps/ # GPS handling
|
||||
│ ├── graphics/ # Display drivers and UI
|
||||
│ ├── platform/ # Platform-specific code
|
||||
│ ├── input/ # Input device handling
|
||||
│ └── concurrency/ # Threading utilities
|
||||
├── variants/ # Hardware variant definitions
|
||||
│ ├── esp32/ # ESP32 variants
|
||||
│ ├── esp32s3/ # ESP32-S3 variants
|
||||
│ ├── nrf52/ # nRF52 variants
|
||||
│ └── rp2xxx/ # RP2040/RP2350 variants
|
||||
├── protobufs/ # Protocol buffer definitions
|
||||
├── boards/ # Custom PlatformIO board definitions
|
||||
└── bin/ # Build and utility scripts
|
||||
```
|
||||
|
||||
## Coding Conventions
|
||||
|
||||
### General Style
|
||||
|
||||
- Follow existing code style - run `trunk fmt` before commits
|
||||
- Prefer `LOG_DEBUG`, `LOG_INFO`, `LOG_WARN`, `LOG_ERROR` for logging
|
||||
- Use `assert()` for invariants that should never fail
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
- Classes: `PascalCase` (e.g., `PositionModule`, `NodeDB`)
|
||||
- Functions/Methods: `camelCase` (e.g., `sendOurPosition`, `getNodeNum`)
|
||||
- Constants/Defines: `UPPER_SNAKE_CASE` (e.g., `MAX_INTERVAL`, `ONE_DAY`)
|
||||
- Member variables: `camelCase` (e.g., `lastGpsSend`, `nodeDB`)
|
||||
- Config defines: `USERPREFS_*` for user-configurable options
|
||||
|
||||
### Key Patterns
|
||||
|
||||
#### Module System
|
||||
|
||||
Modules inherit from `MeshModule` or `ProtobufModule<T>` and implement:
|
||||
|
||||
- `handleReceivedProtobuf()` - Process incoming packets
|
||||
- `allocReply()` - Generate response packets
|
||||
- `runOnce()` - Periodic task execution (returns next run interval in ms)
|
||||
|
||||
```cpp
|
||||
class MyModule : public ProtobufModule<meshtastic_MyMessage>
|
||||
{
|
||||
protected:
|
||||
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_MyMessage *msg) override;
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
```
|
||||
|
||||
#### Configuration Access
|
||||
|
||||
- `config.*` - Device configuration (LoRa, position, power, etc.)
|
||||
- `moduleConfig.*` - Module-specific configuration
|
||||
- `channels.*` - Channel configuration and management
|
||||
|
||||
#### Default Values
|
||||
|
||||
Use the `Default` class helpers in `src/mesh/Default.h`:
|
||||
|
||||
- `Default::getConfiguredOrDefaultMs(configured, default)` - Returns ms, using default if configured is 0
|
||||
- `Default::getConfiguredOrMinimumValue(configured, min)` - Enforces minimum values
|
||||
- `Default::getConfiguredOrDefaultMsScaled(configured, default, numNodes)` - Scales based on network size
|
||||
|
||||
#### Thread Safety
|
||||
|
||||
- Use `concurrency::Lock` for mutex protection
|
||||
- Radio SPI access uses `SPILock`
|
||||
- Prefer `OSThread` for background tasks
|
||||
|
||||
### Hardware Variants
|
||||
|
||||
Each hardware variant has:
|
||||
|
||||
- `variant.h` - Pin definitions and hardware capabilities
|
||||
- `platformio.ini` - Build configuration
|
||||
- Optional: `pins_arduino.h`, `rfswitch.h`
|
||||
|
||||
Key defines in variant.h:
|
||||
|
||||
```cpp
|
||||
#define USE_SX1262 // Radio chip selection
|
||||
#define HAS_GPS 1 // Hardware capabilities
|
||||
#define LORA_CS 36 // Pin assignments
|
||||
#define SX126X_DIO1 14 // Radio-specific pins
|
||||
```
|
||||
|
||||
### Protobuf Messages
|
||||
|
||||
- Defined in `protobufs/meshtastic/*.proto`
|
||||
- Generated code in `src/mesh/generated/`
|
||||
- Regenerate with `bin/regen-protos.sh`
|
||||
- Message types prefixed with `meshtastic_`
|
||||
|
||||
### Conditional Compilation
|
||||
|
||||
```cpp
|
||||
#if !MESHTASTIC_EXCLUDE_GPS // Feature exclusion
|
||||
#ifdef ARCH_ESP32 // Architecture-specific
|
||||
#if defined(USE_SX1262) // Radio-specific
|
||||
#ifdef HAS_SCREEN // Hardware capability
|
||||
#if USERPREFS_EVENT_MODE // User preferences
|
||||
```
|
||||
|
||||
## Build System
|
||||
|
||||
Uses **PlatformIO** with custom scripts:
|
||||
|
||||
- `bin/platformio-pre.py` - Pre-build script
|
||||
- `bin/platformio-custom.py` - Custom build logic
|
||||
|
||||
Build commands:
|
||||
|
||||
```bash
|
||||
pio run -e tbeam # Build specific target
|
||||
pio run -e tbeam -t upload # Build and upload
|
||||
pio run -e native # Build native/Linux version
|
||||
```
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Adding a New Module
|
||||
|
||||
1. Create `src/modules/MyModule.cpp` and `.h`
|
||||
2. Inherit from appropriate base class
|
||||
3. Register in `src/modules/Modules.cpp`
|
||||
4. Add protobuf messages if needed in `protobufs/`
|
||||
|
||||
### Adding a New Hardware Variant
|
||||
|
||||
1. Create directory under `variants/<arch>/<name>/`
|
||||
2. Add `variant.h` with pin definitions
|
||||
3. Add `platformio.ini` with build config
|
||||
4. Reference common configs with `extends`
|
||||
|
||||
### Modifying Configuration Defaults
|
||||
|
||||
- Check `src/mesh/Default.h` for default value defines
|
||||
- Check `src/mesh/NodeDB.cpp` for initialization logic
|
||||
- Consider `isDefaultChannel()` checks for public channel restrictions
|
||||
|
||||
## Important Considerations
|
||||
|
||||
### Traffic Management
|
||||
|
||||
The mesh network has limited bandwidth. When modifying broadcast intervals:
|
||||
|
||||
- Respect minimum intervals on default/public channels
|
||||
- Use `Default::getConfiguredOrMinimumValue()` to enforce minimums
|
||||
- Consider `numOnlineNodes` scaling for congestion control
|
||||
|
||||
### Power Management
|
||||
|
||||
Many devices are battery-powered:
|
||||
|
||||
- Use `IF_ROUTER(routerVal, normalVal)` for role-based defaults
|
||||
- Check `config.power.is_power_saving` for power-saving modes
|
||||
- Implement proper `sleep()` methods in radio interfaces
|
||||
|
||||
### Channel Security
|
||||
|
||||
- `channels.isDefaultChannel(index)` - Check if using default/public settings
|
||||
- Default channels get stricter rate limits to prevent abuse
|
||||
- Private channels may have relaxed limits
|
||||
|
||||
## GitHub Actions CI/CD
|
||||
|
||||
The project uses GitHub Actions extensively for CI/CD. Key workflows are in `.github/workflows/`:
|
||||
|
||||
### Core CI Workflows
|
||||
|
||||
- **`main_matrix.yml`** - Main CI pipeline, runs on push to `master`/`develop` and PRs
|
||||
- Uses `bin/generate_ci_matrix.py` to dynamically generate build targets
|
||||
- Builds all supported hardware variants
|
||||
- PRs build a subset (`--level pr`) for faster feedback
|
||||
|
||||
- **`trunk_check.yml`** - Code quality checks on PRs
|
||||
- Runs Trunk.io for linting and formatting
|
||||
- Must pass before merge
|
||||
|
||||
- **`tests.yml`** - End-to-end and hardware tests
|
||||
- Runs daily on schedule
|
||||
- Includes native tests and hardware-in-the-loop testing
|
||||
|
||||
- **`test_native.yml`** - Native platform unit tests
|
||||
- Runs `pio test -e native`
|
||||
|
||||
### Release Workflows
|
||||
|
||||
- **`release_channels.yml`** - Triggered on GitHub release publish
|
||||
- Builds Docker images
|
||||
- Packages for PPA (Ubuntu), OBS (openSUSE), and COPR (Fedora)
|
||||
- Handles Alpha/Beta/Stable release channels
|
||||
|
||||
- **`nightly.yml`** - Nightly builds from develop branch
|
||||
|
||||
- **`docker_build.yml`** / **`docker_manifest.yml`** - Docker image builds
|
||||
|
||||
### Build Matrix Generation
|
||||
|
||||
The CI uses `bin/generate_ci_matrix.py` to dynamically select which targets to build:
|
||||
|
||||
```bash
|
||||
# Generate full build matrix
|
||||
./bin/generate_ci_matrix.py all
|
||||
|
||||
# Generate PR-level matrix (subset for faster builds)
|
||||
./bin/generate_ci_matrix.py all --level pr
|
||||
```
|
||||
|
||||
Variants can specify their support level in `platformio.ini`:
|
||||
|
||||
- `custom_meshtastic_support_level = 1` - Actively supported, built on every PR
|
||||
- `custom_meshtastic_support_level = 2` - Supported, built on merge to main branches
|
||||
- `board_level = extra` - Extra builds, only on full releases
|
||||
|
||||
### Running Workflows Locally
|
||||
|
||||
Most workflows can be triggered manually via `workflow_dispatch` for testing.
|
||||
|
||||
## Testing
|
||||
|
||||
- Unit tests in `test/` directory
|
||||
- Run with `pio test -e native`
|
||||
- Use `bin/test-simulator.sh` for simulation testing
|
||||
|
||||
## Resources
|
||||
|
||||
- [Documentation](https://meshtastic.org/docs/)
|
||||
@@ -143,7 +143,7 @@ jobs:
|
||||
merge-multiple: true
|
||||
|
||||
- name: Test Report
|
||||
uses: dorny/test-reporter@v2.5.0
|
||||
uses: dorny/test-reporter@v2.4.0
|
||||
with:
|
||||
name: PlatformIO Tests
|
||||
path: testreport.xml
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
name: Run Trunk Fmt on PR Comment
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
trunk-fmt:
|
||||
if: github.event.issue.pull_request != null && contains(github.event.comment.body, 'trunk fmt')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Install trunk
|
||||
run: curl https://get.trunk.io -fsSL | bash
|
||||
|
||||
- name: Run Trunk Fmt
|
||||
run: trunk fmt
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Commit and push changes
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git add .
|
||||
git commit -m "Add firmware version ${{ steps.version.outputs.long }}"
|
||||
git push
|
||||
|
||||
- name: Comment on PR
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
github.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: '`trunk fmt` has been run on this PR.'
|
||||
})
|
||||
+4
-4
@@ -8,20 +8,20 @@ plugins:
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@3.2.497
|
||||
- renovate@42.75.0
|
||||
- checkov@3.2.496
|
||||
- renovate@42.66.14
|
||||
- prettier@3.7.4
|
||||
- trufflehog@3.92.4
|
||||
- yamllint@1.37.1
|
||||
- bandit@1.9.2
|
||||
- trivy@0.68.2
|
||||
- taplo@0.10.0
|
||||
- ruff@0.14.11
|
||||
- ruff@0.14.10
|
||||
- isort@7.0.0
|
||||
- markdownlint@0.47.0
|
||||
- oxipng@10.0.0
|
||||
- svgo@4.0.0
|
||||
- actionlint@1.7.10
|
||||
- actionlint@1.7.9
|
||||
- flake8@7.3.0
|
||||
- hadolint@2.14.0
|
||||
- shfmt@3.6.0
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# Minimal container to run PlatformIO native/portduino tests
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
python3 \
|
||||
python3-pip \
|
||||
git \
|
||||
build-essential \
|
||||
cmake \
|
||||
pkg-config \
|
||||
libssl-dev \
|
||||
libncurses5 \
|
||||
libsdl2-dev \
|
||||
libx11-dev \
|
||||
libxext-dev \
|
||||
libusb-1.0-0-dev \
|
||||
libyaml-cpp-dev \
|
||||
libuv1-dev \
|
||||
libgpiod-dev \
|
||||
libbluetooth-dev \
|
||||
libulfius-dev \
|
||||
liborcania-dev \
|
||||
libmicrohttpd-dev \
|
||||
libjansson-dev \
|
||||
libgnutls28-dev \
|
||||
libcurl4-gnutls-dev \
|
||||
libi2c-dev \
|
||||
openssl \
|
||||
lsb-release \
|
||||
cppcheck \
|
||||
uuid-dev \
|
||||
zlib1g-dev \
|
||||
libbsd-dev \
|
||||
gdb \
|
||||
&& pip3 install --no-cache-dir platformio \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
CMD ["bash"]
|
||||
+1
-1
@@ -38,4 +38,4 @@ cp bin/device-install.* $OUTDIR/
|
||||
cp bin/device-update.* $OUTDIR/
|
||||
|
||||
echo "Copying manifest"
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json || true
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
+1
-1
@@ -49,4 +49,4 @@ if (echo $1 | grep -q "rak4631"); then
|
||||
fi
|
||||
|
||||
echo "Copying manifest"
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json || true
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
+1
-1
@@ -30,4 +30,4 @@ echo "Copying uf2 file"
|
||||
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
|
||||
|
||||
echo "Copying manifest"
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json || true
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -30,4 +30,4 @@ echo "Copying STM32 bin file"
|
||||
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
|
||||
|
||||
echo "Copying manifest"
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json || true
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
Lora:
|
||||
|
||||
### RAK13300in Slot 1
|
||||
Module: sx1262
|
||||
IRQ: 22 #IO6
|
||||
Reset: 16 # IO4
|
||||
Busy: 24 # IO5
|
||||
# Ant_sw: 13 # IO3
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: spidev0.0
|
||||
@@ -1,14 +0,0 @@
|
||||
Lora:
|
||||
Module: sx1262
|
||||
CS: 0
|
||||
IRQ: 6
|
||||
Reset: 2
|
||||
Busy: 4
|
||||
RXen: 1
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
spidev: ch341
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
# USB_Serialnum: 12345678
|
||||
USB_PID: 0x5512
|
||||
USB_VID: 0x1A86
|
||||
SX126X_MAX_POWER: 22
|
||||
+13
-143
@@ -2,12 +2,11 @@
|
||||
# trunk-ignore-all(ruff/F821)
|
||||
# trunk-ignore-all(flake8/F821): For SConstruct imports
|
||||
import sys
|
||||
from os.path import join
|
||||
from os.path import join, basename, isfile
|
||||
import subprocess
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime
|
||||
from typing import Dict
|
||||
|
||||
from readprops import readProps
|
||||
|
||||
@@ -15,47 +14,8 @@ Import("env")
|
||||
platform = env.PioPlatform()
|
||||
progname = env.get("PROGNAME")
|
||||
lfsbin = f"{progname.replace('firmware-', 'littlefs-')}.bin"
|
||||
manifest_ran = False
|
||||
|
||||
def infer_architecture(board_cfg):
|
||||
try:
|
||||
mcu = board_cfg.get("build.mcu") if board_cfg else None
|
||||
except KeyError:
|
||||
mcu = None
|
||||
except Exception:
|
||||
mcu = None
|
||||
if not mcu:
|
||||
return None
|
||||
mcu_l = str(mcu).lower()
|
||||
if "esp32s3" in mcu_l:
|
||||
return "esp32-s3"
|
||||
if "esp32c6" in mcu_l:
|
||||
return "esp32-c6"
|
||||
if "esp32c3" in mcu_l:
|
||||
return "esp32-c3"
|
||||
if "esp32" in mcu_l:
|
||||
return "esp32"
|
||||
if "rp2040" in mcu_l:
|
||||
return "rp2040"
|
||||
if "rp2350" in mcu_l:
|
||||
return "rp2350"
|
||||
if "nrf52" in mcu_l or "nrf52840" in mcu_l:
|
||||
return "nrf52840"
|
||||
if "stm32" in mcu_l:
|
||||
return "stm32"
|
||||
return None
|
||||
|
||||
def manifest_gather(source, target, env):
|
||||
global manifest_ran
|
||||
if manifest_ran:
|
||||
return
|
||||
# Skip manifest generation if we cannot determine architecture (host/native builds)
|
||||
board_arch = infer_architecture(env.BoardConfig())
|
||||
if not board_arch:
|
||||
print(f"Skipping mtjson generation for unknown architecture (env={env.get('PIOENV')})")
|
||||
manifest_ran = True
|
||||
return
|
||||
manifest_ran = True
|
||||
out = []
|
||||
board_platform = env.BoardConfig().get("platform")
|
||||
needs_ota_suffix = board_platform == "nordicnrf52"
|
||||
@@ -87,39 +47,14 @@ def manifest_gather(source, target, env):
|
||||
manifest_write(out, env)
|
||||
|
||||
def manifest_write(files, env):
|
||||
# Defensive: also skip manifest writing if we cannot determine architecture
|
||||
def get_project_option(name):
|
||||
try:
|
||||
return env.GetProjectOption(name)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def get_project_option_any(names):
|
||||
for name in names:
|
||||
val = get_project_option(name)
|
||||
if val is not None:
|
||||
return val
|
||||
return None
|
||||
|
||||
def as_bool(val):
|
||||
return str(val).strip().lower() in ("1", "true", "yes", "on")
|
||||
|
||||
def as_int(val):
|
||||
try:
|
||||
return int(str(val), 10)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
def as_list(val):
|
||||
return [item.strip() for item in str(val).split(",") if item.strip()]
|
||||
|
||||
manifest = {
|
||||
"version": verObj["long"],
|
||||
"build_epoch": build_epoch,
|
||||
"platformioTarget": env.get("PIOENV"),
|
||||
"board": env.get("PIOENV"),
|
||||
"mcu": env.get("BOARD_MCU"),
|
||||
"repo": repo_owner,
|
||||
"files": files,
|
||||
"part": None,
|
||||
"has_mui": False,
|
||||
"has_inkhud": False,
|
||||
}
|
||||
@@ -134,51 +69,6 @@ def manifest_write(files, env):
|
||||
if "MESHTASTIC_INCLUDE_INKHUD" in env.get("CPPDEFINES", []):
|
||||
manifest["has_inkhud"] = True
|
||||
|
||||
pioenv = env.get("PIOENV")
|
||||
device_meta = {}
|
||||
device_meta_fields = [
|
||||
("hwModel", ["custom_meshtastic_hw_model"], as_int),
|
||||
("hwModelSlug", ["custom_meshtastic_hw_model_slug"], str),
|
||||
("architecture", ["custom_meshtastic_architecture"], str),
|
||||
("activelySupported", ["custom_meshtastic_actively_supported"], as_bool),
|
||||
("displayName", ["custom_meshtastic_display_name"], str),
|
||||
("supportLevel", ["custom_meshtastic_support_level"], as_int),
|
||||
("images", ["custom_meshtastic_images"], as_list),
|
||||
("tags", ["custom_meshtastic_tags"], as_list),
|
||||
("requiresDfu", ["custom_meshtastic_requires_dfu"], as_bool),
|
||||
("partitionScheme", ["custom_meshtastic_partition_scheme"], str),
|
||||
("url", ["custom_meshtastic_url"], str),
|
||||
("key", ["custom_meshtastic_key"], str),
|
||||
("variant", ["custom_meshtastic_variant"], str),
|
||||
]
|
||||
|
||||
|
||||
for manifest_key, option_keys, caster in device_meta_fields:
|
||||
raw_val = get_project_option_any(option_keys)
|
||||
if raw_val is None:
|
||||
continue
|
||||
parsed = caster(raw_val) if callable(caster) else raw_val
|
||||
if parsed is not None and parsed != "":
|
||||
device_meta[manifest_key] = parsed
|
||||
|
||||
# Determine architecture once; if we can't infer it, skip manifest generation
|
||||
board_arch = device_meta.get("architecture") or infer_architecture(env.BoardConfig())
|
||||
if not board_arch:
|
||||
print(f"Skipping mtjson write for unknown architecture (env={env.get('PIOENV')})")
|
||||
return
|
||||
|
||||
device_meta["architecture"] = board_arch
|
||||
|
||||
# Always set requiresDfu: true for nrf52840 targets
|
||||
if board_arch == "nrf52840":
|
||||
device_meta["requiresDfu"] = True
|
||||
|
||||
device_meta.setdefault("displayName", pioenv)
|
||||
device_meta.setdefault("activelySupported", False)
|
||||
|
||||
if device_meta:
|
||||
manifest.update(device_meta)
|
||||
|
||||
# Write the manifest to the build directory
|
||||
with open(env.subst("$BUILD_DIR/${PROGNAME}.mt.json"), "w") as f:
|
||||
json.dump(manifest, f, indent=2)
|
||||
@@ -276,12 +166,8 @@ def load_boot_logo(source, target, env):
|
||||
if ("HAS_TFT", 1) in env.get("CPPDEFINES", []):
|
||||
env.AddPreAction(f"$BUILD_DIR/{lfsbin}", load_boot_logo)
|
||||
|
||||
board_arch = infer_architecture(env.BoardConfig())
|
||||
should_skip_manifest = board_arch is None
|
||||
|
||||
# For host/native envs, avoid depending on 'buildprog' (some targets don't define it)
|
||||
mtjson_deps = [] if should_skip_manifest else ["buildprog"]
|
||||
if not should_skip_manifest and platform.name == "espressif32":
|
||||
mtjson_deps = ["buildprog"]
|
||||
if platform.name == "espressif32":
|
||||
# Build littlefs image as part of mtjson target
|
||||
# Equivalent to `pio run -t buildfs`
|
||||
target_lfs = env.DataToBin(
|
||||
@@ -289,27 +175,11 @@ if not should_skip_manifest and platform.name == "espressif32":
|
||||
)
|
||||
mtjson_deps.append(target_lfs)
|
||||
|
||||
if should_skip_manifest:
|
||||
def skip_manifest(source, target, env):
|
||||
print(f"mtjson: skipped for native environment: {env.get('PIOENV')}")
|
||||
|
||||
env.AddCustomTarget(
|
||||
name="mtjson",
|
||||
dependencies=mtjson_deps,
|
||||
actions=[skip_manifest],
|
||||
title="Meshtastic Manifest (skipped)",
|
||||
description="mtjson generation is skipped for native environments",
|
||||
always_build=True,
|
||||
)
|
||||
else:
|
||||
env.AddCustomTarget(
|
||||
name="mtjson",
|
||||
dependencies=mtjson_deps,
|
||||
actions=[manifest_gather],
|
||||
title="Meshtastic Manifest",
|
||||
description="Generating Meshtastic manifest JSON + Checksums",
|
||||
always_build=True,
|
||||
)
|
||||
|
||||
# Run manifest generation as part of the default build pipeline for non-native builds.
|
||||
env.Default("mtjson")
|
||||
env.AddCustomTarget(
|
||||
name="mtjson",
|
||||
dependencies=mtjson_deps,
|
||||
actions=[manifest_gather],
|
||||
title="Meshtastic Manifest",
|
||||
description="Generating Meshtastic manifest JSON + Checksums",
|
||||
always_build=False,
|
||||
)
|
||||
|
||||
+1
-2
@@ -18,9 +18,8 @@ def readProps(prefsLoc):
|
||||
|
||||
# Try to find current build SHA if if the workspace is clean. This could fail if git is not installed
|
||||
try:
|
||||
# Pin abbreviation length to keep local builds and CI matching (avoid auto-shortening)
|
||||
sha = (
|
||||
subprocess.check_output(["git", "rev-parse", "--short=7", "HEAD"])
|
||||
subprocess.check_output(["git", "rev-parse", "--short", "HEAD"])
|
||||
.decode("utf-8")
|
||||
.strip()
|
||||
)
|
||||
|
||||
+47
-36
@@ -1,39 +1,50 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_opi"
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_opi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DLILYGO_TBEAM_1W",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=0",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"psram_type": "opi",
|
||||
"hwids": [
|
||||
[
|
||||
"0x303A",
|
||||
"0x1001"
|
||||
]
|
||||
],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "t-beam-1w"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DLILYGO_TBEAM_1W",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=0",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
"connectivity": [
|
||||
"wifi",
|
||||
"bluetooth",
|
||||
"lora"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"psram_type": "opi",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "t-beam-1w"
|
||||
},
|
||||
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "LilyGo TBeam-1W",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 16777216,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "http://www.lilygo.cn/",
|
||||
"vendor": "LilyGo"
|
||||
}
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "LilyGo TBeam-1W",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 16777216,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "http://www.lilygo.cn/",
|
||||
"vendor": "LilyGo"
|
||||
}
|
||||
+1
-1
@@ -119,7 +119,7 @@ lib_deps =
|
||||
[device-ui_base]
|
||||
lib_deps =
|
||||
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
||||
https://github.com/meshtastic/device-ui/archive/272defcb35651461830ebfd1b39c9167c8f49317.zip
|
||||
https://github.com/meshtastic/device-ui/archive/a8e2f947f7abaf0c5ac8e6dd189a22156335beaa.zip
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
[environmental_base]
|
||||
|
||||
+3
-3
@@ -1149,11 +1149,11 @@ bool Power::axpChipInit()
|
||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO1);
|
||||
|
||||
// sdcard (T-Beam S3) / gnns (T-Watch S3 Plus) power channel
|
||||
// sdcard power channel
|
||||
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
|
||||
#ifndef T_WATCH_S3
|
||||
PMU->enablePowerOutput(XPOWERS_BLDO1);
|
||||
#else
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
// DRV2605 power channel
|
||||
PMU->setPowerChannelVoltage(XPOWERS_BLDO2, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_BLDO2);
|
||||
|
||||
@@ -22,19 +22,15 @@ int BuzzerFeedbackThread::handleInputEvent(const InputEvent *event)
|
||||
|
||||
// Handle different input events with appropriate buzzer feedback
|
||||
switch (event->inputEvent) {
|
||||
#ifdef INPUTDRIVER_ENCODER_TYPE
|
||||
case INPUT_BROKER_SELECT:
|
||||
case INPUT_BROKER_SELECT_LONG:
|
||||
playClick();
|
||||
break;
|
||||
#else
|
||||
case INPUT_BROKER_USER_PRESS:
|
||||
case INPUT_BROKER_ALT_PRESS:
|
||||
playClick(); // Low delay feedback
|
||||
break;
|
||||
|
||||
case INPUT_BROKER_SELECT:
|
||||
case INPUT_BROKER_SELECT_LONG:
|
||||
playBeep();
|
||||
playBeep(); // Confirmation feedback
|
||||
break;
|
||||
#endif
|
||||
|
||||
case INPUT_BROKER_UP:
|
||||
case INPUT_BROKER_UP_LONG:
|
||||
|
||||
+1
-23
@@ -35,14 +35,6 @@ struct ToneDuration {
|
||||
#define NOTE_G6 1568
|
||||
#define NOTE_E7 2637
|
||||
|
||||
#define NOTE_C4 262
|
||||
#define NOTE_E4 330
|
||||
#define NOTE_G4 392
|
||||
#define NOTE_A4 440
|
||||
#define NOTE_C5 523
|
||||
#define NOTE_E5 659
|
||||
#define NOTE_G5 784
|
||||
|
||||
const int DURATION_1_16 = 62; // 1/16 note
|
||||
const int DURATION_1_8 = 125; // 1/8 note
|
||||
const int DURATION_1_4 = 250; // 1/4 note
|
||||
@@ -73,7 +65,7 @@ void playTones(const ToneDuration *tone_durations, int size)
|
||||
|
||||
void playBeep()
|
||||
{
|
||||
ToneDuration melody[] = {{NOTE_B3, DURATION_1_16}};
|
||||
ToneDuration melody[] = {{NOTE_B3, DURATION_1_8}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
|
||||
@@ -197,17 +189,3 @@ void playComboTune()
|
||||
};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
|
||||
void play4ClickDown()
|
||||
{
|
||||
ToneDuration melody[] = {{NOTE_G5, 55}, {NOTE_E5, 55}, {NOTE_C5, 60}, {NOTE_A4, 55}, {NOTE_G4, 55},
|
||||
{NOTE_E4, 65}, {NOTE_C4, 80}, {NOTE_G3, 120}, {NOTE_E3, 160}, {NOTE_SILENT, 120}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
|
||||
void play4ClickUp()
|
||||
{
|
||||
// Quick high-pitched notes with trills
|
||||
ToneDuration melody[] = {{NOTE_F5, 50}, {NOTE_G6, 45}, {NOTE_E7, 60}};
|
||||
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
|
||||
}
|
||||
@@ -7,8 +7,6 @@ void playShutdownMelody();
|
||||
void playGPSEnableBeep();
|
||||
void playGPSDisableBeep();
|
||||
void playComboTune();
|
||||
void play4ClickDown();
|
||||
void play4ClickUp();
|
||||
void playBoop();
|
||||
void playChirp();
|
||||
void playClick();
|
||||
|
||||
@@ -68,7 +68,7 @@ ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const
|
||||
if (r == 0x08 || r == 0x00) {
|
||||
logFoundDevice("SH1106", (uint8_t)addr.address);
|
||||
o_probe = SCREEN_SH1106; // SH1106
|
||||
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07 || r == 0x05) {
|
||||
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
|
||||
logFoundDevice("SSD1306", (uint8_t)addr.address);
|
||||
o_probe = SCREEN_SSD1306; // SSD1306
|
||||
}
|
||||
@@ -487,7 +487,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
}
|
||||
break;
|
||||
case TSL25911_ADDR:
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xA0 | 0x12), 1);
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x12), 1);
|
||||
if (registerValue == 0x50) {
|
||||
type = TSL2591;
|
||||
logFoundDevice("TSL25911", (uint8_t)addr.address);
|
||||
|
||||
+1
-4
@@ -934,11 +934,8 @@ void GPS::setPowerPMU(bool on)
|
||||
// t-beam v1.2 GNSS power channel
|
||||
on ? PMU->enablePowerOutput(XPOWERS_ALDO3) : PMU->disablePowerOutput(XPOWERS_ALDO3);
|
||||
} else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE) {
|
||||
// t-beam-s3-core GNSS power channel
|
||||
// t-beam-s3-core GNSS power channel
|
||||
on ? PMU->enablePowerOutput(XPOWERS_ALDO4) : PMU->disablePowerOutput(XPOWERS_ALDO4);
|
||||
} else if (HW_VENDOR == meshtastic_HardwareModel_T_WATCH_S3) {
|
||||
// t-watch-s3-plus GNSS power channel
|
||||
on ? PMU->enablePowerOutput(XPOWERS_BLDO1) : PMU->disablePowerOutput(XPOWERS_BLDO1);
|
||||
}
|
||||
} else if (model == XPOWERS_AXP192) {
|
||||
// t-beam v1.1 GNSS power channel
|
||||
|
||||
@@ -148,7 +148,7 @@ bool EInkDisplay::connect()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(TTGO_T_ECHO) || defined(ELECROW_ThinkNode_M1) || defined(T_ECHO_LITE) || defined(TTGO_T_ECHO_PLUS)
|
||||
#if defined(TTGO_T_ECHO) || defined(ELECROW_ThinkNode_M1) || defined(T_ECHO_LITE)
|
||||
{
|
||||
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, SPI1);
|
||||
|
||||
|
||||
+2
-18
@@ -312,7 +312,6 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
|
||||
// Only validate the combined value once
|
||||
if (rawRGB > 0 && rawRGB <= 255255255) {
|
||||
LOG_INFO("Setting screen RGB color to user chosen: 0x%06X", rawRGB);
|
||||
// Extract each component as a normal int first
|
||||
int r = (rawRGB >> 16) & 0xFF;
|
||||
int g = (rawRGB >> 8) & 0xFF;
|
||||
@@ -320,16 +319,6 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
|
||||
TFT_MESH = COLOR565(static_cast<uint8_t>(r), static_cast<uint8_t>(g), static_cast<uint8_t>(b));
|
||||
}
|
||||
#ifdef TFT_MESH_OVERRIDE
|
||||
} else if (rawRGB == 0) {
|
||||
LOG_INFO("Setting screen RGB color to TFT_MESH_OVERRIDE: 0x%04X", TFT_MESH_OVERRIDE);
|
||||
// Default to TFT_MESH_OVERRIDE if available
|
||||
TFT_MESH = TFT_MESH_OVERRIDE;
|
||||
#endif
|
||||
} else {
|
||||
// Default best readable yellow color
|
||||
LOG_INFO("Setting screen RGB color to default: (255,255,128)");
|
||||
TFT_MESH = COLOR565(255, 255, 128);
|
||||
}
|
||||
|
||||
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
|
||||
@@ -1440,15 +1429,10 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
|
||||
}
|
||||
nodeDB->updateGUI = false;
|
||||
break;
|
||||
case STATUS_TYPE_POWER: {
|
||||
bool currentUSB = powerStatus->getHasUSB();
|
||||
if (currentUSB != lastPowerUSBState) {
|
||||
lastPowerUSBState = currentUSB;
|
||||
forceDisplay(true);
|
||||
}
|
||||
case STATUS_TYPE_POWER:
|
||||
forceDisplay(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -715,8 +715,6 @@ class Screen : public concurrency::OSThread
|
||||
// Whether we are showing the regular screen (as opposed to booth screen or
|
||||
// Bluetooth PIN screen)
|
||||
bool showingNormalScreen = false;
|
||||
/// Track USB power state to only wake screen on actual power state changes
|
||||
bool lastPowerUSBState = false;
|
||||
|
||||
// Implementation to Adjust Brightness
|
||||
uint8_t brightness = BRIGHTNESS_DEFAULT; // H = 254, MH = 192, ML = 130 L = 103
|
||||
|
||||
@@ -449,14 +449,13 @@ void menuHandler::clockMenu()
|
||||
}
|
||||
void menuHandler::messageResponseMenu()
|
||||
{
|
||||
enum optionsNumbers { Back = 0, ViewMode, DeleteAll, DeleteOldest, ReplyMenu, MuteChannel, Aloud, enumEnd };
|
||||
enum optionsNumbers { Back = 0, ViewMode, DeleteAll, DeleteOldest, ReplyMenu, Aloud, enumEnd };
|
||||
|
||||
static const char *optionsArray[enumEnd];
|
||||
static int optionsEnumArray[enumEnd];
|
||||
int options = 0;
|
||||
|
||||
auto mode = graphics::MessageRenderer::getThreadMode();
|
||||
int threadChannel = graphics::MessageRenderer::getThreadChannel();
|
||||
|
||||
optionsArray[options] = "Back";
|
||||
optionsEnumArray[options++] = Back;
|
||||
@@ -468,15 +467,6 @@ void menuHandler::messageResponseMenu()
|
||||
optionsArray[options] = "View Chats";
|
||||
optionsEnumArray[options++] = ViewMode;
|
||||
|
||||
// If viewing ALL chats, hide “Mute Chat”
|
||||
if (mode != graphics::MessageRenderer::ThreadMode::ALL && mode != graphics::MessageRenderer::ThreadMode::DIRECT) {
|
||||
const uint8_t chIndex = (threadChannel != 0) ? (uint8_t)threadChannel : channels.getPrimaryIndex();
|
||||
auto &chan = channels.getByIndex(chIndex);
|
||||
|
||||
optionsArray[options] = chan.settings.module_settings.is_muted ? "Unmute Channel" : "Mute Channel";
|
||||
optionsEnumArray[options++] = MuteChannel;
|
||||
}
|
||||
|
||||
// Delete submenu
|
||||
optionsArray[options] = "Delete";
|
||||
optionsEnumArray[options++] = 900;
|
||||
@@ -512,14 +502,6 @@ void menuHandler::messageResponseMenu()
|
||||
menuHandler::menuQueue = menuHandler::reply_menu;
|
||||
screen->runNow();
|
||||
|
||||
} else if (selected == MuteChannel) {
|
||||
const uint8_t chIndex = (ch != 0) ? (uint8_t)ch : channels.getPrimaryIndex();
|
||||
auto &chan = channels.getByIndex(chIndex);
|
||||
if (chan.settings.has_module_settings) {
|
||||
chan.settings.module_settings.is_muted = !chan.settings.module_settings.is_muted;
|
||||
nodeDB->saveToDisk();
|
||||
}
|
||||
|
||||
// Delete submenu
|
||||
} else if (selected == 900) {
|
||||
menuHandler::menuQueue = menuHandler::delete_messages_menu;
|
||||
@@ -1840,7 +1822,7 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
|
||||
static const ScreenColorOption colorOptions[] = {
|
||||
{"Back", OptionsAction::Back},
|
||||
{"Default", OptionsAction::Select, ScreenColor(0, 0, 0, true)},
|
||||
{"Meshtastic Green", OptionsAction::Select, ScreenColor(0x67, 0xEA, 0x94)},
|
||||
{"Meshtastic Green", OptionsAction::Select, ScreenColor(103, 234, 148)},
|
||||
{"Yellow", OptionsAction::Select, ScreenColor(255, 255, 128)},
|
||||
{"Red", OptionsAction::Select, ScreenColor(255, 64, 64)},
|
||||
{"Orange", OptionsAction::Select, ScreenColor(255, 160, 20)},
|
||||
@@ -1890,7 +1872,7 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
|
||||
#ifdef TFT_MESH_OVERRIDE
|
||||
TFT_MESH = TFT_MESH_OVERRIDE;
|
||||
#else
|
||||
TFT_MESH = COLOR565(255, 255, 128);
|
||||
TFT_MESH = COLOR565(0x67, 0xEA, 0x94);
|
||||
#endif
|
||||
} else {
|
||||
TFT_MESH = COLOR565(r, g, b);
|
||||
|
||||
@@ -37,9 +37,6 @@ bool ButtonThread::initButton(const ButtonConfig &config)
|
||||
_activeLow = config.activeLow;
|
||||
_touchQuirk = config.touchQuirk;
|
||||
_intRoutine = config.intRoutine;
|
||||
_pressHandler = config.onPress;
|
||||
_releaseHandler = config.onRelease;
|
||||
_suppressLeadUp = config.suppressLeadUpSound;
|
||||
_longLongPress = config.longLongPress;
|
||||
|
||||
userButton = OneButton(config.pinNumber, config.activeLow, config.activePullup);
|
||||
@@ -136,8 +133,6 @@ int32_t ButtonThread::runOnce()
|
||||
|
||||
// Detect start of button press
|
||||
if (buttonCurrentlyPressed && !buttonWasPressed) {
|
||||
if (_pressHandler)
|
||||
_pressHandler();
|
||||
buttonPressStartTime = millis();
|
||||
leadUpPlayed = false;
|
||||
leadUpSequenceActive = false;
|
||||
@@ -145,7 +140,7 @@ int32_t ButtonThread::runOnce()
|
||||
}
|
||||
|
||||
// Progressive lead-up sound system
|
||||
if (!_suppressLeadUp && buttonCurrentlyPressed && (millis() - buttonPressStartTime) >= BUTTON_LEADUP_MS) {
|
||||
if (buttonCurrentlyPressed && (millis() - buttonPressStartTime) >= BUTTON_LEADUP_MS) {
|
||||
|
||||
// Start the progressive sequence if not already active
|
||||
if (!leadUpSequenceActive) {
|
||||
@@ -165,8 +160,6 @@ int32_t ButtonThread::runOnce()
|
||||
|
||||
// Reset when button is released
|
||||
if (!buttonCurrentlyPressed && buttonWasPressed) {
|
||||
if (_releaseHandler)
|
||||
_releaseHandler();
|
||||
leadUpSequenceActive = false;
|
||||
resetLeadUpSequence();
|
||||
}
|
||||
@@ -248,21 +241,7 @@ int32_t ButtonThread::runOnce()
|
||||
this->notifyObservers(&evt);
|
||||
playComboTune();
|
||||
break;
|
||||
#if !HAS_SCREEN
|
||||
case 4:
|
||||
if (moduleConfig.external_notification.enabled && externalNotificationModule) {
|
||||
externalNotificationModule->setMute(!externalNotificationModule->getMute());
|
||||
IF_SCREEN(if (!externalNotificationModule->getMute()) externalNotificationModule->stopNow();)
|
||||
if (externalNotificationModule->getMute()) {
|
||||
LOG_INFO("Temporarily Muted");
|
||||
play4ClickDown(); // Disable tone
|
||||
} else {
|
||||
LOG_INFO("Unmuted");
|
||||
play4ClickUp(); // Enable tone
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
// No valid multipress action
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -13,9 +13,6 @@ struct ButtonConfig {
|
||||
bool activePullup = true;
|
||||
uint32_t pullupSense = 0;
|
||||
voidFuncPtr intRoutine = nullptr;
|
||||
voidFuncPtr onPress = nullptr; // Optional edge callbacks
|
||||
voidFuncPtr onRelease = nullptr; // Optional edge callbacks
|
||||
bool suppressLeadUpSound = false;
|
||||
input_broker_event singlePress = INPUT_BROKER_NONE;
|
||||
input_broker_event longPress = INPUT_BROKER_NONE;
|
||||
uint16_t longPressTime = 500;
|
||||
@@ -97,9 +94,6 @@ class ButtonThread : public Observable<const InputEvent *>, public concurrency::
|
||||
input_broker_event _shortLong = INPUT_BROKER_NONE;
|
||||
|
||||
voidFuncPtr _intRoutine = nullptr;
|
||||
voidFuncPtr _pressHandler = nullptr;
|
||||
voidFuncPtr _releaseHandler = nullptr;
|
||||
bool _suppressLeadUp = false;
|
||||
uint16_t _longPressTime = 500;
|
||||
uint16_t _longLongPressTime = 3900;
|
||||
int _pinNum = 0;
|
||||
|
||||
@@ -39,7 +39,6 @@ enum input_broker_event {
|
||||
#define INPUT_BROKER_MSG_FN_SYMBOL_ON 0xf1
|
||||
#define INPUT_BROKER_MSG_FN_SYMBOL_OFF 0xf2
|
||||
#define INPUT_BROKER_MSG_BLUETOOTH_TOGGLE 0xAA
|
||||
#define INPUT_BROKER_MSG_VOICEMEMO 0xAD
|
||||
#define INPUT_BROKER_MSG_TAB 0x09
|
||||
#define INPUT_BROKER_MSG_EMOTE_LIST 0x8F
|
||||
|
||||
|
||||
@@ -28,18 +28,18 @@ static unsigned char TCA8418TapMap[_TCA8418_NUM_KEYS][13] = {
|
||||
};
|
||||
|
||||
static unsigned char TCA8418LongPressMap[_TCA8418_NUM_KEYS] = {
|
||||
Key::ESC, // 1
|
||||
Key::UP, // 2
|
||||
Key::NONE, // 3
|
||||
Key::LEFT, // 4
|
||||
Key::NONE, // 5
|
||||
Key::RIGHT, // 6
|
||||
Key::NONE, // 7
|
||||
Key::DOWN, // 8
|
||||
Key::NONE, // 9
|
||||
Key::BSP, // *
|
||||
Key::VOICEMEMO, // 0
|
||||
Key::NONE, // #
|
||||
Key::ESC, // 1
|
||||
Key::UP, // 2
|
||||
Key::NONE, // 3
|
||||
Key::LEFT, // 4
|
||||
Key::NONE, // 5
|
||||
Key::RIGHT, // 6
|
||||
Key::NONE, // 7
|
||||
Key::DOWN, // 8
|
||||
Key::NONE, // 9
|
||||
Key::BSP, // *
|
||||
Key::NONE, // 0
|
||||
Key::NONE, // #
|
||||
};
|
||||
|
||||
TCA8418Keyboard::TCA8418Keyboard()
|
||||
|
||||
@@ -25,7 +25,6 @@ class TCA8418KeyboardBase
|
||||
BT_TOGGLE = 0xAA,
|
||||
GPS_TOGGLE = 0x9E,
|
||||
MUTE_TOGGLE = 0xAC,
|
||||
VOICEMEMO = 0xAD,
|
||||
SEND_PING = 0xAF,
|
||||
BL_TOGGLE = 0xAB
|
||||
};
|
||||
|
||||
@@ -56,8 +56,8 @@ static unsigned char TDeckProTapMap[_TCA8418_NUM_KEYS][5] = {
|
||||
{0x00, 0x00, 0x00}, // Ent, $, m, n, b, v, c, x, z, alt
|
||||
{0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00},
|
||||
{0x20, 0x00, Key::VOICEMEMO},
|
||||
{Key::VOICEMEMO, 0x00, 0x00},
|
||||
{0x20, 0x00, 0x00},
|
||||
{0x00, 0x00, '0'},
|
||||
{0x00, 0x00, 0x00} // R_Shift, sym, space, mic, L_Shift
|
||||
};
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ static unsigned char TLoraPagerTapMap[_TCA8418_NUM_KEYS][3] = {{'q', 'Q', '1'},
|
||||
{'z', 'Z', '_'},
|
||||
{'x', 'X', '$'},
|
||||
{'c', 'C', ';'},
|
||||
{'v', 'V', Key::VOICEMEMO},
|
||||
{'v', 'V', '?'},
|
||||
{'b', 'B', '!'},
|
||||
{'n', 'N', ','},
|
||||
{'m', 'M', '.'},
|
||||
|
||||
+1
-28
@@ -163,16 +163,6 @@ int32_t KbI2cBase::runOnce()
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 'v': // sym v - voice memo
|
||||
if (is_sym) {
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = INPUT_BROKER_MSG_VOICEMEMO;
|
||||
is_sym = false; // reset sym state after second keypress
|
||||
} else {
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = key.key;
|
||||
}
|
||||
break;
|
||||
case 0x13: // Code scanner says the SYM key is 0x13
|
||||
is_sym = !is_sym;
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
@@ -380,10 +370,6 @@ int32_t KbI2cBase::runOnce()
|
||||
|
||||
if (i2cBus->available()) {
|
||||
char c = i2cBus->read();
|
||||
// Debug: log every key press
|
||||
if (c != 0x00) {
|
||||
LOG_DEBUG("T-Deck KB: key=0x%02X ('%c'), is_sym=%d", (uint8_t)c, (c >= 0x20 && c < 0x7f) ? c : '?', is_sym);
|
||||
}
|
||||
InputEvent e = {};
|
||||
e.inputEvent = INPUT_BROKER_NONE;
|
||||
e.source = this->_originName;
|
||||
@@ -457,17 +443,6 @@ int32_t KbI2cBase::runOnce()
|
||||
e.kbchar = c;
|
||||
}
|
||||
break;
|
||||
case 0x76: // letter v. voice memo trigger
|
||||
if (is_sym) {
|
||||
is_sym = false;
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = INPUT_BROKER_MSG_VOICEMEMO;
|
||||
LOG_DEBUG("T-Deck: Sym+V pressed, sending VOICEMEMO 0x%02X", INPUT_BROKER_MSG_VOICEMEMO);
|
||||
} else {
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = c;
|
||||
}
|
||||
break;
|
||||
case 0x1b: // ESC
|
||||
e.inputEvent = INPUT_BROKER_CANCEL;
|
||||
break;
|
||||
@@ -491,11 +466,9 @@ int32_t KbI2cBase::runOnce()
|
||||
e.inputEvent = INPUT_BROKER_RIGHT;
|
||||
e.kbchar = 0;
|
||||
break;
|
||||
case 0x3F: // Sym key on some T-Deck variants (sends '?')
|
||||
case 0xc: // Modifier key: 0xc is alt+c (Other options could be: 0xea = shift+mic button or 0x4 shift+$(speaker))
|
||||
case 0xc: // Modifier key: 0xc is alt+c (Other options could be: 0xea = shift+mic button or 0x4 shift+$(speaker))
|
||||
// toggle moddifiers button.
|
||||
is_sym = !is_sym;
|
||||
LOG_DEBUG("T-Deck: Modifier key pressed, is_sym now=%d", is_sym);
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = is_sym ? INPUT_BROKER_MSG_FN_SYMBOL_ON // send 0xf1 to tell CannedMessages to display that the
|
||||
: INPUT_BROKER_MSG_FN_SYMBOL_OFF; // modifier key is active
|
||||
|
||||
+4
-30
@@ -107,10 +107,6 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr;
|
||||
|
||||
#if defined(BUTTON_PIN_TOUCH)
|
||||
ButtonThread *TouchButtonThread = nullptr;
|
||||
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
|
||||
static bool touchBacklightWasOn = false;
|
||||
static bool touchBacklightActive = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
|
||||
@@ -209,7 +205,7 @@ ScanI2C::FoundDevice rgb_found = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE,
|
||||
/// The I2C address of our Air Quality Indicator (if found)
|
||||
ScanI2C::DeviceAddress aqi_found = ScanI2C::ADDRESS_NONE;
|
||||
|
||||
#ifdef HAS_DRV2605
|
||||
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
||||
Adafruit_DRV2605 drv;
|
||||
#endif
|
||||
|
||||
@@ -799,6 +795,7 @@ void setup()
|
||||
// We do this as early as possible because this loads preferences from flash
|
||||
// but we need to do this after main cpu init (esp32setup), because we need the random seed set
|
||||
nodeDB = new NodeDB;
|
||||
|
||||
#if HAS_TFT
|
||||
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
tftSetup();
|
||||
@@ -844,12 +841,7 @@ void setup()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAS_DRV2605
|
||||
#if defined(PIN_DRV_EN)
|
||||
pinMode(PIN_DRV_EN, OUTPUT);
|
||||
digitalWrite(PIN_DRV_EN, HIGH);
|
||||
delay(10);
|
||||
#endif
|
||||
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
||||
drv.begin();
|
||||
drv.selectLibrary(1);
|
||||
// I2C trigger by sending 'go' command
|
||||
@@ -885,7 +877,7 @@ void setup()
|
||||
SPI.begin();
|
||||
#endif
|
||||
#else
|
||||
// ESP32
|
||||
// ESP32
|
||||
#if defined(HW_SPI1_DEVICE)
|
||||
SPI1.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||
LOG_DEBUG("SPI1.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
||||
@@ -1054,24 +1046,6 @@ void setup()
|
||||
};
|
||||
touchConfig.singlePress = INPUT_BROKER_NONE;
|
||||
touchConfig.longPress = INPUT_BROKER_BACK;
|
||||
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
|
||||
// On T-Echo Plus the touch pad should only drive the backlight, not UI navigation/sounds
|
||||
touchConfig.longPress = INPUT_BROKER_NONE;
|
||||
touchConfig.suppressLeadUpSound = true;
|
||||
touchConfig.onPress = []() {
|
||||
touchBacklightWasOn = uiconfig.screen_brightness == 1;
|
||||
if (!touchBacklightWasOn) {
|
||||
digitalWrite(PIN_EINK_EN, HIGH);
|
||||
}
|
||||
touchBacklightActive = true;
|
||||
};
|
||||
touchConfig.onRelease = []() {
|
||||
if (touchBacklightActive && !touchBacklightWasOn) {
|
||||
digitalWrite(PIN_EINK_EN, LOW);
|
||||
}
|
||||
touchBacklightActive = false;
|
||||
};
|
||||
#endif
|
||||
TouchButtonThread->initButton(touchConfig);
|
||||
#endif
|
||||
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ extern bool eink_found;
|
||||
extern bool pmu_found;
|
||||
extern bool isUSBPowered;
|
||||
|
||||
#ifdef HAS_DRV2605
|
||||
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
||||
#include <Adafruit_DRV2605.h>
|
||||
extern Adafruit_DRV2605 drv;
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "configuration.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "meshUtils.h"
|
||||
#include "modules/TextMessageModule.h"
|
||||
#if !MESHTASTIC_EXCLUDE_TRACEROUTE
|
||||
#include "modules/TraceRouteModule.h"
|
||||
#endif
|
||||
@@ -36,10 +35,6 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
||||
return true; // we handled it, so stop processing
|
||||
}
|
||||
|
||||
if (!seenRecently && !wasUpgraded && textMessageModule) {
|
||||
seenRecently = textMessageModule->recentlySeen(p->id);
|
||||
}
|
||||
|
||||
if (seenRecently) {
|
||||
printPacket("Ignore dupe incoming msg", p);
|
||||
rxDupe++;
|
||||
|
||||
@@ -238,6 +238,12 @@ bool NextHopRouter::stopRetransmission(GlobalPacketId key)
|
||||
// call to startRetransmission.
|
||||
packetPool.release(p);
|
||||
|
||||
#ifdef USE_ADAPTIVE_CODING_RATE
|
||||
if (iface) {
|
||||
iface->clearAdaptiveCodingRateState(getFrom(p), p->id);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
|
||||
@@ -246,9 +246,7 @@ uint32_t RadioInterface::getPacketTime(const meshtastic_MeshPacket *p, bool rece
|
||||
/** The delay to use for retransmitting dropped packets */
|
||||
uint32_t RadioInterface::getRetransmissionMsec(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
size_t numbytes = p->which_payload_variant == meshtastic_MeshPacket_decoded_tag
|
||||
? pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded)
|
||||
: p->encrypted.size + MESHTASTIC_HEADER_LENGTH;
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded);
|
||||
uint32_t packetAirtime = getPacketTime(numbytes + sizeof(PacketHeader));
|
||||
// Make sure enough time has elapsed for this packet to be sent and an ACK is received.
|
||||
// LOG_DEBUG("Waiting for flooding message with airtime %d and slotTime is %d", packetAirtime, slotTimeMsec);
|
||||
@@ -620,6 +618,13 @@ void RadioInterface::applyModemConfig()
|
||||
slotTimeMsec = computeSlotTimeMsec();
|
||||
preambleTimeMsec = preambleLength * (pow_of_2(sf) / bw);
|
||||
|
||||
#ifdef USE_ADAPTIVE_CODING_RATE
|
||||
if (adaptiveCrOverride >= 5 && adaptiveCrOverride <= 8 && cr != adaptiveCrOverride) {
|
||||
cr = adaptiveCrOverride;
|
||||
LOG_DEBUG("Adaptive coding rate override set to %u", cr);
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_INFO("Radio freq=%.3f, config.lora.frequency_offset=%.3f", freq, loraConfig.frequency_offset);
|
||||
LOG_INFO("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d", myRegion->name, channelName, loraConfig.modem_preset,
|
||||
channel_num, power);
|
||||
@@ -732,3 +737,70 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
|
||||
sendingPacket = p;
|
||||
return p->encrypted.size + sizeof(PacketHeader);
|
||||
}
|
||||
|
||||
#ifdef USE_ADAPTIVE_CODING_RATE
|
||||
uint8_t RadioInterface::computeAdaptiveCodingRate(uint8_t attempt) const
|
||||
{
|
||||
if (attempt <= 1) {
|
||||
return 5; // Attempt 1: 4/5
|
||||
}
|
||||
if (attempt == 2) {
|
||||
return 7; // Attempt 2: 4/7
|
||||
}
|
||||
return 8; // Attempt 3+: 4/8
|
||||
}
|
||||
|
||||
uint64_t RadioInterface::adaptiveKey(NodeNum from, PacketId id) const
|
||||
{
|
||||
return (static_cast<uint64_t>(from) << 32) | id;
|
||||
}
|
||||
|
||||
void RadioInterface::pruneAdaptiveAttempts(uint32_t now)
|
||||
{
|
||||
const uint32_t expiryMsec = 5 * 60 * 1000UL; // drop state after 5 minutes
|
||||
for (auto it = adaptiveAttempts.begin(); it != adaptiveAttempts.end();) {
|
||||
if (now - it->second.lastUseMsec > expiryMsec) {
|
||||
it = adaptiveAttempts.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t RadioInterface::recordAdaptiveAttempt(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
const uint32_t now = millis();
|
||||
pruneAdaptiveAttempts(now);
|
||||
|
||||
const uint64_t key = adaptiveKey(getFrom(p), p->id);
|
||||
auto &state = adaptiveAttempts[key];
|
||||
if (state.attempts < UINT8_MAX) {
|
||||
state.attempts++;
|
||||
}
|
||||
state.lastUseMsec = now;
|
||||
return state.attempts;
|
||||
}
|
||||
|
||||
bool RadioInterface::applyAdaptiveCodingRate(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
const uint8_t attempt = recordAdaptiveAttempt(p);
|
||||
const uint8_t desiredCr = computeAdaptiveCodingRate(attempt);
|
||||
if (desiredCr < 5 || desiredCr > 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
adaptiveCrOverride = desiredCr;
|
||||
if (cr != desiredCr) {
|
||||
cr = desiredCr;
|
||||
reconfigure();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void RadioInterface::clearAdaptiveCodingRateState(NodeNum from, PacketId id)
|
||||
{
|
||||
adaptiveAttempts.erase(adaptiveKey(from, id));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include "PointerQueue.h"
|
||||
#include "airtime.h"
|
||||
#include "error.h"
|
||||
#ifdef USE_ADAPTIVE_CODING_RATE
|
||||
#include <unordered_map>
|
||||
#endif
|
||||
|
||||
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
|
||||
|
||||
@@ -220,6 +223,11 @@ class RadioInterface
|
||||
// Whether we use the default frequency slot given our LoRa config (region and modem preset)
|
||||
static bool uses_default_frequency_slot;
|
||||
|
||||
#ifdef USE_ADAPTIVE_CODING_RATE
|
||||
/** Clear adaptive coding rate tracking for a completed packet id */
|
||||
void clearAdaptiveCodingRateState(NodeNum from, PacketId id);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
int8_t power = 17; // Set by applyModemConfig()
|
||||
|
||||
@@ -250,6 +258,20 @@ class RadioInterface
|
||||
*/
|
||||
virtual void saveChannelNum(uint32_t savedChannelNum);
|
||||
|
||||
#ifdef USE_ADAPTIVE_CODING_RATE
|
||||
bool applyAdaptiveCodingRate(const meshtastic_MeshPacket *p);
|
||||
struct AdaptiveAttemptState {
|
||||
uint8_t attempts = 0;
|
||||
uint32_t lastUseMsec = 0;
|
||||
};
|
||||
std::unordered_map<uint64_t, AdaptiveAttemptState> adaptiveAttempts;
|
||||
uint8_t adaptiveCrOverride = 0;
|
||||
uint8_t recordAdaptiveAttempt(const meshtastic_MeshPacket *p);
|
||||
uint8_t computeAdaptiveCodingRate(uint8_t attempt) const;
|
||||
void pruneAdaptiveAttempts(uint32_t now);
|
||||
uint64_t adaptiveKey(NodeNum from, PacketId id) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
/**
|
||||
* Convert our modemConfig enum into wf, sf, etc...
|
||||
|
||||
@@ -540,6 +540,9 @@ bool RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
|
||||
packetPool.release(txp);
|
||||
return false;
|
||||
} else {
|
||||
#ifdef USE_ADAPTIVE_CODING_RATE
|
||||
applyAdaptiveCodingRate(txp);
|
||||
#endif
|
||||
configHardwareForSend(); // must be after setStandby
|
||||
|
||||
size_t numbytes = beginSending(txp);
|
||||
|
||||
@@ -53,21 +53,13 @@ template <typename T> bool SX126xInterface<T>::init()
|
||||
#endif
|
||||
|
||||
#if defined(USE_GC1109_PA)
|
||||
// GC1109 FEM chip initialization
|
||||
// See variant.h for full pin mapping and control logic documentation
|
||||
|
||||
// VFEM_Ctrl (LORA_PA_POWER): Power enable for GC1109 LDO (always on)
|
||||
pinMode(LORA_PA_POWER, OUTPUT);
|
||||
digitalWrite(LORA_PA_POWER, HIGH);
|
||||
|
||||
// CSD (LORA_PA_EN): Chip enable - must be HIGH to enable GC1109 for both RX and TX
|
||||
pinMode(LORA_PA_EN, OUTPUT);
|
||||
digitalWrite(LORA_PA_EN, HIGH);
|
||||
|
||||
// CPS (LORA_PA_TX_EN): PA mode select - HIGH enables full PA during TX, LOW for RX (don't care)
|
||||
// Note: TX/RX path switching (CTX) is handled by DIO2 via SX126X_DIO2_AS_RF_SWITCH
|
||||
digitalWrite(LORA_PA_EN, LOW);
|
||||
pinMode(LORA_PA_TX_EN, OUTPUT);
|
||||
digitalWrite(LORA_PA_TX_EN, LOW); // Start in RX-ready state
|
||||
digitalWrite(LORA_PA_TX_EN, LOW);
|
||||
#endif
|
||||
|
||||
#ifdef RF95_FAN_EN
|
||||
@@ -385,13 +377,13 @@ template <typename T> bool SX126xInterface<T>::sleep()
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Control PA mode for GC1109 FEM - CPS pin selects full PA (txon=true) or bypass mode (txon=false) */
|
||||
/** Some boards require GPIO control of tx vs rx paths */
|
||||
template <typename T> void SX126xInterface<T>::setTransmitEnable(bool txon)
|
||||
{
|
||||
#if defined(USE_GC1109_PA)
|
||||
digitalWrite(LORA_PA_POWER, HIGH); // Ensure LDO is on
|
||||
digitalWrite(LORA_PA_EN, HIGH); // CSD=1: Chip enabled
|
||||
digitalWrite(LORA_PA_TX_EN, txon ? 1 : 0); // CPS: 1=full PA, 0=bypass (for RX, CPS is don't care)
|
||||
digitalWrite(LORA_PA_POWER, HIGH);
|
||||
digitalWrite(LORA_PA_EN, HIGH);
|
||||
digitalWrite(LORA_PA_TX_EN, txon ? 1 : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,6 @@ PB_BIND(meshtastic_AdminMessage, meshtastic_AdminMessage, 2)
|
||||
PB_BIND(meshtastic_AdminMessage_InputEvent, meshtastic_AdminMessage_InputEvent, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_AdminMessage_OTAEvent, meshtastic_AdminMessage_OTAEvent, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_HamParameters, meshtastic_HamParameters, AUTO)
|
||||
|
||||
|
||||
|
||||
@@ -113,17 +113,6 @@ typedef struct _meshtastic_AdminMessage_InputEvent {
|
||||
uint16_t touch_y;
|
||||
} meshtastic_AdminMessage_InputEvent;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(32) meshtastic_AdminMessage_OTAEvent_ota_hash_t;
|
||||
/* User is requesting an over the air update.
|
||||
Node will reboot into the OTA loader */
|
||||
typedef struct _meshtastic_AdminMessage_OTAEvent {
|
||||
/* Tell the node to reboot into OTA mode for firmware update via BLE or WiFi (ESP32 only for now) */
|
||||
meshtastic_OTAMode reboot_ota_mode;
|
||||
/* A 32 byte hash of the OTA firmware.
|
||||
Used to verify the integrity of the firmware before applying an update. */
|
||||
meshtastic_AdminMessage_OTAEvent_ota_hash_t ota_hash;
|
||||
} meshtastic_AdminMessage_OTAEvent;
|
||||
|
||||
/* Parameters for setting up Meshtastic for ameteur radio usage */
|
||||
typedef struct _meshtastic_HamParameters {
|
||||
/* Amateur radio call sign, eg. KD2ABC */
|
||||
@@ -299,8 +288,6 @@ typedef struct _meshtastic_AdminMessage {
|
||||
/* Tell the node to reset the nodedb.
|
||||
When true, favorites are preserved through reset. */
|
||||
bool nodedb_reset;
|
||||
/* Tell the node to reset into the OTA Loader */
|
||||
meshtastic_AdminMessage_OTAEvent ota_request;
|
||||
};
|
||||
/* The node generates this key and sends it with any get_x_response packets.
|
||||
The client MUST include the same key with any set_x commands. Key expires after 300 seconds.
|
||||
@@ -342,8 +329,6 @@ extern "C" {
|
||||
#define meshtastic_AdminMessage_payload_variant_reboot_ota_mode_ENUMTYPE meshtastic_OTAMode
|
||||
|
||||
|
||||
#define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_ENUMTYPE meshtastic_OTAMode
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -353,14 +338,12 @@ extern "C" {
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_AdminMessage_init_default {0, {0}, {0, {0}}}
|
||||
#define meshtastic_AdminMessage_InputEvent_init_default {0, 0, 0, 0}
|
||||
#define meshtastic_AdminMessage_OTAEvent_init_default {_meshtastic_OTAMode_MIN, {0, {0}}}
|
||||
#define meshtastic_HamParameters_init_default {"", 0, 0, ""}
|
||||
#define meshtastic_NodeRemoteHardwarePinsResponse_init_default {0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}}
|
||||
#define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0, 0}
|
||||
#define meshtastic_KeyVerificationAdmin_init_default {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0}
|
||||
#define meshtastic_AdminMessage_init_zero {0, {0}, {0, {0}}}
|
||||
#define meshtastic_AdminMessage_InputEvent_init_zero {0, 0, 0, 0}
|
||||
#define meshtastic_AdminMessage_OTAEvent_init_zero {_meshtastic_OTAMode_MIN, {0, {0}}}
|
||||
#define meshtastic_HamParameters_init_zero {"", 0, 0, ""}
|
||||
#define meshtastic_NodeRemoteHardwarePinsResponse_init_zero {0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}}
|
||||
#define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0, 0}
|
||||
@@ -371,8 +354,6 @@ extern "C" {
|
||||
#define meshtastic_AdminMessage_InputEvent_kb_char_tag 2
|
||||
#define meshtastic_AdminMessage_InputEvent_touch_x_tag 3
|
||||
#define meshtastic_AdminMessage_InputEvent_touch_y_tag 4
|
||||
#define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_tag 1
|
||||
#define meshtastic_AdminMessage_OTAEvent_ota_hash_tag 2
|
||||
#define meshtastic_HamParameters_call_sign_tag 1
|
||||
#define meshtastic_HamParameters_tx_power_tag 2
|
||||
#define meshtastic_HamParameters_frequency_tag 3
|
||||
@@ -441,7 +422,6 @@ extern "C" {
|
||||
#define meshtastic_AdminMessage_shutdown_seconds_tag 98
|
||||
#define meshtastic_AdminMessage_factory_reset_config_tag 99
|
||||
#define meshtastic_AdminMessage_nodedb_reset_tag 100
|
||||
#define meshtastic_AdminMessage_ota_request_tag 102
|
||||
#define meshtastic_AdminMessage_session_passkey_tag 101
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
@@ -501,8 +481,7 @@ X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_seconds,reboot_second
|
||||
X(a, STATIC, ONEOF, INT32, (payload_variant,shutdown_seconds,shutdown_seconds), 98) \
|
||||
X(a, STATIC, ONEOF, INT32, (payload_variant,factory_reset_config,factory_reset_config), 99) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,nodedb_reset,nodedb_reset), 100) \
|
||||
X(a, STATIC, SINGULAR, BYTES, session_passkey, 101) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ota_request,ota_request), 102)
|
||||
X(a, STATIC, SINGULAR, BYTES, session_passkey, 101)
|
||||
#define meshtastic_AdminMessage_CALLBACK NULL
|
||||
#define meshtastic_AdminMessage_DEFAULT NULL
|
||||
#define meshtastic_AdminMessage_payload_variant_get_channel_response_MSGTYPE meshtastic_Channel
|
||||
@@ -523,7 +502,6 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ota_request,ota_request), 10
|
||||
#define meshtastic_AdminMessage_payload_variant_store_ui_config_MSGTYPE meshtastic_DeviceUIConfig
|
||||
#define meshtastic_AdminMessage_payload_variant_add_contact_MSGTYPE meshtastic_SharedContact
|
||||
#define meshtastic_AdminMessage_payload_variant_key_verification_MSGTYPE meshtastic_KeyVerificationAdmin
|
||||
#define meshtastic_AdminMessage_payload_variant_ota_request_MSGTYPE meshtastic_AdminMessage_OTAEvent
|
||||
|
||||
#define meshtastic_AdminMessage_InputEvent_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, event_code, 1) \
|
||||
@@ -533,12 +511,6 @@ X(a, STATIC, SINGULAR, UINT32, touch_y, 4)
|
||||
#define meshtastic_AdminMessage_InputEvent_CALLBACK NULL
|
||||
#define meshtastic_AdminMessage_InputEvent_DEFAULT NULL
|
||||
|
||||
#define meshtastic_AdminMessage_OTAEvent_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UENUM, reboot_ota_mode, 1) \
|
||||
X(a, STATIC, SINGULAR, BYTES, ota_hash, 2)
|
||||
#define meshtastic_AdminMessage_OTAEvent_CALLBACK NULL
|
||||
#define meshtastic_AdminMessage_OTAEvent_DEFAULT NULL
|
||||
|
||||
#define meshtastic_HamParameters_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, STRING, call_sign, 1) \
|
||||
X(a, STATIC, SINGULAR, INT32, tx_power, 2) \
|
||||
@@ -572,7 +544,6 @@ X(a, STATIC, OPTIONAL, UINT32, security_number, 4)
|
||||
|
||||
extern const pb_msgdesc_t meshtastic_AdminMessage_msg;
|
||||
extern const pb_msgdesc_t meshtastic_AdminMessage_InputEvent_msg;
|
||||
extern const pb_msgdesc_t meshtastic_AdminMessage_OTAEvent_msg;
|
||||
extern const pb_msgdesc_t meshtastic_HamParameters_msg;
|
||||
extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePinsResponse_msg;
|
||||
extern const pb_msgdesc_t meshtastic_SharedContact_msg;
|
||||
@@ -581,7 +552,6 @@ extern const pb_msgdesc_t meshtastic_KeyVerificationAdmin_msg;
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define meshtastic_AdminMessage_fields &meshtastic_AdminMessage_msg
|
||||
#define meshtastic_AdminMessage_InputEvent_fields &meshtastic_AdminMessage_InputEvent_msg
|
||||
#define meshtastic_AdminMessage_OTAEvent_fields &meshtastic_AdminMessage_OTAEvent_msg
|
||||
#define meshtastic_HamParameters_fields &meshtastic_HamParameters_msg
|
||||
#define meshtastic_NodeRemoteHardwarePinsResponse_fields &meshtastic_NodeRemoteHardwarePinsResponse_msg
|
||||
#define meshtastic_SharedContact_fields &meshtastic_SharedContact_msg
|
||||
@@ -590,7 +560,6 @@ extern const pb_msgdesc_t meshtastic_KeyVerificationAdmin_msg;
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define MESHTASTIC_MESHTASTIC_ADMIN_PB_H_MAX_SIZE meshtastic_AdminMessage_size
|
||||
#define meshtastic_AdminMessage_InputEvent_size 14
|
||||
#define meshtastic_AdminMessage_OTAEvent_size 36
|
||||
#define meshtastic_AdminMessage_size 511
|
||||
#define meshtastic_HamParameters_size 31
|
||||
#define meshtastic_KeyVerificationAdmin_size 25
|
||||
|
||||
@@ -92,8 +92,8 @@ typedef enum _meshtastic_HardwareModel {
|
||||
Less common/prototype boards listed here (needs one more byte over the air)
|
||||
--------------------------------------------------------------------------- */
|
||||
meshtastic_HardwareModel_LORA_RELAY_V1 = 32,
|
||||
/* T-Echo Plus device from LilyGo */
|
||||
meshtastic_HardwareModel_T_ECHO_PLUS = 33,
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_HardwareModel_NRF52840DK = 33,
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_HardwareModel_PPR = 34,
|
||||
/* TODO: REPLACE */
|
||||
@@ -475,10 +475,7 @@ typedef enum _meshtastic_Routing_Error {
|
||||
meshtastic_Routing_Error_ADMIN_PUBLIC_KEY_UNAUTHORIZED = 37,
|
||||
/* Airtime fairness rate limit exceeded for a packet
|
||||
This typically enforced per portnum and is used to prevent a single node from monopolizing airtime */
|
||||
meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED = 38,
|
||||
/* PKI encryption failed, due to no public key for the remote node
|
||||
This is different from PKI_UNKNOWN_PUBKEY which indicates a failure upon receiving a packet */
|
||||
meshtastic_Routing_Error_PKI_SEND_FAIL_PUBLIC_KEY = 39
|
||||
meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED = 38
|
||||
} meshtastic_Routing_Error;
|
||||
|
||||
/* Enum of message types */
|
||||
@@ -1354,12 +1351,8 @@ extern "C" {
|
||||
#define _meshtastic_Position_AltSource_ARRAYSIZE ((meshtastic_Position_AltSource)(meshtastic_Position_AltSource_ALT_BAROMETRIC+1))
|
||||
|
||||
#define _meshtastic_Routing_Error_MIN meshtastic_Routing_Error_NONE
|
||||
#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_PKI_SEND_FAIL_PUBLIC_KEY
|
||||
#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_PKI_SEND_FAIL_PUBLIC_KEY+1))
|
||||
|
||||
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE
|
||||
#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_Routing_Error_MAX meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED
|
||||
#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED+1))
|
||||
|
||||
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE
|
||||
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MAX meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF
|
||||
|
||||
@@ -89,8 +89,9 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
void handleGetCannedMessageModuleMessages(const meshtastic_MeshPacket &req, meshtastic_AdminMessage *response);
|
||||
void handleSetCannedMessageModuleMessages(const char *from_msg);
|
||||
|
||||
// Get current run state (used by VoiceMemoModule to avoid conflicts)
|
||||
#ifdef RAK14014
|
||||
cannedMessageModuleRunState getRunState() const { return runState; }
|
||||
#endif
|
||||
|
||||
// === Packet Interest Filter ===
|
||||
virtual bool wantPacket(const meshtastic_MeshPacket *p) override
|
||||
|
||||
@@ -168,7 +168,7 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
delay = EXT_NOTIFICATION_FAST_THREAD_MS;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_DRV2605
|
||||
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
||||
drv.go();
|
||||
#endif
|
||||
}
|
||||
@@ -283,7 +283,7 @@ void ExternalNotificationModule::setExternalState(uint8_t index, bool on)
|
||||
#ifdef UNPHONE
|
||||
unphone.rgb(red, green, blue);
|
||||
#endif
|
||||
#ifdef HAS_DRV2605
|
||||
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
||||
if (on) {
|
||||
drv.go();
|
||||
} else {
|
||||
@@ -319,7 +319,7 @@ void ExternalNotificationModule::stopNow()
|
||||
externalTurnedOn[i] = 0;
|
||||
}
|
||||
setIntervalFromNow(0);
|
||||
#ifdef HAS_DRV2605
|
||||
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
||||
drv.stop();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -87,9 +87,6 @@
|
||||
#if defined(USE_SX1280) && !MESHTASTIC_EXCLUDE_AUDIO
|
||||
#include "modules/esp32/AudioModule.h"
|
||||
#endif
|
||||
#if defined(HAS_I2S) && !MESHTASTIC_EXCLUDE_VOICEMEMO
|
||||
#include "modules/VoiceMemoModule.h"
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
|
||||
#include "modules/esp32/PaxcounterModule.h"
|
||||
#endif
|
||||
@@ -288,9 +285,6 @@ void setupModules()
|
||||
#if defined(USE_SX1280) && !MESHTASTIC_EXCLUDE_AUDIO
|
||||
audioModule = new AudioModule();
|
||||
#endif
|
||||
#if defined(HAS_I2S) && !MESHTASTIC_EXCLUDE_VOICEMEMO
|
||||
voiceMemoModule = new VoiceMemoModule();
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
|
||||
if (moduleConfig.has_paxcounter && moduleConfig.paxcounter.enabled) {
|
||||
paxcounterModule = new PaxcounterModule();
|
||||
|
||||
@@ -63,9 +63,9 @@
|
||||
SerialModule *serialModule;
|
||||
SerialModuleRadio *serialModuleRadio;
|
||||
|
||||
#if defined(TTGO_T_ECHO) || defined(TTGO_T_ECHO_PLUS) || defined(CANARYONE) || defined(MESHLINK) || \
|
||||
defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) || \
|
||||
defined(ELECROW_ThinkNode_M3) || defined(MUZI_BASE)
|
||||
#if defined(TTGO_T_ECHO) || defined(CANARYONE) || defined(MESHLINK) || defined(ELECROW_ThinkNode_M1) || \
|
||||
defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) || defined(ELECROW_ThinkNode_M3) || \
|
||||
defined(MUZI_BASE)
|
||||
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial")
|
||||
{
|
||||
api_type = TYPE_SERIAL;
|
||||
@@ -204,9 +204,8 @@ int32_t SerialModule::runOnce()
|
||||
Serial.begin(baud);
|
||||
Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
|
||||
}
|
||||
#elif !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && \
|
||||
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && \
|
||||
!defined(MUZI_BASE)
|
||||
#elif !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \
|
||||
!defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && !defined(MUZI_BASE)
|
||||
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
|
||||
#ifdef ARCH_RP2040
|
||||
Serial2.setFIFOSize(RX_BUFFER);
|
||||
@@ -262,7 +261,7 @@ int32_t SerialModule::runOnce()
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \
|
||||
#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \
|
||||
!defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && !defined(MUZI_BASE)
|
||||
else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) {
|
||||
processWXSerial();
|
||||
@@ -537,9 +536,9 @@ ParsedLine parseLine(const char *line)
|
||||
*/
|
||||
void SerialModule::processWXSerial()
|
||||
{
|
||||
#if !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && \
|
||||
!defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && !defined(ARCH_STM32WL) && !defined(MUZI_BASE)
|
||||
#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \
|
||||
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && \
|
||||
!defined(ARCH_STM32WL) && !defined(MUZI_BASE)
|
||||
static unsigned int lastAveraged = 0;
|
||||
static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded.
|
||||
static double dir_sum_sin = 0;
|
||||
|
||||
@@ -45,9 +45,9 @@ int SystemCommandsModule::handleInputEvent(const InputEvent *event)
|
||||
// Mute
|
||||
case INPUT_BROKER_MSG_MUTE_TOGGLE:
|
||||
if (moduleConfig.external_notification.enabled && externalNotificationModule) {
|
||||
externalNotificationModule->setMute(!externalNotificationModule->getMute());
|
||||
externalNotificationModule->setMute(externalNotificationModule->getMute());
|
||||
IF_SCREEN(if (!externalNotificationModule->getMute()) externalNotificationModule->stopNow(); screen->showSimpleBanner(
|
||||
externalNotificationModule->getMute() ? "Notifications\nDisabled" : "Notifications\nEnabled", 3000);)
|
||||
externalNotificationModule->getMute() ? "Notifications\nEnabled" : "Notifications\nDisabled", 3000);)
|
||||
}
|
||||
return 0;
|
||||
// Bluetooth
|
||||
|
||||
@@ -17,9 +17,6 @@ ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp
|
||||
auto &p = mp.decoded;
|
||||
LOG_INFO("Received text msg from=0x%0x, id=0x%x, msg=%.*s", mp.from, mp.id, p.payload.size, p.payload.bytes);
|
||||
#endif
|
||||
// add packet ID to the rolling list of packets
|
||||
textPacketList[textPacketListIndex] = mp.id;
|
||||
textPacketListIndex = (textPacketListIndex + 1) % TEXT_PACKET_LIST_SIZE;
|
||||
|
||||
// We only store/display messages destined for us.
|
||||
devicestate.rx_text_message = mp;
|
||||
@@ -50,13 +47,3 @@ bool TextMessageModule::wantPacket(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
return MeshService::isTextPayload(p);
|
||||
}
|
||||
|
||||
bool TextMessageModule::recentlySeen(uint32_t id)
|
||||
{
|
||||
for (size_t i = 0; i < TEXT_PACKET_LIST_SIZE; i++) {
|
||||
if (textPacketList[i] != 0 && textPacketList[i] == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include "Observer.h"
|
||||
#include "SinglePortModule.h"
|
||||
#define TEXT_PACKET_LIST_SIZE 50
|
||||
|
||||
/**
|
||||
* Text message handling for Meshtastic.
|
||||
@@ -20,8 +19,6 @@ class TextMessageModule : public SinglePortModule, public Observable<const mesht
|
||||
*/
|
||||
TextMessageModule() : SinglePortModule("text", meshtastic_PortNum_TEXT_MESSAGE_APP) {}
|
||||
|
||||
bool recentlySeen(uint32_t id);
|
||||
|
||||
protected:
|
||||
/** Called to handle a particular incoming message
|
||||
*
|
||||
@@ -30,10 +27,6 @@ class TextMessageModule : public SinglePortModule, public Observable<const mesht
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
|
||||
virtual bool wantPacket(const meshtastic_MeshPacket *p) override;
|
||||
|
||||
private:
|
||||
uint32_t textPacketList[TEXT_PACKET_LIST_SIZE] = {0};
|
||||
size_t textPacketListIndex = 0;
|
||||
};
|
||||
|
||||
extern TextMessageModule *textMessageModule;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,180 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "SinglePortModule.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include "input/InputBroker.h"
|
||||
#include "mesh/generated/meshtastic/module_config.pb.h"
|
||||
|
||||
#if defined(ARCH_ESP32) && defined(HAS_I2S) && !MESHTASTIC_EXCLUDE_VOICEMEMO
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ButterworthFilter.h>
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
#include <codec2.h>
|
||||
#include <driver/i2s.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
/**
|
||||
* VoiceMemoModule - Store and forward short codec2 encoded audio messages
|
||||
*
|
||||
* Unlike the existing AudioModule which is designed for real-time push-to-talk,
|
||||
* this module is designed for short voice memos that are:
|
||||
* - Recorded when the user holds Shift+Space
|
||||
* - Encoded with Codec2 for compression
|
||||
* - Sent over the mesh with hop_limit=0 (local only)
|
||||
* - Stored on receiving devices for later playback
|
||||
* - Played back when user long-presses on the notification
|
||||
*/
|
||||
|
||||
// Voice memo states
|
||||
enum class VoiceMemoState { IDLE, RECORDING, SENDING, RECEIVING, PLAYING };
|
||||
|
||||
// Codec2 magic header for voice memos
|
||||
const char VOICEMEMO_MAGIC[4] = {0xc0, 0xde, 0xc2, 0x4d}; // c0dec2M (M for Memo)
|
||||
|
||||
struct VoiceMemoHeader {
|
||||
char magic[4];
|
||||
uint8_t mode; // Codec2 mode
|
||||
uint8_t sequence; // Packet sequence number (for multi-packet memos)
|
||||
uint8_t totalParts; // Total number of packets in this memo (0 = unknown/streaming)
|
||||
uint8_t memoId; // Unique ID for this recording session (to identify related packets)
|
||||
};
|
||||
|
||||
// Maximum recording time in seconds
|
||||
#define VOICEMEMO_MAX_RECORD_SECS 10
|
||||
#define VOICEMEMO_ADC_BUFFER_SIZE 320 // Codec2 samples per frame
|
||||
#define VOICEMEMO_UPSAMPLE_BUFFER_SIZE 3600 // 320 * (44100/8000) * 2 (stereo) ≈ 3528, rounded up
|
||||
#define VOICEMEMO_I2S_PORT I2S_NUM_0
|
||||
// Codec2 mode - use protobuf enum minus 1 to get codec2 library mode
|
||||
#define VOICEMEMO_CODEC2_MODE (meshtastic_ModuleConfig_AudioConfig_Audio_Baud_CODEC2_700 - 1)
|
||||
|
||||
// Storage for received voice memos
|
||||
#define VOICEMEMO_MAX_STORED 5
|
||||
struct StoredVoiceMemo {
|
||||
NodeNum from;
|
||||
uint32_t timestamp;
|
||||
uint8_t data[meshtastic_Constants_DATA_PAYLOAD_LEN * 4]; // Allow up to 4 packets
|
||||
size_t dataLen;
|
||||
uint8_t codec2Mode;
|
||||
uint8_t memoId; // Memo ID from sender (to identify related packets)
|
||||
uint8_t receivedParts; // Bitmask of received packet sequences
|
||||
uint8_t expectedParts; // Total expected parts (0 = unknown)
|
||||
bool played;
|
||||
};
|
||||
|
||||
class VoiceMemoModule : public SinglePortModule, public Observable<const UIFrameEvent *>, private concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
VoiceMemoModule();
|
||||
|
||||
/**
|
||||
* Check if we should draw the UI frame
|
||||
*/
|
||||
bool shouldDraw();
|
||||
|
||||
/**
|
||||
* Handle keyboard input for Shift+Space detection
|
||||
*/
|
||||
int handleInputEvent(const InputEvent *event);
|
||||
|
||||
/**
|
||||
* Play a stored voice memo
|
||||
*/
|
||||
void playStoredMemo(int index);
|
||||
|
||||
/**
|
||||
* Get number of unplayed memos
|
||||
*/
|
||||
int getUnplayedCount();
|
||||
|
||||
/**
|
||||
* Get stored memo info for UI
|
||||
*/
|
||||
const StoredVoiceMemo *getStoredMemo(int index);
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
virtual meshtastic_MeshPacket *allocReply() override;
|
||||
virtual bool wantUIFrame() override { return shouldDraw(); }
|
||||
virtual Observable<const UIFrameEvent *> *getUIFrameObservable() override { return this; }
|
||||
|
||||
#if HAS_SCREEN
|
||||
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
|
||||
#endif
|
||||
|
||||
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
|
||||
|
||||
private:
|
||||
// State machine
|
||||
VoiceMemoState state = VoiceMemoState::IDLE;
|
||||
|
||||
// Codec2
|
||||
CODEC2 *codec2 = nullptr;
|
||||
int encodeCodecSize = 0;
|
||||
int adcBufferSize = 0;
|
||||
|
||||
// Audio buffers
|
||||
int16_t speechBuffer[VOICEMEMO_ADC_BUFFER_SIZE] = {};
|
||||
int16_t outputBuffer[VOICEMEMO_ADC_BUFFER_SIZE] = {};
|
||||
int16_t upsampleBuffer[VOICEMEMO_UPSAMPLE_BUFFER_SIZE] = {}; // For 8kHz->44.1kHz upsampling
|
||||
uint8_t encodedFrame[meshtastic_Constants_DATA_PAYLOAD_LEN] = {};
|
||||
size_t encodedFrameIndex = 0;
|
||||
|
||||
// Recording state
|
||||
uint32_t recordingStartMs = 0;
|
||||
uint32_t sendingCompleteMs = 0; // When sending completed (for "Sent!" display timeout)
|
||||
uint8_t currentMemoId = 0; // Unique ID for current recording session
|
||||
uint8_t currentSequence = 0; // Current packet sequence number
|
||||
|
||||
// I2S state
|
||||
bool i2sInitialized = false;
|
||||
|
||||
// Stored memos for playback
|
||||
StoredVoiceMemo storedMemos[VOICEMEMO_MAX_STORED];
|
||||
int storedMemoCount = 0;
|
||||
|
||||
// Playback state
|
||||
int playingMemoIndex = -1;
|
||||
size_t playbackPosition = 0;
|
||||
|
||||
// Filter for audio cleanup
|
||||
ButterworthFilter *hpFilter = nullptr;
|
||||
|
||||
// Codec2 task for encoding (needs large stack)
|
||||
TaskHandle_t codec2TaskHandle = nullptr;
|
||||
volatile bool codec2TaskRunning = false;
|
||||
volatile bool audioReady = false;
|
||||
|
||||
// Playback task (also needs large stack for Codec2 decoding)
|
||||
TaskHandle_t playbackTaskHandle = nullptr;
|
||||
volatile bool playbackTaskRunning = false;
|
||||
volatile bool playbackReady = false;
|
||||
const StoredVoiceMemo *currentPlaybackMemo = nullptr;
|
||||
|
||||
// Internal methods
|
||||
bool initES7210();
|
||||
bool initI2S();
|
||||
void deinitI2S();
|
||||
void startRecording();
|
||||
void stopRecording();
|
||||
void processRecordingBuffer();
|
||||
void sendEncodedPayload();
|
||||
void storeMemo(const meshtastic_MeshPacket &mp);
|
||||
void playMemo(const StoredVoiceMemo &memo);
|
||||
|
||||
public:
|
||||
// Called by the codec2 task - needs to be public for task function access
|
||||
void doCodec2Encode();
|
||||
void doCodec2Playback();
|
||||
|
||||
// Keyboard observer
|
||||
CallbackObserver<VoiceMemoModule, const InputEvent *> inputObserver =
|
||||
CallbackObserver<VoiceMemoModule, const InputEvent *>(this, &VoiceMemoModule::handleInputEvent);
|
||||
};
|
||||
|
||||
extern VoiceMemoModule *voiceMemoModule;
|
||||
|
||||
#endif // ARCH_ESP32 && HAS_I2S && !MESHTASTIC_EXCLUDE_VOICEMEMO
|
||||
@@ -66,8 +66,6 @@
|
||||
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO
|
||||
#elif defined(T_ECHO_LITE)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_LITE
|
||||
#elif defined(TTGO_T_ECHO_PLUS)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_PLUS
|
||||
#elif defined(ELECROW_ThinkNode_M1)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M1
|
||||
#elif defined(ELECROW_ThinkNode_M3)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "target_specific.h"
|
||||
|
||||
#include "PortduinoGlue.h"
|
||||
#include "SHA256.h"
|
||||
#include "api/ServerAPI.h"
|
||||
#include "linux/gpio/LinuxGPIOPin.h"
|
||||
#include "meshUtils.h"
|
||||
@@ -271,39 +270,7 @@ void portduinoSetup()
|
||||
}
|
||||
std::cout << "autoconf: Found Pi HAT+ " << hat_vendor << " " << autoconf_product << " at /proc/device-tree/hat"
|
||||
<< std::endl;
|
||||
|
||||
// potential TODO: Validate that this is a real UUID
|
||||
std::ifstream hatUUID("/proc/device-tree/hat/uuid");
|
||||
char uuid[38] = {0};
|
||||
if (hatUUID.is_open()) {
|
||||
hatUUID.read(uuid, 37);
|
||||
hatUUID.close();
|
||||
std::cout << "autoconf: UUID " << uuid << std::endl;
|
||||
SHA256 uuid_hash;
|
||||
uint8_t uuid_hash_bytes[32] = {0};
|
||||
|
||||
uuid_hash.reset();
|
||||
uuid_hash.update(uuid, 37);
|
||||
uuid_hash.finalize(uuid_hash_bytes, 32);
|
||||
|
||||
for (int j = 0; j < 16; j++) {
|
||||
portduino_config.device_id[j] = uuid_hash_bytes[j];
|
||||
}
|
||||
portduino_config.has_device_id = true;
|
||||
uint8_t dmac[6] = {0};
|
||||
dmac[0] = (uuid_hash_bytes[17] << 4) | 2;
|
||||
dmac[1] = uuid_hash_bytes[18];
|
||||
dmac[2] = uuid_hash_bytes[19];
|
||||
dmac[3] = uuid_hash_bytes[20];
|
||||
dmac[4] = uuid_hash_bytes[21];
|
||||
dmac[5] = uuid_hash_bytes[22];
|
||||
char macBuf[13] = {0};
|
||||
snprintf(macBuf, sizeof(macBuf), "%02X%02X%02X%02X%02X%02X", dmac[0], dmac[1], dmac[2], dmac[3], dmac[4],
|
||||
dmac[5]);
|
||||
portduino_config.mac_address = macBuf;
|
||||
found_hat = true;
|
||||
}
|
||||
|
||||
found_hat = true;
|
||||
} else {
|
||||
std::cout << "autoconf: Could not locate Pi HAT+ at /proc/device-tree/hat" << std::endl;
|
||||
}
|
||||
@@ -399,14 +366,6 @@ void portduinoSetup()
|
||||
cleanupNameForAutoconf("lora-hat-" + std::string(hat_vendor) + "-" + autoconf_product + ".yaml");
|
||||
} else if (found_ch341) {
|
||||
product_config = cleanupNameForAutoconf("lora-usb-" + std::string(autoconf_product) + ".yaml");
|
||||
// look for more data after the null terminator
|
||||
size_t len = strlen(autoconf_product);
|
||||
if (len < 74) {
|
||||
memcpy(portduino_config.device_id, autoconf_product + len + 1, 16);
|
||||
if (!memfll(portduino_config.device_id, '\0', 16) && !memfll(portduino_config.device_id, 0xff, 16)) {
|
||||
portduino_config.has_device_id = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't try to automatically find config for a device with RAK eeprom.
|
||||
@@ -452,11 +411,9 @@ void portduinoSetup()
|
||||
ch341Hal->getProductString(product_string, 95);
|
||||
std::cout << "CH341 Product " << product_string << std::endl;
|
||||
if (strlen(serial) == 8 && portduino_config.mac_address.length() < 12) {
|
||||
std::cout << "Deriving MAC address from Serial and Product String" << std::endl;
|
||||
uint8_t hash[104] = {0};
|
||||
uint8_t hash[32] = {0};
|
||||
memcpy(hash, serial, 8);
|
||||
memcpy(hash + 8, product_string, strlen(product_string));
|
||||
crypto->hash(hash, 8 + strlen(product_string));
|
||||
crypto->hash(hash, 8);
|
||||
dmac[0] = (hash[0] << 4) | 2;
|
||||
dmac[1] = hash[1];
|
||||
dmac[2] = hash[2];
|
||||
|
||||
@@ -64,7 +64,7 @@ class Ch341Hal : public RadioLibHal
|
||||
void getProductString(char *_product_string, size_t len)
|
||||
{
|
||||
len = len > 95 ? 95 : len;
|
||||
memcpy(_product_string, pinedio.product_string, len);
|
||||
strncpy(_product_string, pinedio.product_string, len);
|
||||
}
|
||||
|
||||
void init() override {}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "SerialConsole.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "gps/RTC.h"
|
||||
#include "mesh/MeshRadio.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
|
||||
#include "TestUtil.h"
|
||||
|
||||
@@ -14,5 +16,19 @@ void initializeTestEnvironment()
|
||||
tv.tv_usec = 0;
|
||||
perhapsSetRTC(RTCQualityNTP, &tv);
|
||||
#endif
|
||||
concurrency::OSThread::setup();
|
||||
}
|
||||
|
||||
void initializeTestEnvironmentMinimal()
|
||||
{
|
||||
// Only satisfy OSThread assertions; skip SerialConsole and platform-specific setup
|
||||
concurrency::hasBeenSetup = true;
|
||||
|
||||
// Ensure region/config globals are sane before any RadioInterface instances compute slot timing
|
||||
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET;
|
||||
config.lora.use_preset = true;
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST;
|
||||
initRegion();
|
||||
|
||||
concurrency::OSThread::setup();
|
||||
}
|
||||
+4
-1
@@ -1,4 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
// Initialize testing environment.
|
||||
void initializeTestEnvironment();
|
||||
void initializeTestEnvironment();
|
||||
|
||||
// Minimal init without creating SerialConsole or portduino peripherals (useful for lightweight logic tests)
|
||||
void initializeTestEnvironmentMinimal();
|
||||
@@ -0,0 +1,164 @@
|
||||
#include <Arduino.h>
|
||||
#include <unity.h>
|
||||
|
||||
#include "TestUtil.h"
|
||||
// Ensure adaptive coding rate logic is available during tests
|
||||
#ifndef USE_ADAPTIVE_CODING_RATE
|
||||
#define USE_ADAPTIVE_CODING_RATE 1
|
||||
#endif
|
||||
#include "mesh/RadioInterface.h"
|
||||
|
||||
class TestRadio : public RadioInterface
|
||||
{
|
||||
public:
|
||||
bool applyForTest(const meshtastic_MeshPacket *p) { return applyAdaptiveCodingRate(p); }
|
||||
|
||||
uint8_t getAttempts(NodeNum from, PacketId id)
|
||||
{
|
||||
#ifdef USE_ADAPTIVE_CODING_RATE
|
||||
auto it = adaptiveAttempts.find(adaptiveKey(from, id));
|
||||
return (it == adaptiveAttempts.end()) ? 0 : it->second.attempts;
|
||||
#else
|
||||
(void)from;
|
||||
(void)id;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_ADAPTIVE_CODING_RATE
|
||||
void setAdaptiveState(NodeNum from, PacketId id, uint8_t attempts, uint32_t lastUse)
|
||||
{
|
||||
adaptiveAttempts[adaptiveKey(from, id)] = {attempts, lastUse};
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t currentCr() const { return cr; }
|
||||
void setCrForTest(uint8_t value) { cr = value; }
|
||||
|
||||
ErrorCode send(meshtastic_MeshPacket *p) override
|
||||
{
|
||||
packetPool.release(p);
|
||||
return ERRNO_OK;
|
||||
}
|
||||
|
||||
uint32_t getPacketTime(uint32_t /*totalPacketLen*/, bool /*received*/ = false) override { return 0; }
|
||||
|
||||
bool reconfigure() override
|
||||
{
|
||||
reconfigureCount++;
|
||||
lastCr = cr;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t reconfigureCount = 0;
|
||||
uint8_t lastCr = 0;
|
||||
};
|
||||
|
||||
void test_attempt_progression()
|
||||
{
|
||||
TestRadio radio;
|
||||
meshtastic_MeshPacket packet = {};
|
||||
packet.from = 0xABCDEF01;
|
||||
packet.id = 0x1;
|
||||
|
||||
TEST_ASSERT_FALSE(radio.applyForTest(&packet));
|
||||
TEST_ASSERT_EQUAL_UINT8(1, radio.getAttempts(packet.from, packet.id));
|
||||
TEST_ASSERT_EQUAL_UINT8(5, radio.currentCr());
|
||||
TEST_ASSERT_EQUAL_UINT32(0, radio.reconfigureCount);
|
||||
|
||||
TEST_ASSERT_TRUE(radio.applyForTest(&packet));
|
||||
TEST_ASSERT_EQUAL_UINT8(2, radio.getAttempts(packet.from, packet.id));
|
||||
TEST_ASSERT_EQUAL_UINT8(7, radio.currentCr());
|
||||
TEST_ASSERT_EQUAL_UINT32(1, radio.reconfigureCount);
|
||||
TEST_ASSERT_EQUAL_UINT8(7, radio.lastCr);
|
||||
|
||||
TEST_ASSERT_TRUE(radio.applyForTest(&packet));
|
||||
TEST_ASSERT_EQUAL_UINT8(3, radio.getAttempts(packet.from, packet.id));
|
||||
TEST_ASSERT_EQUAL_UINT8(8, radio.currentCr());
|
||||
TEST_ASSERT_EQUAL_UINT32(2, radio.reconfigureCount);
|
||||
TEST_ASSERT_EQUAL_UINT8(8, radio.lastCr);
|
||||
}
|
||||
|
||||
void test_attempts_are_per_packet()
|
||||
{
|
||||
TestRadio radio;
|
||||
meshtastic_MeshPacket first = {};
|
||||
first.from = 0x1001;
|
||||
first.id = 0xA;
|
||||
|
||||
meshtastic_MeshPacket second = {};
|
||||
second.from = 0x1001;
|
||||
second.id = 0xB;
|
||||
|
||||
radio.applyForTest(&first);
|
||||
radio.applyForTest(&second);
|
||||
radio.applyForTest(&first);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT8(2, radio.getAttempts(first.from, first.id));
|
||||
TEST_ASSERT_EQUAL_UINT8(1, radio.getAttempts(second.from, second.id));
|
||||
TEST_ASSERT_EQUAL_UINT8(7, radio.currentCr());
|
||||
}
|
||||
|
||||
void test_clear_resets_attempts_and_rate()
|
||||
{
|
||||
TestRadio radio;
|
||||
meshtastic_MeshPacket packet = {};
|
||||
packet.from = 0xCAFE;
|
||||
packet.id = 0x55;
|
||||
|
||||
radio.applyForTest(&packet);
|
||||
radio.applyForTest(&packet);
|
||||
radio.applyForTest(&packet);
|
||||
|
||||
radio.reconfigureCount = 0;
|
||||
radio.setCrForTest(8);
|
||||
radio.clearAdaptiveCodingRateState(packet.from, packet.id);
|
||||
|
||||
TEST_ASSERT_TRUE(radio.applyForTest(&packet));
|
||||
TEST_ASSERT_EQUAL_UINT8(1, radio.getAttempts(packet.from, packet.id));
|
||||
TEST_ASSERT_EQUAL_UINT8(5, radio.currentCr());
|
||||
TEST_ASSERT_EQUAL_UINT32(1, radio.reconfigureCount);
|
||||
}
|
||||
|
||||
void test_prunes_expired_state()
|
||||
{
|
||||
TestRadio radio;
|
||||
meshtastic_MeshPacket packet = {};
|
||||
packet.from = 0xBEEF;
|
||||
packet.id = 0x99;
|
||||
|
||||
radio.applyForTest(&packet);
|
||||
#ifdef USE_ADAPTIVE_CODING_RATE
|
||||
const uint32_t now = millis();
|
||||
radio.setAdaptiveState(packet.from, packet.id, 3, now - (5 * 60 * 1000UL + 50));
|
||||
#endif
|
||||
radio.reconfigureCount = 0;
|
||||
radio.setCrForTest(5);
|
||||
|
||||
TEST_ASSERT_FALSE(radio.applyForTest(&packet));
|
||||
TEST_ASSERT_EQUAL_UINT8(1, radio.getAttempts(packet.from, packet.id));
|
||||
TEST_ASSERT_EQUAL_UINT32(0, radio.reconfigureCount);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
printf("AdaptiveCodingRate test setup start\n");
|
||||
fflush(stdout);
|
||||
// Use minimal init to avoid pulling in SerialConsole/portduino peripherals for these logic-only tests
|
||||
initializeTestEnvironmentMinimal();
|
||||
|
||||
printf("AdaptiveCodingRate test init done\n");
|
||||
fflush(stdout);
|
||||
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(test_attempt_progression);
|
||||
RUN_TEST(test_attempts_are_per_packet);
|
||||
RUN_TEST(test_clear_resets_attempts_and_rate);
|
||||
RUN_TEST(test_prunes_expired_state);
|
||||
UNITY_END();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(1000);
|
||||
}
|
||||
@@ -1,12 +1,5 @@
|
||||
; Port to Disaster Radio's ESP32-v3 Dev Board
|
||||
[env:meshtastic-dr-dev]
|
||||
custom_meshtastic_hw_model = 41
|
||||
custom_meshtastic_hw_model_slug = DR_DEV
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = false
|
||||
custom_meshtastic_display_name = DR-DEV
|
||||
custom_meshtastic_tags = DIY
|
||||
|
||||
extends = esp32_base
|
||||
board = esp32doit-devkit-v1
|
||||
board_level = extra
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
; Hydra - Meshtastic DIY v1 hardware with some specific changes
|
||||
[env:hydra]
|
||||
custom_meshtastic_hw_model = 39
|
||||
custom_meshtastic_hw_model_slug = HYDRA
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = Hydra
|
||||
custom_meshtastic_tags = DIY
|
||||
|
||||
extends = esp32_base
|
||||
board = esp32doit-devkit-v1
|
||||
build_flags =
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
; Meshtastic DIY v1 by Nano VHF Schematic based on ESP32-WROOM-32 (38 pins) devkit & EBYTE E22 SX1262/SX1268 module
|
||||
[env:meshtastic-diy-v1]
|
||||
custom_meshtastic_hw_model = 39
|
||||
custom_meshtastic_hw_model_slug = DIY_V1
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = DIY V1
|
||||
custom_meshtastic_images = diy.svg
|
||||
custom_meshtastic_tags = DIY
|
||||
|
||||
extends = esp32_base
|
||||
board = esp32doit-devkit-v1
|
||||
board_check = true
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
[env:heltec-v1]
|
||||
custom_meshtastic_hw_model = 11
|
||||
custom_meshtastic_hw_model_slug = HELTEC_V1
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = false
|
||||
custom_meshtastic_display_name = Heltec V1
|
||||
custom_meshtastic_tags = Heltec
|
||||
|
||||
;build_type = debug ; to make it possible to step through our jtag debugger
|
||||
extends = esp32_base
|
||||
board_level = extra
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
[env:heltec-v2_1]
|
||||
custom_meshtastic_hw_model = 10
|
||||
custom_meshtastic_hw_model_slug = HELTEC_V2_1
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = false
|
||||
custom_meshtastic_display_name = Heltec V2.1
|
||||
custom_meshtastic_tags = Heltec
|
||||
|
||||
board_level = extra
|
||||
;build_type = debug ; to make it possible to step through our jtag debugger
|
||||
extends = esp32_base
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
[env:heltec-v2_0]
|
||||
custom_meshtastic_hw_model = 5
|
||||
custom_meshtastic_hw_model_slug = HELTEC_V2_0
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = false
|
||||
custom_meshtastic_display_name = Heltec V2.0
|
||||
custom_meshtastic_tags = Heltec
|
||||
|
||||
;build_type = debug ; to make it possible to step through our jtag debugger
|
||||
board_level = extra
|
||||
extends = esp32_base
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
[env:m5stack-core]
|
||||
custom_meshtastic_hw_model = 42
|
||||
custom_meshtastic_hw_model_slug = M5STACK
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = M5 Stack
|
||||
custom_meshtastic_tags = M5Stack
|
||||
|
||||
extends = esp32_base
|
||||
board = m5stack-core-esp32
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
; The 1.0 release of the nano-g1-explorer board
|
||||
[env:nano-g1-explorer]
|
||||
custom_meshtastic_hw_model = 17
|
||||
custom_meshtastic_hw_model_slug = NANO_G1_EXPLORER
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = Nano G1 Explorer
|
||||
custom_meshtastic_tags = B&Q
|
||||
|
||||
extends = esp32_base
|
||||
board = ttgo-t-beam
|
||||
build_flags =
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
; The 1.0 release of the nano-g1 board
|
||||
[env:nano-g1]
|
||||
custom_meshtastic_hw_model = 14
|
||||
custom_meshtastic_hw_model_slug = NANO_G1
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = Nano G1
|
||||
custom_meshtastic_tags = B&Q
|
||||
|
||||
extends = esp32_base
|
||||
board = ttgo-t-beam
|
||||
build_flags =
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
[env:radiomaster_900_bandit_nano]
|
||||
custom_meshtastic_hw_model = 64
|
||||
custom_meshtastic_hw_model_slug = RADIOMASTER_900_BANDIT_NANO
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 2
|
||||
custom_meshtastic_display_name = RadioMaster 900 Bandit Nano
|
||||
custom_meshtastic_tags = RadioMaster
|
||||
|
||||
extends = esp32_base
|
||||
board = esp32doit-devkit-v1
|
||||
build_flags =
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
[env:rak11200]
|
||||
custom_meshtastic_hw_model = 13
|
||||
custom_meshtastic_hw_model_slug = RAK11200
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = RAK WisBlock 11200
|
||||
custom_meshtastic_images = rak11200.svg
|
||||
custom_meshtastic_tags = RAK
|
||||
|
||||
extends = esp32_base
|
||||
board = wiscore_rak11200
|
||||
board_level = pr
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
; The 1.0 release of the nano-g1 board
|
||||
[env:station-g1]
|
||||
custom_meshtastic_hw_model = 25
|
||||
custom_meshtastic_hw_model_slug = STATION_G1
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = Station G1
|
||||
custom_meshtastic_tags = B&Q
|
||||
|
||||
extends = esp32_base
|
||||
board = ttgo-t-beam
|
||||
build_flags =
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
; The 1.0 release of the TBEAM board
|
||||
[env:tbeam]
|
||||
custom_meshtastic_hw_model = 4
|
||||
custom_meshtastic_hw_model_slug = TBEAM
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = LILYGO T-Beam
|
||||
custom_meshtastic_images = tbeam.svg
|
||||
custom_meshtastic_tags = LilyGo
|
||||
|
||||
extends = esp32_base
|
||||
board = ttgo-t-beam
|
||||
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
; The original TBEAM board without the AXP power chip and a few other changes
|
||||
[env:tbeam0_7]
|
||||
custom_meshtastic_hw_model = 6
|
||||
custom_meshtastic_hw_model_slug = TBEAM_V0P7
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = false
|
||||
custom_meshtastic_display_name = LILYGO T-Beam V0.7
|
||||
custom_meshtastic_tags = LilyGo
|
||||
|
||||
board_level = extra
|
||||
extends = esp32_base
|
||||
board = ttgo-t-beam
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
[env:tlora-v1]
|
||||
custom_meshtastic_hw_model = 2
|
||||
custom_meshtastic_hw_model_slug = TLORA_V1
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = false
|
||||
custom_meshtastic_display_name = LILYGO T-LoRa V1
|
||||
custom_meshtastic_tags = LilyGo
|
||||
|
||||
board_level = extra
|
||||
extends = esp32_base
|
||||
board = ttgo-lora32-v1
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
[env:tlora-v2]
|
||||
custom_meshtastic_hw_model = 1
|
||||
custom_meshtastic_hw_model_slug = TLORA_V2
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = false
|
||||
custom_meshtastic_display_name = LILYGO T-LoRa V2
|
||||
custom_meshtastic_tags = LilyGo
|
||||
|
||||
board_level = extra
|
||||
extends = esp32_base
|
||||
board = ttgo-lora32-v1
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
[env:tlora-v2-1-1_6]
|
||||
custom_meshtastic_hw_model = 3
|
||||
custom_meshtastic_hw_model_slug = TLORA_V2_1_1P6
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = LILYGO T-LoRa V2.1-1.6
|
||||
custom_meshtastic_images = tlora-v2-1-1_6.svg
|
||||
custom_meshtastic_tags = LilyGo
|
||||
|
||||
extends = esp32_base
|
||||
board = ttgo-lora32-v21
|
||||
board_check = true
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
[env:tlora-v2-1-1_8]
|
||||
custom_meshtastic_hw_model = 15
|
||||
custom_meshtastic_hw_model_slug = TLORA_V2_1_1P8
|
||||
custom_meshtastic_architecture = esp32
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = LILYGO T-LoRa V2.1-1.8
|
||||
custom_meshtastic_images = tlora-v2-1-1_8.svg
|
||||
custom_meshtastic_tags = LilyGo, 2.4GHz
|
||||
|
||||
extends = esp32_base
|
||||
board_level = extra
|
||||
board = ttgo-lora32-v21
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
[env:heltec-ht62-esp32c3-sx1262]
|
||||
custom_meshtastic_hw_model = 53
|
||||
custom_meshtastic_hw_model_slug = HELTEC_HT62
|
||||
custom_meshtastic_architecture = esp32-c3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Heltec HT62
|
||||
custom_meshtastic_images = heltec-ht62-esp32c3-sx1262.svg
|
||||
custom_meshtastic_tags = Heltec
|
||||
|
||||
extends = esp32c3_base
|
||||
board = esp32-c3-devkitm-1
|
||||
board_level = pr
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
[env:m5stack-unitc6l]
|
||||
custom_meshtastic_hw_model = 111
|
||||
custom_meshtastic_hw_model_slug = M5STACK_C6L
|
||||
custom_meshtastic_architecture = esp32-c6
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = M5Stack Unit C6L
|
||||
custom_meshtastic_images = m5_c6l.svg
|
||||
custom_meshtastic_tags = M5Stack
|
||||
|
||||
extends = esp32c6_base
|
||||
board = esp32-c6-devkitc-1
|
||||
;OpenOCD flash method
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
[env:CDEBYTE_EoRa-S3]
|
||||
custom_meshtastic_hw_model = 61
|
||||
custom_meshtastic_hw_model_slug = CDEBYTE_EORA_S3
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = EBYTE EoRa-S3
|
||||
custom_meshtastic_tags = EByte
|
||||
custom_meshtastic_requires_dfu = true
|
||||
|
||||
extends = esp32s3_base
|
||||
board = CDEBYTE_EoRa-S3
|
||||
build_flags =
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
[env:thinknode_m2]
|
||||
custom_meshtastic_hw_model = 90
|
||||
custom_meshtastic_hw_model_slug = THINKNODE_M2
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = ThinkNode M2
|
||||
custom_meshtastic_images = thinknode_m2.svg
|
||||
custom_meshtastic_tags = Elecrow
|
||||
custom_meshtastic_requires_dfu = false
|
||||
|
||||
extends = esp32s3_base
|
||||
board = ESP32-S3-WROOM-1-N4
|
||||
build_flags =
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
[env:thinknode_m5]
|
||||
custom_meshtastic_hw_model = 107
|
||||
custom_meshtastic_hw_model_slug = THINKNODE_M5
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = ThinkNode M5
|
||||
custom_meshtastic_images = thinknode_m1.svg
|
||||
custom_meshtastic_tags = Elecrow
|
||||
custom_meshtastic_requires_dfu = false
|
||||
|
||||
extends = esp32s3_base
|
||||
board = ESP32-S3-WROOM-1-N4
|
||||
build_flags =
|
||||
|
||||
@@ -75,17 +75,6 @@ build_flags =
|
||||
-D DISPLAY_SET_RESOLUTION
|
||||
|
||||
[env:elecrow-adv-24-28-tft]
|
||||
custom_meshtastic_hw_model = 97
|
||||
custom_meshtastic_hw_model_slug = CROWPANEL
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Crowpanel Adv 2.4/2.8 TFT
|
||||
custom_meshtastic_images = crowpanel_2_4.svg, crowpanel_2_8.svg
|
||||
custom_meshtastic_tags = Elecrow
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 16MB
|
||||
|
||||
extends = crowpanel_small_esp32s3_base
|
||||
build_flags =
|
||||
${crowpanel_small_esp32s3_base.build_flags}
|
||||
@@ -110,17 +99,6 @@ build_flags =
|
||||
-D LGFX_TOUCH_ROTATION=0
|
||||
|
||||
[env:elecrow-adv-35-tft]
|
||||
custom_meshtastic_hw_model = 97
|
||||
custom_meshtastic_hw_model_slug = CROWPANEL
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Crowpanel Adv 3.5 TFT
|
||||
custom_meshtastic_images = crowpanel_3_5.svg
|
||||
custom_meshtastic_tags = Elecrow
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 16MB
|
||||
|
||||
extends = crowpanel_small_esp32s3_base
|
||||
board_level = pr
|
||||
build_flags =
|
||||
@@ -149,17 +127,6 @@ build_flags =
|
||||
|
||||
; 4.3, 5.0, 7.0 inch 800x480 IPS (V1)
|
||||
[env:elecrow-adv1-43-50-70-tft]
|
||||
custom_meshtastic_hw_model = 97
|
||||
custom_meshtastic_hw_model_slug = CROWPANEL
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Crowpanel Adv 4.3/5.0/7.0 TFT
|
||||
custom_meshtastic_images = crowpanel_5_0.svg, crowpanel_7_0.svg
|
||||
custom_meshtastic_tags = Elecrow
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 16MB
|
||||
|
||||
extends = crowpanel_large_esp32s3_base
|
||||
build_flags =
|
||||
${crowpanel_large_esp32s3_base.build_flags}
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
[env:heltec-v3]
|
||||
custom_meshtastic_hw_model = 43
|
||||
custom_meshtastic_hw_model_slug = HELTEC_V3
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Heltec V3
|
||||
custom_meshtastic_images = heltec-v3.svg, heltec-v3-case.svg
|
||||
custom_meshtastic_tags = Heltec
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
|
||||
[env:heltec-v3]
|
||||
extends = esp32s3_base
|
||||
board = heltec_wifi_lora_32_V3
|
||||
board_level = pr
|
||||
|
||||
@@ -10,17 +10,6 @@ build_flags =
|
||||
|
||||
|
||||
[env:heltec-v4]
|
||||
custom_meshtastic_hw_model = 110
|
||||
custom_meshtastic_hw_model_slug = HELTEC_V4
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Heltec V4
|
||||
custom_meshtastic_images = heltec_v4.svg
|
||||
custom_meshtastic_tags = Heltec
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 16MB
|
||||
|
||||
extends = heltec_v4_base
|
||||
build_flags =
|
||||
${heltec_v4_base.build_flags}
|
||||
|
||||
@@ -29,32 +29,10 @@
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
|
||||
// ---- GC1109 RF FRONT END CONFIGURATION ----
|
||||
// The Heltec V4 uses a GC1109 FEM chip with integrated PA and LNA
|
||||
// RF path: SX1262 -> GC1109 PA -> Pi attenuator -> Antenna
|
||||
// Measured net TX gain (non-linear due to PA compression):
|
||||
// +11dB at 0-15dBm input (e.g., 10dBm in -> 21dBm out)
|
||||
// +10dB at 16-17dBm input
|
||||
// +9dB at 18-19dBm input
|
||||
// +7dB at 21dBm input (e.g., 21dBm in -> 28dBm out max)
|
||||
// Control logic (from GC1109 datasheet):
|
||||
// Shutdown: CSD=0, CTX=X, CPS=X
|
||||
// Receive LNA: CSD=1, CTX=0, CPS=X (17dB gain, 2dB NF)
|
||||
// Transmit bypass: CSD=1, CTX=1, CPS=0 (~1dB loss, no PA)
|
||||
// Transmit PA: CSD=1, CTX=1, CPS=1 (full PA enabled)
|
||||
// Pin mapping:
|
||||
// CTX (pin 6) -> SX1262 DIO2: TX/RX path select (automatic via SX126X_DIO2_AS_RF_SWITCH)
|
||||
// CSD (pin 4) -> GPIO2: Chip enable (HIGH=on, LOW=shutdown)
|
||||
// CPS (pin 5) -> GPIO46: PA mode select (HIGH=full PA, LOW=bypass)
|
||||
// VCC0/VCC1 -> Vfem via U3 LDO, controlled by GPIO7
|
||||
#define USE_GC1109_PA
|
||||
#define LORA_PA_POWER 7 // VFEM_Ctrl - GC1109 LDO power enable
|
||||
#define LORA_PA_EN 2 // CSD - GC1109 chip enable (HIGH=on)
|
||||
#define LORA_PA_TX_EN 46 // CPS - GC1109 PA mode (HIGH=full PA, LOW=bypass)
|
||||
|
||||
// GC1109 FEM: TX/RX path switching is handled by DIO2 -> CTX pin (via SX126X_DIO2_AS_RF_SWITCH)
|
||||
// GPIO46 is CPS (PA mode), not TX control - setTransmitEnable() handles it in SX126xInterface.cpp
|
||||
// Do NOT use SX126X_TXEN/RXEN as that would cause double-control of GPIO46
|
||||
#define USE_GC1109_PA // We have a GC1109 power amplifier+attenuator
|
||||
#define LORA_PA_POWER 7 // power en
|
||||
#define LORA_PA_EN 2
|
||||
#define LORA_PA_TX_EN 46 // enable tx
|
||||
|
||||
#if HAS_TFT
|
||||
#define USE_TFTDISPLAY 1
|
||||
|
||||
@@ -1,15 +1,4 @@
|
||||
[env:heltec-vision-master-e213]
|
||||
custom_meshtastic_hw_model = 67
|
||||
custom_meshtastic_hw_model_slug = HELTEC_VISION_MASTER_E213
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Heltec Vision Master E213
|
||||
custom_meshtastic_images = heltec-vision-master-e213.svg
|
||||
custom_meshtastic_tags = Heltec
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
|
||||
extends = esp32s3_base
|
||||
board = heltec_vision_master_e213
|
||||
board_build.partitions = default_8MB.csv
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
; Using the original screen class
|
||||
[env:heltec-vision-master-e290]
|
||||
custom_meshtastic_hw_model = 68
|
||||
custom_meshtastic_hw_model_slug = HELTEC_VISION_MASTER_E290
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Heltec Vision Master E290
|
||||
custom_meshtastic_images = heltec-vision-master-e290.svg
|
||||
custom_meshtastic_tags = Heltec
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
|
||||
extends = esp32s3_base
|
||||
board = heltec_vision_master_e290
|
||||
board_build.partitions = default_8MB.csv
|
||||
|
||||
@@ -1,15 +1,4 @@
|
||||
[env:heltec-vision-master-t190]
|
||||
custom_meshtastic_hw_model = 66
|
||||
custom_meshtastic_hw_model_slug = HELTEC_VISION_MASTER_T190
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Heltec Vision Master T190
|
||||
custom_meshtastic_images = heltec-vision-master-t190.svg
|
||||
custom_meshtastic_tags = Heltec
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
|
||||
extends = esp32s3_base
|
||||
board = heltec_vision_master_t190
|
||||
board_build.partitions = default_8MB.csv
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
; Using the original screen class
|
||||
[env:heltec-wireless-paper]
|
||||
custom_meshtastic_hw_model = 49
|
||||
custom_meshtastic_hw_model_slug = HELTEC_WIRELESS_PAPER
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Heltec Wireless Paper
|
||||
custom_meshtastic_images = heltec-wireless-paper.svg
|
||||
custom_meshtastic_tags = Heltec
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
|
||||
extends = esp32s3_base
|
||||
board = heltec_wifi_lora_32_V3
|
||||
board_build.partitions = default_8MB.csv
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
[env:heltec-wireless-paper-v1_0]
|
||||
custom_meshtastic_hw_model = 57
|
||||
custom_meshtastic_hw_model_slug = HELTEC_WIRELESS_PAPER_V1_0
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = false
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = Heltec Wireless Paper V1.0
|
||||
custom_meshtastic_images = heltec-wireless-paper-v1_0.svg
|
||||
custom_meshtastic_tags = Heltec
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
|
||||
extends = esp32s3_base
|
||||
board_level = extra
|
||||
board = heltec_wifi_lora_32_V3
|
||||
|
||||
@@ -1,15 +1,4 @@
|
||||
[env:heltec-wireless-tracker]
|
||||
custom_meshtastic_hw_model = 48
|
||||
custom_meshtastic_hw_model_slug = HELTEC_WIRELESS_TRACKER
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Heltec Wireless Tracker V1.1
|
||||
custom_meshtastic_images = heltec-wireless-tracker.svg
|
||||
custom_meshtastic_tags = Heltec
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
|
||||
extends = esp32s3_base
|
||||
board = heltec_wireless_tracker
|
||||
board_build.partitions = default_8MB.csv
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
[env:heltec-wireless-tracker-V1-0]
|
||||
custom_meshtastic_hw_model = 58
|
||||
custom_meshtastic_hw_model_slug = HELTEC_WIRELESS_TRACKER_V1_0
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = false
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = Heltec Wireless Tracker V1.0
|
||||
custom_meshtastic_images = heltec-wireless-tracker.svg
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
|
||||
extends = esp32s3_base
|
||||
board_level = extra
|
||||
board = heltec_wireless_tracker
|
||||
|
||||
@@ -73,29 +73,7 @@
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
|
||||
// ---- GC1109 RF FRONT END CONFIGURATION ----
|
||||
// The Heltec Wireless Tracker V2 uses a GC1109 FEM chip with integrated PA and LNA
|
||||
// RF path: SX1262 -> GC1109 PA -> Pi attenuator -> Antenna
|
||||
// Measured net TX gain (non-linear due to PA compression):
|
||||
// +11dB at 0-15dBm input (e.g., 10dBm in -> 21dBm out)
|
||||
// +10dB at 16-17dBm input
|
||||
// +9dB at 18-19dBm input
|
||||
// +7dB at 21dBm input (e.g., 21dBm in -> 28dBm out max)
|
||||
// Control logic (from GC1109 datasheet):
|
||||
// Shutdown: CSD=0, CTX=X, CPS=X
|
||||
// Receive LNA: CSD=1, CTX=0, CPS=X (17dB gain, 2dB NF)
|
||||
// Transmit bypass: CSD=1, CTX=1, CPS=0 (~1dB loss, no PA)
|
||||
// Transmit PA: CSD=1, CTX=1, CPS=1 (full PA enabled)
|
||||
// Pin mapping:
|
||||
// CTX (pin 6) -> SX1262 DIO2: TX/RX path select (automatic via SX126X_DIO2_AS_RF_SWITCH)
|
||||
// CSD (pin 4) -> GPIO4: Chip enable (HIGH=on, LOW=shutdown)
|
||||
// CPS (pin 5) -> GPIO46: PA mode select (HIGH=full PA, LOW=bypass)
|
||||
// VCC0/VCC1 -> Vfem via U3 LDO, controlled by GPIO7
|
||||
#define USE_GC1109_PA
|
||||
#define LORA_PA_POWER 7 // VFEM_Ctrl - GC1109 LDO power enable
|
||||
#define LORA_PA_EN 4 // CSD - GC1109 chip enable (HIGH=on)
|
||||
#define LORA_PA_TX_EN 46 // CPS - GC1109 PA mode (HIGH=full PA, LOW=bypass)
|
||||
|
||||
// GC1109 FEM: TX/RX path switching is handled by DIO2 -> CTX pin (via SX126X_DIO2_AS_RF_SWITCH)
|
||||
// GPIO46 is CPS (PA mode), not TX control - setTransmitEnable() handles it in SX126xInterface.cpp
|
||||
// Do NOT use SX126X_TXEN/RXEN as that would cause double-control of GPIO46
|
||||
#define USE_GC1109_PA // We have a GC1109 power amplifier+attenuator
|
||||
#define LORA_PA_POWER 7 // power en
|
||||
#define LORA_PA_EN 4
|
||||
#define LORA_PA_TX_EN 46 // enable tx
|
||||
@@ -1,14 +1,4 @@
|
||||
[env:heltec-wsl-v3]
|
||||
custom_meshtastic_hw_model = 44
|
||||
custom_meshtastic_hw_model_slug = HELTEC_WSL_V3
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Heltec Wireless Stick Lite V3
|
||||
custom_meshtastic_images = heltec-wsl-v3.svg
|
||||
custom_meshtastic_tags = Heltec
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
|
||||
[env:heltec-wsl-v3]
|
||||
extends = esp32s3_base
|
||||
board = heltec_wifi_lora_32_V3
|
||||
board_build.partitions = default_8MB.csv
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
[env:picomputer-s3]
|
||||
custom_meshtastic_hw_model = 52
|
||||
custom_meshtastic_hw_model_slug = PICOMPUTER_S3
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = Pi Computer S3
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
|
||||
extends = esp32s3_base
|
||||
board = bpi_picow_esp32_s3
|
||||
board_check = true
|
||||
|
||||
@@ -1,15 +1,4 @@
|
||||
[env:rak3312]
|
||||
custom_meshtastic_hw_model = 106
|
||||
custom_meshtastic_hw_model_slug = RAK3312
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = RAK3312
|
||||
custom_meshtastic_images = rak_3312.svg
|
||||
custom_meshtastic_tags = RAK
|
||||
custom_meshtastic_requires_dfu = false
|
||||
custom_meshtastic_partition_scheme = 16MB
|
||||
|
||||
extends = esp32s3_base
|
||||
board = wiscore_rak3312
|
||||
board_level = pr
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
; Seeed Studio SenseCAP Indicator
|
||||
[env:seeed-sensecap-indicator]
|
||||
custom_meshtastic_hw_model = 70
|
||||
custom_meshtastic_hw_model_slug = SENSECAP_INDICATOR
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Seeed SenseCAP Indicator
|
||||
custom_meshtastic_images = seeed-sensecap-indicator.svg
|
||||
custom_meshtastic_tags = Seeed
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
= true
|
||||
|
||||
extends = esp32s3_base
|
||||
platform_packages =
|
||||
platformio/framework-arduinoespressif32 @ https://github.com/mverch67/arduino-esp32/archive/aef7fef6de3329ed6f75512d46d63bba12b09bb5.zip ; add_tca9535 (based on 2.0.16)
|
||||
|
||||
@@ -1,15 +1,4 @@
|
||||
[env:seeed-xiao-s3]
|
||||
custom_meshtastic_hw_model = 81
|
||||
custom_meshtastic_hw_model_slug = SEEED_XIAO_S3
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 3
|
||||
custom_meshtastic_display_name = Seeed Xiao ESP32-S3
|
||||
custom_meshtastic_images = seeed-xiao-s3.svg
|
||||
custom_meshtastic_tags = Seeed
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 8MB
|
||||
|
||||
extends = esp32s3_base
|
||||
board = seeed-xiao-s3
|
||||
board_level = pr
|
||||
|
||||
@@ -1,15 +1,4 @@
|
||||
[env:station-g2]
|
||||
custom_meshtastic_hw_model = 31
|
||||
custom_meshtastic_hw_model_slug = STATION_G2
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 2
|
||||
custom_meshtastic_display_name = Station G2
|
||||
custom_meshtastic_images = station-g2.svg
|
||||
custom_meshtastic_tags = B&Q
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 16MB
|
||||
|
||||
extends = esp32s3_base
|
||||
board = station-g2
|
||||
board_level = pr
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user