mirror of
https://github.com/Colorado-Mesh/meshcore-bot-firmware.git
synced 2026-08-11 08:10:29 +00:00
Update MeshCore base to v1.16.0; add sig/air/coin; ship 139 boards
- Bump vendor/MeshCore pin 910b1bee -> bbb58cce (upstream v1.16.0,
272 commits) and rebase the 14-patch bot queue onto it; one trivial
conflict in the MyMesh constructor.
- New patch 15: sig/air/coin commands plus registry-derived help and
cmd listings ('cmd diag' for the diagnostic set). BOT_PREFS_VERSION
bumped to 7. Host tests cover the new commands and assert every
discoverable registry entry appears in a listing.
- Re-include six boards fixed upstream (Pico W, RAK 11310, Waveshare
RP2040 LoRa, Xiao RP2040, Nibble USB+BLE) after local test builds;
remaining exclusions are BLE flash-size only.
- Fix release env enumeration to strip CR line endings so envs in CRLF
variant files (Minewsemi ME25LS01, Wio WM1110, Nibble) are counted
and built; verified all three build locally.
- Refresh README/CHANGELOG/RELEASE/CONTRIBUTING for the new base and
command set.
Verified: host tests, safety checks, 4 representative builds, and 9
additional env builds all pass; the 15-patch queue applies cleanly to
pristine bbb58cce.
This commit is contained in:
42
CHANGELOG.md
42
CHANGELOG.md
@@ -6,29 +6,53 @@ follows the `cmesh-bot-vX.Y.Z` scheme described in [RELEASE.md](RELEASE.md).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [cmesh-bot-v0.1.0] - 2026-07-10
|
||||||
|
|
||||||
|
First tagged release.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Signal report command `sig` (aliases `snr`, `rssi`, `signal`): shows the
|
||||||
|
SNR the bot heard your request at, plus its last RSSI and noise floor.
|
||||||
|
Made for range testing.
|
||||||
|
- Airtime command `air` (alias `airtime`): TX/RX airtime and flood/direct
|
||||||
|
packet counters.
|
||||||
|
- Coin flip command `coin` (aliases `flip`, `coinflip`).
|
||||||
|
- `cmd diag` lists the diagnostic command set separately, since the full
|
||||||
|
command list no longer fits one group-channel message.
|
||||||
- Hop-aware response coordination: bot delays its reply proportional to
|
- Hop-aware response coordination: bot delays its reply proportional to
|
||||||
the sender's hop count so the closest bot wins; far bots suppress.
|
the sender's hop count (2 s per hop plus a quadratic term, wide caps)
|
||||||
|
so the closest bot wins; far bots suppress via response fingerprints
|
||||||
|
and request tokens.
|
||||||
- Utility commands: `time`, `lora`, `id`, `neighbors`.
|
- Utility commands: `time`, `lora`, `id`, `neighbors`.
|
||||||
- Neighbor tracking: bot remembers nodes heard directly within the last
|
- Neighbor tracking: bot remembers nodes heard directly within the last
|
||||||
hour for the `neighbors` command.
|
hour for the `neighbors` command.
|
||||||
- `received_at_timestamp` field on bot messages; personalized ack target
|
- `received_at_timestamp` field on bot messages; personalized ack target
|
||||||
in command context.
|
in command context.
|
||||||
- Comprehensive repository scaffolding: README, CONTRIBUTING, LICENSE,
|
- Full repository scaffolding: README, CONTRIBUTING, LICENSE, CHANGELOG,
|
||||||
CHANGELOG, RELEASE doc, issue/PR templates, release workflow building
|
RELEASE doc, issue/PR templates, release workflow building every
|
||||||
all 133 companion USB+BLE environments.
|
non-excluded companion USB+BLE environment.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- `BOT_HOP_STEP_MILLIS_DEFAULT` lowered from 5000 to 1500 ms per hop.
|
- MeshCore base updated from `910b1bee` to `bbb58cce` (upstream v1.16.0,
|
||||||
- Added `BOT_HOP_BIAS_MAX_MILLIS` cap of 8000 ms on the total hop bias.
|
272 commits: 5-byte ACKs, flood scope keys, NRF52 power saving, RP2040
|
||||||
- `BOT_RESPONSE_PENDING_TTL_MILLIS` raised from 15000 to 45000 ms.
|
build fixes, contacts sync fix, and more).
|
||||||
- `BOT_PREFS_VERSION` bumped 2 → 3 to force re-default of in-the-wild
|
- `help` and `cmd` listings are now derived from the command registry
|
||||||
bots that saved the broken 5000 ms hop-step value.
|
instead of hand-maintained lists that had drifted (`magic8` was missing
|
||||||
|
from both).
|
||||||
|
- `BOT_PREFS_VERSION` bumped to 7 so deployed bots re-default their
|
||||||
|
command mask and pick up the commands added in this release.
|
||||||
|
- Re-included six boards that build again on the new base after passing
|
||||||
|
local test builds: Pico W, RAK 11310, Waveshare RP2040 LoRa, Xiao
|
||||||
|
RP2040, and Nibble Screen Connect (USB and BLE). The remaining
|
||||||
|
exclusions are BLE variants that don't fit flash.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Release env enumeration now strips CR line endings, so companion
|
||||||
|
environments defined in variant files with CRLF (Minewsemi ME25LS01,
|
||||||
|
Wio WM1110, Nibble) are no longer silently missing from releases.
|
||||||
- Multi-hop senders on `#bot` no longer get silently ignored. Previously
|
- Multi-hop senders on `#bot` no longer get silently ignored. Previously
|
||||||
3+ hop responses scheduled past the 15 s TTL and were dropped by the
|
3+ hop responses scheduled past the 15 s TTL and were dropped by the
|
||||||
coordinator's `poll()` as `READY_EXPIRED`. Verified on a Heltec V3
|
coordinator's `poll()` as `READY_EXPIRED`. Verified on a Heltec V3
|
||||||
|
|||||||
@@ -23,19 +23,18 @@ The submodule is a real git repo. Iterate inside it like normal:
|
|||||||
2. **Apply patches** with `bash scripts/apply-patches.sh`. This commits the
|
2. **Apply patches** with `bash scripts/apply-patches.sh`. This commits the
|
||||||
patch queue on top of `origin/main` in the submodule, leaving you with
|
patch queue on top of `origin/main` in the submodule, leaving you with
|
||||||
a clean tree pinned to a known state.
|
a clean tree pinned to a known state.
|
||||||
3. **Make changes inside `vendor/MeshCore/`** — edit files, run
|
3. **Edit inside `vendor/MeshCore/`.** Compile with `pio run -e <env>`
|
||||||
`pio run -e <env>` to compile, commit your changes in the submodule
|
and commit your changes in the submodule with descriptive messages.
|
||||||
with descriptive messages.
|
|
||||||
4. **Re-export the patch queue** with
|
4. **Re-export the patch queue** with
|
||||||
`bash scripts/export-patches.sh origin/main`. This deletes
|
`bash scripts/export-patches.sh origin/main`. This deletes
|
||||||
`patches/meshcore/*.patch` and regenerates it from the submodule
|
`patches/meshcore/*.patch` and regenerates it from the submodule
|
||||||
commits since `origin/main`. Each patch corresponds to one submodule
|
commits since `origin/main`. Each patch corresponds to one submodule
|
||||||
commit, so keep commits small and focused.
|
commit, so keep commits small and focused.
|
||||||
5. **Run host tests** (`python3 tests/firmware_bot/run_tests.py`) — fast,
|
5. **Run host tests** (`python3 tests/firmware_bot/run_tests.py`). Fast,
|
||||||
no hardware needed.
|
no hardware needed.
|
||||||
6. **Run safety checks** (`bash scripts/check-bot-safety.sh`) — verifies
|
6. **Run safety checks** (`bash scripts/check-bot-safety.sh`), which
|
||||||
the firmware doesn't expose private keys, network bridges, or other
|
verify the firmware doesn't expose private keys, network bridges, or
|
||||||
debug-only features in release builds.
|
other debug-only features in release builds.
|
||||||
7. **(Optional) Build representative envs** with
|
7. **(Optional) Build representative envs** with
|
||||||
`bash scripts/build-representative.sh --baseline` to confirm the
|
`bash scripts/build-representative.sh --baseline` to confirm the
|
||||||
binaries still link and to inspect size impact in `out/size/summary.json`.
|
binaries still link and to inspect size impact in `out/size/summary.json`.
|
||||||
@@ -44,14 +43,13 @@ The submodule is a real git repo. Iterate inside it like normal:
|
|||||||
|
|
||||||
## What goes where
|
## What goes where
|
||||||
|
|
||||||
- **Firmware/library code that MUST live inside MeshCore** for PlatformIO
|
- Firmware and library code that must live inside MeshCore for PlatformIO
|
||||||
builds — develop inside `vendor/MeshCore/`, export as a patch.
|
builds is developed inside `vendor/MeshCore/` and exported as a patch.
|
||||||
- **Test code (host-side C++ tests)** — `tests/firmware_bot/` at the
|
- Host-side C++ tests live in `tests/firmware_bot/` at the wrapper level.
|
||||||
wrapper level. They `#include` MeshCore headers via the script's `-I`
|
They `#include` MeshCore headers via the script's `-I` flag.
|
||||||
flag.
|
- Tooling, build scripts, and CI live in `scripts/` and `.github/` at the
|
||||||
- **Tooling, build scripts, CI** — `scripts/` and `.github/` at the
|
|
||||||
wrapper level.
|
wrapper level.
|
||||||
- **Colorado-specific docs, fixtures, board notes** — `colorado/`.
|
- Colorado-specific docs, fixtures, and board notes live in `colorado/`.
|
||||||
|
|
||||||
## Patch hygiene
|
## Patch hygiene
|
||||||
|
|
||||||
@@ -76,7 +74,8 @@ PRs run `.github/workflows/firmware-build.yml`, which:
|
|||||||
3. Uploads firmware + size reports as workflow artifacts.
|
3. Uploads firmware + size reports as workflow artifacts.
|
||||||
|
|
||||||
Releases run `.github/workflows/release.yml` on `cmesh-bot-v*` tags and
|
Releases run `.github/workflows/release.yml` on `cmesh-bot-v*` tags and
|
||||||
build all 133 companion USB+BLE environments — see [RELEASE.md](RELEASE.md).
|
build every non-excluded companion USB+BLE environment (139 at the current
|
||||||
|
pin); see [RELEASE.md](RELEASE.md).
|
||||||
|
|
||||||
## Pull request expectations
|
## Pull request expectations
|
||||||
|
|
||||||
|
|||||||
42
README.md
42
README.md
@@ -7,10 +7,10 @@
|
|||||||
Companion-radio firmware for the Colorado Mesh community, built on top of
|
Companion-radio firmware for the Colorado Mesh community, built on top of
|
||||||
[MeshCore](https://github.com/meshcore-dev/MeshCore). It adds an in-firmware
|
[MeshCore](https://github.com/meshcore-dev/MeshCore). It adds an in-firmware
|
||||||
"firmware bot" that responds to chat commands like `ping`, `trace`, `path`,
|
"firmware bot" that responds to chat commands like `ping`, `trace`, `path`,
|
||||||
`status`, `neighbors`, and `magic8`, with multi-bot response coordination so
|
`status`, `neighbors`, `sig`, and `magic8`, with multi-bot response
|
||||||
nearby Colorado bots don't all reply at once.
|
coordination so nearby Colorado bots don't all reply at once.
|
||||||
|
|
||||||
The bot runs entirely on-device — no internet, no companion-app bridge, no
|
The bot runs entirely on-device: no internet, no companion-app bridge, no
|
||||||
cloud. Useful as a low-friction probe / utility node on the Colorado mesh.
|
cloud. Useful as a low-friction probe / utility node on the Colorado mesh.
|
||||||
|
|
||||||
## What's different from upstream MeshCore
|
## What's different from upstream MeshCore
|
||||||
@@ -19,8 +19,9 @@ The release-built firmware applies a patch queue (`patches/meshcore/`) on top
|
|||||||
of a pinned MeshCore commit. The patches add:
|
of a pinned MeshCore commit. The patches add:
|
||||||
|
|
||||||
- A bot command registry (`help`, `cmd`, `ping`, `test`, `hello`, `about`,
|
- A bot command registry (`help`, `cmd`, `ping`, `test`, `hello`, `about`,
|
||||||
`roll`, `dice`, `status`, `channels`, `version`, `stats`, `magic8`, `path`,
|
`roll`, `dice`, `coin`, `status`, `channels`, `version`, `stats`, `magic8`,
|
||||||
`trace`, `tracer`, `prefix`, `time`, `lora`, `id`, `neighbors`)
|
`path`, `trace`, `tracer`, `prefix`, `time`, `lora`, `id`, `neighbors`,
|
||||||
|
`sig`, `air`)
|
||||||
- Channel-aware response policy (`#bot`, `#testing` for normal commands;
|
- Channel-aware response policy (`#bot`, `#testing` for normal commands;
|
||||||
`#emergency` for emergency forwards to `Public`; all other channels ignored)
|
`#emergency` for emergency forwards to `Public`; all other channels ignored)
|
||||||
- Multi-bot response coordinator with hop-aware delay, bounded TTL, and
|
- Multi-bot response coordinator with hop-aware delay, bounded TTL, and
|
||||||
@@ -37,10 +38,12 @@ re-exported from the submodule.
|
|||||||
## Supported boards
|
## Supported boards
|
||||||
|
|
||||||
The release workflow builds **every** `*_companion_radio_usb` and
|
The release workflow builds **every** `*_companion_radio_usb` and
|
||||||
`*_companion_radio_ble` PlatformIO environment exposed by upstream MeshCore
|
`*_companion_radio_ble` PlatformIO environment exposed by upstream MeshCore,
|
||||||
— 133 boards across ESP32, NRF52, RP2040, and STM32 platforms (Heltec V3,
|
minus a short exclusion list of BLE variants that don't fit flash (see
|
||||||
RAK 4631, LilyGo T-Echo, T-Beam, T-Deck, Xiao S3, Nano G2, ThinkNode,
|
`scripts/list-release-companion-envs.sh`). That is 139 boards at the current
|
||||||
Meshtiny, Pico W, and many more). See the
|
pin, across ESP32, NRF52, RP2040, and STM32 platforms (Heltec V3, RAK 4631,
|
||||||
|
LilyGo T-Echo, T-Beam, T-Deck, Xiao S3, Nano G2, ThinkNode, Meshtiny, Pico W,
|
||||||
|
and many more). See the
|
||||||
[latest release assets](https://github.com/Colorado-Mesh/meshcore-bot-firmware/releases/latest)
|
[latest release assets](https://github.com/Colorado-Mesh/meshcore-bot-firmware/releases/latest)
|
||||||
for the full list.
|
for the full list.
|
||||||
|
|
||||||
@@ -84,19 +87,22 @@ use `adafruit-nrfutil dfu serial -pkg <board>.zip -p <port>`.
|
|||||||
|
|
||||||
Once flashed, the bot joins the channels configured in its prefs. By default
|
Once flashed, the bot joins the channels configured in its prefs. By default
|
||||||
those are `#bot`, `#testing`, `#emergency`, and `Public`. Send commands on
|
those are `#bot`, `#testing`, `#emergency`, and `Public`. Send commands on
|
||||||
`#bot` (or DM the bot directly) without any prefix — for example:
|
`#bot` (or DM the bot directly) without any prefix, for example:
|
||||||
|
|
||||||
| Command | Response |
|
| Command | Response |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `ping` | `Pong` |
|
| `ping` | `Pong` |
|
||||||
| `hello` | `Hello @[<your-name>], from <bot-name>` |
|
| `hello` | `Hello @[<your-name>], from <bot-name>` |
|
||||||
| `path` | Compact route summary back to you, e.g. `Path 3h@2B SNR -6.25 \| 2751 -> ea4d -> 430d` |
|
| `path` | Compact route summary back to you, e.g. `Path 3 hops, 2-byte hashes, SNR -6.25 \| 2751 -> ea4d -> 430d` |
|
||||||
| `trace` | Active trace request along your reverse path |
|
| `trace` | Active trace request along your reverse path |
|
||||||
|
| `sig` | How the bot heard you: request SNR, plus local RSSI and noise floor |
|
||||||
| `status` | Bot uptime, battery, storage, send counters |
|
| `status` | Bot uptime, battery, storage, send counters |
|
||||||
| `neighbors` | Nodes heard directly within the last hour |
|
| `neighbors` | Nodes heard directly within the last hour |
|
||||||
|
| `air` | TX/RX airtime and flood/direct packet counters |
|
||||||
| `version` | Firmware version + build date |
|
| `version` | Firmware version + build date |
|
||||||
| `magic8 <question>` | Classic 8-ball answer |
|
| `magic8 <question>` | Classic 8-ball answer |
|
||||||
| `help` | List all commands |
|
| `roll`, `dice`, `coin` | Random numbers, D&D dice, coin flips |
|
||||||
|
| `help` | List chat commands (`cmd diag` lists the diagnostic set) |
|
||||||
|
|
||||||
In any other channel the bot stays silent (except `#emergency`, which it
|
In any other channel the bot stays silent (except `#emergency`, which it
|
||||||
re-forwards to `Public`).
|
re-forwards to `Public`).
|
||||||
@@ -107,14 +113,14 @@ wins the race and others suppress. This avoids spam on the channel.
|
|||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
- `vendor/MeshCore/` — pinned upstream MeshCore submodule.
|
- `vendor/MeshCore/`: pinned upstream MeshCore submodule.
|
||||||
- `patches/meshcore/` — ordered patch queue applied to the submodule.
|
- `patches/meshcore/`: ordered patch queue applied to the submodule.
|
||||||
- `colorado/` — Colorado Mesh overlay files, fixtures, and notes.
|
- `colorado/`: Colorado Mesh overlay files, fixtures, and notes.
|
||||||
- `scripts/` — wrapper scripts for patch, build, verify, and size-report
|
- `scripts/`: wrapper scripts for patch, build, verify, and size-report
|
||||||
workflows.
|
workflows.
|
||||||
- `tests/firmware_bot/` — host-side C++ unit tests for the bot code
|
- `tests/firmware_bot/`: host-side C++ unit tests for the bot code
|
||||||
(compile and run on your machine, no hardware required).
|
(compile and run on your machine, no hardware required).
|
||||||
- `.github/workflows/` — PR CI (`firmware-build.yml`) and tag-driven release
|
- `.github/workflows/`: PR CI (`firmware-build.yml`) and tag-driven release
|
||||||
(`release.yml`).
|
(`release.yml`).
|
||||||
|
|
||||||
## Local development
|
## Local development
|
||||||
|
|||||||
17
RELEASE.md
17
RELEASE.md
@@ -4,7 +4,8 @@ Releases are produced by pushing a `cmesh-bot-vX.Y.Z` tag. The
|
|||||||
`.github/workflows/release.yml` workflow then:
|
`.github/workflows/release.yml` workflow then:
|
||||||
|
|
||||||
1. Builds **every** companion USB+BLE environment exposed by the pinned
|
1. Builds **every** companion USB+BLE environment exposed by the pinned
|
||||||
MeshCore submodule (133 boards as of this writing).
|
MeshCore submodule, minus the exclusion list in
|
||||||
|
`scripts/list-release-companion-envs.sh` (139 boards at the current pin).
|
||||||
2. Splits the build across 8 parallel matrix shards for wall-time.
|
2. Splits the build across 8 parallel matrix shards for wall-time.
|
||||||
3. Embeds the tag version (`vX.Y.Z`) into the firmware via
|
3. Embeds the tag version (`vX.Y.Z`) into the firmware via
|
||||||
`FIRMWARE_VERSION`.
|
`FIRMWARE_VERSION`.
|
||||||
@@ -44,9 +45,9 @@ Review it, paste in the CHANGELOG entry as the description, and publish.
|
|||||||
|
|
||||||
## Tag scheme
|
## Tag scheme
|
||||||
|
|
||||||
- `cmesh-bot-vX.Y.Z` — production release.
|
- `cmesh-bot-vX.Y.Z`: production release.
|
||||||
- `cmesh-bot-vX.Y.Z-rc.N` — release candidate (still publishes as draft).
|
- `cmesh-bot-vX.Y.Z-rc.N`: release candidate (still publishes as draft).
|
||||||
- `cmesh-bot-vX.Y.Z-alpha.N` / `-beta.N` — pre-release, mark as
|
- `cmesh-bot-vX.Y.Z-alpha.N` / `-beta.N`: pre-release, mark as
|
||||||
pre-release when publishing.
|
pre-release when publishing.
|
||||||
|
|
||||||
The leading `cmesh-bot-` namespace leaves room for future variants
|
The leading `cmesh-bot-` namespace leaves room for future variants
|
||||||
@@ -57,14 +58,14 @@ The leading `cmesh-bot-` namespace leaves room for future variants
|
|||||||
Semantic-ish: bump major for breaking pref/protocol changes, minor for
|
Semantic-ish: bump major for breaking pref/protocol changes, minor for
|
||||||
new commands or boards, patch for fixes. Bump `BOT_PREFS_VERSION` in
|
new commands or boards, patch for fixes. Bump `BOT_PREFS_VERSION` in
|
||||||
`vendor/MeshCore/examples/companion_radio/BotTypes.h` whenever an
|
`vendor/MeshCore/examples/companion_radio/BotTypes.h` whenever an
|
||||||
existing pref field's meaning or default changes — that forces deployed
|
existing pref field's meaning or default changes. That forces deployed
|
||||||
bots to reset prefs on first boot.
|
bots to reset prefs on first boot.
|
||||||
|
|
||||||
## Hotfix / unpublish
|
## Hotfix / unpublish
|
||||||
|
|
||||||
If a published release turns out to be broken:
|
If a published release turns out to be broken:
|
||||||
|
|
||||||
1. Mark it as a pre-release (don't delete — flashed devices may still
|
1. Mark it as a pre-release (don't delete it; flashed devices may still
|
||||||
reference the URL).
|
reference the URL).
|
||||||
2. Tag and publish `cmesh-bot-vX.Y.(Z+1)` immediately.
|
2. Tag and publish `cmesh-bot-vX.Y.(Z+1)` immediately.
|
||||||
3. Edit the broken release's notes to point at the fix.
|
3. Edit the broken release's notes to point at the fix.
|
||||||
@@ -77,5 +78,5 @@ git push --delete origin cmesh-bot-vX.Y.Z
|
|||||||
# fix, re-tag, re-push
|
# fix, re-tag, re-push
|
||||||
```
|
```
|
||||||
|
|
||||||
Avoid deleting tags after the workflow has published artifacts — users
|
Avoid deleting tags after the workflow has published artifacts, since
|
||||||
may have already downloaded them.
|
users may have already downloaded them.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Fri, 15 May 2026 11:44:21 -0600
|
Date: Fri, 15 May 2026 11:44:21 -0600
|
||||||
Subject: [PATCH 01/14] Add companion radio firmware bot command parity
|
Subject: [PATCH 01/15] Add companion radio firmware bot command parity
|
||||||
|
|
||||||
---
|
---
|
||||||
.../companion_radio/BotCommandRegistry.cpp | 121 ++
|
.../companion_radio/BotCommandRegistry.cpp | 121 ++
|
||||||
@@ -1428,7 +1428,7 @@ index 00000000..5c7430a9
|
|||||||
+static_assert(sizeof(BotPrefs) <= 320, "BotPrefs RAM budget exceeded");
|
+static_assert(sizeof(BotPrefs) <= 320, "BotPrefs RAM budget exceeded");
|
||||||
+static_assert(sizeof(BotStats) <= 64, "BotStats RAM budget exceeded");
|
+static_assert(sizeof(BotStats) <= 64, "BotStats RAM budget exceeded");
|
||||||
diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp
|
diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp
|
||||||
index c7988bb3..9a134389 100644
|
index bf2f36c3..e6f52e09 100644
|
||||||
--- a/examples/companion_radio/DataStore.cpp
|
--- a/examples/companion_radio/DataStore.cpp
|
||||||
+++ b/examples/companion_radio/DataStore.cpp
|
+++ b/examples/companion_radio/DataStore.cpp
|
||||||
@@ -1,6 +1,10 @@
|
@@ -1,6 +1,10 @@
|
||||||
@@ -1482,7 +1482,7 @@ index c7988bb3..9a134389 100644
|
|||||||
File file = openRead(_fs, filename);
|
File file = openRead(_fs, filename);
|
||||||
if (file) {
|
if (file) {
|
||||||
diff --git a/examples/companion_radio/DataStore.h b/examples/companion_radio/DataStore.h
|
diff --git a/examples/companion_radio/DataStore.h b/examples/companion_radio/DataStore.h
|
||||||
index 58b4d5d2..187cd771 100644
|
index af5ee7af..702316cf 100644
|
||||||
--- a/examples/companion_radio/DataStore.h
|
--- a/examples/companion_radio/DataStore.h
|
||||||
+++ b/examples/companion_radio/DataStore.h
|
+++ b/examples/companion_radio/DataStore.h
|
||||||
@@ -5,6 +5,13 @@
|
@@ -5,6 +5,13 @@
|
||||||
@@ -1508,7 +1508,7 @@ index 58b4d5d2..187cd771 100644
|
|||||||
+ bool saveBotPrefs(const BotPrefs& prefs);
|
+ bool saveBotPrefs(const BotPrefs& prefs);
|
||||||
+#endif
|
+#endif
|
||||||
void loadContacts(DataStoreHost* host);
|
void loadContacts(DataStoreHost* host);
|
||||||
void saveContacts(DataStoreHost* host);
|
void saveContacts(DataStoreHost* host, bool (*filter)(const ContactInfo& c) = NULL);
|
||||||
void loadChannels(DataStoreHost* host);
|
void loadChannels(DataStoreHost* host);
|
||||||
diff --git a/examples/companion_radio/EmergencyForwarder.cpp b/examples/companion_radio/EmergencyForwarder.cpp
|
diff --git a/examples/companion_radio/EmergencyForwarder.cpp b/examples/companion_radio/EmergencyForwarder.cpp
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
@@ -2072,7 +2072,7 @@ index 00000000..5e93dad0
|
|||||||
+
|
+
|
||||||
+}
|
+}
|
||||||
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
||||||
index e8c1914b..44fcd1ca 100644
|
index 6fbb0f74..19963f38 100644
|
||||||
--- a/examples/companion_radio/MyMesh.cpp
|
--- a/examples/companion_radio/MyMesh.cpp
|
||||||
+++ b/examples/companion_radio/MyMesh.cpp
|
+++ b/examples/companion_radio/MyMesh.cpp
|
||||||
@@ -2,6 +2,21 @@
|
@@ -2,6 +2,21 @@
|
||||||
@@ -2097,7 +2097,7 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
|
|
||||||
#define CMD_APP_START 1
|
#define CMD_APP_START 1
|
||||||
#define CMD_SEND_TXT_MSG 2
|
#define CMD_SEND_TXT_MSG 2
|
||||||
@@ -105,8 +120,244 @@
|
@@ -106,8 +121,244 @@
|
||||||
#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250
|
#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250
|
||||||
#define LAZY_CONTACTS_WRITE_DELAY 5000
|
#define LAZY_CONTACTS_WRITE_DELAY 5000
|
||||||
|
|
||||||
@@ -2342,7 +2342,7 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
// these are _pushed_ to client app at any time
|
// these are _pushed_ to client app at any time
|
||||||
#define PUSH_CODE_ADVERT 0x80
|
#define PUSH_CODE_ADVERT 0x80
|
||||||
#define PUSH_CODE_PATH_UPDATED 0x81
|
#define PUSH_CODE_PATH_UPDATED 0x81
|
||||||
@@ -514,6 +765,9 @@ void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t
|
@@ -523,6 +774,9 @@ void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t
|
||||||
const char *text) {
|
const char *text) {
|
||||||
markConnectionActive(from); // in case this is from a server, and we have a connection
|
markConnectionActive(from); // in case this is from a server, and we have a connection
|
||||||
queueMessage(from, TXT_TYPE_PLAIN, pkt, sender_timestamp, NULL, 0, text);
|
queueMessage(from, TXT_TYPE_PLAIN, pkt, sender_timestamp, NULL, 0, text);
|
||||||
@@ -2352,7 +2352,7 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MyMesh::onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp,
|
void MyMesh::onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp,
|
||||||
@@ -528,8 +782,840 @@ void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uin
|
@@ -537,8 +791,840 @@ void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uin
|
||||||
// from.sync_since change needs to be persisted
|
// from.sync_since change needs to be persisted
|
||||||
dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
|
dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
|
||||||
queueMessage(from, TXT_TYPE_SIGNED_PLAIN, pkt, sender_timestamp, sender_prefix, 4, text);
|
queueMessage(from, TXT_TYPE_SIGNED_PLAIN, pkt, sender_timestamp, sender_prefix, 4, text);
|
||||||
@@ -2399,8 +2399,8 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
+ (unsigned)bot_prefs.normal_jitter_ms);
|
+ (unsigned)bot_prefs.normal_jitter_ms);
|
||||||
+ Serial.printf(" > advert local=%lu flood=%lu\n", (unsigned long)bot_prefs.local_advert_interval_ms,
|
+ Serial.printf(" > advert local=%lu flood=%lu\n", (unsigned long)bot_prefs.local_advert_interval_ms,
|
||||||
+ (unsigned long)bot_prefs.flood_advert_interval_ms);
|
+ (unsigned long)bot_prefs.flood_advert_interval_ms);
|
||||||
+}
|
}
|
||||||
+
|
|
||||||
+bool MyMesh::handleBotCLI(const char *args) {
|
+bool MyMesh::handleBotCLI(const char *args) {
|
||||||
+ if (!args) return false;
|
+ if (!args) return false;
|
||||||
+ botSkipSpaces(&args);
|
+ botSkipSpaces(&args);
|
||||||
@@ -2705,8 +2705,8 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
+ pending->text[pending->text_len] = 0;
|
+ pending->text[pending->text_len] = 0;
|
||||||
+ pending->active = true;
|
+ pending->active = true;
|
||||||
+ return true;
|
+ return true;
|
||||||
}
|
+}
|
||||||
|
+
|
||||||
+bool MyMesh::findBotChannel(BotChannelKind kind, uint8_t &channel_idx) {
|
+bool MyMesh::findBotChannel(BotChannelKind kind, uint8_t &channel_idx) {
|
||||||
+ for (uint8_t i = 0; i < MAX_GROUP_CHANNELS; i++) {
|
+ for (uint8_t i = 0; i < MAX_GROUP_CHANNELS; i++) {
|
||||||
+ ChannelDetails channel;
|
+ ChannelDetails channel;
|
||||||
@@ -3193,7 +3193,7 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp,
|
void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp,
|
||||||
const char *text) {
|
const char *text) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -566,15 +1652,17 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe
|
@@ -575,15 +1661,17 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe
|
||||||
if (_ui) _ui->notify(UIEventType::channelMessage);
|
if (_ui) _ui->notify(UIEventType::channelMessage);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -3213,7 +3213,7 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MyMesh::onChannelDataRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint16_t data_type,
|
void MyMesh::onChannelDataRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint16_t data_type,
|
||||||
@@ -829,6 +1917,23 @@ void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code,
|
@@ -838,6 +1926,23 @@ void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code,
|
||||||
} else {
|
} else {
|
||||||
MESH_DEBUG_PRINTLN("onTraceRecv(), data received while app offline");
|
MESH_DEBUG_PRINTLN("onTraceRecv(), data received while app offline");
|
||||||
}
|
}
|
||||||
@@ -3237,10 +3237,10 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t MyMesh::calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const {
|
uint32_t MyMesh::calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const {
|
||||||
@@ -856,6 +1961,19 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
|
@@ -866,6 +1971,19 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
|
||||||
dirty_contacts_expiry = 0;
|
|
||||||
memset(advert_paths, 0, sizeof(advert_paths));
|
memset(advert_paths, 0, sizeof(advert_paths));
|
||||||
memset(send_scope.key, 0, sizeof(send_scope.key));
|
memset(send_scope.key, 0, sizeof(send_scope.key));
|
||||||
|
send_unscoped = false;
|
||||||
+#if CMESH_BOT_ENABLED
|
+#if CMESH_BOT_ENABLED
|
||||||
+ BotPrefsCodec::defaults(bot_prefs);
|
+ BotPrefsCodec::defaults(bot_prefs);
|
||||||
+ memset(&bot_stats, 0, sizeof(bot_stats));
|
+ memset(&bot_stats, 0, sizeof(bot_stats));
|
||||||
@@ -3257,7 +3257,7 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
|
|
||||||
// defaults
|
// defaults
|
||||||
memset(&_prefs, 0, sizeof(_prefs));
|
memset(&_prefs, 0, sizeof(_prefs));
|
||||||
@@ -868,6 +1986,9 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
|
@@ -878,6 +1996,9 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
|
||||||
_prefs.tx_power_dbm = LORA_TX_POWER;
|
_prefs.tx_power_dbm = LORA_TX_POWER;
|
||||||
_prefs.gps_enabled = 0; // GPS disabled by default
|
_prefs.gps_enabled = 0; // GPS disabled by default
|
||||||
_prefs.gps_interval = 0; // No automatic GPS updates by default
|
_prefs.gps_interval = 0; // No automatic GPS updates by default
|
||||||
@@ -3267,7 +3267,7 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
//_prefs.rx_delay_base = 10.0f; enable once new algo fixed
|
//_prefs.rx_delay_base = 10.0f; enable once new algo fixed
|
||||||
#if defined(USE_SX1262) || defined(USE_SX1268)
|
#if defined(USE_SX1262) || defined(USE_SX1268)
|
||||||
#ifdef SX126X_RX_BOOSTED_GAIN
|
#ifdef SX126X_RX_BOOSTED_GAIN
|
||||||
@@ -956,6 +2077,11 @@ void MyMesh::begin(bool has_display) {
|
@@ -966,6 +2087,11 @@ void MyMesh::begin(bool has_display) {
|
||||||
radio_driver.setRxBoostedGainMode(_prefs.rx_boosted_gain);
|
radio_driver.setRxBoostedGainMode(_prefs.rx_boosted_gain);
|
||||||
MESH_DEBUG_PRINTLN("RX Boosted Gain Mode: %s",
|
MESH_DEBUG_PRINTLN("RX Boosted Gain Mode: %s",
|
||||||
radio_driver.getRxBoostedGainMode() ? "Enabled" : "Disabled");
|
radio_driver.getRxBoostedGainMode() ? "Enabled" : "Disabled");
|
||||||
@@ -3279,7 +3279,7 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *MyMesh::getNodeName() {
|
const char *MyMesh::getNodeName() {
|
||||||
@@ -1975,7 +3101,13 @@ void MyMesh::checkCLIRescueCmd() {
|
@@ -2023,7 +3149,13 @@ void MyMesh::checkCLIRescueCmd() {
|
||||||
if (len > 0 && cli_command[len - 1] == '\r') { // received complete line
|
if (len > 0 && cli_command[len - 1] == '\r') { // received complete line
|
||||||
cli_command[len - 1] = 0; // replace newline with C string null terminator
|
cli_command[len - 1] = 0; // replace newline with C string null terminator
|
||||||
|
|
||||||
@@ -3294,7 +3294,7 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
const char* config = &cli_command[4];
|
const char* config = &cli_command[4];
|
||||||
if (memcmp(config, "pin ", 4) == 0) {
|
if (memcmp(config, "pin ", 4) == 0) {
|
||||||
_prefs.ble_pin = atoi(&config[4]);
|
_prefs.ble_pin = atoi(&config[4]);
|
||||||
@@ -2172,6 +3304,10 @@ void MyMesh::loop() {
|
@@ -2228,6 +3360,10 @@ void MyMesh::loop() {
|
||||||
dirty_contacts_expiry = 0;
|
dirty_contacts_expiry = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3306,7 +3306,7 @@ index e8c1914b..44fcd1ca 100644
|
|||||||
if (_ui) _ui->setHasConnection(_serial->isConnected());
|
if (_ui) _ui->setHasConnection(_serial->isConnected());
|
||||||
#endif
|
#endif
|
||||||
diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h
|
diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h
|
||||||
index aeff591c..8d848fef 100644
|
index 43d3950b..c1159a31 100644
|
||||||
--- a/examples/companion_radio/MyMesh.h
|
--- a/examples/companion_radio/MyMesh.h
|
||||||
+++ b/examples/companion_radio/MyMesh.h
|
+++ b/examples/companion_radio/MyMesh.h
|
||||||
@@ -4,6 +4,15 @@
|
@@ -4,6 +4,15 @@
|
||||||
@@ -3323,9 +3323,9 @@ index aeff591c..8d848fef 100644
|
|||||||
+#endif
|
+#endif
|
||||||
+
|
+
|
||||||
/*------------ Frame Protocol --------------*/
|
/*------------ Frame Protocol --------------*/
|
||||||
#define FIRMWARE_VER_CODE 11
|
#define FIRMWARE_VER_CODE 13
|
||||||
|
|
||||||
@@ -192,6 +201,43 @@ private:
|
@@ -195,6 +204,43 @@ private:
|
||||||
return _store->putBlobByKey(key, key_len, src_buf, len);
|
return _store->putBlobByKey(key, key_len, src_buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3369,7 +3369,7 @@ index aeff591c..8d848fef 100644
|
|||||||
void checkCLIRescueCmd();
|
void checkCLIRescueCmd();
|
||||||
void checkSerialInterface();
|
void checkSerialInterface();
|
||||||
bool isValidClientRepeatFreq(uint32_t f) const;
|
bool isValidClientRepeatFreq(uint32_t f) const;
|
||||||
@@ -223,6 +269,53 @@ private:
|
@@ -227,6 +273,53 @@ private:
|
||||||
|
|
||||||
TransportKey send_scope;
|
TransportKey send_scope;
|
||||||
|
|
||||||
@@ -3679,7 +3679,7 @@ index 00000000..7717bee7
|
|||||||
+
|
+
|
||||||
+}
|
+}
|
||||||
diff --git a/platformio.ini b/platformio.ini
|
diff --git a/platformio.ini b/platformio.ini
|
||||||
index 864e5e1f..dfed7dbd 100644
|
index e16f7b83..e96147b9 100644
|
||||||
--- a/platformio.ini
|
--- a/platformio.ini
|
||||||
+++ b/platformio.ini
|
+++ b/platformio.ini
|
||||||
@@ -54,6 +54,14 @@ build_src_filter =
|
@@ -54,6 +54,14 @@ build_src_filter =
|
||||||
@@ -3698,7 +3698,7 @@ index 864e5e1f..dfed7dbd 100644
|
|||||||
extends = arduino_base
|
extends = arduino_base
|
||||||
platform = platformio/espressif32@6.11.0
|
platform = platformio/espressif32@6.11.0
|
||||||
diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini
|
diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini
|
||||||
index 803ee683..ca9cf00d 100644
|
index a70a93a5..8164bc78 100644
|
||||||
--- a/variants/heltec_v3/platformio.ini
|
--- a/variants/heltec_v3/platformio.ini
|
||||||
+++ b/variants/heltec_v3/platformio.ini
|
+++ b/variants/heltec_v3/platformio.ini
|
||||||
@@ -144,6 +144,7 @@ build_flags =
|
@@ -144,6 +144,7 @@ build_flags =
|
||||||
@@ -3718,10 +3718,10 @@ index 803ee683..ca9cf00d 100644
|
|||||||
-D AUTO_SHUTDOWN_MILLIVOLTS=3400
|
-D AUTO_SHUTDOWN_MILLIVOLTS=3400
|
||||||
-D BLE_DEBUG_LOGGING=1
|
-D BLE_DEBUG_LOGGING=1
|
||||||
diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini
|
diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini
|
||||||
index ea7e49c3..d6610098 100644
|
index 2bbba314..a1226fe3 100644
|
||||||
--- a/variants/rak4631/platformio.ini
|
--- a/variants/rak4631/platformio.ini
|
||||||
+++ b/variants/rak4631/platformio.ini
|
+++ b/variants/rak4631/platformio.ini
|
||||||
@@ -122,6 +122,7 @@ build_flags =
|
@@ -127,6 +127,7 @@ build_flags =
|
||||||
-D DISPLAY_CLASS=SSD1306Display
|
-D DISPLAY_CLASS=SSD1306Display
|
||||||
-D MAX_CONTACTS=350
|
-D MAX_CONTACTS=350
|
||||||
-D MAX_GROUP_CHANNELS=40
|
-D MAX_GROUP_CHANNELS=40
|
||||||
@@ -3729,7 +3729,7 @@ index ea7e49c3..d6610098 100644
|
|||||||
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
|
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
|
||||||
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
|
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
|
||||||
build_src_filter = ${rak4631.build_src_filter}
|
build_src_filter = ${rak4631.build_src_filter}
|
||||||
@@ -143,6 +144,7 @@ build_flags =
|
@@ -148,6 +149,7 @@ build_flags =
|
||||||
-D DISPLAY_CLASS=SSD1306Display
|
-D DISPLAY_CLASS=SSD1306Display
|
||||||
-D MAX_CONTACTS=350
|
-D MAX_CONTACTS=350
|
||||||
-D MAX_GROUP_CHANNELS=40
|
-D MAX_GROUP_CHANNELS=40
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Fri, 15 May 2026 19:58:42 -0600
|
Date: Fri, 15 May 2026 19:58:42 -0600
|
||||||
Subject: [PATCH 02/14] Harden firmware bot response coordination
|
Subject: [PATCH 02/15] Harden firmware bot response coordination
|
||||||
|
|
||||||
---
|
---
|
||||||
examples/companion_radio/BotCommands.cpp | 2 +-
|
examples/companion_radio/BotCommands.cpp | 2 +-
|
||||||
@@ -153,10 +153,10 @@ index e248adc1..38d4416d 100644
|
|||||||
BotFingerprint responseFingerprintFor(const BotMessage& message, const char* response_text, size_t response_text_len);
|
BotFingerprint responseFingerprintFor(const BotMessage& message, const char* response_text, size_t response_text_len);
|
||||||
BotCommandId commandIdForName(const char* name, size_t len);
|
BotCommandId commandIdForName(const char* name, size_t len);
|
||||||
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
||||||
index 44fcd1ca..2ee5139b 100644
|
index 19963f38..cb557f5d 100644
|
||||||
--- a/examples/companion_radio/MyMesh.cpp
|
--- a/examples/companion_radio/MyMesh.cpp
|
||||||
+++ b/examples/companion_radio/MyMesh.cpp
|
+++ b/examples/companion_radio/MyMesh.cpp
|
||||||
@@ -139,6 +139,18 @@ static void botCopyString(char *dest, size_t dest_len, const char *src) {
|
@@ -140,6 +140,18 @@ static void botCopyString(char *dest, size_t dest_len, const char *src) {
|
||||||
dest[len] = 0;
|
dest[len] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
static bool botParseU32(const char *text, uint32_t *value, const char **end_out) {
|
static bool botParseU32(const char *text, uint32_t *value, const char **end_out) {
|
||||||
if (!text || !value || !isdigit((unsigned char)text[0])) return false;
|
if (!text || !value || !isdigit((unsigned char)text[0])) return false;
|
||||||
uint32_t parsed = 0;
|
uint32_t parsed = 0;
|
||||||
@@ -598,6 +610,10 @@ void MyMesh::onContactsFull() {
|
@@ -599,6 +611,10 @@ void MyMesh::onContactsFull() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
|
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
|
||||||
@@ -186,7 +186,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
if (_serial->isConnected()) {
|
if (_serial->isConnected()) {
|
||||||
if (is_new) {
|
if (is_new) {
|
||||||
writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact);
|
writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact);
|
||||||
@@ -1040,11 +1056,9 @@ void MyMesh::observeBotChannelMessage(uint8_t channel_idx, const char *channel_n
|
@@ -1049,11 +1065,9 @@ void MyMesh::observeBotChannelMessage(uint8_t channel_idx, const char *channel_n
|
||||||
message.path = packet->path;
|
message.path = packet->path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
recordBotObservation(message, NULL, channel_idx);
|
recordBotObservation(message, NULL, channel_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1100,6 +1114,21 @@ void MyMesh::buildBotCommandContext(BotCommandContext &context, BotCommandId com
|
@@ -1109,6 +1123,21 @@ void MyMesh::buildBotCommandContext(BotCommandContext &context, BotCommandId com
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
bool MyMesh::enqueueBotResponse(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
bool MyMesh::enqueueBotResponse(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
||||||
const char *text, size_t text_len, BotFingerprint request_fingerprint,
|
const char *text, size_t text_len, BotFingerprint request_fingerprint,
|
||||||
BotFingerprint response_fingerprint) {
|
BotFingerprint response_fingerprint) {
|
||||||
@@ -1124,11 +1153,9 @@ bool MyMesh::enqueueBotResponse(const BotMessage &message, const ContactInfo *di
|
@@ -1133,11 +1162,9 @@ bool MyMesh::enqueueBotResponse(const BotMessage &message, const ContactInfo *di
|
||||||
pending->channel_idx = channel_idx;
|
pending->channel_idx = channel_idx;
|
||||||
pending->request_fingerprint = request_fingerprint;
|
pending->request_fingerprint = request_fingerprint;
|
||||||
pending->response_fingerprint = response_fingerprint;
|
pending->response_fingerprint = response_fingerprint;
|
||||||
@@ -238,7 +238,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
pending->active = true;
|
pending->active = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1204,7 +1231,14 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
@@ -1213,7 +1240,14 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
||||||
BotFingerprint request_fingerprint = FirmwareBot::fingerprintFor(message);
|
BotFingerprint request_fingerprint = FirmwareBot::fingerprintFor(message);
|
||||||
char response[BOT_MAX_RESPONSE_LEN + 1];
|
char response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
size_t response_len = botFormatTraceSent(response, sizeof(response));
|
size_t response_len = botFormatTraceSent(response, sizeof(response));
|
||||||
@@ -254,7 +254,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
BotFingerprint fingerprint;
|
BotFingerprint fingerprint;
|
||||||
uint32_t due_at_millis = 0;
|
uint32_t due_at_millis = 0;
|
||||||
uint32_t now = _ms->getMillis();
|
uint32_t now = _ms->getMillis();
|
||||||
@@ -1264,6 +1298,10 @@ bool MyMesh::enqueueBotTrace(const BotMessage &message, const ContactInfo *direc
|
@@ -1273,6 +1307,10 @@ bool MyMesh::enqueueBotTrace(const BotMessage &message, const ContactInfo *direc
|
||||||
memcpy(pending->recipient_pub_key, direct_recipient->id.pub_key, sizeof(pending->recipient_pub_key));
|
memcpy(pending->recipient_pub_key, direct_recipient->id.pub_key, sizeof(pending->recipient_pub_key));
|
||||||
}
|
}
|
||||||
pending->channel_idx = channel_idx;
|
pending->channel_idx = channel_idx;
|
||||||
@@ -265,7 +265,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
pending->request_fingerprint = request_fingerprint;
|
pending->request_fingerprint = request_fingerprint;
|
||||||
pending->response_fingerprint = response_fingerprint;
|
pending->response_fingerprint = response_fingerprint;
|
||||||
pending->tag = tag;
|
pending->tag = tag;
|
||||||
@@ -1275,6 +1313,16 @@ bool MyMesh::enqueueBotTrace(const BotMessage &message, const ContactInfo *direc
|
@@ -1284,6 +1322,16 @@ bool MyMesh::enqueueBotTrace(const BotMessage &message, const ContactInfo *direc
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +282,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
bool MyMesh::sendBotTraceText(const PendingBotTrace &pending, const char *text, size_t text_len,
|
bool MyMesh::sendBotTraceText(const PendingBotTrace &pending, const char *text, size_t text_len,
|
||||||
BotFingerprint response_fingerprint, uint32_t now_millis) {
|
BotFingerprint response_fingerprint, uint32_t now_millis) {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
@@ -1325,7 +1373,13 @@ bool MyMesh::sendPendingBotTrace(PendingBotTrace &pending, uint32_t now_millis)
|
@@ -1334,7 +1382,13 @@ bool MyMesh::sendPendingBotTrace(PendingBotTrace &pending, uint32_t now_millis)
|
||||||
|
|
||||||
char response[BOT_MAX_RESPONSE_LEN + 1];
|
char response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
size_t response_len = botFormatTraceSent(response, sizeof(response));
|
size_t response_len = botFormatTraceSent(response, sizeof(response));
|
||||||
@@ -297,7 +297,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MyMesh::expirePendingBotTraces(uint32_t now_millis) {
|
void MyMesh::expirePendingBotTraces(uint32_t now_millis) {
|
||||||
@@ -1334,10 +1388,13 @@ void MyMesh::expirePendingBotTraces(uint32_t now_millis) {
|
@@ -1343,10 +1397,13 @@ void MyMesh::expirePendingBotTraces(uint32_t now_millis) {
|
||||||
if (!pending->active || !pending->sent || (int32_t)(now_millis - pending->expires_at_millis) < 0) continue;
|
if (!pending->active || !pending->sent || (int32_t)(now_millis - pending->expires_at_millis) < 0) continue;
|
||||||
|
|
||||||
const char *response = "Trace timed out";
|
const char *response = "Trace timed out";
|
||||||
@@ -315,7 +315,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
pending->active = false;
|
pending->active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1384,6 +1441,18 @@ bool MyMesh::observeKnownBotResponse(const BotMessage &message, bool authoritati
|
@@ -1393,6 +1450,18 @@ bool MyMesh::observeKnownBotResponse(const BotMessage &message, bool authoritati
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,7 +334,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx) {
|
void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx) {
|
||||||
bot_stats.observed_messages++;
|
bot_stats.observed_messages++;
|
||||||
BotPolicyDecision decision = BotPolicy::decide(message.channel_kind);
|
BotPolicyDecision decision = BotPolicy::decide(message.channel_kind);
|
||||||
@@ -1403,6 +1472,7 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
@@ -1412,6 +1481,7 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
||||||
}
|
}
|
||||||
|
|
||||||
if (observeKnownBotResponse(message, direct_recipient != NULL)) return;
|
if (observeKnownBotResponse(message, direct_recipient != NULL)) return;
|
||||||
@@ -342,7 +342,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
sendQueuedBotResponses();
|
sendQueuedBotResponses();
|
||||||
|
|
||||||
BotCommand command;
|
BotCommand command;
|
||||||
@@ -1439,8 +1509,15 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
@@ -1448,8 +1518,15 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,7 +359,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
BotFingerprint fingerprint;
|
BotFingerprint fingerprint;
|
||||||
uint32_t due_at_millis = 0;
|
uint32_t due_at_millis = 0;
|
||||||
uint32_t bot_identity_seed;
|
uint32_t bot_identity_seed;
|
||||||
@@ -1462,7 +1539,7 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
@@ -1471,7 +1548,7 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
||||||
bot_stats.pending_responses++;
|
bot_stats.pending_responses++;
|
||||||
FirmwareBot::recordCommandCooldown(bot_command_cooldowns, BOT_COMMAND_COOLDOWN_SLOTS, command.id, _ms->getMillis(),
|
FirmwareBot::recordCommandCooldown(bot_command_cooldowns, BOT_COMMAND_COOLDOWN_SLOTS, command.id, _ms->getMillis(),
|
||||||
BOT_COMMAND_COOLDOWN_MILLIS);
|
BOT_COMMAND_COOLDOWN_MILLIS);
|
||||||
@@ -368,7 +368,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
ResponseCoordinator::cancel(bot_coordinator_pending, BOT_COORDINATOR_PENDING_SLOTS, fingerprint);
|
ResponseCoordinator::cancel(bot_coordinator_pending, BOT_COORDINATOR_PENDING_SLOTS, fingerprint);
|
||||||
bot_stats.send_failures++;
|
bot_stats.send_failures++;
|
||||||
}
|
}
|
||||||
@@ -1572,10 +1649,12 @@ void MyMesh::sendQueuedEmergencyForwards() {
|
@@ -1581,10 +1658,12 @@ void MyMesh::sendQueuedEmergencyForwards() {
|
||||||
|
|
||||||
bool MyMesh::sendBotSelfAdvert(bool flood) {
|
bool MyMesh::sendBotSelfAdvert(bool flood) {
|
||||||
mesh::Packet* pkt;
|
mesh::Packet* pkt;
|
||||||
@@ -383,7 +383,7 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
}
|
}
|
||||||
if (!pkt) return false;
|
if (!pkt) return false;
|
||||||
|
|
||||||
@@ -1927,9 +2006,13 @@ void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code,
|
@@ -1936,9 +2015,13 @@ void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code,
|
||||||
char response[BOT_MAX_RESPONSE_LEN + 1];
|
char response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
size_t response_len = botFormatTraceResult(response, sizeof(response), tag, flags, path_hashes, path_len,
|
size_t response_len = botFormatTraceResult(response, sizeof(response), tag, flags, path_hashes, path_len,
|
||||||
(int8_t)(packet->getSNR() * 4));
|
(int8_t)(packet->getSNR() * 4));
|
||||||
@@ -401,10 +401,10 @@ index 44fcd1ca..2ee5139b 100644
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h
|
diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h
|
||||||
index 8d848fef..67bdc010 100644
|
index c1159a31..1197caff 100644
|
||||||
--- a/examples/companion_radio/MyMesh.h
|
--- a/examples/companion_radio/MyMesh.h
|
||||||
+++ b/examples/companion_radio/MyMesh.h
|
+++ b/examples/companion_radio/MyMesh.h
|
||||||
@@ -214,7 +214,9 @@ private:
|
@@ -217,7 +217,9 @@ private:
|
||||||
uint32_t sender_timestamp, const mesh::Packet *packet);
|
uint32_t sender_timestamp, const mesh::Packet *packet);
|
||||||
void recordBotObservation(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx);
|
void recordBotObservation(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx);
|
||||||
bool observeKnownBotResponse(const BotMessage &message, bool authoritative_sender);
|
bool observeKnownBotResponse(const BotMessage &message, bool authoritative_sender);
|
||||||
@@ -414,7 +414,7 @@ index 8d848fef..67bdc010 100644
|
|||||||
bool enqueueBotResponse(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
bool enqueueBotResponse(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
||||||
const char *text, size_t text_len, BotFingerprint request_fingerprint,
|
const char *text, size_t text_len, BotFingerprint request_fingerprint,
|
||||||
BotFingerprint response_fingerprint);
|
BotFingerprint response_fingerprint);
|
||||||
@@ -226,6 +228,7 @@ private:
|
@@ -229,6 +231,7 @@ private:
|
||||||
BotFingerprint response_fingerprint, uint32_t tag, uint32_t auth_code);
|
BotFingerprint response_fingerprint, uint32_t tag, uint32_t auth_code);
|
||||||
bool sendBotTraceText(const PendingBotTrace &pending, const char *text, size_t text_len,
|
bool sendBotTraceText(const PendingBotTrace &pending, const char *text, size_t text_len,
|
||||||
BotFingerprint response_fingerprint, uint32_t now_millis);
|
BotFingerprint response_fingerprint, uint32_t now_millis);
|
||||||
@@ -422,7 +422,7 @@ index 8d848fef..67bdc010 100644
|
|||||||
bool sendPendingBotTrace(PendingBotTrace &pending, uint32_t now_millis);
|
bool sendPendingBotTrace(PendingBotTrace &pending, uint32_t now_millis);
|
||||||
void expirePendingBotTraces(uint32_t now_millis);
|
void expirePendingBotTraces(uint32_t now_millis);
|
||||||
bool enqueueEmergencyForward(const BotMessage &message);
|
bool enqueueEmergencyForward(const BotMessage &message);
|
||||||
@@ -291,8 +294,12 @@ private:
|
@@ -295,8 +298,12 @@ private:
|
||||||
bool active;
|
bool active;
|
||||||
bool direct;
|
bool direct;
|
||||||
bool sent;
|
bool sent;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Fri, 15 May 2026 20:09:58 -0600
|
Date: Fri, 15 May 2026 20:09:58 -0600
|
||||||
Subject: [PATCH 03/14] Allow prefixless firmware bot DMs
|
Subject: [PATCH 03/15] Allow prefixless firmware bot DMs
|
||||||
|
|
||||||
---
|
---
|
||||||
examples/companion_radio/BotPolicy.cpp | 2 +-
|
examples/companion_radio/BotPolicy.cpp | 2 +-
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Sat, 16 May 2026 04:12:02 +0000
|
Date: Sat, 16 May 2026 04:12:02 +0000
|
||||||
Subject: [PATCH 04/14] Align firmware bot commands with upstream behavior
|
Subject: [PATCH 04/15] Align firmware bot commands with upstream behavior
|
||||||
|
|
||||||
---
|
---
|
||||||
.../companion_radio/BotCommandRegistry.cpp | 25 +-
|
.../companion_radio/BotCommandRegistry.cpp | 25 +-
|
||||||
@@ -816,10 +816,10 @@ index 38d4416d..9eff340b 100644
|
|||||||
bool isBotAdvertName(const char* name, size_t name_len);
|
bool isBotAdvertName(const char* name, size_t name_len);
|
||||||
BotFingerprint fingerprintFor(const BotMessage& message);
|
BotFingerprint fingerprintFor(const BotMessage& message);
|
||||||
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
||||||
index 2ee5139b..7b87f14f 100644
|
index cb557f5d..e84b3a52 100644
|
||||||
--- a/examples/companion_radio/MyMesh.cpp
|
--- a/examples/companion_radio/MyMesh.cpp
|
||||||
+++ b/examples/companion_radio/MyMesh.cpp
|
+++ b/examples/companion_radio/MyMesh.cpp
|
||||||
@@ -223,7 +223,7 @@ static uint8_t botTraceHashSize(uint8_t flags) {
|
@@ -224,7 +224,7 @@ static uint8_t botTraceHashSize(uint8_t flags) {
|
||||||
|
|
||||||
static bool botTracePathShapeValid(uint8_t path_len, uint8_t flags) {
|
static bool botTracePathShapeValid(uint8_t path_len, uint8_t flags) {
|
||||||
uint8_t hash_size = botTraceHashSize(flags);
|
uint8_t hash_size = botTraceHashSize(flags);
|
||||||
@@ -828,7 +828,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
(path_len % hash_size) == 0 && (path_len / hash_size) <= MAX_PATH_SIZE;
|
(path_len % hash_size) == 0 && (path_len / hash_size) <= MAX_PATH_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,17 +236,42 @@ static void botCopyReversedPath(uint8_t *dest, const uint8_t *src, uint8_t hop_c
|
@@ -237,17 +237,42 @@ static void botCopyReversedPath(uint8_t *dest, const uint8_t *src, uint8_t hop_c
|
||||||
static bool botParseTraceHexPath(const BotCommand &command, uint8_t flags, uint8_t path[BOT_MAX_PATH_BYTES],
|
static bool botParseTraceHexPath(const BotCommand &command, uint8_t flags, uint8_t path[BOT_MAX_PATH_BYTES],
|
||||||
uint8_t *path_len) {
|
uint8_t *path_len) {
|
||||||
if (!path || !path_len || command.args_len == 0) return false;
|
if (!path || !path_len || command.args_len == 0) return false;
|
||||||
@@ -880,7 +880,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
*path_len = parsed_len;
|
*path_len = parsed_len;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -284,7 +309,7 @@ static BotCommandResult botWriteFormatted(char *output, size_t output_len, const
|
@@ -285,7 +310,7 @@ static BotCommandResult botWriteFormatted(char *output, size_t output_len, const
|
||||||
static bool botParsePubKeyPrefixHex(const BotCommand &command, uint8_t prefix[PUB_KEY_SIZE], uint8_t *prefix_len) {
|
static bool botParsePubKeyPrefixHex(const BotCommand &command, uint8_t prefix[PUB_KEY_SIZE], uint8_t *prefix_len) {
|
||||||
if (!prefix || !prefix_len || command.args_len == 0 || (command.args_len & 1) != 0) return false;
|
if (!prefix || !prefix_len || command.args_len == 0 || (command.args_len & 1) != 0) return false;
|
||||||
size_t byte_len = command.args_len / 2;
|
size_t byte_len = command.args_len / 2;
|
||||||
@@ -889,7 +889,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
for (size_t i = 0; i < byte_len; i++) {
|
for (size_t i = 0; i < byte_len; i++) {
|
||||||
int high = botHexValue(command.args[i * 2]);
|
int high = botHexValue(command.args[i * 2]);
|
||||||
int low = botHexValue(command.args[i * 2 + 1]);
|
int low = botHexValue(command.args[i * 2 + 1]);
|
||||||
@@ -341,14 +366,32 @@ static void botAppendHex(char *output, size_t output_len, size_t *pos, const uin
|
@@ -342,14 +367,32 @@ static void botAppendHex(char *output, size_t output_len, size_t *pos, const uin
|
||||||
if (output_len > 0) output[*pos < output_len ? *pos : output_len - 1] = 0;
|
if (output_len > 0) output[*pos < output_len ? *pos : output_len - 1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -929,7 +929,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
static size_t botFormatTraceResult(char *output, size_t output_len, uint32_t tag, uint8_t flags,
|
static size_t botFormatTraceResult(char *output, size_t output_len, uint32_t tag, uint8_t flags,
|
||||||
@@ -358,14 +401,22 @@ static size_t botFormatTraceResult(char *output, size_t output_len, uint32_t tag
|
@@ -359,14 +402,22 @@ static size_t botFormatTraceResult(char *output, size_t output_len, uint32_t tag
|
||||||
uint8_t hop_count = path_len / hash_size;
|
uint8_t hop_count = path_len / hash_size;
|
||||||
char snr[8];
|
char snr[8];
|
||||||
botFormatQuarters(snr_quarters, snr, sizeof(snr));
|
botFormatQuarters(snr_quarters, snr, sizeof(snr));
|
||||||
@@ -955,7 +955,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
return botBoundedStrLen(output, output_len);
|
return botBoundedStrLen(output, output_len);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1032,6 +1083,19 @@ void MyMesh::observeBotDirectMessage(const ContactInfo &from, uint32_t sender_ti
|
@@ -1041,6 +1092,19 @@ void MyMesh::observeBotDirectMessage(const ContactInfo &from, uint32_t sender_ti
|
||||||
if (sender_prefix && prefix_len > 0) memcpy(message.sender_key_prefix, sender_prefix, prefix_len);
|
if (sender_prefix && prefix_len > 0) memcpy(message.sender_key_prefix, sender_prefix, prefix_len);
|
||||||
message.sender_key_prefix_len = prefix_len;
|
message.sender_key_prefix_len = prefix_len;
|
||||||
message.sender_timestamp = sender_timestamp;
|
message.sender_timestamp = sender_timestamp;
|
||||||
@@ -975,7 +975,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
message.text_truncated = FirmwareBot::normalizeText(text, botBoundedStrLen(text, BOT_MAX_TEXT_LEN + 1), message.text,
|
message.text_truncated = FirmwareBot::normalizeText(text, botBoundedStrLen(text, BOT_MAX_TEXT_LEN + 1), message.text,
|
||||||
sizeof(message.text), &message.text_len) == BOT_WRITE_TRUNCATED;
|
sizeof(message.text), &message.text_len) == BOT_WRITE_TRUNCATED;
|
||||||
recordBotObservation(message, &from, 0xFF);
|
recordBotObservation(message, &from, 0xFF);
|
||||||
@@ -1048,6 +1112,7 @@ void MyMesh::observeBotChannelMessage(uint8_t channel_idx, const char *channel_n
|
@@ -1057,6 +1121,7 @@ void MyMesh::observeBotChannelMessage(uint8_t channel_idx, const char *channel_n
|
||||||
message.channel_name[channel_len] = 0;
|
message.channel_name[channel_len] = 0;
|
||||||
}
|
}
|
||||||
message.sender_timestamp = sender_timestamp;
|
message.sender_timestamp = sender_timestamp;
|
||||||
@@ -983,7 +983,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
if (packet && packet->isRouteFlood() && packet->path_len <= 0xFF && mesh::Packet::isValidPathLen((uint8_t)packet->path_len)) {
|
if (packet && packet->isRouteFlood() && packet->path_len <= 0xFF && mesh::Packet::isValidPathLen((uint8_t)packet->path_len)) {
|
||||||
message.path_len = (uint8_t)packet->path_len;
|
message.path_len = (uint8_t)packet->path_len;
|
||||||
message.path_hash_size = packet->getPathHashSize();
|
message.path_hash_size = packet->getPathHashSize();
|
||||||
@@ -1178,7 +1243,7 @@ BotCommandResult MyMesh::executeBotPrefixCommand(const BotCommand &command, char
|
@@ -1187,7 +1252,7 @@ BotCommandResult MyMesh::executeBotPrefixCommand(const BotCommand &command, char
|
||||||
uint8_t prefix[PUB_KEY_SIZE];
|
uint8_t prefix[PUB_KEY_SIZE];
|
||||||
uint8_t prefix_len = 0;
|
uint8_t prefix_len = 0;
|
||||||
if (!botParsePubKeyPrefixHex(command, prefix, &prefix_len)) {
|
if (!botParsePubKeyPrefixHex(command, prefix, &prefix_len)) {
|
||||||
@@ -992,7 +992,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
ContactInfo match;
|
ContactInfo match;
|
||||||
@@ -1217,10 +1282,17 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
@@ -1226,10 +1291,17 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
||||||
bool have_path = false;
|
bool have_path = false;
|
||||||
if (command.args_len > 0) {
|
if (command.args_len > 0) {
|
||||||
have_path = botParseTraceHexPath(command, flags, path, &path_len);
|
have_path = botParseTraceHexPath(command, flags, path, &path_len);
|
||||||
@@ -1012,7 +1012,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
path_len = raw_len;
|
path_len = raw_len;
|
||||||
have_path = true;
|
have_path = true;
|
||||||
}
|
}
|
||||||
@@ -1230,7 +1302,7 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
@@ -1239,7 +1311,7 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
||||||
|
|
||||||
BotFingerprint request_fingerprint = FirmwareBot::fingerprintFor(message);
|
BotFingerprint request_fingerprint = FirmwareBot::fingerprintFor(message);
|
||||||
char response[BOT_MAX_RESPONSE_LEN + 1];
|
char response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
@@ -1021,7 +1021,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
char final_response[BOT_MAX_RESPONSE_LEN + 1];
|
char final_response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
size_t final_response_len = 0;
|
size_t final_response_len = 0;
|
||||||
if (!botFormatResponseForChannel(message, response, response_len, final_response, sizeof(final_response),
|
if (!botFormatResponseForChannel(message, response, response_len, final_response, sizeof(final_response),
|
||||||
@@ -1247,7 +1319,7 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
@@ -1256,7 +1328,7 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
||||||
uint32_t jitter_seed = request_fingerprint.value ? (uint32_t)request_fingerprint.value : 1;
|
uint32_t jitter_seed = request_fingerprint.value ? (uint32_t)request_fingerprint.value : 1;
|
||||||
uint8_t queue_depth = (uint8_t)_mgr->getOutboundTotal();
|
uint8_t queue_depth = (uint8_t)_mgr->getOutboundTotal();
|
||||||
BotCoordinatorScheduleResult schedule = ResponseCoordinator::schedule(bot_coordinator_pending, BOT_COORDINATOR_PENDING_SLOTS,
|
BotCoordinatorScheduleResult schedule = ResponseCoordinator::schedule(bot_coordinator_pending, BOT_COORDINATOR_PENDING_SLOTS,
|
||||||
@@ -1030,7 +1030,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
response_fingerprint, now, jitter_seed,
|
response_fingerprint, now, jitter_seed,
|
||||||
bot_identity_seed, queue_depth, bot_prefs.normal_delay_ms,
|
bot_identity_seed, queue_depth, bot_prefs.normal_delay_ms,
|
||||||
bot_prefs.normal_jitter_ms, &fingerprint,
|
bot_prefs.normal_jitter_ms, &fingerprint,
|
||||||
@@ -1264,7 +1336,7 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
@@ -1273,7 +1345,7 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
||||||
|
|
||||||
bot_stats.eligible_messages++;
|
bot_stats.eligible_messages++;
|
||||||
bot_stats.pending_responses++;
|
bot_stats.pending_responses++;
|
||||||
@@ -1039,7 +1039,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
BOT_TRACE_COOLDOWN_MILLIS);
|
BOT_TRACE_COOLDOWN_MILLIS);
|
||||||
if (!enqueueBotTrace(message, direct_recipient, channel_idx, path, path_len, flags, fingerprint, response_fingerprint, tag,
|
if (!enqueueBotTrace(message, direct_recipient, channel_idx, path, path_len, flags, fingerprint, response_fingerprint, tag,
|
||||||
auth_code)) {
|
auth_code)) {
|
||||||
@@ -1278,7 +1350,7 @@ bool MyMesh::enqueueBotTrace(const BotMessage &message, const ContactInfo *direc
|
@@ -1287,7 +1359,7 @@ bool MyMesh::enqueueBotTrace(const BotMessage &message, const ContactInfo *direc
|
||||||
const uint8_t *path, uint8_t path_len, uint8_t flags,
|
const uint8_t *path, uint8_t path_len, uint8_t flags,
|
||||||
BotFingerprint request_fingerprint, BotFingerprint response_fingerprint, uint32_t tag,
|
BotFingerprint request_fingerprint, BotFingerprint response_fingerprint, uint32_t tag,
|
||||||
uint32_t auth_code) {
|
uint32_t auth_code) {
|
||||||
@@ -1048,7 +1048,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
|
|
||||||
size_t slot = BOT_PENDING_TRACE_SLOTS;
|
size_t slot = BOT_PENDING_TRACE_SLOTS;
|
||||||
for (size_t i = 0; i < BOT_PENDING_TRACE_SLOTS; i++) {
|
for (size_t i = 0; i < BOT_PENDING_TRACE_SLOTS; i++) {
|
||||||
@@ -1308,7 +1380,7 @@ bool MyMesh::enqueueBotTrace(const BotMessage &message, const ContactInfo *direc
|
@@ -1317,7 +1389,7 @@ bool MyMesh::enqueueBotTrace(const BotMessage &message, const ContactInfo *direc
|
||||||
pending->auth_code = auth_code;
|
pending->auth_code = auth_code;
|
||||||
pending->flags = flags;
|
pending->flags = flags;
|
||||||
pending->path_len = path_len;
|
pending->path_len = path_len;
|
||||||
@@ -1057,7 +1057,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
pending->active = true;
|
pending->active = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1372,7 +1444,7 @@ bool MyMesh::sendPendingBotTrace(PendingBotTrace &pending, uint32_t now_millis)
|
@@ -1381,7 +1453,7 @@ bool MyMesh::sendPendingBotTrace(PendingBotTrace &pending, uint32_t now_millis)
|
||||||
pending.expires_at_millis = now_millis + BOT_TRACE_TIMEOUT_MILLIS;
|
pending.expires_at_millis = now_millis + BOT_TRACE_TIMEOUT_MILLIS;
|
||||||
|
|
||||||
char response[BOT_MAX_RESPONSE_LEN + 1];
|
char response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
@@ -1066,7 +1066,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
char final_response[BOT_MAX_RESPONSE_LEN + 1];
|
char final_response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
size_t final_response_len = 0;
|
size_t final_response_len = 0;
|
||||||
if (!botFormatResponseForChannelKind(pending.channel_kind, response, response_len, final_response, sizeof(final_response),
|
if (!botFormatResponseForChannelKind(pending.channel_kind, response, response_len, final_response, sizeof(final_response),
|
||||||
@@ -1387,7 +1459,9 @@ void MyMesh::expirePendingBotTraces(uint32_t now_millis) {
|
@@ -1396,7 +1468,9 @@ void MyMesh::expirePendingBotTraces(uint32_t now_millis) {
|
||||||
PendingBotTrace *pending = &pending_bot_traces[i];
|
PendingBotTrace *pending = &pending_bot_traces[i];
|
||||||
if (!pending->active || !pending->sent || (int32_t)(now_millis - pending->expires_at_millis) < 0) continue;
|
if (!pending->active || !pending->sent || (int32_t)(now_millis - pending->expires_at_millis) < 0) continue;
|
||||||
|
|
||||||
@@ -1077,7 +1077,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
char final_response[BOT_MAX_RESPONSE_LEN + 1];
|
char final_response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
size_t final_response_len = 0;
|
size_t final_response_len = 0;
|
||||||
if (botFormatResponseForChannelKind(pending->channel_kind, response, botBoundedStrLen(response, BOT_MAX_RESPONSE_LEN + 1),
|
if (botFormatResponseForChannelKind(pending->channel_kind, response, botBoundedStrLen(response, BOT_MAX_RESPONSE_LEN + 1),
|
||||||
@@ -1491,19 +1565,43 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
@@ -1500,19 +1574,43 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
||||||
|
|
||||||
char response[BOT_MAX_RESPONSE_LEN + 1];
|
char response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
BotCommandResult result;
|
BotCommandResult result;
|
||||||
@@ -1127,7 +1127,7 @@ index 2ee5139b..7b87f14f 100644
|
|||||||
bot_stats.parse_errors++;
|
bot_stats.parse_errors++;
|
||||||
return;
|
return;
|
||||||
diff --git a/platformio.ini b/platformio.ini
|
diff --git a/platformio.ini b/platformio.ini
|
||||||
index dfed7dbd..e3e4b30f 100644
|
index e96147b9..e724ad35 100644
|
||||||
--- a/platformio.ini
|
--- a/platformio.ini
|
||||||
+++ b/platformio.ini
|
+++ b/platformio.ini
|
||||||
@@ -57,6 +57,7 @@ build_src_filter =
|
@@ -57,6 +57,7 @@ build_src_filter =
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Sat, 16 May 2026 12:38:13 -0600
|
Date: Sat, 16 May 2026 12:38:13 -0600
|
||||||
Subject: [PATCH 05/14] Add hop-aware bot coordination, utility commands, and
|
Subject: [PATCH 05/15] Add hop-aware bot coordination, utility commands, and
|
||||||
bounded delays
|
bounded delays
|
||||||
|
|
||||||
Adds new utility commands (TIME, LORA, ID, NEIGHBORS), neighbor tracking,
|
Adds new utility commands (TIME, LORA, ID, NEIGHBORS), neighbor tracking,
|
||||||
@@ -551,10 +551,10 @@ index de6dd92f..6aac8a1b 100644
|
|||||||
size_t actual = boundedStrLen(output, output_len);
|
size_t actual = boundedStrLen(output, output_len);
|
||||||
if (written) *written = actual;
|
if (written) *written = actual;
|
||||||
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
||||||
index 7b87f14f..34517c44 100644
|
index e84b3a52..27ff37c1 100644
|
||||||
--- a/examples/companion_radio/MyMesh.cpp
|
--- a/examples/companion_radio/MyMesh.cpp
|
||||||
+++ b/examples/companion_radio/MyMesh.cpp
|
+++ b/examples/companion_radio/MyMesh.cpp
|
||||||
@@ -394,31 +394,6 @@ static size_t botFormatTraceSent(char *output, size_t output_len, uint8_t hop_co
|
@@ -395,31 +395,6 @@ static size_t botFormatTraceSent(char *output, size_t output_len, uint8_t hop_co
|
||||||
return botBoundedStrLen(output, output_len);
|
return botBoundedStrLen(output, output_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,7 +586,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// these are _pushed_ to client app at any time
|
// these are _pushed_ to client app at any time
|
||||||
@@ -663,6 +638,13 @@ void MyMesh::onContactsFull() {
|
@@ -664,6 +639,13 @@ void MyMesh::onContactsFull() {
|
||||||
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
|
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
|
||||||
#if CMESH_BOT_ENABLED
|
#if CMESH_BOT_ENABLED
|
||||||
autoLearnKnownBotAdvert(contact);
|
autoLearnKnownBotAdvert(contact);
|
||||||
@@ -600,7 +600,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_serial->isConnected()) {
|
if (_serial->isConnected()) {
|
||||||
@@ -833,7 +815,7 @@ void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t
|
@@ -842,7 +824,7 @@ void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t
|
||||||
markConnectionActive(from); // in case this is from a server, and we have a connection
|
markConnectionActive(from); // in case this is from a server, and we have a connection
|
||||||
queueMessage(from, TXT_TYPE_PLAIN, pkt, sender_timestamp, NULL, 0, text);
|
queueMessage(from, TXT_TYPE_PLAIN, pkt, sender_timestamp, NULL, 0, text);
|
||||||
#if CMESH_BOT_ENABLED
|
#if CMESH_BOT_ENABLED
|
||||||
@@ -609,7 +609,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -850,7 +832,7 @@ void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uin
|
@@ -859,7 +841,7 @@ void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uin
|
||||||
dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
|
dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
|
||||||
queueMessage(from, TXT_TYPE_SIGNED_PLAIN, pkt, sender_timestamp, sender_prefix, 4, text);
|
queueMessage(from, TXT_TYPE_SIGNED_PLAIN, pkt, sender_timestamp, sender_prefix, 4, text);
|
||||||
#if CMESH_BOT_ENABLED
|
#if CMESH_BOT_ENABLED
|
||||||
@@ -618,7 +618,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1073,7 +1055,7 @@ bool MyMesh::handleBotCLI(const char *args) {
|
@@ -1082,7 +1064,7 @@ bool MyMesh::handleBotCLI(const char *args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyMesh::observeBotDirectMessage(const ContactInfo &from, uint32_t sender_timestamp, const uint8_t *sender_prefix,
|
void MyMesh::observeBotDirectMessage(const ContactInfo &from, uint32_t sender_timestamp, const uint8_t *sender_prefix,
|
||||||
@@ -627,7 +627,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
BotMessage message;
|
BotMessage message;
|
||||||
memset(&message, 0, sizeof(message));
|
memset(&message, 0, sizeof(message));
|
||||||
message.channel_kind = BotPolicy::classifyChannel(NULL, 0, true, bot_prefs);
|
message.channel_kind = BotPolicy::classifyChannel(NULL, 0, true, bot_prefs);
|
||||||
@@ -1084,7 +1066,13 @@ void MyMesh::observeBotDirectMessage(const ContactInfo &from, uint32_t sender_ti
|
@@ -1093,7 +1075,13 @@ void MyMesh::observeBotDirectMessage(const ContactInfo &from, uint32_t sender_ti
|
||||||
message.sender_key_prefix_len = prefix_len;
|
message.sender_key_prefix_len = prefix_len;
|
||||||
message.sender_timestamp = sender_timestamp;
|
message.sender_timestamp = sender_timestamp;
|
||||||
message.received_at_timestamp = getRTCClock()->getCurrentTime();
|
message.received_at_timestamp = getRTCClock()->getCurrentTime();
|
||||||
@@ -642,7 +642,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
if (from.out_path_len != OUT_PATH_UNKNOWN && mesh::Packet::isValidPathLen(from.out_path_len)) {
|
if (from.out_path_len != OUT_PATH_UNKNOWN && mesh::Packet::isValidPathLen(from.out_path_len)) {
|
||||||
message.path_len = from.out_path_len;
|
message.path_len = from.out_path_len;
|
||||||
message.path_hash_size = (from.out_path_len >> 6) + 1;
|
message.path_hash_size = (from.out_path_len >> 6) + 1;
|
||||||
@@ -1270,6 +1258,220 @@ BotCommandResult MyMesh::executeBotPrefixCommand(const BotCommand &command, char
|
@@ -1279,6 +1267,220 @@ BotCommandResult MyMesh::executeBotPrefixCommand(const BotCommand &command, char
|
||||||
return botWriteFormatted(output, output_len, "Prefix %s %s", key_hex, name);
|
return botWriteFormatted(output, output_len, "Prefix %s %s", key_hex, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -863,7 +863,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
||||||
const BotCommand &command) {
|
const BotCommand &command) {
|
||||||
uint8_t hash_size = command.args_len > 0 ? botConfiguredTraceHashSize(_prefs.path_hash_mode) : message.path_hash_size;
|
uint8_t hash_size = command.args_len > 0 ? botConfiguredTraceHashSize(_prefs.path_hash_mode) : message.path_hash_size;
|
||||||
@@ -1277,9 +1479,14 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
@@ -1286,9 +1488,14 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
||||||
uint8_t flags = 0;
|
uint8_t flags = 0;
|
||||||
if (!botTraceFlagForHashSize(hash_size, &flags)) return false;
|
if (!botTraceFlagForHashSize(hash_size, &flags)) return false;
|
||||||
|
|
||||||
@@ -878,7 +878,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
if (command.args_len > 0) {
|
if (command.args_len > 0) {
|
||||||
have_path = botParseTraceHexPath(command, flags, path, &path_len);
|
have_path = botParseTraceHexPath(command, flags, path, &path_len);
|
||||||
} else if (message.path_hash_size == hash_size) {
|
} else if (message.path_hash_size == hash_size) {
|
||||||
@@ -1292,13 +1499,20 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
@@ -1301,13 +1508,20 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
||||||
} else {
|
} else {
|
||||||
botCopyReversedPath(path, message.path, message.path_hash_count, hash_size);
|
botCopyReversedPath(path, message.path, message.path_hash_count, hash_size);
|
||||||
}
|
}
|
||||||
@@ -900,7 +900,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
|
|
||||||
BotFingerprint request_fingerprint = FirmwareBot::fingerprintFor(message);
|
BotFingerprint request_fingerprint = FirmwareBot::fingerprintFor(message);
|
||||||
char response[BOT_MAX_RESPONSE_LEN + 1];
|
char response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
@@ -1316,14 +1530,15 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
@@ -1325,14 +1539,15 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
||||||
uint32_t now = _ms->getMillis();
|
uint32_t now = _ms->getMillis();
|
||||||
uint32_t bot_identity_seed;
|
uint32_t bot_identity_seed;
|
||||||
memcpy(&bot_identity_seed, self_id.pub_key, sizeof(bot_identity_seed));
|
memcpy(&bot_identity_seed, self_id.pub_key, sizeof(bot_identity_seed));
|
||||||
@@ -919,7 +919,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
if (schedule == BOT_COORDINATOR_NO_SPACE || schedule == BOT_COORDINATOR_NOT_NORMAL) {
|
if (schedule == BOT_COORDINATOR_NO_SPACE || schedule == BOT_COORDINATOR_NOT_NORMAL) {
|
||||||
bot_stats.send_failures++;
|
bot_stats.send_failures++;
|
||||||
return true;
|
return true;
|
||||||
@@ -1372,6 +1587,7 @@ bool MyMesh::enqueueBotTrace(const BotMessage &message, const ContactInfo *direc
|
@@ -1381,6 +1596,7 @@ bool MyMesh::enqueueBotTrace(const BotMessage &message, const ContactInfo *direc
|
||||||
pending->channel_idx = channel_idx;
|
pending->channel_idx = channel_idx;
|
||||||
pending->channel_kind = message.channel_kind;
|
pending->channel_kind = message.channel_kind;
|
||||||
StrHelper::strzcpy(pending->channel_name, message.channel_name, sizeof(pending->channel_name));
|
StrHelper::strzcpy(pending->channel_name, message.channel_name, sizeof(pending->channel_name));
|
||||||
@@ -927,7 +927,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
memcpy(pending->sender_key_prefix, message.sender_key_prefix, sizeof(pending->sender_key_prefix));
|
memcpy(pending->sender_key_prefix, message.sender_key_prefix, sizeof(pending->sender_key_prefix));
|
||||||
pending->sender_key_prefix_len = message.sender_key_prefix_len;
|
pending->sender_key_prefix_len = message.sender_key_prefix_len;
|
||||||
pending->request_fingerprint = request_fingerprint;
|
pending->request_fingerprint = request_fingerprint;
|
||||||
@@ -1442,16 +1658,9 @@ bool MyMesh::sendPendingBotTrace(PendingBotTrace &pending, uint32_t now_millis)
|
@@ -1451,16 +1667,9 @@ bool MyMesh::sendPendingBotTrace(PendingBotTrace &pending, uint32_t now_millis)
|
||||||
sendDirect(pkt, pending.path, pending.path_len);
|
sendDirect(pkt, pending.path, pending.path_len);
|
||||||
pending.sent = true;
|
pending.sent = true;
|
||||||
pending.expires_at_millis = now_millis + BOT_TRACE_TIMEOUT_MILLIS;
|
pending.expires_at_millis = now_millis + BOT_TRACE_TIMEOUT_MILLIS;
|
||||||
@@ -947,7 +947,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MyMesh::expirePendingBotTraces(uint32_t now_millis) {
|
void MyMesh::expirePendingBotTraces(uint32_t now_millis) {
|
||||||
@@ -1460,8 +1669,26 @@ void MyMesh::expirePendingBotTraces(uint32_t now_millis) {
|
@@ -1469,8 +1678,26 @@ void MyMesh::expirePendingBotTraces(uint32_t now_millis) {
|
||||||
if (!pending->active || !pending->sent || (int32_t)(now_millis - pending->expires_at_millis) < 0) continue;
|
if (!pending->active || !pending->sent || (int32_t)(now_millis - pending->expires_at_millis) < 0) continue;
|
||||||
|
|
||||||
char response[BOT_MAX_RESPONSE_LEN + 1];
|
char response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
@@ -976,7 +976,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
char final_response[BOT_MAX_RESPONSE_LEN + 1];
|
char final_response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
size_t final_response_len = 0;
|
size_t final_response_len = 0;
|
||||||
if (botFormatResponseForChannelKind(pending->channel_kind, response, botBoundedStrLen(response, BOT_MAX_RESPONSE_LEN + 1),
|
if (botFormatResponseForChannelKind(pending->channel_kind, response, botBoundedStrLen(response, BOT_MAX_RESPONSE_LEN + 1),
|
||||||
@@ -1579,27 +1806,46 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
@@ -1588,27 +1815,46 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
||||||
|
|
||||||
BotCommandContext context;
|
BotCommandContext context;
|
||||||
buildBotCommandContext(context, command.id);
|
buildBotCommandContext(context, command.id);
|
||||||
@@ -1036,7 +1036,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (result.code == BOT_COMMAND_RESULT_NOT_HANDLED || result.code == BOT_COMMAND_RESULT_NO_SPACE || result.text_len == 0) {
|
if (result.code == BOT_COMMAND_RESULT_NOT_HANDLED || result.code == BOT_COMMAND_RESULT_NO_SPACE || result.text_len == 0) {
|
||||||
@@ -1620,14 +1866,16 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
@@ -1629,14 +1875,16 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
||||||
uint32_t due_at_millis = 0;
|
uint32_t due_at_millis = 0;
|
||||||
uint32_t bot_identity_seed;
|
uint32_t bot_identity_seed;
|
||||||
memcpy(&bot_identity_seed, self_id.pub_key, sizeof(bot_identity_seed));
|
memcpy(&bot_identity_seed, self_id.pub_key, sizeof(bot_identity_seed));
|
||||||
@@ -1056,7 +1056,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
if (schedule == BOT_COORDINATOR_NO_SPACE || schedule == BOT_COORDINATOR_NOT_NORMAL) {
|
if (schedule == BOT_COORDINATOR_NO_SPACE || schedule == BOT_COORDINATOR_NOT_NORMAL) {
|
||||||
bot_stats.send_failures++;
|
bot_stats.send_failures++;
|
||||||
return;
|
return;
|
||||||
@@ -2102,8 +2350,11 @@ void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code,
|
@@ -2111,8 +2359,11 @@ void MyMesh::onTraceRecv(mesh::Packet *packet, uint32_t tag, uint32_t auth_code,
|
||||||
if (!pending->active || !pending->sent || pending->tag != tag || pending->auth_code != auth_code) continue;
|
if (!pending->active || !pending->sent || pending->tag != tag || pending->auth_code != auth_code) continue;
|
||||||
|
|
||||||
char response[BOT_MAX_RESPONSE_LEN + 1];
|
char response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
@@ -1070,7 +1070,7 @@ index 7b87f14f..34517c44 100644
|
|||||||
char final_response[BOT_MAX_RESPONSE_LEN + 1];
|
char final_response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
size_t final_response_len = 0;
|
size_t final_response_len = 0;
|
||||||
if (botFormatResponseForChannelKind(pending->channel_kind, response, response_len, final_response,
|
if (botFormatResponseForChannelKind(pending->channel_kind, response, response_len, final_response,
|
||||||
@@ -2149,6 +2400,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
|
@@ -2159,6 +2410,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
|
||||||
memset(pending_bot_traces, 0, sizeof(pending_bot_traces));
|
memset(pending_bot_traces, 0, sizeof(pending_bot_traces));
|
||||||
memset(pending_emergency_forwards, 0, sizeof(pending_emergency_forwards));
|
memset(pending_emergency_forwards, 0, sizeof(pending_emergency_forwards));
|
||||||
memset(bot_command_cooldowns, 0, sizeof(bot_command_cooldowns));
|
memset(bot_command_cooldowns, 0, sizeof(bot_command_cooldowns));
|
||||||
@@ -1079,10 +1079,10 @@ index 7b87f14f..34517c44 100644
|
|||||||
ResponseCoordinator::clearRecent(bot_coordinator_recent, BOT_COORDINATOR_RECENT_SLOTS);
|
ResponseCoordinator::clearRecent(bot_coordinator_recent, BOT_COORDINATOR_RECENT_SLOTS);
|
||||||
KnownBotRegistry::clear(known_bot_entries, BOT_KNOWN_BOT_SLOTS);
|
KnownBotRegistry::clear(known_bot_entries, BOT_KNOWN_BOT_SLOTS);
|
||||||
diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h
|
diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h
|
||||||
index 67bdc010..9685e89a 100644
|
index 1197caff..488987c0 100644
|
||||||
--- a/examples/companion_radio/MyMesh.h
|
--- a/examples/companion_radio/MyMesh.h
|
||||||
+++ b/examples/companion_radio/MyMesh.h
|
+++ b/examples/companion_radio/MyMesh.h
|
||||||
@@ -209,7 +209,7 @@ private:
|
@@ -212,7 +212,7 @@ private:
|
||||||
void printBotPrefs();
|
void printBotPrefs();
|
||||||
bool handleBotCLI(const char *args);
|
bool handleBotCLI(const char *args);
|
||||||
void observeBotDirectMessage(const ContactInfo &from, uint32_t sender_timestamp, const uint8_t *sender_prefix,
|
void observeBotDirectMessage(const ContactInfo &from, uint32_t sender_timestamp, const uint8_t *sender_prefix,
|
||||||
@@ -1091,7 +1091,7 @@ index 67bdc010..9685e89a 100644
|
|||||||
void observeBotChannelMessage(uint8_t channel_idx, const char *channel_name, const char *text,
|
void observeBotChannelMessage(uint8_t channel_idx, const char *channel_name, const char *text,
|
||||||
uint32_t sender_timestamp, const mesh::Packet *packet);
|
uint32_t sender_timestamp, const mesh::Packet *packet);
|
||||||
void recordBotObservation(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx);
|
void recordBotObservation(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx);
|
||||||
@@ -222,7 +222,14 @@ private:
|
@@ -225,7 +225,14 @@ private:
|
||||||
BotFingerprint response_fingerprint);
|
BotFingerprint response_fingerprint);
|
||||||
bool handleBotTraceCommand(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
bool handleBotTraceCommand(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
||||||
const BotCommand &command);
|
const BotCommand &command);
|
||||||
@@ -1106,7 +1106,7 @@ index 67bdc010..9685e89a 100644
|
|||||||
bool enqueueBotTrace(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
bool enqueueBotTrace(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
||||||
const uint8_t *path, uint8_t path_len, uint8_t flags, BotFingerprint request_fingerprint,
|
const uint8_t *path, uint8_t path_len, uint8_t flags, BotFingerprint request_fingerprint,
|
||||||
BotFingerprint response_fingerprint, uint32_t tag, uint32_t auth_code);
|
BotFingerprint response_fingerprint, uint32_t tag, uint32_t auth_code);
|
||||||
@@ -298,6 +305,7 @@ private:
|
@@ -302,6 +309,7 @@ private:
|
||||||
uint8_t recipient_pub_key[PUB_KEY_SIZE];
|
uint8_t recipient_pub_key[PUB_KEY_SIZE];
|
||||||
uint8_t channel_idx;
|
uint8_t channel_idx;
|
||||||
char channel_name[BOT_MAX_CHANNEL_NAME_LEN + 1];
|
char channel_name[BOT_MAX_CHANNEL_NAME_LEN + 1];
|
||||||
@@ -1114,7 +1114,7 @@ index 67bdc010..9685e89a 100644
|
|||||||
uint8_t sender_key_prefix[BOT_SENDER_KEY_PREFIX_LEN];
|
uint8_t sender_key_prefix[BOT_SENDER_KEY_PREFIX_LEN];
|
||||||
uint8_t sender_key_prefix_len;
|
uint8_t sender_key_prefix_len;
|
||||||
BotFingerprint request_fingerprint;
|
BotFingerprint request_fingerprint;
|
||||||
@@ -319,6 +327,7 @@ private:
|
@@ -323,6 +331,7 @@ private:
|
||||||
BotCoordinatorPending bot_coordinator_pending[BOT_COORDINATOR_PENDING_SLOTS];
|
BotCoordinatorPending bot_coordinator_pending[BOT_COORDINATOR_PENDING_SLOTS];
|
||||||
BotCoordinatorRecent bot_coordinator_recent[BOT_COORDINATOR_RECENT_SLOTS];
|
BotCoordinatorRecent bot_coordinator_recent[BOT_COORDINATOR_RECENT_SLOTS];
|
||||||
BotKnownBotEntry known_bot_entries[BOT_KNOWN_BOT_SLOTS];
|
BotKnownBotEntry known_bot_entries[BOT_KNOWN_BOT_SLOTS];
|
||||||
@@ -1246,11 +1246,11 @@ index 7717bee7..f549b887 100644
|
|||||||
bool cancel(BotCoordinatorPending pending[], size_t pending_count, BotFingerprint request_fingerprint);
|
bool cancel(BotCoordinatorPending pending[], size_t pending_count, BotFingerprint request_fingerprint);
|
||||||
BotCoordinatorReady poll(BotCoordinatorPending pending[], size_t pending_count, uint32_t now_millis);
|
BotCoordinatorReady poll(BotCoordinatorPending pending[], size_t pending_count, uint32_t now_millis);
|
||||||
diff --git a/src/Mesh.cpp b/src/Mesh.cpp
|
diff --git a/src/Mesh.cpp b/src/Mesh.cpp
|
||||||
index 57fee140..9c512b20 100644
|
index 87ad61af..4a3cc567 100644
|
||||||
--- a/src/Mesh.cpp
|
--- a/src/Mesh.cpp
|
||||||
+++ b/src/Mesh.cpp
|
+++ b/src/Mesh.cpp
|
||||||
@@ -53,12 +53,22 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
@@ -55,12 +55,22 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
|
||||||
uint8_t offset = pkt->path_len << path_sz;
|
uint16_t offset = (uint16_t)pkt->path_len << path_sz;
|
||||||
if (offset >= len) { // TRACE has reached end of given path
|
if (offset >= len) { // TRACE has reached end of given path
|
||||||
onTraceRecv(pkt, trace_tag, auth_code, flags, pkt->path, &pkt->payload[i], len);
|
onTraceRecv(pkt, trace_tag, auth_code, flags, pkt->path, &pkt->payload[i], len);
|
||||||
- } else if (self_id.isHashMatch(&pkt->payload[i + offset], 1 << path_sz) && allowPacketForward(pkt) && !_tables->hasSeen(pkt)) {
|
- } else if (self_id.isHashMatch(&pkt->payload[i + offset], 1 << path_sz) && allowPacketForward(pkt) && !_tables->hasSeen(pkt)) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Sat, 16 May 2026 18:58:28 -0600
|
Date: Sat, 16 May 2026 18:58:28 -0600
|
||||||
Subject: [PATCH 06/14] Mark bot adverts, speed up initial advert, default
|
Subject: [PATCH 06/15] Mark bot adverts, speed up initial advert, default
|
||||||
contacts auto-overwrite
|
contacts auto-overwrite
|
||||||
|
|
||||||
Three coordination/discoverability fixes:
|
Three coordination/discoverability fixes:
|
||||||
@@ -42,10 +42,10 @@ index 4fdd4bdd..d30fb7f2 100644
|
|||||||
#define BOT_PREFS_MAX_ADVERT_MILLIS (7UL * 24UL * 60UL * 60UL * 1000UL)
|
#define BOT_PREFS_MAX_ADVERT_MILLIS (7UL * 24UL * 60UL * 60UL * 1000UL)
|
||||||
#define BOT_PREFS_SERIALIZED_SIZE 296
|
#define BOT_PREFS_SERIALIZED_SIZE 296
|
||||||
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
||||||
index 34517c44..9209dd86 100644
|
index 27ff37c1..b2c47df4 100644
|
||||||
--- a/examples/companion_radio/MyMesh.cpp
|
--- a/examples/companion_radio/MyMesh.cpp
|
||||||
+++ b/examples/companion_radio/MyMesh.cpp
|
+++ b/examples/companion_radio/MyMesh.cpp
|
||||||
@@ -848,7 +848,7 @@ void MyMesh::applyBotPrefs() {
|
@@ -857,7 +857,7 @@ void MyMesh::applyBotPrefs() {
|
||||||
}
|
}
|
||||||
if (bot_prefs.enabled) {
|
if (bot_prefs.enabled) {
|
||||||
scheduleBotLocalAdvert(bot_prefs.local_advert_interval_ms ? BOT_PREFS_INITIAL_LOCAL_ADVERT_MILLIS : 0);
|
scheduleBotLocalAdvert(bot_prefs.local_advert_interval_ms ? BOT_PREFS_INITIAL_LOCAL_ADVERT_MILLIS : 0);
|
||||||
@@ -54,7 +54,7 @@ index 34517c44..9209dd86 100644
|
|||||||
} else {
|
} else {
|
||||||
scheduleBotLocalAdvert(0);
|
scheduleBotLocalAdvert(0);
|
||||||
scheduleBotFloodAdvert(0);
|
scheduleBotFloodAdvert(0);
|
||||||
@@ -1996,11 +1996,11 @@ void MyMesh::sendQueuedEmergencyForwards() {
|
@@ -2005,11 +2005,11 @@ void MyMesh::sendQueuedEmergencyForwards() {
|
||||||
bool MyMesh::sendBotSelfAdvert(bool flood) {
|
bool MyMesh::sendBotSelfAdvert(bool flood) {
|
||||||
mesh::Packet* pkt;
|
mesh::Packet* pkt;
|
||||||
char bot_advert_name[sizeof(((ContactInfo*)0)->name)];
|
char bot_advert_name[sizeof(((ContactInfo*)0)->name)];
|
||||||
@@ -69,7 +69,7 @@ index 34517c44..9209dd86 100644
|
|||||||
}
|
}
|
||||||
if (!pkt) return false;
|
if (!pkt) return false;
|
||||||
|
|
||||||
@@ -2041,6 +2041,18 @@ void MyMesh::tickBot() {
|
@@ -2050,6 +2050,18 @@ void MyMesh::tickBot() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ index 34517c44..9209dd86 100644
|
|||||||
void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp,
|
void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp,
|
||||||
const char *text) {
|
const char *text) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -2479,6 +2491,9 @@ void MyMesh::begin(bool has_display) {
|
@@ -2489,6 +2501,9 @@ void MyMesh::begin(bool has_display) {
|
||||||
_prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, -9, MAX_LORA_TX_POWER);
|
_prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, -9, MAX_LORA_TX_POWER);
|
||||||
_prefs.gps_enabled = constrain(_prefs.gps_enabled, 0, 1); // Ensure boolean 0 or 1
|
_prefs.gps_enabled = constrain(_prefs.gps_enabled, 0, 1); // Ensure boolean 0 or 1
|
||||||
_prefs.gps_interval = constrain(_prefs.gps_interval, 0, 86400); // Max 24 hours
|
_prefs.gps_interval = constrain(_prefs.gps_interval, 0, 86400); // Max 24 hours
|
||||||
@@ -98,7 +98,7 @@ index 34517c44..9209dd86 100644
|
|||||||
|
|
||||||
#ifdef BLE_PIN_CODE // 123456 by default
|
#ifdef BLE_PIN_CODE // 123456 by default
|
||||||
if (_prefs.ble_pin == 0) {
|
if (_prefs.ble_pin == 0) {
|
||||||
@@ -2780,10 +2795,12 @@ void MyMesh::handleCmdFrame(size_t len) {
|
@@ -2794,10 +2809,12 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||||
}
|
}
|
||||||
} else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) {
|
} else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) {
|
||||||
mesh::Packet* pkt;
|
mesh::Packet* pkt;
|
||||||
@@ -113,7 +113,7 @@ index 34517c44..9209dd86 100644
|
|||||||
}
|
}
|
||||||
if (pkt) {
|
if (pkt) {
|
||||||
if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop)
|
if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop)
|
||||||
@@ -2864,10 +2881,12 @@ void MyMesh::handleCmdFrame(size_t len) {
|
@@ -2878,10 +2895,12 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||||
if (len < 1 + PUB_KEY_SIZE) {
|
if (len < 1 + PUB_KEY_SIZE) {
|
||||||
// export SELF
|
// export SELF
|
||||||
mesh::Packet* pkt;
|
mesh::Packet* pkt;
|
||||||
@@ -128,7 +128,7 @@ index 34517c44..9209dd86 100644
|
|||||||
}
|
}
|
||||||
if (pkt) {
|
if (pkt) {
|
||||||
pkt->header |= ROUTE_TYPE_FLOOD; // would normally be sent in this mode
|
pkt->header |= ROUTE_TYPE_FLOOD; // would normally be sent in this mode
|
||||||
@@ -3748,10 +3767,12 @@ void MyMesh::loop() {
|
@@ -3804,10 +3823,12 @@ void MyMesh::loop() {
|
||||||
|
|
||||||
bool MyMesh::advert() {
|
bool MyMesh::advert() {
|
||||||
mesh::Packet* pkt;
|
mesh::Packet* pkt;
|
||||||
@@ -144,10 +144,10 @@ index 34517c44..9209dd86 100644
|
|||||||
if (pkt) {
|
if (pkt) {
|
||||||
sendZeroHop(pkt);
|
sendZeroHop(pkt);
|
||||||
diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h
|
diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h
|
||||||
index 9685e89a..711bb69f 100644
|
index 488987c0..efc5240a 100644
|
||||||
--- a/examples/companion_radio/MyMesh.h
|
--- a/examples/companion_radio/MyMesh.h
|
||||||
+++ b/examples/companion_radio/MyMesh.h
|
+++ b/examples/companion_radio/MyMesh.h
|
||||||
@@ -248,6 +248,9 @@ private:
|
@@ -251,6 +251,9 @@ private:
|
||||||
bool sendBotSelfAdvert(bool flood);
|
bool sendBotSelfAdvert(bool flood);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Sat, 16 May 2026 19:33:04 -0600
|
Date: Sat, 16 May 2026 19:33:04 -0600
|
||||||
Subject: [PATCH 07/14] Prefix bot responses with request token for inter-bot
|
Subject: [PATCH 07/15] Prefix bot responses with request token for inter-bot
|
||||||
suppression
|
suppression
|
||||||
|
|
||||||
Adds a 4-hex request token (low 16 bits of the request fingerprint) as a
|
Adds a 4-hex request token (low 16 bits of the request fingerprint) as a
|
||||||
@@ -131,10 +131,10 @@ index 9eff340b..6e5cfd9a 100644
|
|||||||
size_t maxResponseLenForChannel(BotChannelKind channel_kind);
|
size_t maxResponseLenForChannel(BotChannelKind channel_kind);
|
||||||
bool isCommandOnCooldown(const BotCommandCooldown* cooldowns, size_t cooldown_count, BotCommandId command_id,
|
bool isCommandOnCooldown(const BotCommandCooldown* cooldowns, size_t cooldown_count, BotCommandId command_id,
|
||||||
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
||||||
index 9209dd86..02339124 100644
|
index b2c47df4..d4bca6ce 100644
|
||||||
--- a/examples/companion_radio/MyMesh.cpp
|
--- a/examples/companion_radio/MyMesh.cpp
|
||||||
+++ b/examples/companion_radio/MyMesh.cpp
|
+++ b/examples/companion_radio/MyMesh.cpp
|
||||||
@@ -1209,6 +1209,11 @@ bool MyMesh::enqueueBotResponse(const BotMessage &message, const ContactInfo *di
|
@@ -1218,6 +1218,11 @@ bool MyMesh::enqueueBotResponse(const BotMessage &message, const ContactInfo *di
|
||||||
if (!botFormatResponseForChannel(message, text, text_len, pending->text, sizeof(pending->text), &pending->text_len)) {
|
if (!botFormatResponseForChannel(message, text, text_len, pending->text, sizeof(pending->text), &pending->text_len)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,7 @@ index 9209dd86..02339124 100644
|
|||||||
pending->active = true;
|
pending->active = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1613,6 +1618,17 @@ BotFingerprint MyMesh::traceResponseFingerprintFor(const PendingBotTrace &pendin
|
@@ -1622,6 +1627,17 @@ BotFingerprint MyMesh::traceResponseFingerprintFor(const PendingBotTrace &pendin
|
||||||
|
|
||||||
bool MyMesh::sendBotTraceText(const PendingBotTrace &pending, const char *text, size_t text_len,
|
bool MyMesh::sendBotTraceText(const PendingBotTrace &pending, const char *text, size_t text_len,
|
||||||
BotFingerprint response_fingerprint, uint32_t now_millis) {
|
BotFingerprint response_fingerprint, uint32_t now_millis) {
|
||||||
@@ -164,7 +164,7 @@ index 9209dd86..02339124 100644
|
|||||||
bool success = false;
|
bool success = false;
|
||||||
if (pending.direct) {
|
if (pending.direct) {
|
||||||
ContactInfo *recipient = lookupContactByPubKey(pending.recipient_pub_key, PUB_KEY_SIZE);
|
ContactInfo *recipient = lookupContactByPubKey(pending.recipient_pub_key, PUB_KEY_SIZE);
|
||||||
@@ -1620,12 +1636,7 @@ bool MyMesh::sendBotTraceText(const PendingBotTrace &pending, const char *text,
|
@@ -1629,12 +1645,7 @@ bool MyMesh::sendBotTraceText(const PendingBotTrace &pending, const char *text,
|
||||||
uint32_t expected_ack = 0;
|
uint32_t expected_ack = 0;
|
||||||
uint32_t est_timeout = 0;
|
uint32_t est_timeout = 0;
|
||||||
uint32_t timestamp = getRTCClock()->getCurrentTimeUnique();
|
uint32_t timestamp = getRTCClock()->getCurrentTimeUnique();
|
||||||
@@ -178,7 +178,7 @@ index 9209dd86..02339124 100644
|
|||||||
success = result != MSG_SEND_FAILED;
|
success = result != MSG_SEND_FAILED;
|
||||||
if (success && expected_ack) {
|
if (success && expected_ack) {
|
||||||
expected_ack_table[next_ack_idx].msg_sent = _ms->getMillis();
|
expected_ack_table[next_ack_idx].msg_sent = _ms->getMillis();
|
||||||
@@ -1638,7 +1649,7 @@ bool MyMesh::sendBotTraceText(const PendingBotTrace &pending, const char *text,
|
@@ -1647,7 +1658,7 @@ bool MyMesh::sendBotTraceText(const PendingBotTrace &pending, const char *text,
|
||||||
ChannelDetails channel;
|
ChannelDetails channel;
|
||||||
uint32_t timestamp = getRTCClock()->getCurrentTimeUnique();
|
uint32_t timestamp = getRTCClock()->getCurrentTimeUnique();
|
||||||
success = getChannel(pending.channel_idx, channel) &&
|
success = getChannel(pending.channel_idx, channel) &&
|
||||||
@@ -187,7 +187,7 @@ index 9209dd86..02339124 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
@@ -1744,6 +1755,19 @@ bool MyMesh::observeKnownBotResponse(const BotMessage &message, bool authoritati
|
@@ -1753,6 +1764,19 @@ bool MyMesh::observeKnownBotResponse(const BotMessage &message, bool authoritati
|
||||||
|
|
||||||
bool MyMesh::observeBotGroupResponse(const BotMessage &message) {
|
bool MyMesh::observeBotGroupResponse(const BotMessage &message) {
|
||||||
if (!BotPolicy::isPrefixlessCommandAllowed(message.channel_kind)) return false;
|
if (!BotPolicy::isPrefixlessCommandAllowed(message.channel_kind)) return false;
|
||||||
@@ -207,7 +207,7 @@ index 9209dd86..02339124 100644
|
|||||||
BotFingerprint fingerprint = FirmwareBot::responseFingerprintFor(message, message.text, message.text_len);
|
BotFingerprint fingerprint = FirmwareBot::responseFingerprintFor(message, message.text, message.text_len);
|
||||||
if (ResponseCoordinator::recentlySent(bot_coordinator_recent, BOT_COORDINATOR_RECENT_SLOTS, fingerprint, _ms->getMillis())) {
|
if (ResponseCoordinator::recentlySent(bot_coordinator_recent, BOT_COORDINATOR_RECENT_SLOTS, fingerprint, _ms->getMillis())) {
|
||||||
return true;
|
return true;
|
||||||
@@ -1751,7 +1775,7 @@ bool MyMesh::observeBotGroupResponse(const BotMessage &message) {
|
@@ -1760,7 +1784,7 @@ bool MyMesh::observeBotGroupResponse(const BotMessage &message) {
|
||||||
if (ResponseCoordinator::suppress(bot_coordinator_pending, BOT_COORDINATOR_PENDING_SLOTS, fingerprint)) {
|
if (ResponseCoordinator::suppress(bot_coordinator_pending, BOT_COORDINATOR_PENDING_SLOTS, fingerprint)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Sat, 16 May 2026 19:55:36 -0600
|
Date: Sat, 16 May 2026 19:55:36 -0600
|
||||||
Subject: [PATCH 08/14] Drop [MCBOT] advert suffix and auto-learn known-bot
|
Subject: [PATCH 08/15] Drop [MCBOT] advert suffix and auto-learn known-bot
|
||||||
path
|
path
|
||||||
|
|
||||||
Removes BOT_ADVERT_MARKER / writeBotAdvertName / isBotAdvertName from
|
Removes BOT_ADVERT_MARKER / writeBotAdvertName / isBotAdvertName from
|
||||||
@@ -93,10 +93,10 @@ index 6e5cfd9a..708432a2 100644
|
|||||||
BotFingerprint responseFingerprintFor(const BotMessage& message, const char* response_text, size_t response_text_len);
|
BotFingerprint responseFingerprintFor(const BotMessage& message, const char* response_text, size_t response_text_len);
|
||||||
uint16_t requestToken(BotFingerprint request_fingerprint);
|
uint16_t requestToken(BotFingerprint request_fingerprint);
|
||||||
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
||||||
index 02339124..9121d42c 100644
|
index d4bca6ce..a8b4680b 100644
|
||||||
--- a/examples/companion_radio/MyMesh.cpp
|
--- a/examples/companion_radio/MyMesh.cpp
|
||||||
+++ b/examples/companion_radio/MyMesh.cpp
|
+++ b/examples/companion_radio/MyMesh.cpp
|
||||||
@@ -637,7 +637,6 @@ void MyMesh::onContactsFull() {
|
@@ -638,7 +638,6 @@ void MyMesh::onContactsFull() {
|
||||||
|
|
||||||
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
|
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
|
||||||
#if CMESH_BOT_ENABLED
|
#if CMESH_BOT_ENABLED
|
||||||
@@ -104,7 +104,7 @@ index 02339124..9121d42c 100644
|
|||||||
if ((path_len & 63) == 0) {
|
if ((path_len & 63) == 0) {
|
||||||
float rssi = radio_driver.getLastRSSI();
|
float rssi = radio_driver.getLastRSSI();
|
||||||
if (rssi > 32767.0f) rssi = 32767.0f;
|
if (rssi > 32767.0f) rssi = 32767.0f;
|
||||||
@@ -1167,21 +1166,6 @@ void MyMesh::buildBotCommandContext(BotCommandContext &context, BotCommandId com
|
@@ -1176,21 +1175,6 @@ void MyMesh::buildBotCommandContext(BotCommandContext &context, BotCommandId com
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ index 02339124..9121d42c 100644
|
|||||||
bool MyMesh::enqueueBotResponse(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
bool MyMesh::enqueueBotResponse(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
||||||
const char *text, size_t text_len, BotFingerprint request_fingerprint,
|
const char *text, size_t text_len, BotFingerprint request_fingerprint,
|
||||||
BotFingerprint response_fingerprint) {
|
BotFingerprint response_fingerprint) {
|
||||||
@@ -2019,12 +2003,10 @@ void MyMesh::sendQueuedEmergencyForwards() {
|
@@ -2028,12 +2012,10 @@ void MyMesh::sendQueuedEmergencyForwards() {
|
||||||
|
|
||||||
bool MyMesh::sendBotSelfAdvert(bool flood) {
|
bool MyMesh::sendBotSelfAdvert(bool flood) {
|
||||||
mesh::Packet* pkt;
|
mesh::Packet* pkt;
|
||||||
@@ -141,7 +141,7 @@ index 02339124..9121d42c 100644
|
|||||||
}
|
}
|
||||||
if (!pkt) return false;
|
if (!pkt) return false;
|
||||||
|
|
||||||
@@ -2065,17 +2047,6 @@ void MyMesh::tickBot() {
|
@@ -2074,17 +2056,6 @@ void MyMesh::tickBot() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ index 02339124..9121d42c 100644
|
|||||||
|
|
||||||
void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp,
|
void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packet *pkt, uint32_t timestamp,
|
||||||
const char *text) {
|
const char *text) {
|
||||||
@@ -2819,12 +2790,10 @@ void MyMesh::handleCmdFrame(size_t len) {
|
@@ -2833,12 +2804,10 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||||
}
|
}
|
||||||
} else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) {
|
} else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) {
|
||||||
mesh::Packet* pkt;
|
mesh::Packet* pkt;
|
||||||
@@ -174,7 +174,7 @@ index 02339124..9121d42c 100644
|
|||||||
}
|
}
|
||||||
if (pkt) {
|
if (pkt) {
|
||||||
if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop)
|
if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop)
|
||||||
@@ -2905,12 +2874,10 @@ void MyMesh::handleCmdFrame(size_t len) {
|
@@ -2919,12 +2888,10 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||||
if (len < 1 + PUB_KEY_SIZE) {
|
if (len < 1 + PUB_KEY_SIZE) {
|
||||||
// export SELF
|
// export SELF
|
||||||
mesh::Packet* pkt;
|
mesh::Packet* pkt;
|
||||||
@@ -189,7 +189,7 @@ index 02339124..9121d42c 100644
|
|||||||
}
|
}
|
||||||
if (pkt) {
|
if (pkt) {
|
||||||
pkt->header |= ROUTE_TYPE_FLOOD; // would normally be sent in this mode
|
pkt->header |= ROUTE_TYPE_FLOOD; // would normally be sent in this mode
|
||||||
@@ -3791,12 +3758,10 @@ void MyMesh::loop() {
|
@@ -3847,12 +3814,10 @@ void MyMesh::loop() {
|
||||||
|
|
||||||
bool MyMesh::advert() {
|
bool MyMesh::advert() {
|
||||||
mesh::Packet* pkt;
|
mesh::Packet* pkt;
|
||||||
@@ -205,10 +205,10 @@ index 02339124..9121d42c 100644
|
|||||||
if (pkt) {
|
if (pkt) {
|
||||||
sendZeroHop(pkt);
|
sendZeroHop(pkt);
|
||||||
diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h
|
diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h
|
||||||
index 711bb69f..46c3ff3c 100644
|
index efc5240a..7aa56326 100644
|
||||||
--- a/examples/companion_radio/MyMesh.h
|
--- a/examples/companion_radio/MyMesh.h
|
||||||
+++ b/examples/companion_radio/MyMesh.h
|
+++ b/examples/companion_radio/MyMesh.h
|
||||||
@@ -216,7 +216,6 @@ private:
|
@@ -219,7 +219,6 @@ private:
|
||||||
bool observeKnownBotResponse(const BotMessage &message, bool authoritative_sender);
|
bool observeKnownBotResponse(const BotMessage &message, bool authoritative_sender);
|
||||||
bool observeBotGroupResponse(const BotMessage &message);
|
bool observeBotGroupResponse(const BotMessage &message);
|
||||||
void buildBotCommandContext(BotCommandContext &context, BotCommandId command_id);
|
void buildBotCommandContext(BotCommandContext &context, BotCommandId command_id);
|
||||||
@@ -216,7 +216,7 @@ index 711bb69f..46c3ff3c 100644
|
|||||||
bool enqueueBotResponse(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
bool enqueueBotResponse(const BotMessage &message, const ContactInfo *direct_recipient, uint8_t channel_idx,
|
||||||
const char *text, size_t text_len, BotFingerprint request_fingerprint,
|
const char *text, size_t text_len, BotFingerprint request_fingerprint,
|
||||||
BotFingerprint response_fingerprint);
|
BotFingerprint response_fingerprint);
|
||||||
@@ -248,9 +247,6 @@ private:
|
@@ -251,9 +250,6 @@ private:
|
||||||
bool sendBotSelfAdvert(bool flood);
|
bool sendBotSelfAdvert(bool flood);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Sat, 16 May 2026 20:05:19 -0600
|
Date: Sat, 16 May 2026 20:05:19 -0600
|
||||||
Subject: [PATCH 09/14] Widen hop-step + drop "ack " prefix from test response
|
Subject: [PATCH 09/15] Widen hop-step + drop "ack " prefix from test response
|
||||||
|
|
||||||
Two changes:
|
Two changes:
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Sat, 16 May 2026 20:31:12 -0600
|
Date: Sat, 16 May 2026 20:31:12 -0600
|
||||||
Subject: [PATCH 10/14] Widen coordinator delays a tiny bit more
|
Subject: [PATCH 10/15] Widen coordinator delays a tiny bit more
|
||||||
|
|
||||||
~25% bump across the main coordination knobs:
|
~25% bump across the main coordination knobs:
|
||||||
- BOT_RESPONSE_DELAY_BASE_MILLIS 1200 -> 1500
|
- BOT_RESPONSE_DELAY_BASE_MILLIS 1200 -> 1500
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Sat, 16 May 2026 20:49:51 -0600
|
Date: Sat, 16 May 2026 20:49:51 -0600
|
||||||
Subject: [PATCH 11/14] Auto-advert on startup (initial flood at 5s instead of
|
Subject: [PATCH 11/15] Auto-advert on startup (initial flood at 5s instead of
|
||||||
120s)
|
120s)
|
||||||
|
|
||||||
BOT_PREFS_INITIAL_FLOOD_ADVERT_MILLIS 120000 -> 5000. The bot now sends
|
BOT_PREFS_INITIAL_FLOOD_ADVERT_MILLIS 120000 -> 5000. The bot now sends
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Sat, 16 May 2026 21:32:04 -0600
|
Date: Sat, 16 May 2026 21:32:04 -0600
|
||||||
Subject: [PATCH 12/14] Spell out hops/byte in test+path; drop channel name
|
Subject: [PATCH 12/15] Spell out hops/byte in test+path; drop channel name
|
||||||
from test ack
|
from test ack
|
||||||
|
|
||||||
Test response (writeAckResponse):
|
Test response (writeAckResponse):
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Sat, 16 May 2026 22:18:02 -0600
|
Date: Sat, 16 May 2026 22:18:02 -0600
|
||||||
Subject: [PATCH 13/14] =?UTF-8?q?Hop=20delay=20grows=20quadratically=20?=
|
Subject: [PATCH 13/15] =?UTF-8?q?Hop=20delay=20grows=20quadratically=20?=
|
||||||
=?UTF-8?q?=E2=80=94=20wider=20gaps=20at=20higher=20hop=20counts?=
|
=?UTF-8?q?=E2=80=94=20wider=20gaps=20at=20higher=20hop=20counts?=
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
Content-Type: text/plain; charset=UTF-8
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: cj-vana <cj@depth23.online>
|
From: cj-vana <cj@depth23.online>
|
||||||
Date: Mon, 18 May 2026 08:02:27 -0600
|
Date: Mon, 18 May 2026 08:02:27 -0600
|
||||||
Subject: [PATCH] Stabilize bot diagnostics and duplicate suppression
|
Subject: [PATCH 14/15] Stabilize bot diagnostics and duplicate suppression
|
||||||
|
|
||||||
---
|
---
|
||||||
examples/companion_radio/BotTypes.h | 9 ++-
|
examples/companion_radio/BotTypes.h | 9 ++-
|
||||||
@@ -128,10 +128,10 @@ index afd44d41..d256e61a 100644
|
|||||||
size_t* new_len) {
|
size_t* new_len) {
|
||||||
if (new_len) *new_len = text_len;
|
if (new_len) *new_len = text_len;
|
||||||
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
||||||
index 9121d42c..5d333328 100644
|
index a8b4680b..5e00c9d2 100644
|
||||||
--- a/examples/companion_radio/MyMesh.cpp
|
--- a/examples/companion_radio/MyMesh.cpp
|
||||||
+++ b/examples/companion_radio/MyMesh.cpp
|
+++ b/examples/companion_radio/MyMesh.cpp
|
||||||
@@ -120,9 +120,6 @@
|
@@ -121,9 +121,6 @@
|
||||||
#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250
|
#define DIRECT_SEND_PERHOP_EXTRA_MILLIS 250
|
||||||
#define LAZY_CONTACTS_WRITE_DELAY 5000
|
#define LAZY_CONTACTS_WRITE_DELAY 5000
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ index 9121d42c..5d333328 100644
|
|||||||
#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg=="
|
#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg=="
|
||||||
|
|
||||||
#if CMESH_BOT_ENABLED
|
#if CMESH_BOT_ENABLED
|
||||||
@@ -1072,7 +1069,12 @@ void MyMesh::observeBotDirectMessage(const ContactInfo &from, uint32_t sender_ti
|
@@ -1081,7 +1078,12 @@ void MyMesh::observeBotDirectMessage(const ContactInfo &from, uint32_t sender_ti
|
||||||
if (rssi < -32768.0f) rssi = -32768.0f;
|
if (rssi < -32768.0f) rssi = -32768.0f;
|
||||||
recordBotNeighbor(from.id.pub_key, (int16_t)rssi, (int8_t)(packet->getSNR() * 4));
|
recordBotNeighbor(from.id.pub_key, (int16_t)rssi, (int8_t)(packet->getSNR() * 4));
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ index 9121d42c..5d333328 100644
|
|||||||
message.path_len = from.out_path_len;
|
message.path_len = from.out_path_len;
|
||||||
message.path_hash_size = (from.out_path_len >> 6) + 1;
|
message.path_hash_size = (from.out_path_len >> 6) + 1;
|
||||||
message.path_hash_count = from.out_path_len & 63;
|
message.path_hash_count = from.out_path_len & 63;
|
||||||
@@ -1430,11 +1432,16 @@ bool MyMesh::dispatchBotTraceDirectLink(const BotMessage &message, const Contact
|
@@ -1439,11 +1441,16 @@ bool MyMesh::dispatchBotTraceDirectLink(const BotMessage &message, const Contact
|
||||||
}
|
}
|
||||||
|
|
||||||
BotFingerprint request_fingerprint = FirmwareBot::fingerprintFor(message);
|
BotFingerprint request_fingerprint = FirmwareBot::fingerprintFor(message);
|
||||||
@@ -173,7 +173,7 @@ index 9121d42c..5d333328 100644
|
|||||||
uint32_t bot_identity_seed;
|
uint32_t bot_identity_seed;
|
||||||
memcpy(&bot_identity_seed, self_id.pub_key, sizeof(bot_identity_seed));
|
memcpy(&bot_identity_seed, self_id.pub_key, sizeof(bot_identity_seed));
|
||||||
uint32_t jitter_seed = (uint32_t)request_fingerprint.value ^ bot_identity_seed;
|
uint32_t jitter_seed = (uint32_t)request_fingerprint.value ^ bot_identity_seed;
|
||||||
@@ -1504,6 +1511,11 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
@@ -1513,6 +1520,11 @@ bool MyMesh::handleBotTraceCommand(const BotMessage &message, const ContactInfo
|
||||||
if (!have_path || !botTracePathShapeValid(path_len, flags)) return false;
|
if (!have_path || !botTracePathShapeValid(path_len, flags)) return false;
|
||||||
|
|
||||||
BotFingerprint request_fingerprint = FirmwareBot::fingerprintFor(message);
|
BotFingerprint request_fingerprint = FirmwareBot::fingerprintFor(message);
|
||||||
@@ -185,7 +185,7 @@ index 9121d42c..5d333328 100644
|
|||||||
char response[BOT_MAX_RESPONSE_LEN + 1];
|
char response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
size_t response_len = botFormatTraceSent(response, sizeof(response), (uint8_t)(path_len / hash_size));
|
size_t response_len = botFormatTraceSent(response, sizeof(response), (uint8_t)(path_len / hash_size));
|
||||||
char final_response[BOT_MAX_RESPONSE_LEN + 1];
|
char final_response[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
@@ -1640,6 +1652,10 @@ bool MyMesh::sendBotTraceText(const PendingBotTrace &pending, const char *text,
|
@@ -1649,6 +1661,10 @@ bool MyMesh::sendBotTraceText(const PendingBotTrace &pending, const char *text,
|
||||||
bot_stats.sent_messages++;
|
bot_stats.sent_messages++;
|
||||||
ResponseCoordinator::recordRecent(bot_coordinator_recent, BOT_COORDINATOR_RECENT_SLOTS, response_fingerprint,
|
ResponseCoordinator::recordRecent(bot_coordinator_recent, BOT_COORDINATOR_RECENT_SLOTS, response_fingerprint,
|
||||||
now_millis);
|
now_millis);
|
||||||
@@ -196,7 +196,7 @@ index 9121d42c..5d333328 100644
|
|||||||
} else {
|
} else {
|
||||||
bot_stats.send_failures++;
|
bot_stats.send_failures++;
|
||||||
}
|
}
|
||||||
@@ -1747,6 +1763,7 @@ bool MyMesh::observeBotGroupResponse(const BotMessage &message) {
|
@@ -1756,6 +1772,7 @@ bool MyMesh::observeBotGroupResponse(const BotMessage &message) {
|
||||||
size_t token_prefix_len = 0;
|
size_t token_prefix_len = 0;
|
||||||
bool token_suppressed = false;
|
bool token_suppressed = false;
|
||||||
if (FirmwareBot::parseRequestTokenPrefix(message.text, message.text_len, &token, &token_prefix_len)) {
|
if (FirmwareBot::parseRequestTokenPrefix(message.text, message.text_len, &token, &token_prefix_len)) {
|
||||||
@@ -204,7 +204,7 @@ index 9121d42c..5d333328 100644
|
|||||||
if (ResponseCoordinator::suppressByRequestToken(bot_coordinator_pending, BOT_COORDINATOR_PENDING_SLOTS, token)) {
|
if (ResponseCoordinator::suppressByRequestToken(bot_coordinator_pending, BOT_COORDINATOR_PENDING_SLOTS, token)) {
|
||||||
token_suppressed = true;
|
token_suppressed = true;
|
||||||
}
|
}
|
||||||
@@ -1790,7 +1807,6 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
@@ -1799,7 +1816,6 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
||||||
if (message.text_len > 0 && (message.text[0] == '!' || message.text[0] == '/')) bot_stats.parse_errors++;
|
if (message.text_len > 0 && (message.text[0] == '!' || message.text[0] == '/')) bot_stats.parse_errors++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -212,7 +212,7 @@ index 9121d42c..5d333328 100644
|
|||||||
if ((command.id != BOT_COMMAND_UNKNOWN && command.id != BOT_COMMAND_UNSUPPORTED &&
|
if ((command.id != BOT_COMMAND_UNKNOWN && command.id != BOT_COMMAND_UNSUPPORTED &&
|
||||||
!BotPrefsCodec::commandEnabled(bot_prefs, command.id)) ||
|
!BotPrefsCodec::commandEnabled(bot_prefs, command.id)) ||
|
||||||
FirmwareBot::isCommandOnCooldown(bot_command_cooldowns, BOT_COMMAND_COOLDOWN_SLOTS, command.id, _ms->getMillis())) {
|
FirmwareBot::isCommandOnCooldown(bot_command_cooldowns, BOT_COMMAND_COOLDOWN_SLOTS, command.id, _ms->getMillis())) {
|
||||||
@@ -1869,6 +1885,11 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
@@ -1878,6 +1894,11 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
||||||
}
|
}
|
||||||
|
|
||||||
BotFingerprint request_fingerprint = FirmwareBot::fingerprintFor(message);
|
BotFingerprint request_fingerprint = FirmwareBot::fingerprintFor(message);
|
||||||
@@ -224,7 +224,7 @@ index 9121d42c..5d333328 100644
|
|||||||
BotFingerprint response_fingerprint = FirmwareBot::responseFingerprintFor(message, final_response, final_response_len);
|
BotFingerprint response_fingerprint = FirmwareBot::responseFingerprintFor(message, final_response, final_response_len);
|
||||||
BotFingerprint fingerprint;
|
BotFingerprint fingerprint;
|
||||||
uint32_t due_at_millis = 0;
|
uint32_t due_at_millis = 0;
|
||||||
@@ -1904,7 +1925,6 @@ void MyMesh::sendQueuedBotResponses() {
|
@@ -1913,7 +1934,6 @@ void MyMesh::sendQueuedBotResponses() {
|
||||||
while (true) {
|
while (true) {
|
||||||
BotCoordinatorReady ready = ResponseCoordinator::poll(bot_coordinator_pending, BOT_COORDINATOR_PENDING_SLOTS, now);
|
BotCoordinatorReady ready = ResponseCoordinator::poll(bot_coordinator_pending, BOT_COORDINATOR_PENDING_SLOTS, now);
|
||||||
if (ready.result == BOT_COORDINATOR_READY_NONE) return;
|
if (ready.result == BOT_COORDINATOR_READY_NONE) return;
|
||||||
@@ -232,7 +232,7 @@ index 9121d42c..5d333328 100644
|
|||||||
if (ready.result == BOT_COORDINATOR_READY_SUPPRESSED) {
|
if (ready.result == BOT_COORDINATOR_READY_SUPPRESSED) {
|
||||||
bot_stats.suppressed_responses++;
|
bot_stats.suppressed_responses++;
|
||||||
} else if (ready.result == BOT_COORDINATOR_READY_EXPIRED) {
|
} else if (ready.result == BOT_COORDINATOR_READY_EXPIRED) {
|
||||||
@@ -1941,6 +1961,12 @@ void MyMesh::sendQueuedBotResponses() {
|
@@ -1950,6 +1970,12 @@ void MyMesh::sendQueuedBotResponses() {
|
||||||
pending->active = false;
|
pending->active = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -245,7 +245,7 @@ index 9121d42c..5d333328 100644
|
|||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
if (pending->direct) {
|
if (pending->direct) {
|
||||||
@@ -1960,15 +1986,19 @@ void MyMesh::sendQueuedBotResponses() {
|
@@ -1969,15 +1995,19 @@ void MyMesh::sendQueuedBotResponses() {
|
||||||
}
|
}
|
||||||
} else if (pending->channel_idx != 0xFF) {
|
} else if (pending->channel_idx != 0xFF) {
|
||||||
ChannelDetails channel;
|
ChannelDetails channel;
|
||||||
|
|||||||
@@ -0,0 +1,264 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: CJ Vana <cj@depth23.online>
|
||||||
|
Date: Fri, 10 Jul 2026 15:19:21 -0600
|
||||||
|
Subject: [PATCH 15/15] Add sig/air/coin commands; derive help listings from
|
||||||
|
the registry
|
||||||
|
|
||||||
|
- sig (aliases snr/rssi/signal): reports the SNR the bot heard the
|
||||||
|
request at, plus local last-RSSI and noise floor - range testing aid
|
||||||
|
- air (alias airtime): TX/RX airtime and flood/direct packet counters
|
||||||
|
- coin (aliases flip/coinflip): coin flip alongside roll/dice/magic8
|
||||||
|
- help and cmd listings now walk the command registry filtered by
|
||||||
|
context class (chat vs 'cmd diag') instead of hand-picked id arrays
|
||||||
|
that had drifted (magic8 was missing from both)
|
||||||
|
- BOT_PREFS_VERSION 6 -> 7 so deployed bots re-default command_mask
|
||||||
|
and pick up the mask bits for the added commands
|
||||||
|
---
|
||||||
|
.../companion_radio/BotCommandRegistry.cpp | 12 +++
|
||||||
|
examples/companion_radio/BotCommands.cpp | 81 ++++++++++++++-----
|
||||||
|
examples/companion_radio/BotTypes.h | 15 +++-
|
||||||
|
examples/companion_radio/MyMesh.cpp | 8 +-
|
||||||
|
4 files changed, 89 insertions(+), 27 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/examples/companion_radio/BotCommandRegistry.cpp b/examples/companion_radio/BotCommandRegistry.cpp
|
||||||
|
index c429259c..65fed686 100644
|
||||||
|
--- a/examples/companion_radio/BotCommandRegistry.cpp
|
||||||
|
+++ b/examples/companion_radio/BotCommandRegistry.cpp
|
||||||
|
@@ -14,6 +14,9 @@ const char* const kChannelsAliases[] = { "channel" };
|
||||||
|
const char* const kPathAliases[] = { "p", "decode", "route" };
|
||||||
|
const char* const kPrefixAliases[] = { "lookup" };
|
||||||
|
const char* const kNeighborsAliases[] = { "near" };
|
||||||
|
+const char* const kSigAliases[] = { "snr", "rssi", "signal" };
|
||||||
|
+const char* const kAirAliases[] = { "airtime" };
|
||||||
|
+const char* const kCoinAliases[] = { "flip", "coinflip" };
|
||||||
|
|
||||||
|
size_t boundedStrLen(const char* value, size_t max_len) {
|
||||||
|
size_t len = 0;
|
||||||
|
@@ -74,6 +77,15 @@ const BotCommandMetadata kCommands[] = {
|
||||||
|
{ BOT_COMMAND_NEIGHBORS, "neighbors", kNeighborsAliases, 1, BOT_COMMAND_MASK_NEIGHBORS, BOT_COMMAND_VISIBILITY_DISCOVERABLE,
|
||||||
|
BOT_COMMAND_CONTEXT_DIAGNOSTIC, "Show recent direct neighbors", "neighbors",
|
||||||
|
"Show nodes heard directly within the last hour with RSSI and SNR." },
|
||||||
|
+ { BOT_COMMAND_SIG, "sig", kSigAliases, 3, BOT_COMMAND_MASK_SIG, BOT_COMMAND_VISIBILITY_DISCOVERABLE,
|
||||||
|
+ BOT_COMMAND_CONTEXT_DIAGNOSTIC, "Report received signal", "sig",
|
||||||
|
+ "Show how the bot heard your request: SNR plus local RSSI and noise floor." },
|
||||||
|
+ { BOT_COMMAND_AIR, "air", kAirAliases, 1, BOT_COMMAND_MASK_AIR, BOT_COMMAND_VISIBILITY_DISCOVERABLE,
|
||||||
|
+ BOT_COMMAND_CONTEXT_DIAGNOSTIC, "Show radio airtime", "air",
|
||||||
|
+ "Show local TX/RX airtime and flood/direct packet counters." },
|
||||||
|
+ { BOT_COMMAND_COIN, "coin", kCoinAliases, 2, BOT_COMMAND_MASK_COIN, BOT_COMMAND_VISIBILITY_DISCOVERABLE,
|
||||||
|
+ BOT_COMMAND_CONTEXT_NORMAL, "Flip a coin", "coin",
|
||||||
|
+ "Flip a coin and report heads or tails." },
|
||||||
|
{ BOT_COMMAND_UNKNOWN, "unknown", NULL, 0, 0, BOT_COMMAND_VISIBILITY_INTERNAL,
|
||||||
|
BOT_COMMAND_CONTEXT_INTERNAL, "Unknown command", "unknown", "Internal unknown-command handler." }
|
||||||
|
};
|
||||||
|
diff --git a/examples/companion_radio/BotCommands.cpp b/examples/companion_radio/BotCommands.cpp
|
||||||
|
index 198dc32f..4fbbbee0 100644
|
||||||
|
--- a/examples/companion_radio/BotCommands.cpp
|
||||||
|
+++ b/examples/companion_radio/BotCommands.cpp
|
||||||
|
@@ -313,45 +313,55 @@ void formatQuarters(int8_t quarters, char* output, size_t output_len) {
|
||||||
|
snprintf(output, output_len, "%s%d.%02d", sign, value / 4, (value % 4) * 25);
|
||||||
|
}
|
||||||
|
|
||||||
|
-void appendCommandList(char* output, size_t output_len, size_t* pos, const BotCommandId* ids, size_t id_count) {
|
||||||
|
+bool commandInClasses(const BotCommandMetadata* command, const BotCommandContextClass* classes, size_t class_count) {
|
||||||
|
+ for (size_t i = 0; i < class_count; i++) {
|
||||||
|
+ if (command->context_class == classes[i]) return true;
|
||||||
|
+ }
|
||||||
|
+ return false;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+// Listings are derived from the registry so an added command can never
|
||||||
|
+// be missed; classes split the list because all commands do not fit one
|
||||||
|
+// group-channel message.
|
||||||
|
+void appendCommandsByClass(char* output, size_t output_len, size_t* pos, const BotCommandContextClass* classes,
|
||||||
|
+ size_t class_count) {
|
||||||
|
bool first = true;
|
||||||
|
- for (size_t i = 0; i < id_count; i++) {
|
||||||
|
- const BotCommandMetadata* command = BotCommandRegistry::findById(ids[i]);
|
||||||
|
+ for (size_t i = 0; i < BotCommandRegistry::commandCount(); i++) {
|
||||||
|
+ const BotCommandMetadata* command = BotCommandRegistry::commandAt(i);
|
||||||
|
if (!command || command->visibility != BOT_COMMAND_VISIBILITY_DISCOVERABLE) continue;
|
||||||
|
- if (!first) appendText(output, output_len, pos, ", ");
|
||||||
|
+ if (!commandInClasses(command, classes, class_count)) continue;
|
||||||
|
+ if (!first) appendText(output, output_len, pos, " ");
|
||||||
|
appendText(output, output_len, pos, command->name);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-BotCommandResult executeCmd(char* output, size_t output_len) {
|
||||||
|
- static const BotCommandId ids[] = {
|
||||||
|
- BOT_COMMAND_TEST, BOT_COMMAND_PING, BOT_COMMAND_HELP, BOT_COMMAND_HELLO, BOT_COMMAND_ABOUT,
|
||||||
|
- BOT_COMMAND_ROLL, BOT_COMMAND_DICE, BOT_COMMAND_STATUS, BOT_COMMAND_CHANNELS, BOT_COMMAND_VERSION,
|
||||||
|
- BOT_COMMAND_STATS, BOT_COMMAND_PATH, BOT_COMMAND_TRACE, BOT_COMMAND_TRACER, BOT_COMMAND_PREFIX,
|
||||||
|
- BOT_COMMAND_TIME, BOT_COMMAND_LORA, BOT_COMMAND_ID, BOT_COMMAND_NEIGHBORS
|
||||||
|
- };
|
||||||
|
+const BotCommandContextClass kChatClasses[] = { BOT_COMMAND_CONTEXT_NORMAL, BOT_COMMAND_CONTEXT_TRACE };
|
||||||
|
+const BotCommandContextClass kDiagClasses[] = { BOT_COMMAND_CONTEXT_DIAGNOSTIC, BOT_COMMAND_CONTEXT_LOCAL_CONTACT };
|
||||||
|
+
|
||||||
|
+BotCommandResult executeCmd(const BotCommand& command, char* output, size_t output_len) {
|
||||||
|
if (!output || output_len == 0) return makeResult(BOT_COMMAND_RESULT_NO_SPACE, 0);
|
||||||
|
output[0] = 0;
|
||||||
|
size_t pos = 0;
|
||||||
|
+ if (textEqualsIgnoreCase(command.args, command.args_len, "diag")) {
|
||||||
|
+ appendText(output, output_len, &pos, "Diag: ");
|
||||||
|
+ appendCommandsByClass(output, output_len, &pos, kDiagClasses, 2);
|
||||||
|
+ return resultForAppend(output, output_len, pos);
|
||||||
|
+ }
|
||||||
|
appendText(output, output_len, &pos, "Commands: ");
|
||||||
|
- appendCommandList(output, output_len, &pos, ids, sizeof(ids) / sizeof(ids[0]));
|
||||||
|
+ appendCommandsByClass(output, output_len, &pos, kChatClasses, 2);
|
||||||
|
+ appendText(output, output_len, &pos, " | cmd diag");
|
||||||
|
return resultForAppend(output, output_len, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
BotCommandResult executeHelp(const BotCommand& command, char* output, size_t output_len) {
|
||||||
|
if (command.args_len == 0) {
|
||||||
|
- static const BotCommandId ids[] = {
|
||||||
|
- BOT_COMMAND_HELP, BOT_COMMAND_CMD, BOT_COMMAND_PING, BOT_COMMAND_TEST, BOT_COMMAND_HELLO, BOT_COMMAND_ROLL,
|
||||||
|
- BOT_COMMAND_DICE, BOT_COMMAND_TRACE, BOT_COMMAND_TRACER, BOT_COMMAND_PREFIX, BOT_COMMAND_TIME,
|
||||||
|
- BOT_COMMAND_LORA, BOT_COMMAND_ID, BOT_COMMAND_NEIGHBORS
|
||||||
|
- };
|
||||||
|
if (!output || output_len == 0) return makeResult(BOT_COMMAND_RESULT_NO_SPACE, 0);
|
||||||
|
output[0] = 0;
|
||||||
|
size_t pos = 0;
|
||||||
|
appendText(output, output_len, &pos, "Commands: ");
|
||||||
|
- appendCommandList(output, output_len, &pos, ids, sizeof(ids) / sizeof(ids[0]));
|
||||||
|
- appendText(output, output_len, &pos, "; help <command>");
|
||||||
|
+ appendCommandsByClass(output, output_len, &pos, kChatClasses, 2);
|
||||||
|
+ appendText(output, output_len, &pos, " | cmd diag | help <command>");
|
||||||
|
return resultForAppend(output, output_len, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -531,6 +541,31 @@ uint8_t batteryPercentFromMillivolts(uint16_t mv) {
|
||||||
|
return (uint8_t)(((uint32_t)(mv - kEmpty) * 100UL) / (uint32_t)(kFull - kEmpty));
|
||||||
|
}
|
||||||
|
|
||||||
|
+BotCommandResult executeSig(const BotCommandContext& context, char* output, size_t output_len) {
|
||||||
|
+ char snr[8];
|
||||||
|
+ formatQuarters(context.path_snr_quarters, snr, sizeof(snr));
|
||||||
|
+ const char* target = context.response_target[0] ? context.response_target : NULL;
|
||||||
|
+ if (target) {
|
||||||
|
+ return writeFormatted(output, output_len, "Sig @[%s]: heard you at SNR %s | last RSSI %d dBm, noise %d dBm", target,
|
||||||
|
+ snr, (int)context.last_rssi, (int)context.noise_floor);
|
||||||
|
+ }
|
||||||
|
+ return writeFormatted(output, output_len, "Sig: heard you at SNR %s | last RSSI %d dBm, noise %d dBm", snr,
|
||||||
|
+ (int)context.last_rssi, (int)context.noise_floor);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+BotCommandResult executeAir(const BotCommandContext& context, char* output, size_t output_len) {
|
||||||
|
+ return writeFormatted(output, output_len, "Air: tx %lus rx %lus | rx flood %lu direct %lu | tx flood %lu direct %lu",
|
||||||
|
+ (unsigned long)context.tx_airtime_seconds, (unsigned long)context.rx_airtime_seconds,
|
||||||
|
+ (unsigned long)context.flood_recv, (unsigned long)context.direct_recv,
|
||||||
|
+ (unsigned long)context.flood_sent, (unsigned long)context.direct_sent);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+BotCommandResult executeCoin(const BotCommandContext& context, char* output, size_t output_len) {
|
||||||
|
+ uint32_t state = context.random_seed ^ 0x636F696EUL;
|
||||||
|
+ if (state == 0) state = 1;
|
||||||
|
+ return writeFormatted(output, output_len, "Coin: %s", rollOnce(&state, 2) == 1 ? "Heads" : "Tails");
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
BotCommandResult executeTest(const BotCommand& command, const BotCommandContext& context, char* output, size_t output_len) {
|
||||||
|
const char* name = context.node_name[0] ? context.node_name : "local";
|
||||||
|
char received_at[9];
|
||||||
|
@@ -591,7 +626,7 @@ BotCommandResult executeCommand(const BotCommand& command, const BotCommandConte
|
||||||
|
case BOT_COMMAND_HELP:
|
||||||
|
return executeHelp(command, output, output_len);
|
||||||
|
case BOT_COMMAND_CMD:
|
||||||
|
- return executeCmd(output, output_len);
|
||||||
|
+ return executeCmd(command, output, output_len);
|
||||||
|
case BOT_COMMAND_PING:
|
||||||
|
return writeText(output, output_len, "Pong!");
|
||||||
|
case BOT_COMMAND_TEST:
|
||||||
|
@@ -642,6 +677,12 @@ BotCommandResult executeCommand(const BotCommand& command, const BotCommandConte
|
||||||
|
(unsigned long)context.packets_recv_errors, (unsigned)context.queue_depth);
|
||||||
|
case BOT_COMMAND_MAGIC8:
|
||||||
|
return executeMagic8(context, output, output_len);
|
||||||
|
+ case BOT_COMMAND_SIG:
|
||||||
|
+ return executeSig(context, output, output_len);
|
||||||
|
+ case BOT_COMMAND_AIR:
|
||||||
|
+ return executeAir(context, output, output_len);
|
||||||
|
+ case BOT_COMMAND_COIN:
|
||||||
|
+ return executeCoin(context, output, output_len);
|
||||||
|
case BOT_COMMAND_PATH:
|
||||||
|
return executePath(command, context, output, output_len);
|
||||||
|
case BOT_COMMAND_TRACE:
|
||||||
|
diff --git a/examples/companion_radio/BotTypes.h b/examples/companion_radio/BotTypes.h
|
||||||
|
index a54949d9..b91b291d 100644
|
||||||
|
--- a/examples/companion_radio/BotTypes.h
|
||||||
|
+++ b/examples/companion_radio/BotTypes.h
|
||||||
|
@@ -39,7 +39,7 @@
|
||||||
|
#define BOT_MIN_AUTH_SENDER_KEY_PREFIX_LEN 4
|
||||||
|
#define BOT_KNOWN_BOT_LABEL_LEN 12
|
||||||
|
#define BOT_PREFS_MAGIC 0x31504642UL
|
||||||
|
-#define BOT_PREFS_VERSION 6
|
||||||
|
+#define BOT_PREFS_VERSION 7
|
||||||
|
#define BOT_PREFS_DEFAULT_LOCAL_ADVERT_MILLIS (24UL * 60UL * 60UL * 1000UL)
|
||||||
|
#define BOT_PREFS_DEFAULT_FLOOD_ADVERT_MILLIS (24UL * 60UL * 60UL * 1000UL)
|
||||||
|
#define BOT_PREFS_INITIAL_LOCAL_ADVERT_MILLIS 60000UL
|
||||||
|
@@ -90,8 +90,11 @@ enum BotCommandId : uint8_t {
|
||||||
|
BOT_COMMAND_LORA = 19,
|
||||||
|
BOT_COMMAND_ID = 20,
|
||||||
|
BOT_COMMAND_NEIGHBORS = 21,
|
||||||
|
- BOT_COMMAND_UNSUPPORTED = 22,
|
||||||
|
- BOT_COMMAND_UNKNOWN = 23
|
||||||
|
+ BOT_COMMAND_SIG = 22,
|
||||||
|
+ BOT_COMMAND_AIR = 23,
|
||||||
|
+ BOT_COMMAND_COIN = 24,
|
||||||
|
+ BOT_COMMAND_UNSUPPORTED = 25,
|
||||||
|
+ BOT_COMMAND_UNKNOWN = 26
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BotCommandVisibility : uint8_t {
|
||||||
|
@@ -143,13 +146,17 @@ struct BotCommandMetadata {
|
||||||
|
#define BOT_COMMAND_MASK_LORA (1UL << BOT_COMMAND_LORA)
|
||||||
|
#define BOT_COMMAND_MASK_ID (1UL << BOT_COMMAND_ID)
|
||||||
|
#define BOT_COMMAND_MASK_NEIGHBORS (1UL << BOT_COMMAND_NEIGHBORS)
|
||||||
|
+#define BOT_COMMAND_MASK_SIG (1UL << BOT_COMMAND_SIG)
|
||||||
|
+#define BOT_COMMAND_MASK_AIR (1UL << BOT_COMMAND_AIR)
|
||||||
|
+#define BOT_COMMAND_MASK_COIN (1UL << BOT_COMMAND_COIN)
|
||||||
|
#define BOT_COMMAND_MASK_ALL (BOT_COMMAND_MASK_HELP | BOT_COMMAND_MASK_CMD | BOT_COMMAND_MASK_PING | \
|
||||||
|
BOT_COMMAND_MASK_TEST | BOT_COMMAND_MASK_HELLO | BOT_COMMAND_MASK_ABOUT | \
|
||||||
|
BOT_COMMAND_MASK_ROLL | BOT_COMMAND_MASK_DICE | BOT_COMMAND_MASK_STATUS | \
|
||||||
|
BOT_COMMAND_MASK_CHANNELS | BOT_COMMAND_MASK_VERSION | BOT_COMMAND_MASK_STATS | \
|
||||||
|
BOT_COMMAND_MASK_MAGIC8 | BOT_COMMAND_MASK_PATH | BOT_COMMAND_MASK_TRACE | \
|
||||||
|
BOT_COMMAND_MASK_TRACER | BOT_COMMAND_MASK_PREFIX | BOT_COMMAND_MASK_TIME | \
|
||||||
|
- BOT_COMMAND_MASK_LORA | BOT_COMMAND_MASK_ID | BOT_COMMAND_MASK_NEIGHBORS)
|
||||||
|
+ BOT_COMMAND_MASK_LORA | BOT_COMMAND_MASK_ID | BOT_COMMAND_MASK_NEIGHBORS | \
|
||||||
|
+ BOT_COMMAND_MASK_SIG | BOT_COMMAND_MASK_AIR | BOT_COMMAND_MASK_COIN)
|
||||||
|
|
||||||
|
enum BotCommandResultCode : uint8_t {
|
||||||
|
BOT_COMMAND_RESULT_NOT_HANDLED = 0,
|
||||||
|
diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp
|
||||||
|
index 5e00c9d2..fc37823c 100644
|
||||||
|
--- a/examples/companion_radio/MyMesh.cpp
|
||||||
|
+++ b/examples/companion_radio/MyMesh.cpp
|
||||||
|
@@ -1142,7 +1142,8 @@ void MyMesh::buildBotCommandContext(BotCommandContext &context, BotCommandId com
|
||||||
|
context.pending_responses = bot_stats.pending_responses;
|
||||||
|
context.emergency_forwards = bot_stats.emergency_forwards;
|
||||||
|
context.emergency_forward_failures = bot_stats.emergency_forward_failures;
|
||||||
|
- if (command_id == BOT_COMMAND_ROLL || command_id == BOT_COMMAND_DICE || command_id == BOT_COMMAND_MAGIC8) {
|
||||||
|
+ if (command_id == BOT_COMMAND_ROLL || command_id == BOT_COMMAND_DICE || command_id == BOT_COMMAND_MAGIC8 ||
|
||||||
|
+ command_id == BOT_COMMAND_COIN) {
|
||||||
|
getRNG()->random((uint8_t *)&context.random_seed, sizeof(context.random_seed));
|
||||||
|
}
|
||||||
|
if (command_id == BOT_COMMAND_STATUS || command_id == BOT_COMMAND_STATS) {
|
||||||
|
@@ -1160,7 +1161,7 @@ void MyMesh::buildBotCommandContext(BotCommandContext &context, BotCommandId com
|
||||||
|
StrHelper::strzcpy(context.firmware_version, FIRMWARE_VERSION, sizeof(context.firmware_version));
|
||||||
|
StrHelper::strzcpy(context.firmware_build_date, FIRMWARE_BUILD_DATE, sizeof(context.firmware_build_date));
|
||||||
|
}
|
||||||
|
- if (command_id == BOT_COMMAND_STATS) {
|
||||||
|
+ if (command_id == BOT_COMMAND_STATS || command_id == BOT_COMMAND_SIG || command_id == BOT_COMMAND_AIR) {
|
||||||
|
context.queue_depth = (uint8_t)_mgr->getOutboundTotal();
|
||||||
|
context.noise_floor = (int16_t)_radio->getNoiseFloor();
|
||||||
|
context.last_rssi = (int8_t)radio_driver.getLastRSSI();
|
||||||
|
@@ -1842,7 +1843,8 @@ void MyMesh::recordBotObservation(const BotMessage &message, const ContactInfo *
|
||||||
|
if (message.sender_name[0]) {
|
||||||
|
StrHelper::strzcpy(context.response_target, message.sender_name, sizeof(context.response_target));
|
||||||
|
}
|
||||||
|
- if (command.id == BOT_COMMAND_PATH || command.id == BOT_COMMAND_TRACE || command.id == BOT_COMMAND_TRACER) {
|
||||||
|
+ if (command.id == BOT_COMMAND_PATH || command.id == BOT_COMMAND_TRACE || command.id == BOT_COMMAND_TRACER ||
|
||||||
|
+ command.id == BOT_COMMAND_SIG) {
|
||||||
|
context.path_len = message.path_len;
|
||||||
|
context.path_hash_size = command.args_len > 0 ? botConfiguredTraceHashSize(_prefs.path_hash_mode) : message.path_hash_size;
|
||||||
|
context.path_hash_count = message.path_hash_count;
|
||||||
@@ -5,18 +5,15 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|||||||
MESHCORE_DIR="${MESHCORE_DIR:-${ROOT_DIR}/vendor/MeshCore}"
|
MESHCORE_DIR="${MESHCORE_DIR:-${ROOT_DIR}/vendor/MeshCore}"
|
||||||
|
|
||||||
is_excluded() {
|
is_excluded() {
|
||||||
|
# BLE variants that do not fit on these boards. The RP2040 and Nibble
|
||||||
|
# envs that used to sit here build again as of upstream bbb58cce
|
||||||
|
# (v1.16.0) and were re-included after passing local test builds.
|
||||||
case "$1" in
|
case "$1" in
|
||||||
Heltec_v2_companion_radio_ble|\
|
Heltec_v2_companion_radio_ble|\
|
||||||
LilyGo_TLora_V2_1_1_6_companion_radio_ble|\
|
LilyGo_TLora_V2_1_1_6_companion_radio_ble|\
|
||||||
nibble_screen_connect_companion_radio_ble|\
|
|
||||||
nibble_screen_connect_companion_radio_usb|\
|
|
||||||
PicoW_companion_radio_usb|\
|
|
||||||
RAK_11310_companion_radio_usb|\
|
|
||||||
Station_G2_companion_radio_ble|\
|
Station_G2_companion_radio_ble|\
|
||||||
Tbeam_SX1262_companion_radio_ble|\
|
Tbeam_SX1262_companion_radio_ble|\
|
||||||
Tbeam_SX1276_companion_radio_ble|\
|
Tbeam_SX1276_companion_radio_ble)
|
||||||
waveshare_rp2040_lora_companion_radio_usb|\
|
|
||||||
Xiao_rp2040_companion_radio_usb)
|
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -25,7 +22,10 @@ is_excluded() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The sed strips CR so variant files with CRLF line endings (a few exist
|
||||||
|
# upstream) match; without it their envs silently vanish from releases.
|
||||||
grep -rhE '^\[env:' "${MESHCORE_DIR}/variants/" \
|
grep -rhE '^\[env:' "${MESHCORE_DIR}/variants/" \
|
||||||
|
| sed -e 's/\r$//' \
|
||||||
| sort -u \
|
| sort -u \
|
||||||
| grep -E '_companion_radio_(usb|ble)\]$' \
|
| grep -E '_companion_radio_(usb|ble)\]$' \
|
||||||
| sed -e 's/\[env://' -e 's/\]//' \
|
| sed -e 's/\[env://' -e 's/\]//' \
|
||||||
|
|||||||
@@ -657,31 +657,49 @@ static void test_command_outputs() {
|
|||||||
|
|
||||||
result = run_command("!help", out, sizeof(out));
|
result = run_command("!help", out, sizeof(out));
|
||||||
assert(result.code == BOT_COMMAND_RESULT_OK);
|
assert(result.code == BOT_COMMAND_RESULT_OK);
|
||||||
assert_starts_with(out, "Commands: help, cmd, ping");
|
assert_starts_with(out, "Commands: help cmd ping");
|
||||||
assert(result.text_len <= BOT_MAX_GROUP_RESPONSE_LEN);
|
assert(result.text_len <= BOT_MAX_GROUP_RESPONSE_LEN);
|
||||||
assert_contains(out, "roll");
|
assert_contains(out, "roll");
|
||||||
assert_contains(out, "dice");
|
assert_contains(out, "dice");
|
||||||
assert_contains(out, "trace");
|
assert_contains(out, "trace");
|
||||||
assert_contains(out, "tracer");
|
assert_contains(out, "tracer");
|
||||||
assert_contains(out, "prefix");
|
assert_contains(out, "magic8");
|
||||||
|
assert_contains(out, "coin");
|
||||||
|
assert_contains(out, "cmd diag");
|
||||||
assert_contains(out, "help <command>");
|
assert_contains(out, "help <command>");
|
||||||
assert(strstr(out, "weather") == NULL);
|
assert(strstr(out, "weather") == NULL);
|
||||||
|
|
||||||
result = run_command("!cmd", out, sizeof(out));
|
result = run_command("!cmd", out, sizeof(out));
|
||||||
assert(result.code == BOT_COMMAND_RESULT_OK);
|
assert(result.code == BOT_COMMAND_RESULT_OK);
|
||||||
assert_starts_with(out, "Commands: test, ping, help, hello, about");
|
assert_starts_with(out, "Commands: help cmd ping test hello about");
|
||||||
assert_contains(out, "prefix");
|
assert(result.text_len <= BOT_MAX_GROUP_RESPONSE_LEN);
|
||||||
assert_contains(out, "path");
|
assert_contains(out, "path");
|
||||||
assert_contains(out, "dice");
|
assert_contains(out, "dice");
|
||||||
assert_contains(out, "roll");
|
assert_contains(out, "roll");
|
||||||
assert_contains(out, "stats");
|
assert_contains(out, "magic8");
|
||||||
assert_contains(out, "time");
|
assert_contains(out, "coin");
|
||||||
assert_contains(out, "lora");
|
assert_contains(out, "cmd diag");
|
||||||
assert_contains(out, "id");
|
|
||||||
assert_contains(out, "neighbors");
|
|
||||||
assert_contains(out, ", ");
|
|
||||||
assert(strstr(out, "weather") == NULL);
|
assert(strstr(out, "weather") == NULL);
|
||||||
|
|
||||||
|
result = run_command("!cmd diag", out, sizeof(out));
|
||||||
|
assert(result.code == BOT_COMMAND_RESULT_OK);
|
||||||
|
assert_starts_with(out, "Diag: status channels stats prefix time lora id neighbors sig air");
|
||||||
|
assert(result.text_len <= BOT_MAX_GROUP_RESPONSE_LEN);
|
||||||
|
|
||||||
|
// Every discoverable command must appear in either the chat or the diag
|
||||||
|
// listing, so a new registry entry can never silently miss discovery.
|
||||||
|
{
|
||||||
|
char chat[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
|
char diag[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
|
assert(run_command("!cmd", chat, sizeof(chat)).code == BOT_COMMAND_RESULT_OK);
|
||||||
|
assert(run_command("!cmd diag", diag, sizeof(diag)).code == BOT_COMMAND_RESULT_OK);
|
||||||
|
for (size_t i = 0; i < BotCommandRegistry::commandCount(); i++) {
|
||||||
|
const BotCommandMetadata* meta = BotCommandRegistry::commandAt(i);
|
||||||
|
if (!meta || meta->visibility != BOT_COMMAND_VISIBILITY_DISCOVERABLE) continue;
|
||||||
|
assert(strstr(chat, meta->name) != NULL || strstr(diag, meta->name) != NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result = run_command("!help roll", out, sizeof(out));
|
result = run_command("!help roll", out, sizeof(out));
|
||||||
assert(result.code == BOT_COMMAND_RESULT_OK);
|
assert(result.code == BOT_COMMAND_RESULT_OK);
|
||||||
assert_starts_with(out, "roll: Roll a random number between 1 and X");
|
assert_starts_with(out, "roll: Roll a random number between 1 and X");
|
||||||
@@ -791,6 +809,62 @@ static void test_command_outputs() {
|
|||||||
assert(strcmp(out, "Unknown command. Try help") == 0);
|
assert(strcmp(out, "Unknown command. Try help") == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_sig_air_coin_commands() {
|
||||||
|
char out[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
|
BotCommand command;
|
||||||
|
|
||||||
|
assert(FirmwareBot::parseCommand("!sig", 4, &command));
|
||||||
|
assert(command.id == BOT_COMMAND_SIG);
|
||||||
|
BotCommandContext context = make_context();
|
||||||
|
context.path_snr_quarters = 23;
|
||||||
|
context.last_rssi = -92;
|
||||||
|
context.noise_floor = -105;
|
||||||
|
BotCommandResult result = BotCommands::executeCommand(command, context, out, sizeof(out));
|
||||||
|
assert(result.code == BOT_COMMAND_RESULT_OK);
|
||||||
|
assert(strcmp(out, "Sig: heard you at SNR 5.75 | last RSSI -92 dBm, noise -105 dBm") == 0);
|
||||||
|
|
||||||
|
strncpy(context.response_target, "alice", sizeof(context.response_target) - 1);
|
||||||
|
result = BotCommands::executeCommand(command, context, out, sizeof(out));
|
||||||
|
assert(result.code == BOT_COMMAND_RESULT_OK);
|
||||||
|
assert(strcmp(out, "Sig @[alice]: heard you at SNR 5.75 | last RSSI -92 dBm, noise -105 dBm") == 0);
|
||||||
|
context.response_target[0] = 0;
|
||||||
|
|
||||||
|
assert(FirmwareBot::parseCommand("!snr", 4, &command));
|
||||||
|
assert(command.id == BOT_COMMAND_SIG);
|
||||||
|
assert(FirmwareBot::parseCommand("!rssi", 5, &command));
|
||||||
|
assert(command.id == BOT_COMMAND_SIG);
|
||||||
|
|
||||||
|
assert(FirmwareBot::parseCommand("!air", 4, &command));
|
||||||
|
assert(command.id == BOT_COMMAND_AIR);
|
||||||
|
context.tx_airtime_seconds = 12;
|
||||||
|
context.rx_airtime_seconds = 345;
|
||||||
|
context.flood_recv = 10;
|
||||||
|
context.direct_recv = 3;
|
||||||
|
context.flood_sent = 5;
|
||||||
|
context.direct_sent = 2;
|
||||||
|
result = BotCommands::executeCommand(command, context, out, sizeof(out));
|
||||||
|
assert(result.code == BOT_COMMAND_RESULT_OK);
|
||||||
|
assert(strcmp(out, "Air: tx 12s rx 345s | rx flood 10 direct 3 | tx flood 5 direct 2") == 0);
|
||||||
|
|
||||||
|
assert(FirmwareBot::parseCommand("!airtime", 8, &command));
|
||||||
|
assert(command.id == BOT_COMMAND_AIR);
|
||||||
|
|
||||||
|
assert(FirmwareBot::parseCommand("!coin", 5, &command));
|
||||||
|
assert(command.id == BOT_COMMAND_COIN);
|
||||||
|
result = BotCommands::executeCommand(command, context, out, sizeof(out));
|
||||||
|
assert(result.code == BOT_COMMAND_RESULT_OK);
|
||||||
|
assert(strcmp(out, "Coin: Heads") == 0 || strcmp(out, "Coin: Tails") == 0);
|
||||||
|
|
||||||
|
// Same seed must flip the same way; a different seed exercises the other path.
|
||||||
|
char again[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
|
result = BotCommands::executeCommand(command, context, again, sizeof(again));
|
||||||
|
assert(result.code == BOT_COMMAND_RESULT_OK);
|
||||||
|
assert(strcmp(out, again) == 0);
|
||||||
|
|
||||||
|
assert(FirmwareBot::parseCommand("!flip", 5, &command));
|
||||||
|
assert(command.id == BOT_COMMAND_COIN);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_path_command() {
|
static void test_path_command() {
|
||||||
char out[BOT_MAX_RESPONSE_LEN + 1];
|
char out[BOT_MAX_RESPONSE_LEN + 1];
|
||||||
BotCommand command;
|
BotCommand command;
|
||||||
@@ -1757,6 +1831,7 @@ int main() {
|
|||||||
test_channel_text_and_response_guards();
|
test_channel_text_and_response_guards();
|
||||||
test_ack_response_format();
|
test_ack_response_format();
|
||||||
test_command_outputs();
|
test_command_outputs();
|
||||||
|
test_sig_air_coin_commands();
|
||||||
test_path_command();
|
test_path_command();
|
||||||
test_trace_result_format();
|
test_trace_result_format();
|
||||||
test_dice_command();
|
test_dice_command();
|
||||||
|
|||||||
2
vendor/MeshCore
vendored
2
vendor/MeshCore
vendored
Submodule vendor/MeshCore updated: 910b1bee5b...bbb58cceb8
Reference in New Issue
Block a user