The N6JET Virtual Hotspot is a software-only testing suite for the JET reflector family. It consists of a Python-based YSF protocol test client (ysf-vhotspot.py) and a web-based control dashboard that provides a GUI for running tests and monitoring reflector health — all without any RF hardware. No radio, no MMDVM board, no RF emitted — pure network testing.
| Reflector | Protocol | Port | Test Status |
|---|---|---|---|
| YSF 95110 (YSFJET) | YSF / C4FM | 42002 | Full test support (ping, TX, monitor) |
| XLXJET | XLX / D-Star | 42000 | Port check only (protocol test TBD) |
| URFJET | URF Multi-Protocol | 42000 | Port check only (protocol test TBD) |
| M17JET | M17 | 17000 | Port check only (protocol test TBD) |
All four reflectors run on the same VPS (5.161.215.224).
A software-only YSF client that implements the minimum YSF reflector protocol for testing connections and DG-ID routing.
A browser-based control panel for testing all four JET reflectors. Provides ping, TX, and monitor tests against YSFJET, with port-check status for XLXJET, URFJET, and M17JET. Includes DG-ID selector, module grid (A–Z), activity log with per-reflector filtering, and CLI command preview.
The dashboard is restricted to Tailscale access only for security.
A shared C library built from G4KLX's GPL YSFClients components that provides FICH encode/decode functions callable from Python via ctypes. Used for DG-ID extraction from live YSF packets.
# Quick ping test — verify reflector responds
/opt/pYSFReflector/ysf-vhotspot.py --host 127.0.0.1 --port 42002 --call N6JET --dgid 0 --ping
# Send test transmission on DG-ID 1
/opt/pYSFReflector/ysf-vhotspot.py --host 127.0.0.1 --port 42002 --call N6JET --dgid 1 --tx
# Listen for 30 seconds
/opt/pYSFReflector/ysf-vhotspot.py --host 127.0.0.1 --port 42002 --call N6JET --dgid 0 --duration 30
| Option | Description |
|---|---|
--host | Reflector IP address (required) |
--port | Reflector port (default: 42002) |
--call | Your callsign (required) |
--dgid | DG-ID to use, 0-99 (default: 0) |
--tx | Send a test transmission |
--ping | Quick connect/verify/disconnect |
--duration | Listen duration in seconds (default: 60) |
The virtual hotspot implements the minimum YSF reflector protocol:
| Packet | Size | Purpose |
|---|---|---|
YSFP | 14 bytes | Poll/register — keeps the connection alive |
YSFD | 155 bytes | Voice data — header + FICH + voice payload |
YSFU | 14 bytes | Unlink/disconnect |
YSFPREFLECTOR | 14 bytes | Acknowledgment from reflector |
Poll packets are sent every 3 seconds to maintain the connection.
| Endpoint | Description |
|---|---|
?action=status | Check all reflector ports |
?action=ping&reflector=ysf | Ping a specific reflector |
?action=ping_all | Ping all four reflectors |
?action=tx&reflector=ysf&dgid=1 | Send TX test on a DG-ID (YSF only) |
?action=monitor&reflector=ysf&duration=10 | Listen for live traffic (YSF only) |
20:42:46 [CON] YSFJET port 42002: LISTENING ✓
20:42:46 [CON] XLXJET port 42000: LISTENING ✓
20:42:46 [CON] URFJET port 42000: LISTENING ✓
20:42:46 [CON] M17JET port 17000: LISTENING ✓
03:44:02 [PNG] PING OK — Reflector at 127.0.0.1:42002 is reachable
03:44:02 [PNG] XLX — UP — port 42000
03:44:02 [PNG] URF — UP — port 42000
03:44:02 [PNG] M17 — UP — port 17000
All four reflectors confirmed operational.
The virtual hotspot currently sends packets with a simplified FICH that doesn't pass the full Golay/convolution decode chain. The reflector receives the packets and processes them, but the DG-ID decodes as -1 (invalid FICH).
Root cause: The encode_fich() and get_dgid() functions in libfich.so have an offset alignment issue. The encode writes the FICH correctly but the decode reads from a slightly different position in the packet.
Impact: The virtual hotspot works for connectivity testing (ping, connect, disconnect, TX confirmation) but doesn't yet produce valid DG-ID values in the reflector logs.
Workaround: Use a real Yaesu radio (FT5D, FT3D, etc.) with DG-ID set on the radio. The radio produces properly encoded FICH that libfich.so will decode correctly.