10. Service Model (ART 0582)
10.1 Service Portfolio
| Service |
Type |
Status |
Responsibility |
| StaticUIService |
Core |
Implemented |
Serve mobile UI assets from static/ with MIME types |
| ControlService |
Core |
Implemented |
/WSradio JSON command dispatch, state broadcast, memory management |
| BackendFactoryService |
Core |
Implemented |
create_backend(model) selects ft710/ic7300/ic7300mk2 based on MRRC_RADIO_MODEL |
| RXAudioService |
Core |
Implemented |
Capture radio USB audio → Opus encode → /WSaudioRX tagged frame broadcast (per-backend sample rate) |
| TXAudioService |
Core |
Implemented |
Receive /WSaudioTX tagged frames → Opus decode → resample if needed → PyAudio → radio |
| SpectrumService |
Core |
Implemented |
Real scope data (FT4222 SPI or CI-V 0x27) + S-meter fallback → /WSspectrum binary broadcast |
| CATSerialService |
Core |
Implemented |
Yaesu ASCII-CAT transport (FT-710 verified path; also the basis for the backends/yaesu/ core) over the USB Enhanced COM Port (38400, 8N1) |
| CIVSerialService |
Core |
Implemented |
|
| YaesuCatService |
Core |
Implemented |
FTDX10/FTDX101D/FTDX101MP/FTX-1F/FT-891: shared profile-driven ASCII-CAT core (backends/yaesu/) — transport ported from the verified FT-710 path, per-model tables with provenance; TX gated while unverified, no scope stream (S-meter fallback) |
| PollingService |
Core |
Implemented |
7-task adaptive background polling with priority-command yield |
| ScopePipeService |
Core |
Implemented |
Manage scope_pipe subprocess lifecycle; read stdout/stderr |
| MemoryChannelService |
Core |
Implemented |
/api/mem_channels GET/POST with JSON persistence |
| ATR1000Service |
Optional |
Implemented |
/WSatr1000 Browser↔︎Server: optional external-tuner state + tune assist, token-gated, closed when disabled |
| AuthService |
Support |
Implemented |
Password login, session tokens, cookie management, WS gating. WS/HTTP tokens resolve as Authorization: Bearer → mrrc_auth cookie → deprecated ?token= (AD-024) |
| StatusService |
Support |
Implemented |
/api/status full radio state JSON |
| ProcessService |
Support |
Implemented |
start.sh / stop.sh background service management, PID file |
| SupportService |
Support |
Implemented |
/api/support/{bundle,upload,save}: server-built, allow-list-redacted diagnostics bundle (logs + redacted config + env/radio/audio snapshot) plus the report loop (upload to the dedicated receiver, or save locally); see AD-021 |
10.2 Service Dependencies
ControlService
→ BackendFactoryService → CATSerialService / CIVSerialService
→ PollingService
RXAudioService
→ AudioHandler (PyAudio capture + Opus encode)
TXAudioService
→ AudioHandler (Opus decode + PyAudio playback)
SpectrumService
→ ScopePipeService (FT-710 FT4222 path)
→ CIVScopeService (IC-7300 0x27 path)
→ YaesuCatService (FTDX10/FTDX101D/FTDX101MP/FTX-1F/FT-891 ASCII-CAT — no scope producer, so the fallback below is the only spectrum path)
→ PollingService (S-meter fallback path)
PollingService
→ backend serial service (CAT or CI-V)
→ RadioState
StaticUIService
→ browser runtime
AuthService
→ all WebSocket endpoints (token resolved by `_token_from_ws_handshake`, AD-024)
→ all HTTP routes (cookie-based middleware)
10.3 Service Interfaces
| Service |
Input |
Output |
Protocol |
| ControlService |
JSON commands |
JSON state updates |
WS /WSradio |
| RXAudioService |
PyAudio PCM chunks |
Tagged binary frames (Opus/PCM) |
WS /WSaudioRX |
| TXAudioService |
Tagged binary frames + text control |
PyAudio playback |
WS /WSaudioTX |
| SpectrumService |
ScopeFrame or RadioState |
Binary spectrum frames (v1/v2) |
WS /WSspectrum |
| BackendFactoryService |
MRRC_RADIO_MODEL env var |
RadioBackend instance + RadioCapabilities |
Import-time factory |
| CATSerialService |
Command strings |
Response strings |
Serial (38400,8N1) Yaesu CAT |
| CIVSerialService |
CI-V command frames |
CI-V response frames |
Serial (115200,8N1) Icom CI-V |
| MemoryChannelService |
JSON array |
JSON array + broadcast |
HTTP /api/mem_channels |
| AuthService |
Password + request |
Cookie + token + redirect |
HTTP /api/auth/* |
| StatusService |
GET request |
Full radio state JSON (50+ fields) |
HTTP /api/status |
| SupportService |
POST + JSON body |
Bundle id/listing, receiver id, local path |
HTTP /api/support/bundle, /api/support/upload, /api/support/save |
| ATR1000Service |
JSON atrTune / ping |
JSON atrState / atrTuneResult / pong |
WS /WSatr1000 |
10.3.1 Cloud Hub 前置能力新增的接口(2026-09-30)
GET /api/session_metrics —— 会话遥测(AD-023):并发 Listener 数、上行占用、丢帧与解码失败计数。 用途是给 Hub 侧容量决策提供真实数据(RX 扇出的触发器 AD-H12 依赖它)。 经云端入口访问时,前缀由 FT710Settings.basePath 决定,调用方不得硬编码根路径。
鉴权沿用既有会话机制,但令牌不得出现在查询串(AD-024):改用 Cookie 或 Authorization: Bearer。
10.4 Control Service Command Contract
Key commands (see _execute_set_command in server.py and the active backend for complete mapping):
| Command Field |
Values |
CAT Command |
Notes |
freq / vfo_a_freq |
Hz int |
FA<9d>; |
Set VFO-A frequency |
vfo_b_freq |
Hz int |
FB<9d>; |
Set VFO-B frequency |
mode |
“USB”,“LSB”,… |
MD0<X>; |
Set operating mode |
ptt |
true/false |
TX1; / TX0; |
Priority command path; preempts poll queries |
tune |
true/false |
TX2; + AC003; / AC000; + TX0; |
Tune carrier + tuner start/stop sequence |
filter / filter_width |
00–23 |
<prefix><NN>; |
Filter width index. The prefix is YaesuModelProfile.filter_width_prefix = "SH" + P1 (0 = main VFO) + P2 (bandwidth on): SH00 for the FT-710 and the FTDX10/FTDX101/FTX-1 family, SH01 for the FT-891 (Hamlib newcat.c:9658-9663, int on = is_ft891). The 3-character SH0NN form — a missing P1/P2 digit — is silently ignored by the radio. Post-set SH0; read-back (~150 ms) broadcasts the radio’s actual index; it takes the trailing two digits, so it parses both prefixes |
af_gain |
0–255 |
AG0<NNN>; |
AF gain |
rf_gain |
0–255 |
RG0<NNN>; |
RF gain |
meter_display |
0–5 |
MS<P1>0; |
Radio front-panel meter selection |
amc_level |
1–100 |
AO<NNN>; |
AMC output level |
rf_power |
5–100 |
PC<NNN>; |
RF power |
preamp |
0,1,2 |
PA0<N>; |
OFF/AMP1/AMP2 |
att / attenuator |
0,1,2,3 |
RA0<N>; |
OFF/6dB/12dB/18dB |
nr / noise_reduction |
true/false |
NR0<0/1>; |
Noise reduction toggle |
nb / noise_blanker |
true/false |
NB0<0/1>; |
Noise blanker toggle |
an / auto_notch |
true/false |
BC0<0/1>; |
Auto notch toggle |
comp / compressor |
true/false |
PR0<0/1>; |
Compressor toggle |
tuner |
0,1,2 |
AC000; / AC001; / AC003; |
ATU OFF/ON/TUNE start; mapping differs from Hamlib (AC010/AC011) — see gap-analysis §1.1 note |
vfo |
“A”,“B” |
VS0; / VS1; |
Active VFO switch |
split |
true/false |
ST<0/1>; |
Split operation |
power |
true / false / "restart" / "cancelRescue" |
PS1; / PS0; |
false = 关机并保持关闭(先取消任何救援,绝不发 PS1);"restart" = 关机后由 _power_rescue() 持续尝试唤醒(每 30 s 一轮、上限 15 min、可取消,每轮复用 _power_on_radio());"cancelRescue" = 只停救援、不碰电台;true = 单次开机尝试(维护脚本/老客户端,语义未变)。Guards(V2.13 的实测结论,逐条保留):PS1 后 15 s 启动窗口内拒绝 PS0(带剩余秒数);PS1 ≤3 次并由 FA; / CI-V 回读校验;PS0 双发;发射中拒绝(radio.is_transmitting 或 FT8 的 _ft8_transmitting());端口未连接时救援不写、等 watchdog 重连。PS; 仍在 Tier 3 轮询供 power_on |
band |
“20m”,“40m”,… |
BS<NN>; |
Band stacking register |
scope_span |
0–9 |
SS05<NN>; |
Scope span index |
scope_speed |
0–5 |
SS00<NN>; |
Scope sweep speed |
scope_mode |
0–9 |
SS06<NN>; |
Scope display mode |
The table above shows the FT-710 backend mapping. The IC-7300/MK2 backend exposes the same WebSocket fields but translates them inside backends/ic7300/civ_controller.py to CI-V framed commands (e.g., frequency set via 0x05 BCD, mode set via 0x06, PTT via 0x1C 0x00). The frontend discovers the available bands, modes, filters, and meter labels from fullState.capabilities rather than hardcoding them.
10.5 Service Quality Targets
| Service |
Quality Target |
| ControlService |
PTT/TUNE commands bypass queued polls and execute with low latency |
| RXAudioService |
Continuous playback under LAN jitter; Opus 64kbps default |
| TXAudioService |
Low-latency mic → radio path (< 500ms) |
| SpectrumService |
Ticks 30 Hz; real scope ~11 fps, fallback ~30 fps; per-socket tier picks 1701B or 851B and the divider (AD-025); identical binary format on both paths |
| CATSerialService |
Serial lock prevents interleaved commands; timeout 3s |
| AuthService |
30-day session; all WS endpoints gated; redirect on expiry |