Skip to content

KISS modem over TCP (meshtasticd raw modem mode) - #4

Merged
A13xB0 merged 3 commits into
mainfrom
kiss-tcp
Sep 16, 2026
Merged

A13xB0 merged 3 commits into
mainfrom
kiss-tcp

Conversation

@A13xB0

@A13xB0 A13xB0 commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator

Warning

Awaiting upstream review of meshtastic/firmware#11863

KISS modem over TCP, for meshtasticd's raw modem mode

A kiss radio's device can now be tcp://host:port. This lets RepeaterTastic use a Linux LoRa HAT (SPI) or CH341 USB stick through meshtasticd's raw modem mode, which serves the radio with the same Mesh KISS v2 protocol, so no Heltec/RAK board is needed.

radio:
    driver: kiss
    device: tcp://127.0.0.1:4405

It needs a patched meshtasticd for now: the raw-modem branch of A13xB0/firmware, until it is proposed and merged upstream. This PR is separate from the native SPI driver (#3) and based on main only.

Changes

  • internal/radio/kiss: tcp:// devices connect with a net.Dialer (connect timeout DialTimeout, default 5s; TCP keepalives; no Nagle) instead of opening a serial port. They reconnect and re-apply the config the same way as serial. TCPAddr() parses and validates the address. Tests: the fake modem is served over a loopback TCP listener, covering handshake, configure, RX with escaping and RxMeta, TX, and a meshtasticd restart (drop, refused dials, reconnect, config re-applied). Address parsing is tested too.
  • internal/config: a malformed tcp:// device is rejected. Two radios on the same tcp:// address are refused, with host names compared case-insensitively, because meshtasticd serves one client at a time.
  • kisstool: --dev tcp://host:port works (help text updated).
  • Web GUI: the setup Test modem probe accepts tcp:// devices. Before a password is set it only dials loopback addresses, so the unauthenticated probe can't be pointed at other hosts. The UI is unchanged and needs no rebuild.
  • Docs: new docs/meshtasticd-raw-modem.md covers building and enabling the fork, the config.yaml snippet, the RepeaterTastic config, and caveats: no auth on the port, one client, Docker networking, tx_enabled and regional power limits. It is linked from the README docs table, docs/configuration.md and docs/hardware.md.

Testing

  • go vet ./... and go test ./... pass.
  • Tested against the patched meshtasticd on SimRadio in Docker (meshtasticd -s --raw-modem 4405):
    • kisstool info --dev tcp://127.0.0.1:… reports meshtasticd sim, Mesh KISS v2, patched;
    • kisstool listen configures EU_868 LongFast and reads it back;
    • the daemon with device: tcp://… opens the radio and logs radio configured.
  • Not tested on real RF hardware; there was no radio. SimRadio can't transmit, so send-text gets TxDone failure there as expected.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SJZ75CWob1eMXeTa8Q2nLc

random-thought and others added 3 commits September 15, 2026 22:13
A kiss radio's device can now be tcp://host:port. The driver dials it with a
connect timeout and TCP keepalives instead of opening a serial port, and
reconnects and re-applies the config exactly as for a serial modem. This is
how RepeaterTastic uses meshtasticd's raw modem mode, which serves a Linux LoRa
HAT or CH341 stick with the Mesh KISS v2 protocol (currently the raw-modem
branch of A13xB0/firmware).

- config: a malformed tcp:// device is rejected, and two radios can't share
  one (host names compared case-insensitively).
- kisstool: --dev tcp://host:port works.
- web: the setup "Test modem" probe accepts tcp:// devices; before a password
  is set it only dials loopback addresses.
- docs: meshtasticd-raw-modem.md, linked from the README, configuration and
  hardware pages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SJZ75CWob1eMXeTa8Q2nLc
Edit radio and Add radio get a USB modem / meshtasticd switch: meshtasticd takes a host and port
and saves tcp://host:port, with a hint about RawModemPort. The setup wizard lists meshtasticd's raw
modem next to the serial ports.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SJZ75CWob1eMXeTa8Q2nLc
FESC FESC TFEND decoded to FEND; the second FESC is an invalid escaped byte and
is dropped, so TFEND is then a literal 0xDC, matching the modem firmware.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SJZ75CWob1eMXeTa8Q2nLc
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.

2 participants