summaryrefslogtreecommitdiff
path: root/stacks/crdop/docs/HOST-PROTOCOL-SPEC.md
blob: d45c7e5871b52274b31e6d29d966c24c26c66ea1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# M25 SoftModem host protocol — implementation spec (frozen for v1.0.0)

**CRDOP** = **MAX25-SoftModem** · Native host wire for MAX25-SoftModem · **Not** ARDOP FEC/ARQ.

**Normative code:** `stacks/crdop/lib/m25_host_protocol.py` · **Consumer:** `max25d` `CrdopTcpBackend`, `audio-dummyd`, `crdopc` launcher.

---

## Transport

| Channel | Default port | Wire |
|---------|--------------|------|
| **Control** | **8515** | Line-oriented ASCII, **`\n`** terminated (native) |
| **Data** | **8516** (= ctrl + 1) | Binary AX.25 UI body **without** HDLC flags or FCS |

| Mode | Control terminator | Data semantics |
|------|-------------------|----------------|
| **Native M25/KISS** | `\n` | KISS DATA equivalent — 16+ byte UI body |

### Bench alternate ports

When `soft-crdop` and `audio-dummyd` run on one host, bench daemon may use **8520/8521** via CLI. Production `crdopc` and INI default **8515/8516**.

---

## Control commands (native)

All commands are single lines. Reply is one line ending `\n`.

| Command | Args | Reply | Behaviour |
|---------|------|-------|-----------|
| `INITIALIZE` | — | `OK` | Reset session state |
| `PROTOCOLMODE` | `KISS` | `OK` | Select KISS-semantics data channel |
| `MYCALL` | `CALL-SSID` | `OK` | Store station ID (uppercase) |
| `LISTEN` | `TRUE`/`FALSE` | `OK` | RX enable (default true) |
| `PING` | — | `OK` | Liveness |
| `STATUS` | — | `STATUS ready mycall=…` | State snapshot |
| *(unknown)* | — | `ERR unknown command` | |

**Not supported on native path:** `PROTOCOLMODE FEC`, `FECMODE`, ARQ bandwidth commands — ARDOP is a separate optional plugin, not part of CRDOP.

---

## Data channel

### TX (host → modem)

1. TCP connect to data port.
2. Send **one** AX.25 UI frame body: `dest(7) + src(7) + ctrl(1) + pid(1) + info(0..256)`.
3. Modem responds `OK` or `ERR …` (ASCII line).

Modem builds on-air: HDLC flags, bit-stuffing, frequency-toggle line code, AFSK PHY — see `acoustic_engine.encode_ax25_ui()`.

### RX (modem → host)

Native bench: optional `STATUS` lines on control channel. Production: `max25d` parses demodulated UI and displays `[CRDOP AX25 UI src>dst] text`.

---

## max25d integration

```ini
[devices]
soft-crdop = crdop:default

[device.soft-crdop]
host = 127.0.0.1
port = 8515
listen = yes
```

`CrdopTcpBackend` on `open()`:

1. TCP connect `host:port` (ctrl), `host:port+1` (data).
2. Send `INITIALIZE`, `PROTOCOLMODE KISS`, `MYCALL …`, `LISTEN TRUE` (each `\n`).

---

## Layer separation

| Layer | On data TCP | On air |
|-------|-------------|--------|
| AX.25 UI body | ✅ | Inside HDLC |
| HDLC + CRC-16 | ❌ | ✅ |
| Bell 202 AFSK | ❌ | ✅ |

Same rule as KISS `0x00` DATA frames in `kiss_bridge.py`.

---

## Compliance tests

| Test | Command |
|------|---------|
| Unit | `pytest stacks/daemon/test_crdop_backend.py` |
| Bench host | `python3 stacks/crdop/tools/audio-dummyd.py --ctrl-port 8515 --data-port 8516` |
| Loopback DSP | `pytest stacks/crdop/test_bell202_line_code.py` |

---

## Version

Frozen for **MAX25-Stack v1.0.0** (dev track `CUR999`). Changes require bump in this file + `PROTOCOL.md` + `test_crdop_backend.py`.
git clone -b <branch> https://cgit.mode42.com/<repo>.git
git clone -b <branch> git://cgit.mode42.com/<repo>.git

info@mode42.com