7. Subject Area Model (APP 408)
7.1 Subject Areas
ClientSession
owns WebSocket memberships and UI state
RadioControl
owns CAT serial command state: frequency, mode, PTT, gains, filter
ScopeSystem
owns FT4222 SPI data intake + S-meter fallback generation
AudioSystem
owns PyAudio capture/playback, Opus codec, WS audio fan-out
SpectrumDisplay
owns FFT data, waterfall rendering, S-meter smoothing, frequency scale
RadioState
owns all mirrored radio state with dirty-field change tracking
PollingSystem
owns 7-task adaptive background polling cadence
OperationalConfig
owns serial port, web port, auth, host/port config
7.2 Entity Definitions
| Entity | Attributes | Description |
|---|---|---|
| ClientSession | websocket, channel_type, connected_at | Runtime connection in ctrl_clients, spectrum_clients, audio_rx_clients, audio_tx_clients |
| RadioConnection | serial_port, baudrate, connected, model_id | CAT serial port state within CatController |
| RadioState | vfo_a_freq, vfo_b_freq, active_vfo, mode, tx_status, s_meter, af_gain, rf_gain, rf_power, filter_width, preamp, attenuator, noise_blanker, noise_reduction, auto_notch, compressor, compressor_level, nr_level, nb_level, tuner_status, power_on, squelch, mic_gain, split, vox, break_in, comp_meter, alc_meter, power_meter, swr_meter, id_meter, vd_meter, scope_span, scope_speed, scope_mode, scope_start_freq, serial_connected | Dataclass with dirty-field tracking |
| CatCommand | prefix, value, response | Serial CAT command: send "FA014200000;" → receive "FA014200000;" |
| ScopeFrame | wf1[850], wf2[850], s_meter, vfoa_freq, mode, scope_span, scope_mode, preamp, attenuator, scope_start_freq | Parsed from scope_pipe stdout payload |
| SpectrumFrame | version_byte, wf1_bytes[850], wf2_bytes[850] | Binary frame broadcast via /WSspectrum |
| AudioChunk | pcm_bytes, sample_count, timestamp | Raw Int16 PCM from PyAudio capture |
| AudioFrame | tag_byte, payload_bytes | Tagged dual-codec frame (0x00=PCM, 0x01=Opus) broadcast via /WSaudioRX |
| OpusEncoder | bitrate, frame_size, cap_bytes | Server-side libopus encoder via ctypes |
| OpusDecoder | sample_rate, channels | WASM Opus decoder in browser |
| PollTier | interval, commands, fields | One tier of the 7-task polling scheduler |
| MemoryChannel | index, frequency, mode, label | Memory record persisted in mem_channels.json |
| AuthToken | token_hex, created_at | 32-byte random hex session token |
| SCOPE_PIPE_Process | pid, stdout, stderr | Subprocess running scope_pipe.py for FT4222 SPI I/O |
7.3 Relationships
| Relationship | Cardinality | Description |
|---|---|---|
| ClientSession → RadioState | N:1 | Multiple browsers see same state via broadcast |
| CatCommand → RadioState | 1:1 | Each CAT response updates one or more state fields |
| ScopeFrame → SpectrumFrame | 1:1 | Each parsed scope frame produces one spectrum frame |
| AudioChunk → AudioFrame | 1:N | One PCM chunk may produce multiple Opus frames (20ms boundaries) |
| RadioState → ClientSession | 1:N | Dirty-field state updates fan out to all ctrl_clients |
| PollTier → CatCommand | 1:N | Each tier sends multiple CAT queries per cycle |
7.4 State Ownership
| State | Owner | Persistence |
|---|---|---|
| Connected WebSockets | server.py global sets |
Runtime only |
| Radio state | RadioState dataclass |
Runtime only |
| CAT connection | CatController instance |
Runtime only |
| Scope data | ScopeHandler instance |
Runtime only |
| Audio streams | AudioHandler instance |
Runtime only |
| Poll schedule | PollScheduler instance |
Runtime only |
| Memory channels | /api/mem_channels + mem_channels.json |
Filesystem (JSON) |
| Auth tokens | _auth_tokens set |
Runtime only (cleared on restart) |
| UI state | radioState object, DOM |
Browser session/cookies |
| Waterfall pixels | Canvas image data | Browser runtime only |