|
| 1 | +# Meshtastic Firmware - Copilot Instructions |
| 2 | + |
| 3 | +This document provides context and guidelines for AI assistants working with the Meshtastic firmware codebase. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +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. |
| 8 | + |
| 9 | +### Supported Hardware Platforms |
| 10 | + |
| 11 | +- **ESP32** (ESP32, ESP32-S3, ESP32-C3) - Most common platform |
| 12 | +- **nRF52** (nRF52840, nRF52833) - Low power Nordic chips |
| 13 | +- **RP2040/RP2350** - Raspberry Pi Pico variants |
| 14 | +- **STM32WL** - STM32 with integrated LoRa |
| 15 | +- **Linux/Portduino** - Native Linux builds (Raspberry Pi, etc.) |
| 16 | + |
| 17 | +### Supported Radio Chips |
| 18 | + |
| 19 | +- **SX1262/SX1268** - Sub-GHz LoRa (868/915 MHz regions) |
| 20 | +- **SX1280** - 2.4 GHz LoRa |
| 21 | +- **LR1110/LR1120/LR1121** - Wideband radios (sub-GHz and 2.4 GHz capable, but not simultaneously) |
| 22 | +- **RF95** - Legacy RFM95 modules |
| 23 | +- **LLCC68** - Low-cost LoRa |
| 24 | + |
| 25 | +### MQTT Integration |
| 26 | + |
| 27 | +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. |
| 28 | + |
| 29 | +#### Key Components |
| 30 | + |
| 31 | +- **`src/mqtt/MQTT.cpp`** - Main MQTT client singleton, handles connection and message routing |
| 32 | +- **`src/mqtt/ServiceEnvelope.cpp`** - Protobuf wrapper for mesh packets sent over MQTT |
| 33 | +- **`moduleConfig.mqtt`** - MQTT module configuration |
| 34 | + |
| 35 | +#### MQTT Topic Structure |
| 36 | + |
| 37 | +Messages are published/subscribed using a hierarchical topic format: |
| 38 | + |
| 39 | +``` |
| 40 | +{root}/{channel_id}/{gateway_id} |
| 41 | +``` |
| 42 | + |
| 43 | +- `root` - Configurable prefix (default: `msh`) |
| 44 | +- `channel_id` - Channel name/identifier |
| 45 | +- `gateway_id` - Node ID of the publishing gateway |
| 46 | + |
| 47 | +#### Configuration Defaults (from `Default.h`) |
| 48 | + |
| 49 | +```cpp |
| 50 | +#define default_mqtt_address "mqtt.meshtastic.org" |
| 51 | +#define default_mqtt_username "meshdev" |
| 52 | +#define default_mqtt_password "large4cats" |
| 53 | +#define default_mqtt_root "msh" |
| 54 | +#define default_mqtt_encryption_enabled true |
| 55 | +#define default_mqtt_tls_enabled false |
| 56 | +``` |
| 57 | +
|
| 58 | +#### Key Concepts |
| 59 | +
|
| 60 | +- **Uplink** - Mesh packets sent TO the MQTT broker (controlled by `uplink_enabled` per channel) |
| 61 | +- **Downlink** - MQTT messages received and injected INTO the mesh (controlled by `downlink_enabled` per channel) |
| 62 | +- **Encryption** - When `encryption_enabled` is true, only encrypted packets are sent; plaintext JSON is disabled |
| 63 | +- **ServiceEnvelope** - Protobuf wrapper containing packet + channel_id + gateway_id for routing |
| 64 | +- **JSON Support** - Optional JSON encoding for integration with external systems (disabled on nRF52 by default) |
| 65 | +
|
| 66 | +#### PKI Messages |
| 67 | +
|
| 68 | +PKI (Public Key Infrastructure) messages have special handling: |
| 69 | +
|
| 70 | +- Accepted on a special "PKI" channel |
| 71 | +- Allow encrypted DMs between nodes that discovered each other on downlink-enabled channels |
| 72 | +
|
| 73 | +## Project Structure |
| 74 | +
|
| 75 | +``` |
| 76 | +firmware/ |
| 77 | +├── src/ # Main source code |
| 78 | +│ ├── main.cpp # Application entry point |
| 79 | +│ ├── mesh/ # Core mesh networking |
| 80 | +│ │ ├── NodeDB.* # Node database management |
| 81 | +│ │ ├── Router.* # Packet routing |
| 82 | +│ │ ├── Channels.* # Channel management |
| 83 | +│ │ ├── *Interface.* # Radio interface implementations |
| 84 | +│ │ └── generated/ # Protobuf generated code |
| 85 | +│ ├── modules/ # Feature modules (Position, Telemetry, etc.) |
| 86 | +│ ├── gps/ # GPS handling |
| 87 | +│ ├── graphics/ # Display drivers and UI |
| 88 | +│ ├── platform/ # Platform-specific code |
| 89 | +│ ├── input/ # Input device handling |
| 90 | +│ └── concurrency/ # Threading utilities |
| 91 | +├── variants/ # Hardware variant definitions |
| 92 | +│ ├── esp32/ # ESP32 variants |
| 93 | +│ ├── esp32s3/ # ESP32-S3 variants |
| 94 | +│ ├── nrf52/ # nRF52 variants |
| 95 | +│ └── rp2xxx/ # RP2040/RP2350 variants |
| 96 | +├── protobufs/ # Protocol buffer definitions |
| 97 | +├── boards/ # Custom PlatformIO board definitions |
| 98 | +└── bin/ # Build and utility scripts |
| 99 | +``` |
| 100 | +
|
| 101 | +## Coding Conventions |
| 102 | +
|
| 103 | +### General Style |
| 104 | +
|
| 105 | +- Follow existing code style - run `trunk fmt` before commits |
| 106 | +- Prefer `LOG_DEBUG`, `LOG_INFO`, `LOG_WARN`, `LOG_ERROR` for logging |
| 107 | +- Use `assert()` for invariants that should never fail |
| 108 | +
|
| 109 | +### Naming Conventions |
| 110 | +
|
| 111 | +- Classes: `PascalCase` (e.g., `PositionModule`, `NodeDB`) |
| 112 | +- Functions/Methods: `camelCase` (e.g., `sendOurPosition`, `getNodeNum`) |
| 113 | +- Constants/Defines: `UPPER_SNAKE_CASE` (e.g., `MAX_INTERVAL`, `ONE_DAY`) |
| 114 | +- Member variables: `camelCase` (e.g., `lastGpsSend`, `nodeDB`) |
| 115 | +- Config defines: `USERPREFS_*` for user-configurable options |
| 116 | +
|
| 117 | +### Key Patterns |
| 118 | +
|
| 119 | +#### Module System |
| 120 | +
|
| 121 | +Modules inherit from `MeshModule` or `ProtobufModule<T>` and implement: |
| 122 | +
|
| 123 | +- `handleReceivedProtobuf()` - Process incoming packets |
| 124 | +- `allocReply()` - Generate response packets |
| 125 | +- `runOnce()` - Periodic task execution (returns next run interval in ms) |
| 126 | +
|
| 127 | +```cpp |
| 128 | +class MyModule : public ProtobufModule<meshtastic_MyMessage> |
| 129 | +{ |
| 130 | + protected: |
| 131 | + virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_MyMessage *msg) override; |
| 132 | + virtual int32_t runOnce() override; |
| 133 | +}; |
| 134 | +``` |
| 135 | + |
| 136 | +#### Configuration Access |
| 137 | + |
| 138 | +- `config.*` - Device configuration (LoRa, position, power, etc.) |
| 139 | +- `moduleConfig.*` - Module-specific configuration |
| 140 | +- `channels.*` - Channel configuration and management |
| 141 | + |
| 142 | +#### Default Values |
| 143 | + |
| 144 | +Use the `Default` class helpers in `src/mesh/Default.h`: |
| 145 | + |
| 146 | +- `Default::getConfiguredOrDefaultMs(configured, default)` - Returns ms, using default if configured is 0 |
| 147 | +- `Default::getConfiguredOrMinimumValue(configured, min)` - Enforces minimum values |
| 148 | +- `Default::getConfiguredOrDefaultMsScaled(configured, default, numNodes)` - Scales based on network size |
| 149 | + |
| 150 | +#### Thread Safety |
| 151 | + |
| 152 | +- Use `concurrency::Lock` for mutex protection |
| 153 | +- Radio SPI access uses `SPILock` |
| 154 | +- Prefer `OSThread` for background tasks |
| 155 | + |
| 156 | +### Hardware Variants |
| 157 | + |
| 158 | +Each hardware variant has: |
| 159 | + |
| 160 | +- `variant.h` - Pin definitions and hardware capabilities |
| 161 | +- `platformio.ini` - Build configuration |
| 162 | +- Optional: `pins_arduino.h`, `rfswitch.h` |
| 163 | + |
| 164 | +Key defines in variant.h: |
| 165 | + |
| 166 | +```cpp |
| 167 | +#define USE_SX1262 // Radio chip selection |
| 168 | +#define HAS_GPS 1 // Hardware capabilities |
| 169 | +#define LORA_CS 36 // Pin assignments |
| 170 | +#define SX126X_DIO1 14 // Radio-specific pins |
| 171 | +``` |
| 172 | +
|
| 173 | +### Protobuf Messages |
| 174 | +
|
| 175 | +- Defined in `protobufs/meshtastic/*.proto` |
| 176 | +- Generated code in `src/mesh/generated/` |
| 177 | +- Regenerate with `bin/regen-protos.sh` |
| 178 | +- Message types prefixed with `meshtastic_` |
| 179 | +
|
| 180 | +### Conditional Compilation |
| 181 | +
|
| 182 | +```cpp |
| 183 | +#if !MESHTASTIC_EXCLUDE_GPS // Feature exclusion |
| 184 | +#ifdef ARCH_ESP32 // Architecture-specific |
| 185 | +#if defined(USE_SX1262) // Radio-specific |
| 186 | +#ifdef HAS_SCREEN // Hardware capability |
| 187 | +#if USERPREFS_EVENT_MODE // User preferences |
| 188 | +``` |
| 189 | + |
| 190 | +## Build System |
| 191 | + |
| 192 | +Uses **PlatformIO** with custom scripts: |
| 193 | + |
| 194 | +- `bin/platformio-pre.py` - Pre-build script |
| 195 | +- `bin/platformio-custom.py` - Custom build logic |
| 196 | + |
| 197 | +Build commands: |
| 198 | + |
| 199 | +```bash |
| 200 | +pio run -e tbeam # Build specific target |
| 201 | +pio run -e tbeam -t upload # Build and upload |
| 202 | +pio run -e native # Build native/Linux version |
| 203 | +``` |
| 204 | + |
| 205 | +## Common Tasks |
| 206 | + |
| 207 | +### Adding a New Module |
| 208 | + |
| 209 | +1. Create `src/modules/MyModule.cpp` and `.h` |
| 210 | +2. Inherit from appropriate base class |
| 211 | +3. Register in `src/modules/Modules.cpp` |
| 212 | +4. Add protobuf messages if needed in `protobufs/` |
| 213 | + |
| 214 | +### Adding a New Hardware Variant |
| 215 | + |
| 216 | +1. Create directory under `variants/<arch>/<name>/` |
| 217 | +2. Add `variant.h` with pin definitions |
| 218 | +3. Add `platformio.ini` with build config |
| 219 | +4. Reference common configs with `extends` |
| 220 | + |
| 221 | +### Modifying Configuration Defaults |
| 222 | + |
| 223 | +- Check `src/mesh/Default.h` for default value defines |
| 224 | +- Check `src/mesh/NodeDB.cpp` for initialization logic |
| 225 | +- Consider `isDefaultChannel()` checks for public channel restrictions |
| 226 | + |
| 227 | +## Important Considerations |
| 228 | + |
| 229 | +### Traffic Management |
| 230 | + |
| 231 | +The mesh network has limited bandwidth. When modifying broadcast intervals: |
| 232 | + |
| 233 | +- Respect minimum intervals on default/public channels |
| 234 | +- Use `Default::getConfiguredOrMinimumValue()` to enforce minimums |
| 235 | +- Consider `numOnlineNodes` scaling for congestion control |
| 236 | + |
| 237 | +### Power Management |
| 238 | + |
| 239 | +Many devices are battery-powered: |
| 240 | + |
| 241 | +- Use `IF_ROUTER(routerVal, normalVal)` for role-based defaults |
| 242 | +- Check `config.power.is_power_saving` for power-saving modes |
| 243 | +- Implement proper `sleep()` methods in radio interfaces |
| 244 | + |
| 245 | +### Channel Security |
| 246 | + |
| 247 | +- `channels.isDefaultChannel(index)` - Check if using default/public settings |
| 248 | +- Default channels get stricter rate limits to prevent abuse |
| 249 | +- Private channels may have relaxed limits |
| 250 | + |
| 251 | +## GitHub Actions CI/CD |
| 252 | + |
| 253 | +The project uses GitHub Actions extensively for CI/CD. Key workflows are in `.github/workflows/`: |
| 254 | + |
| 255 | +### Core CI Workflows |
| 256 | + |
| 257 | +- **`main_matrix.yml`** - Main CI pipeline, runs on push to `master`/`develop` and PRs |
| 258 | + - Uses `bin/generate_ci_matrix.py` to dynamically generate build targets |
| 259 | + - Builds all supported hardware variants |
| 260 | + - PRs build a subset (`--level pr`) for faster feedback |
| 261 | + |
| 262 | +- **`trunk_check.yml`** - Code quality checks on PRs |
| 263 | + - Runs Trunk.io for linting and formatting |
| 264 | + - Must pass before merge |
| 265 | + |
| 266 | +- **`tests.yml`** - End-to-end and hardware tests |
| 267 | + - Runs daily on schedule |
| 268 | + - Includes native tests and hardware-in-the-loop testing |
| 269 | + |
| 270 | +- **`test_native.yml`** - Native platform unit tests |
| 271 | + - Runs `pio test -e native` |
| 272 | + |
| 273 | +### Release Workflows |
| 274 | + |
| 275 | +- **`release_channels.yml`** - Triggered on GitHub release publish |
| 276 | + - Builds Docker images |
| 277 | + - Packages for PPA (Ubuntu), OBS (openSUSE), and COPR (Fedora) |
| 278 | + - Handles Alpha/Beta/Stable release channels |
| 279 | + |
| 280 | +- **`nightly.yml`** - Nightly builds from develop branch |
| 281 | + |
| 282 | +- **`docker_build.yml`** / **`docker_manifest.yml`** - Docker image builds |
| 283 | + |
| 284 | +### Build Matrix Generation |
| 285 | + |
| 286 | +The CI uses `bin/generate_ci_matrix.py` to dynamically select which targets to build: |
| 287 | + |
| 288 | +```bash |
| 289 | +# Generate full build matrix |
| 290 | +./bin/generate_ci_matrix.py all |
| 291 | + |
| 292 | +# Generate PR-level matrix (subset for faster builds) |
| 293 | +./bin/generate_ci_matrix.py all --level pr |
| 294 | +``` |
| 295 | + |
| 296 | +Variants can specify their support level in `platformio.ini`: |
| 297 | + |
| 298 | +- `custom_meshtastic_support_level = 1` - Actively supported, built on every PR |
| 299 | +- `custom_meshtastic_support_level = 2` - Supported, built on merge to main branches |
| 300 | +- `board_level = extra` - Extra builds, only on full releases |
| 301 | + |
| 302 | +### Running Workflows Locally |
| 303 | + |
| 304 | +Most workflows can be triggered manually via `workflow_dispatch` for testing. |
| 305 | + |
| 306 | +## Testing |
| 307 | + |
| 308 | +- Unit tests in `test/` directory |
| 309 | +- Run with `pio test -e native` |
| 310 | +- Use `bin/test-simulator.sh` for simulation testing |
| 311 | + |
| 312 | +## Resources |
| 313 | + |
| 314 | +- [Documentation](https://meshtastic.org/docs/) |
0 commit comments