Skip to content

YSF Reflector Protocol

YSF is Vexillum’s implementation of a Yaesu System Fusion reflector, modeled on the tag and framing conventions used by MMDVM-family YSFReflector implementations. A client polls to join a single shared room, exchanges data frames, and can query reflector status.

Field Value
Transport UDP only
Default listen port 42000
Authentication None
Default designator 12345

A client should handle:

  • YSFP / YSFP poll and acknowledgment (the reflector echoes its own room name, not the client’s callsign)
  • YSFU unlink/disconnect
  • YSFD data frames, including the stream-end bit
  • YSFS status query and its 42-byte reply
  • YSFO / YSFI options/info frames, which are accepted and acknowledged as control traffic but otherwise discarded

Vexillum’s YSF reflector has no module concept - every connected session shares a single room, and only one stream can be active across the whole reflector at a time.

All fields are fixed-width ASCII unless noted otherwise.

Tag Length Layout Purpose
YSFP 14 [0:4] tag YSFP, [4:14] callsign (10 bytes) Poll / login
YSFU 14 [0:4] tag YSFU, [4:14] callsign (10 bytes) Unlink / disconnect
YSFD 5 - 200 [0:4] tag YSFD, [4:] frame payload Data/voice frame
YSFS any [0:4] tag YSFS Status query
YSFO/YSFI any [0:4] tag YSFO or YSFI Options/info - acknowledged, discarded

YSFD frames carry a single stream-end flag at a fixed offset (see Stream behavior below); everything else in the frame is opaque payload as far as this reflector is concerned.

A YSFS packet of any length triggers a fixed 42-byte status reply.

Offset Bytes Field Notes
0 4 Tag ASCII YSFS
4 5 Designator 5 ASCII digits - either the configured designator, or a hash of the room name if the configured value isn’t 5 digits
9 16 Room name Uppercased, space-padded to 16 bytes
25 14 Description Space-padded to 14 bytes
39 3 Peer count ASCII digits, zero-padded, clamped to 000-999
BuildStatus("12345", "MYHUB", "Test reflector", 3)
  -> "YSFS" + "12345" + "MYHUB           " + "Test reflector" + "003"

Poll acknowledgment echoes the reflector’s name

Section titled “Poll acknowledgment echoes the reflector’s name”

Unlike every other mode documented here, a YSFP poll acknowledgment does not echo the client’s own callsign back. It echoes the reflector’s own room name instead:

Client                                   Server
  |                                        |
  | YSFP                                   |
  | callsign = client callsign             |
  |--------------------------------------->|
  |                                        |
  | YSFP                                   |
  | callsign field = reflector's room name |
  |<---------------------------------------|

A client that assumes the acknowledgment’s callsign field is its own callsign echoed back will see the reflector’s room name instead - see Common implementation mistakes.

YSFO and YSFI packets are accepted and counted as inbound control traffic, but the reflector takes no other action: no state changes, and no reply is sent. Treat these as informational frames a client may send, but should not expect a response to.

Parameter Value
Session timeout 120 seconds
Cleanup tick interval 30 seconds
Stream idle timeout 3 seconds
Session cap 4096

Follows the general session/stream lifecycle described in the reference overview. There is no per-module partitioning: all sessions share one room, and the reflector admits exactly one active stream across the entire instance at a time.

  • The first accepted YSFD frame opens the reflector’s single active stream.
  • While a stream is active, only frames from that same sender are forwarded; frames from other senders are dropped.
  • A stream ends when a YSFD frame is at least 35 bytes long and byte offset 34 has bit 0x01 set: frame[34] & 0x01 != 0. This mirrors the real YSF FICH end-of-transmission bit position, one of the few places this implementation lines up with genuine YSF framing.
  • A stream is also released if idle for 3 seconds with no new frame.
  • Accepted YSFD frames are forwarded verbatim to every other connected session. The sender never receives its own frames back.
DISCONNECTED
  |
  v
CONNECTING (sent YSFP)
  |
  v
READY (received YSFP ack)
  |
  +-- PTT active --> TRANSMITTING
  |
  +-- incoming YSFD frame --> RECEIVING

Terminal conditions: transport failure, session timeout (120 seconds without traffic), inbound YSFU, or user shutdown.

Expecting your own callsign back in the poll acknowledgment

Section titled “Expecting your own callsign back in the poll acknowledgment”

The YSFP acknowledgment’s callsign field contains the reflector’s room name, not the callsign the client sent. Code that compares the acknowledgment’s callsign field against the client’s own callsign to confirm the poll succeeded will find a mismatch on every successful poll.

Missing the frame-length guard on stream end

Section titled “Missing the frame-length guard on stream end”

The stream-end check requires the frame to be longer than 34 bytes before it inspects byte 34. A short YSFD frame can never signal stream end regardless of its content - pad accordingly if your transmission’s final frame would otherwise be shorter.

These are fire-and-forget as far as this reflector is concerned. Don’t block waiting for an acknowledgment that will never arrive.

There is no module concept in this implementation’s YSF support - every connected session, regardless of any module-like field a client might embed in its own payload, shares the same single active stream.

A poll for callsign KC1AWV:

Field Value
Tag YSFP
Callsign KC1AWV··· (space-padded to 10)

The corresponding acknowledgment, from a reflector configured with room name VEXGO:

Field Value
Tag YSFP
Callsign field VEXGO···· (reflector’s own room name, space-padded to 10)

A status reply from a reflector with designator 12345, room name MYHUB, description Test reflector, and 3 connected peers:

Field Value
Tag YSFS
Designator 12345
Room name MYHUB (padded to 16)
Description Test reflector (padded to 14)
Peer count 003

YSF is implemented as a Vexillum mode runtime (internal/modes/ysf). Its tag names and stream-end bit position follow MMDVM/YSFReflector convention; the single-room model, session timeouts, and session cap are Vexillum-specific.

  • No module or room partitioning - one shared room per instance.
  • One active stream at a time, reflector-wide.
  • No FICH parsing beyond the single stream-end bit.
  • YSFO/YSFI are acknowledged as control traffic but have no functional effect.
  1. Implement YSFP poll and confirm your client correctly reads the reflector’s room name back, not its own callsign.
  2. Implement YSFD data forwarding, including the byte-34 stream-end check.
  3. Implement YSFS status query and reply parsing.
  4. Add YSFU unlink.
  5. If your client emits YSFO/YSFI, don’t wait for a reply.
  6. Test against a running Vexillum YSF instance before assuming compatibility with other YSFReflector-family implementations.