N6JET Virtual Hotspot — Network Test Tool

What is it?

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.

Purpose

JET Reflector Family

ReflectorProtocolPortTest Status
YSF 95110 (YSFJET)YSF / C4FM42002Full test support (ping, TX, monitor)
XLXJETXLX / D-Star42000Port check only (protocol test TBD)
URFJETURF Multi-Protocol42000Port check only (protocol test TBD)
M17JETM1717000Port check only (protocol test TBD)

All four reflectors run on the same VPS (5.161.215.224).

Components

ysf-vhotspot.py — CLI Test Client

A software-only YSF client that implements the minimum YSF reflector protocol for testing connections and DG-ID routing.

Web Dashboard — GUI Control Panel

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.

libfich.so — FICH Decoder Library

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.

Usage Examples

# 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

Command Line Options

OptionDescription
--hostReflector IP address (required)
--portReflector port (default: 42002)
--callYour callsign (required)
--dgidDG-ID to use, 0-99 (default: 0)
--txSend a test transmission
--pingQuick connect/verify/disconnect
--durationListen duration in seconds (default: 60)

YSF Protocol Implementation

The virtual hotspot implements the minimum YSF reflector protocol:

PacketSizePurpose
YSFP14 bytesPoll/register — keeps the connection alive
YSFD155 bytesVoice data — header + FICH + voice payload
YSFU14 bytesUnlink/disconnect
YSFPREFLECTOR14 bytesAcknowledgment from reflector

Poll packets are sent every 3 seconds to maintain the connection.

Dashboard API

EndpointDescription
?action=statusCheck all reflector ports
?action=ping&reflector=ysfPing a specific reflector
?action=ping_allPing all four reflectors
?action=tx&reflector=ysf&dgid=1Send TX test on a DG-ID (YSF only)
?action=monitor&reflector=ysf&duration=10Listen for live traffic (YSF only)

Test Results (May 11, 2026)

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.

Known Issue: DG-ID Encode/Decode Roundtrip

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.

Next Steps

  1. Debug encode/decode offset alignment in libfich.so (FICH DG-ID roundtrip)
  2. Build protocol-specific test scripts for XLXJET (D-Star), URFJET (URF), and M17JET (M17)
  3. Add module selection support to XLX/URF/M17 test scripts
  4. Add automated test suite / scheduled health checks
  5. Add DG-ID sweep test (send on DG-ID 1, 2, 3... verify each logged correctly)

Return to n6jet.com