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)

鉴权沿用既有会话机制,但令牌不得出现在查询串(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