How FT HAM Really Works with FT8 & FT4
This page describes how FT HAM actually implements FT8 and FT4. It is not a generic protocol overview, but a precise description of the QSO engine used by the app.
Scope and Authority
Everything described here reflects real FT HAM behavior. If this document and the code ever disagree, the code wins.
FT HAM Design Principles
- Explicit finite state machine — no inferred transitions
- One active DX per QSO (strict callsign locking)
- RX and TX symmetrically advance state
- Retries repeat the same semantic message
- RR73 always terminates the QSO
- Final 73 is etiquette-only
- Measured SNR and reported SNR are tracked independently
- FT8 and FT4 share identical logic, only timing differs
Real FT8 QSO Examples
These examples show exactly how FT HAM expects FT8 QSOs to unfold on-air.
Clean QSO — Ideal Conditions
CQ EA4IQL IN80
EA1ABC EA4IQL IN73
EA4IQL EA1ABC +05
EA1ABC EA4IQL R+03
EA4IQL EA1ABC RR73
Once RR73 is sent or received, FT HAM immediately completes the QSO.
Weak Signal — Retries and QSB
CQ EA4IQL IN80
EA1ABC EA4IQL IN73
EA4IQL EA1ABC +02
EA4IQL EA1ABC +02
EA1ABC EA4IQL R-01
EA4IQL EA1ABC RR73
Repeating the same message avoids ambiguous state transitions and keeps both stations synchronized.
Message Semantics (FT8MessageComposer)
| Index | Generated Message | Actual FT8 Usage |
|---|---|---|
| 0 | CQ DE GRID | General CQ (only to initiate CQ) |
| 1 | DX DE GRID | Response to CQ from DX |
| 2 | DX DE +SNR | Sending signal report |
| 3 | DX DE R+SNR | ACK of report received |
| 4 | DX DE RRR | Final confirmation (QSO still active) |
| 5 | DX DE 73 | Courtesy-only QSO closure |
RRR and 73 are different messages. +SNR and R+SNR are never used together.
Correct FT8 Flow (WSJT-X Compatible)
Case A — You Call CQ
DX: CQ DXCALL GRID
YOU: DX TU GRID
DX: TU DX +SNR
YOU: DX TU R+SNR
DX: TU DX RRR
YOU: DX TU 73
Case B — DX Calls You
DX: DX TU GRID
YOU: DX TU +SNR
DX: TU DX R+SNR
YOU: DX TU RRR
DX: TU DX 73
- +SNR and R+SNR are mutually exclusive
- RRR is only sent by the station replying to a report
3️⃣ Message Matching Logic
| QSO State | RX Message | Action |
|---|---|---|
| idle | CQ DX GRID | reply → [1] |
| idle | DX TU GRID | reply → [2] |
| waitingForReply | DX TU +SNR | select [3] |
| waitingForReply | DX TU R+SNR | select [4] |
| waitingForRRR | DX TU RRR | select [5] |
| waitingForRRR | DX TU 73 | complete QSO |
This table ensures the matcher does not confuse acknowledgements or assume a strictly linear flow.
4️⃣ State × Message Table
| Current State | Expected RX | Extra Conditions | Action | New State |
|---|---|---|---|---|
| idle | .cq | message.allowsReply | select TX1 (Grid) | waitingForReply(dx) |
| idle | .gridExchange | message.forMe | select TX2 (Report) | waitingForRRR(dx) |
| calling(dx) | (none) | (no RX) | — | waitingForReply(dx) |
| waitingForReply(dx) | .standardSignalReport | message.callsign == dx & message.forMe | select TX2 | waitingForRRR(dx) |
| waitingForReply(dx) | .rrr / .rr73 | message.callsign == dx & message.forMe | select TX3 | completed(dx) |
| sendingReport(dx) | (none) | (no RX) | — | waitingForRRR(dx) |
| waitingForRRR(dx) | .rrr | message.callsign == dx & message.forMe | select TX3 | completed(dx) |
| waitingForRRR(dx) | .rr73 | message.callsign == dx & message.forMe | no TX | completed(dx) |
| waitingForRRR(dx) | .final73 | message.callsign == dx & message.forMe | no TX | completed(dx) |
FT8 does not require always sending a final 73.
Frequently Asked Questions
Conclusion
FT HAM implements FT8 and FT4 as strict, deterministic protocols. This behavior is intentional, compatible with WSJT-X practice, and safe to use as an implementation reference.