Skip to content

For packets with a path set; auto try again if no echo was heard. High Availability Link for Overwhelmed Meshes - Project HALO. Stop the flood#2367

Open
mikecarper wants to merge 11 commits intomeshcore-dev:mainfrom
mikecarper:halo-direct-path-retries
Open

For packets with a path set; auto try again if no echo was heard. High Availability Link for Overwhelmed Meshes - Project HALO. Stop the flood#2367
mikecarper wants to merge 11 commits intomeshcore-dev:mainfrom
mikecarper:halo-direct-path-retries

Conversation

@mikecarper
Copy link
Copy Markdown

This PR adds direct-retry behavior for direct-path traffic when an expected forward echo is not overheard, with link-quality gating that can be configured (5db is the default). So if the SF is 7 then we can expect that -7.5db is the limit; if the link is below -2.5db then this will not try again as the odds of success is low. For busy repeaters this value can be increased to 10 or so; so the retry logic only triggers if the SNR is +2.5 or better. Default value is off. neighbor list is checked first with optional fallback to recently heard repeater prefixes. wait uses 4 times the packet-time equivalent with minimum floor of 200ms

Starts the retry wait window after actual TX complete. Cancels pending retry when a valid forward echo is received.

Covers direct retry target selection for:
- PATH, REQ, RESPONSE, TXT_MSG, ANON_REQ
- ACK
- MULTIPART packets carrying ACK payloads
- TRACE (with existing downstream-hop guard)

Added to the CLI :
- get/set direct.retry.heard on|off
- get/set direct.retry.margin <db>

@mikecarper
Copy link
Copy Markdown
Author

mikecarper commented Apr 23, 2026

https://analyzer.letsmesh.net/packets?packet_id=671326411

image
DEBUG: 00:24:20 - 24/4/2026 U direct retry armed (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:24:21 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:24:21 - 24/4/2026 U direct retry resent (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:24:21 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=300)
DEBUG: 00:24:21 - 24/4/2026 U direct retry canceled_echo (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:24:21 - 24/4/2026 U direct retry good (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:24:21 - 24/4/2026 U direct retry armed (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:24:22 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:24:22 - 24/4/2026 U direct retry canceled_echo (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:24:22 - 24/4/2026 U direct retry good (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:24:22 - 24/4/2026 U direct retry armed (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:24:22 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:24:23 - 24/4/2026 U direct retry canceled_echo (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:24:23 - 24/4/2026 U direct retry good (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:24:23 - 24/4/2026 U direct retry armed (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:24:23 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:24:23 - 24/4/2026 U direct retry canceled_echo (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:24:23 - 24/4/2026 U direct retry good (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:24:23 - 24/4/2026 U direct retry armed (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:24:24 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:24:24 - 24/4/2026 U direct retry canceled_echo (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:24:24 - 24/4/2026 U direct retry good (type=9, route=D, payload_len=31, delay=0)
image
DEBUG: 00:27:55 - 24/4/2026 U direct retry armed (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:27:55 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:27:55 - 24/4/2026 U direct retry canceled_echo (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:27:55 - 24/4/2026 U direct retry good (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:27:55 - 24/4/2026 U direct retry armed (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:27:55 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:27:56 - 24/4/2026 U direct retry canceled_echo (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:27:56 - 24/4/2026 U direct retry good (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:27:56 - 24/4/2026 U direct retry armed (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:27:56 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:27:56 - 24/4/2026 U direct retry resent (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:27:56 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=300)
DEBUG: 00:27:56 - 24/4/2026 U direct retry canceled_echo (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:27:56 - 24/4/2026 U direct retry good (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:27:56 - 24/4/2026 U direct retry armed (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:27:57 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:27:57 - 24/4/2026 U direct retry canceled_echo (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:27:57 - 24/4/2026 U direct retry good (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:27:57 - 24/4/2026 U direct retry armed (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:27:57 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=200)
DEBUG: 00:27:58 - 24/4/2026 U direct retry resent (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:27:58 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=300)
DEBUG: 00:27:58 - 24/4/2026 U direct retry resent (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:27:58 - 24/4/2026 U direct retry queued (type=9, route=D, payload_len=31, delay=400)
DEBUG: 00:27:59 - 24/4/2026 U direct retry canceled_echo (type=9, route=D, payload_len=31, delay=0)
DEBUG: 00:27:59 - 24/4/2026 U direct retry good (type=9, route=D, payload_len=31, delay=0)

This seems to be working

@mikecarper
Copy link
Copy Markdown
Author

mikecarper commented Apr 24, 2026

G2 Repeater.zip
V4 Repeater.zip

To monitor as meshdebug is set in these 2 firmware builds

in one window
picocom -b 115200 /dev/ttyACM0 --imap lfcrlf --logfile /tmp/mesh.log
in another window

tail -F /tmp/mesh.log | rg --line-buffered "direct retry"

31 hop trace ping pong to one of the more busy repeaters in the area
https://analyzer.letsmesh.net/packets?packet_id=676770803

@mikecarper
Copy link
Copy Markdown
Author

https://github.com/Brent-A/mcsim seems to show this helps; better than showing it hurts.

DM Test

Result 1 (count test: count=1 vs count=6)

  • 30 paired seeds, 180s each.
  • off: sent 1277, delivered 150, acked 38
  • on: sent 1278, delivered 153, acked 39
  • Delta: +3 delivered (+2.00%), +1 acked
  • Per-seed: better in 1, worse in 0, equal in 29

Result 2 (explicit enable/disable by margin: margin=40 vs margin=0, both count=6)

  • 30 paired seeds, 180s each.
  • off: sent 1277, delivered 152, acked 38
  • on: sent 1278, delivered 153, acked 39
  • Delta: +1 delivered (+0.66%), +1 acked

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant