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
|
#!/usr/bin/env python3
"""Offline unit tests for BayComKissBackend (no kernel hardware)."""
from __future__ import annotations
import os
import sys
from pathlib import Path
from unittest.mock import patch
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "stacks" / "daemon"))
from device_backends import BayComKissBackend, DeviceBackendConfig # noqa: E402
from ax25_codec import ax25_build_ui, ax25_parse_ui # noqa: E402
from kiss_bridge import KissDecoder, format_rx_line, kiss_data_frame # noqa: E402
def test_baycom_kiss_default_link() -> None:
cfg = DeviceBackendConfig(device_id="baycom-ser12", backend_type="baycom-kiss", baycom_modem="a")
backend = BayComKissBackend(cfg, on_rx=lambda _l: None)
assert backend._path in ("/var/run/baycom-pr/kiss", f"/var/run/baycom-pr/kiss-a")
assert backend.backend_type == "baycom-kiss"
assert backend._is_pty is True
def test_baycom_kiss_transmit_kiss_frame() -> None:
cfg = DeviceBackendConfig(
device_id="baycom-ser12",
backend_type="baycom-kiss",
kiss_link="/var/run/baycom-pr/kiss",
)
backend = BayComKissBackend(cfg, on_rx=lambda _l: None)
backend._fd = 99
backend._kiss_active = True
written: list[bytes] = []
with patch("os.write", side_effect=lambda _fd, data: written.append(data) or len(data)):
with patch("termios.tcdrain"):
ok, display = backend.transmit("CB-0", "QST", "hello", ax25_ui=True)
assert ok, display
assert written and written[0].startswith(b"\xc0")
assert "hello" in display
def test_baycom_kiss_rx_decode_path() -> None:
"""RX path: KISS bytes → AX.25 UI → on_rx line (same decoder as _rx_loop)."""
rx_lines: list[str] = []
frame = ax25_build_ui("REMOTE-0", "CB-0", b"73")
pkt = kiss_data_frame(0, frame)
decoder = KissDecoder()
for _port, payload in decoder.feed(pkt):
parsed = ax25_parse_ui(payload)
assert parsed is not None
src, dst, info = parsed
assert src == "REMOTE"
assert dst == "CB"
assert info == b"73"
from kiss_bridge import format_rx_line
rx_lines.append(format_rx_line(src, dst, info, ax25_ui=True))
assert rx_lines and "73" in rx_lines[0]
def test_baycom_kiss_modem_b_link() -> None:
cfg = DeviceBackendConfig(
device_id="baycom-b",
backend_type="baycom-kiss",
baycom_modem="b",
kiss_link="/var/run/baycom-pr/kiss-b",
)
backend = BayComKissBackend(cfg, on_rx=lambda _l: None)
assert backend._path == "/var/run/baycom-pr/kiss-b"
def test_baycom_kiss_open_missing_path() -> None:
backend = BayComKissBackend(
DeviceBackendConfig(device_id="baycom-ser12", kiss_link="/nonexistent/kiss/path"),
on_rx=lambda _l: None,
)
assert not backend.open()
assert backend.status == "error-no-device"
def main() -> int:
test_baycom_kiss_default_link()
test_baycom_kiss_modem_b_link()
test_baycom_kiss_transmit_kiss_frame()
test_baycom_kiss_rx_decode_path()
test_baycom_kiss_open_missing_path()
print("OK: baycom backend tests")
return 0
if __name__ == "__main__":
sys.exit(main())
|