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.
Status
Section titled “Status”| Field | Value |
|---|---|
| Transport | UDP only |
| Default listen port | 42000 |
| Authentication | None |
| Default designator | 12345 |
Design overview
Section titled “Design overview”A client should handle:
YSFP/YSFPpoll and acknowledgment (the reflector echoes its own room name, not the client’s callsign)YSFUunlink/disconnectYSFDdata frames, including the stream-end bitYSFSstatus query and its 42-byte replyYSFO/YSFIoptions/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.
Packet format
Section titled “Packet format”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.
Status query and reply
Section titled “Status query and reply”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 |
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:
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.
Options and info frames
Section titled “Options and info frames”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.
Session behavior
Section titled “Session behavior”| 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.
Stream behavior and ending a transmission
Section titled “Stream behavior and ending a transmission”- The first accepted
YSFDframe 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
YSFDframe is at least 35 bytes long and byte offset34has bit0x01set: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
YSFDframes are forwarded verbatim to every other connected session. The sender never receives its own frames back.
Minimal client state machine
Section titled “Minimal client state machine”Terminal conditions: transport failure, session timeout (120 seconds without
traffic), inbound YSFU, or user shutdown.
Common implementation mistakes
Section titled “Common implementation mistakes”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.
Expecting a reply to YSFO/YSFI
Section titled “Expecting a reply to YSFO/YSFI”These are fire-and-forget as far as this reflector is concerned. Don’t block waiting for an acknowledgment that will never arrive.
Assuming per-module isolation
Section titled “Assuming per-module isolation”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.
Example packet values
Section titled “Example packet values”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 |
Relationship to Vexillum
Section titled “Relationship to Vexillum”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.
Current limitations
Section titled “Current limitations”- 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/YSFIare acknowledged as control traffic but have no functional effect.
Development recommendations
Section titled “Development recommendations”- Implement
YSFPpoll and confirm your client correctly reads the reflector’s room name back, not its own callsign. - Implement
YSFDdata forwarding, including the byte-34 stream-end check. - Implement
YSFSstatus query and reply parsing. - Add
YSFUunlink. - If your client emits
YSFO/YSFI, don’t wait for a reply. - Test against a running Vexillum YSF instance before assuming compatibility with other YSFReflector-family implementations.